diff options
author | Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> | 2007-09-30 15:36:00 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-10-12 18:43:37 -0400 |
commit | c0bb87f7b8a145b56d45484713e1b1f37ce7e626 (patch) | |
tree | ab990d6b3b3205280ea04e90a1facda05288bca3 /arch/arm/mach-ns9xxx/time.c | |
parent | cef5975d453bbc1bbf29ceb7d80749feebc22a74 (diff) |
[ARM] 4593/1: ns9xxx: implement generic clockevents
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.c | 150 |
1 files changed, 108 insertions, 42 deletions
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c index d29345501762..6f295158b168 100644 --- a/arch/arm/mach-ns9xxx/time.c +++ b/arch/arm/mach-ns9xxx/time.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/stringify.h> | 14 | #include <linux/stringify.h> |
15 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
16 | #include <linux/clockchips.h> | ||
16 | 17 | ||
17 | #include <asm/arch-ns9xxx/regs-sys.h> | 18 | #include <asm/arch-ns9xxx/regs-sys.h> |
18 | #include <asm/arch-ns9xxx/clock.h> | 19 | #include <asm/arch-ns9xxx/clock.h> |
@@ -20,18 +21,87 @@ | |||
20 | #include <asm/arch/system.h> | 21 | #include <asm/arch/system.h> |
21 | #include "generic.h" | 22 | #include "generic.h" |
22 | 23 | ||
23 | #define TIMERCLOCKSELECT 64 | 24 | #define TIMER_CLOCKSOURCE 0 |
24 | #define TIMER_CLOCKSOURCE 1 | 25 | #define TIMER_CLOCKEVENT 1 |
26 | static u32 latch; | ||
25 | 27 | ||
26 | static irqreturn_t | 28 | static cycle_t ns9xxx_clocksource_read(void) |
27 | ns9xxx_timer_interrupt(int irq, void *dev_id) | 29 | { |
30 | return SYS_TR(TIMER_CLOCKSOURCE); | ||
31 | } | ||
32 | |||
33 | static struct clocksource ns9xxx_clocksource = { | ||
34 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE), | ||
35 | .rating = 300, | ||
36 | .read = ns9xxx_clocksource_read, | ||
37 | .mask = CLOCKSOURCE_MASK(32), | ||
38 | .shift = 20, | ||
39 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
40 | }; | ||
41 | |||
42 | static void ns9xxx_clockevent_setmode(enum clock_event_mode mode, | ||
43 | struct clock_event_device *clk) | ||
44 | { | ||
45 | u32 tc = SYS_TC(TIMER_CLOCKEVENT); | ||
46 | |||
47 | switch(mode) { | ||
48 | case CLOCK_EVT_MODE_PERIODIC: | ||
49 | SYS_TRC(TIMER_CLOCKEVENT) = latch; | ||
50 | REGSET(tc, SYS_TCx, REN, EN); | ||
51 | REGSET(tc, SYS_TCx, INTS, EN); | ||
52 | REGSET(tc, SYS_TCx, TEN, EN); | ||
53 | break; | ||
54 | |||
55 | case CLOCK_EVT_MODE_ONESHOT: | ||
56 | REGSET(tc, SYS_TCx, REN, DIS); | ||
57 | REGSET(tc, SYS_TCx, INTS, EN); | ||
58 | |||
59 | /* fall through */ | ||
60 | |||
61 | case CLOCK_EVT_MODE_UNUSED: | ||
62 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
63 | case CLOCK_EVT_MODE_RESUME: | ||
64 | default: | ||
65 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
66 | break; | ||
67 | } | ||
68 | |||
69 | SYS_TC(TIMER_CLOCKEVENT) = tc; | ||
70 | } | ||
71 | |||
72 | static int ns9xxx_clockevent_setnextevent(unsigned long evt, | ||
73 | struct clock_event_device *clk) | ||
74 | { | ||
75 | u32 tc = SYS_TC(TIMER_CLOCKEVENT); | ||
76 | |||
77 | if (REGGET(tc, SYS_TCx, TEN)) { | ||
78 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
79 | SYS_TC(TIMER_CLOCKEVENT) = tc; | ||
80 | } | ||
81 | |||
82 | REGSET(tc, SYS_TCx, TEN, EN); | ||
83 | |||
84 | SYS_TRC(TIMER_CLOCKEVENT) = evt; | ||
85 | |||
86 | SYS_TC(TIMER_CLOCKEVENT) = tc; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static struct clock_event_device ns9xxx_clockevent_device = { | ||
92 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT), | ||
93 | .shift = 20, | ||
94 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
95 | .set_mode = ns9xxx_clockevent_setmode, | ||
96 | .set_next_event = ns9xxx_clockevent_setnextevent, | ||
97 | }; | ||
98 | |||
99 | static irqreturn_t ns9xxx_clockevent_handler(int irq, void *dev_id) | ||
28 | { | 100 | { |
29 | int timerno = irq - IRQ_TIMER0; | 101 | int timerno = irq - IRQ_TIMER0; |
30 | u32 tc; | 102 | u32 tc; |
31 | 103 | ||
32 | write_seqlock(&xtime_lock); | 104 | struct clock_event_device *evt = &ns9xxx_clockevent_device; |
33 | timer_tick(); | ||
34 | write_sequnlock(&xtime_lock); | ||
35 | 105 | ||
36 | /* clear irq */ | 106 | /* clear irq */ |
37 | tc = SYS_TC(timerno); | 107 | tc = SYS_TC(timerno); |
@@ -44,50 +114,21 @@ ns9xxx_timer_interrupt(int irq, void *dev_id) | |||
44 | REGSET(tc, SYS_TCx, INTC, UNSET); | 114 | REGSET(tc, SYS_TCx, INTC, UNSET); |
45 | SYS_TC(timerno) = tc; | 115 | SYS_TC(timerno) = tc; |
46 | 116 | ||
47 | return IRQ_HANDLED; | 117 | evt->event_handler(evt); |
48 | } | ||
49 | |||
50 | static struct irqaction ns9xxx_timer_irq = { | ||
51 | .name = "NS9xxx Timer Tick", | ||
52 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | ||
53 | .handler = ns9xxx_timer_interrupt, | ||
54 | }; | ||
55 | 118 | ||
56 | static cycle_t ns9xxx_clocksource_read(void) | 119 | return IRQ_HANDLED; |
57 | { | ||
58 | return SYS_TR(TIMER_CLOCKSOURCE); | ||
59 | } | 120 | } |
60 | 121 | ||
61 | static struct clocksource ns9xxx_clocksource = { | 122 | static struct irqaction ns9xxx_clockevent_action = { |
62 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE), | 123 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT), |
63 | .rating = 300, | 124 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
64 | .read = ns9xxx_clocksource_read, | 125 | .handler = ns9xxx_clockevent_handler, |
65 | .mask = CLOCKSOURCE_MASK(32), | ||
66 | .shift = 20, | ||
67 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
68 | }; | 126 | }; |
69 | 127 | ||
70 | static void __init ns9xxx_timer_init(void) | 128 | static void __init ns9xxx_timer_init(void) |
71 | { | 129 | { |
72 | int tc; | 130 | int tc; |
73 | 131 | ||
74 | /* disable timer */ | ||
75 | if ((tc = SYS_TC(0)) & SYS_TCx_TEN) | ||
76 | SYS_TC(0) = tc & ~SYS_TCx_TEN; | ||
77 | |||
78 | SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0); | ||
79 | |||
80 | REGSET(tc, SYS_TCx, TEN, EN); | ||
81 | REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */ | ||
82 | REGSET(tc, SYS_TCx, INTS, EN); | ||
83 | REGSET(tc, SYS_TCx, UDS, DOWN); | ||
84 | REGSET(tc, SYS_TCx, TDBG, STOP); | ||
85 | REGSET(tc, SYS_TCx, TSZ, 32); | ||
86 | REGSET(tc, SYS_TCx, REN, EN); | ||
87 | SYS_TC(0) = tc; | ||
88 | |||
89 | setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); | ||
90 | |||
91 | tc = SYS_TC(TIMER_CLOCKSOURCE); | 132 | tc = SYS_TC(TIMER_CLOCKSOURCE); |
92 | if (REGGET(tc, SYS_TCx, TEN)) { | 133 | if (REGGET(tc, SYS_TCx, TEN)) { |
93 | REGSET(tc, SYS_TCx, TEN, DIS); | 134 | REGSET(tc, SYS_TCx, TEN, DIS); |
@@ -111,6 +152,31 @@ static void __init ns9xxx_timer_init(void) | |||
111 | ns9xxx_clocksource.shift); | 152 | ns9xxx_clocksource.shift); |
112 | 153 | ||
113 | clocksource_register(&ns9xxx_clocksource); | 154 | clocksource_register(&ns9xxx_clocksource); |
155 | |||
156 | latch = SH_DIV(ns9xxx_cpuclock(), HZ, 0); | ||
157 | |||
158 | tc = SYS_TC(TIMER_CLOCKEVENT); | ||
159 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
160 | REGSET(tc, SYS_TCx, TDBG, STOP); | ||
161 | REGSET(tc, SYS_TCx, TLCS, CPU); | ||
162 | REGSET(tc, SYS_TCx, TM, IEE); | ||
163 | REGSET(tc, SYS_TCx, INTS, DIS); | ||
164 | REGSET(tc, SYS_TCx, UDS, DOWN); | ||
165 | REGSET(tc, SYS_TCx, TSZ, 32); | ||
166 | REGSET(tc, SYS_TCx, REN, EN); | ||
167 | SYS_TC(TIMER_CLOCKEVENT) = tc; | ||
168 | |||
169 | ns9xxx_clockevent_device.mult = div_sc(ns9xxx_cpuclock(), | ||
170 | NSEC_PER_SEC, ns9xxx_clockevent_device.shift); | ||
171 | ns9xxx_clockevent_device.max_delta_ns = | ||
172 | clockevent_delta2ns(-1, &ns9xxx_clockevent_device); | ||
173 | ns9xxx_clockevent_device.min_delta_ns = | ||
174 | clockevent_delta2ns(1, &ns9xxx_clockevent_device); | ||
175 | |||
176 | ns9xxx_clockevent_device.cpumask = cpumask_of_cpu(0); | ||
177 | clockevents_register_device(&ns9xxx_clockevent_device); | ||
178 | |||
179 | setup_irq(IRQ_TIMER0 + TIMER_CLOCKEVENT, &ns9xxx_clockevent_action); | ||
114 | } | 180 | } |
115 | 181 | ||
116 | struct sys_timer ns9xxx_timer = { | 182 | struct sys_timer ns9xxx_timer = { |