Add a clockevent driver for i.MX systems. Signed-off-by: Luotao Fu Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/time.c | 71 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 12 deletions(-) Index: arch/arm/mach-imx/time.c =================================================================== --- a/arch/arm/mach-imx/time.c.orig +++ b/arch/arm/mach-imx/time.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,52 @@ /* Use timer 1 as system timer */ #define TIMER_BASE IMX_TIM1_BASE -static unsigned long evt_diff; +enum clock_event_mode clockevent_mode = 0; + +static void imx_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + IMX_TCMP(IMX_TIM1_BASE) = IMX_TCN(IMX_TIM1_BASE) + evt; +} + +static void imx_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_PERIODIC: + case CLOCK_EVT_ONESHOT: + IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN; + break; + + case CLOCK_EVT_SHUTDOWN: + IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN; + return; + } + + clockevent_mode = mode; +} + +static struct clock_event_device clockevent_imx = { + .name = "imx_timer1", + .capabilities = CLOCK_CAP_NEXTEVT | CLOCK_CAP_TICK | + CLOCK_CAP_UPDATE | CLOCK_CAP_PROFILE, + .shift = 32, + .set_mode = imx_set_mode, + .set_next_event = imx_set_next_event, +}; + +static int __init imx_clockevent_init(void) +{ + clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC, + clockevent_imx.shift); + clockevent_imx.max_delta_ns = + clockevent_delta2ns(0xfffffffe, &clockevent_imx); + clockevent_imx.min_delta_ns = + clockevent_delta2ns(0xf, &clockevent_imx); + register_local_clockevent(&clockevent_imx); + + return 0; +} /* * IRQ handler for the timer @@ -42,10 +88,12 @@ imx_timer_interrupt(int irq, void *dev_i if (tstat & TSTAT_COMP) { do { - write_seqlock(&xtime_lock); - timer_tick(); - write_sequnlock(&xtime_lock); - IMX_TCMP(TIMER_BASE) += evt_diff; + clockevent_imx.event_handler(); + + if (clockevent_mode != CLOCK_EVT_PERIODIC) + break; + + IMX_TCMP(TIMER_BASE) += LATCH; } while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE) - IMX_TCN(TIMER_BASE)) < 0)); @@ -70,10 +118,8 @@ static void __init imx_timer_hardware_in */ IMX_TCTL(TIMER_BASE) = 0; IMX_TPRER(TIMER_BASE) = 0; - IMX_TCMP(TIMER_BASE) = LATCH - 1; - - IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN; - evt_diff = LATCH; + IMX_TCMP(TIMER_BASE) = LATCH; + IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN | TCTL_IRQEN; } cycle_t imx_get_cycles(void) @@ -82,12 +128,12 @@ cycle_t imx_get_cycles(void) } static struct clocksource clocksource_imx = { - .name = "imx_timer1", + .name = "imx_timer1", .rating = 200, .read = imx_get_cycles, .mask = 0xFFFFFFFF, - .shift = 20, - .is_continuous = 1, + .shift = 20, + .is_continuous = 1, }; static int __init imx_clocksource_init(void) @@ -103,6 +149,7 @@ static void __init imx_timer_init(void) { imx_timer_hardware_init(); imx_clocksource_init(); + imx_clockevent_init(); /* * Make irqs happen for the system timer -- Dipl.-Ing. Sascha Hauer | http://www.pengutronix.de Pengutronix - Linux Solutions for Science and Industry Handelsregister: Amtsgericht Hildesheim, HRA 2686 Hannoversche Str. 2, 31134 Hildesheim, Germany Phone: +49-5121-206917-0 | Fax: +49-5121-206917-9 - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/