aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ns9xxx/time.c
diff options
context:
space:
mode:
authorUwe Kleine-König <ukleinek@informatik.uni-freiburg.de>2007-09-30 15:35:48 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-10-12 18:43:37 -0400
commitcef5975d453bbc1bbf29ceb7d80749feebc22a74 (patch)
tree5a433a0d1ea7730d6dffe3f5db72c866535b7d0d /arch/arm/mach-ns9xxx/time.c
parentf02e579558cf2aba06ecc7d4515661286b60f411 (diff)
[ARM] 4592/1: ns9xxx: clocksource driver
Signed-off-by: Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ns9xxx/time.c')
-rw-r--r--arch/arm/mach-ns9xxx/time.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c
index 3327d302618d..d29345501762 100644
--- a/arch/arm/mach-ns9xxx/time.c
+++ b/arch/arm/mach-ns9xxx/time.c
@@ -11,6 +11,9 @@
11#include <linux/jiffies.h> 11#include <linux/jiffies.h>
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/irq.h> 13#include <linux/irq.h>
14#include <linux/stringify.h>
15#include <linux/clocksource.h>
16
14#include <asm/arch-ns9xxx/regs-sys.h> 17#include <asm/arch-ns9xxx/regs-sys.h>
15#include <asm/arch-ns9xxx/clock.h> 18#include <asm/arch-ns9xxx/clock.h>
16#include <asm/arch-ns9xxx/irqs.h> 19#include <asm/arch-ns9xxx/irqs.h>
@@ -18,8 +21,7 @@
18#include "generic.h" 21#include "generic.h"
19 22
20#define TIMERCLOCKSELECT 64 23#define TIMERCLOCKSELECT 64
21 24#define TIMER_CLOCKSOURCE 1
22static u32 usecs_per_tick;
23 25
24static irqreturn_t 26static irqreturn_t
25ns9xxx_timer_interrupt(int irq, void *dev_id) 27ns9xxx_timer_interrupt(int irq, void *dev_id)
@@ -45,39 +47,30 @@ ns9xxx_timer_interrupt(int irq, void *dev_id)
45 return IRQ_HANDLED; 47 return IRQ_HANDLED;
46} 48}
47 49
48static unsigned long ns9xxx_timer_gettimeoffset(void)
49{
50 /* return the microseconds which have passed since the last interrupt
51 * was _serviced_. That is, if an interrupt is pending or the counter
52 * reloads, return one period more. */
53
54 u32 counter1 = SYS_TR(0);
55 int pending = SYS_ISR & (1 << IRQ_TIMER0);
56 u32 counter2 = SYS_TR(0);
57 u32 elapsed;
58
59 if (pending || counter2 > counter1)
60 elapsed = 2 * SYS_TRC(0) - counter2;
61 else
62 elapsed = SYS_TRC(0) - counter1;
63
64 return (elapsed * usecs_per_tick) >> 16;
65
66}
67
68static struct irqaction ns9xxx_timer_irq = { 50static struct irqaction ns9xxx_timer_irq = {
69 .name = "NS9xxx Timer Tick", 51 .name = "NS9xxx Timer Tick",
70 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 52 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
71 .handler = ns9xxx_timer_interrupt, 53 .handler = ns9xxx_timer_interrupt,
72}; 54};
73 55
56static cycle_t ns9xxx_clocksource_read(void)
57{
58 return SYS_TR(TIMER_CLOCKSOURCE);
59}
60
61static struct clocksource ns9xxx_clocksource = {
62 .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE),
63 .rating = 300,
64 .read = ns9xxx_clocksource_read,
65 .mask = CLOCKSOURCE_MASK(32),
66 .shift = 20,
67 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
68};
69
74static void __init ns9xxx_timer_init(void) 70static void __init ns9xxx_timer_init(void)
75{ 71{
76 int tc; 72 int tc;
77 73
78 usecs_per_tick =
79 SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16);
80
81 /* disable timer */ 74 /* disable timer */
82 if ((tc = SYS_TC(0)) & SYS_TCx_TEN) 75 if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
83 SYS_TC(0) = tc & ~SYS_TCx_TEN; 76 SYS_TC(0) = tc & ~SYS_TCx_TEN;
@@ -94,9 +87,32 @@ static void __init ns9xxx_timer_init(void)
94 SYS_TC(0) = tc; 87 SYS_TC(0) = tc;
95 88
96 setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); 89 setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq);
90
91 tc = SYS_TC(TIMER_CLOCKSOURCE);
92 if (REGGET(tc, SYS_TCx, TEN)) {
93 REGSET(tc, SYS_TCx, TEN, DIS);
94 SYS_TC(TIMER_CLOCKSOURCE) = tc;
95 }
96
97 SYS_TRC(TIMER_CLOCKSOURCE) = 0;
98
99 REGSET(tc, SYS_TCx, TEN, EN);
100 REGSET(tc, SYS_TCx, TDBG, STOP);
101 REGSET(tc, SYS_TCx, TLCS, CPU);
102 REGSET(tc, SYS_TCx, TM, IEE);
103 REGSET(tc, SYS_TCx, INTS, DIS);
104 REGSET(tc, SYS_TCx, UDS, UP);
105 REGSET(tc, SYS_TCx, TSZ, 32);
106 REGSET(tc, SYS_TCx, REN, EN);
107
108 SYS_TC(TIMER_CLOCKSOURCE) = tc;
109
110 ns9xxx_clocksource.mult = clocksource_hz2mult(ns9xxx_cpuclock(),
111 ns9xxx_clocksource.shift);
112
113 clocksource_register(&ns9xxx_clocksource);
97} 114}
98 115
99struct sys_timer ns9xxx_timer = { 116struct sys_timer ns9xxx_timer = {
100 .init = ns9xxx_timer_init, 117 .init = ns9xxx_timer_init,
101 .offset = ns9xxx_timer_gettimeoffset,
102}; 118};