aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ns9xxx
diff options
context:
space:
mode:
authorUwe Kleine-König <ukleinek@informatik.uni-freiburg.de>2007-09-30 15:36:00 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-10-12 18:43:37 -0400
commitc0bb87f7b8a145b56d45484713e1b1f37ce7e626 (patch)
treeab990d6b3b3205280ea04e90a1facda05288bca3 /arch/arm/mach-ns9xxx
parentcef5975d453bbc1bbf29ceb7d80749feebc22a74 (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')
-rw-r--r--arch/arm/mach-ns9xxx/time.c150
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
26static u32 latch;
25 27
26static irqreturn_t 28static cycle_t ns9xxx_clocksource_read(void)
27ns9xxx_timer_interrupt(int irq, void *dev_id) 29{
30 return SYS_TR(TIMER_CLOCKSOURCE);
31}
32
33static 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
42static 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
72static 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
91static 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
99static 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
50static 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
56static cycle_t ns9xxx_clocksource_read(void) 119 return IRQ_HANDLED;
57{
58 return SYS_TR(TIMER_CLOCKSOURCE);
59} 120}
60 121
61static struct clocksource ns9xxx_clocksource = { 122static 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
70static void __init ns9xxx_timer_init(void) 128static 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
116struct sys_timer ns9xxx_timer = { 182struct sys_timer ns9xxx_timer = {