2013-08-08 15:08:06 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2013 by John Crispin < blogic @ openwrt . org >
*/
# include <linux/clockchips.h>
# include <linux/clocksource.h>
# include <linux/interrupt.h>
# include <linux/reset.h>
# include <linux/init.h>
# include <linux/time.h>
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/of_address.h>
# include <asm/mach-ralink/ralink_regs.h>
# define SYSTICK_FREQ (50 * 1000)
# define SYSTICK_CONFIG 0x00
# define SYSTICK_COMPARE 0x04
# define SYSTICK_COUNT 0x08
/* route systick irq to mips irq 7 instead of the r4k-timer */
# define CFG_EXT_STK_EN 0x2
/* enable the counter */
# define CFG_CNT_EN 0x1
struct systick_device {
void __iomem * membase ;
struct clock_event_device dev ;
int irq_requested ;
int freq_scale ;
} ;
2015-07-06 14:12:03 +03:00
static int systick_set_oneshot ( struct clock_event_device * evt ) ;
static int systick_shutdown ( struct clock_event_device * evt ) ;
2013-08-08 15:08:06 +04:00
static int systick_next_event ( unsigned long delta ,
struct clock_event_device * evt )
{
struct systick_device * sdev ;
u32 count ;
sdev = container_of ( evt , struct systick_device , dev ) ;
count = ioread32 ( sdev - > membase + SYSTICK_COUNT ) ;
count = ( count + delta ) % SYSTICK_FREQ ;
2015-11-04 13:50:10 +03:00
iowrite32 ( count , sdev - > membase + SYSTICK_COMPARE ) ;
2013-08-08 15:08:06 +04:00
return 0 ;
}
static void systick_event_handler ( struct clock_event_device * dev )
{
/* noting to do here */
}
static irqreturn_t systick_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * dev = ( struct clock_event_device * ) dev_id ;
dev - > event_handler ( dev ) ;
return IRQ_HANDLED ;
}
static struct systick_device systick = {
. dev = {
/*
* cevt - r4k uses 300 , make sure systick
* gets used if available
*/
2015-07-06 14:12:03 +03:00
. rating = 310 ,
. features = CLOCK_EVT_FEAT_ONESHOT ,
. set_next_event = systick_next_event ,
. set_state_shutdown = systick_shutdown ,
. set_state_oneshot = systick_set_oneshot ,
. event_handler = systick_event_handler ,
2013-08-08 15:08:06 +04:00
} ,
} ;
static struct irqaction systick_irqaction = {
. handler = systick_interrupt ,
. flags = IRQF_PERCPU | IRQF_TIMER ,
. dev_id = & systick . dev ,
} ;
2015-07-06 14:12:03 +03:00
static int systick_shutdown ( struct clock_event_device * evt )
2013-08-08 15:08:06 +04:00
{
struct systick_device * sdev ;
sdev = container_of ( evt , struct systick_device , dev ) ;
2015-07-06 14:12:03 +03:00
if ( sdev - > irq_requested )
free_irq ( systick . dev . irq , & systick_irqaction ) ;
sdev - > irq_requested = 0 ;
iowrite32 ( 0 , systick . membase + SYSTICK_CONFIG ) ;
return 0 ;
}
static int systick_set_oneshot ( struct clock_event_device * evt )
{
struct systick_device * sdev ;
sdev = container_of ( evt , struct systick_device , dev ) ;
if ( ! sdev - > irq_requested )
setup_irq ( systick . dev . irq , & systick_irqaction ) ;
sdev - > irq_requested = 1 ;
iowrite32 ( CFG_EXT_STK_EN | CFG_CNT_EN ,
systick . membase + SYSTICK_CONFIG ) ;
return 0 ;
2013-08-08 15:08:06 +04:00
}
static void __init ralink_systick_init ( struct device_node * np )
{
systick . membase = of_iomap ( np , 0 ) ;
if ( ! systick . membase )
return ;
systick_irqaction . name = np - > name ;
systick . dev . name = np - > name ;
clockevents_calc_mult_shift ( & systick . dev , SYSTICK_FREQ , 60 ) ;
systick . dev . max_delta_ns = clockevent_delta2ns ( 0x7fff , & systick . dev ) ;
systick . dev . min_delta_ns = clockevent_delta2ns ( 0x3 , & systick . dev ) ;
systick . dev . irq = irq_of_parse_and_map ( np , 0 ) ;
if ( ! systick . dev . irq ) {
pr_err ( " %s: request_irq failed " , np - > name ) ;
return ;
}
clocksource_mmio_init ( systick . membase + SYSTICK_COUNT , np - > name ,
SYSTICK_FREQ , 301 , 16 , clocksource_mmio_readl_up ) ;
clockevents_register_device ( & systick . dev ) ;
2013-12-08 19:22:53 +04:00
pr_info ( " %s: running - mult: %d, shift: %d \n " ,
2013-08-08 15:08:06 +04:00
np - > name , systick . dev . mult , systick . dev . shift ) ;
}
CLOCKSOURCE_OF_DECLARE ( systick , " ralink,cevt-systick " , ralink_systick_init ) ;