diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2011-08-10 02:37:55 +0800 |
---|---|---|
committer | Eric Miao <eric.y.miao@gmail.com> | 2011-08-11 10:10:46 +0800 |
commit | af9dafb1dcf320a46783e09764c758bc4e32ed94 (patch) | |
tree | 36cd1fcd0ae97621f6d4d4cb02a94548677d0c8f /arch | |
parent | 71c0c341403cb141e3580817947e56a4386db4c8 (diff) |
ARM: mmp: Change the way we use timer 0 as clockevent timer.
Instead of setting up a match interrupt for 'current_time + delta'
on ->set_next_event(), program timer 0 to count down from 'delta - 1'
and trigger an interrupt when it reaches zero.
Signed-off-by: Lennert Buytenhek <buytenh@laptop.org>
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-mmp/time.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c index c53715edfa8..4e91ee6e27c 100644 --- a/arch/arm/mach-mmp/time.c +++ b/arch/arm/mach-mmp/time.c @@ -75,28 +75,51 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) { struct clock_event_device *c = dev_id; - /* disable and clear pending interrupt status */ - __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); - __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0)); + /* + * Clear pending interrupt status. + */ + __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0)); + + /* + * Disable timer 0. + */ + __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER); + c->event_handler(c); + return IRQ_HANDLED; } static int timer_set_next_event(unsigned long delta, struct clock_event_device *dev) { - unsigned long flags, next; + unsigned long flags; local_irq_save(flags); - /* clear pending interrupt status and enable */ + /* + * Disable timer 0. + */ + __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER); + + /* + * Clear and enable timer match 0 interrupt. + */ __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0)); __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0)); - next = timer_read() + delta; - __raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0)); + /* + * Setup new clockevent timer value. + */ + __raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0)); + + /* + * Enable timer 0. + */ + __raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER); local_irq_restore(flags); + return 0; } @@ -152,10 +175,10 @@ static void __init timer_config(void) (TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3)); __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR); - /* free-running mode */ - __raw_writel(0x3, TIMERS_VIRT_BASE + TMR_CMR); + /* set timer 0 to periodic mode, and timer 1 to free-running mode */ + __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR); - __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */ + __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */ __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */ __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); @@ -163,8 +186,8 @@ static void __init timer_config(void) __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1)); /* clear status */ __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1)); - /* enable timer counter */ - __raw_writel(0x3, TIMERS_VIRT_BASE + TMR_CER); + /* enable timer 1 counter */ + __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER); } static struct irqaction timer_irq = { |