diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 17:40:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 17:40:48 -0500 |
commit | e8cbce976050a9f874a8b07012ddeb9b9eb59603 (patch) | |
tree | 3660d00f49a70e20c74c3d41027ea8598ad926d7 /arch/arm/mach-msm | |
parent | b3c37522928b5452588fc202eaa0f11f6e339256 (diff) | |
parent | 27fdb577435e336e4b00b9e51626f9002b88a86c (diff) |
Merge tag 'timer' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
timer changes for msm
A very simple series. We used to have more churn in the timer
area, so this is kept separate. Will probably put this into the
drivers series next time.
* tag 'timer' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc:
msm: timer: Use clockevents_config_and_register()
msm: timer: Setup interrupt after registering clockevent
msm: timer: Remove SoC specific #ifdefs
msm: timer: Remove msm_clocks[] and simplify code
msm: timer: Fix ONESHOT mode interrupts
msm: timer: Use GPT for clockevents and DGT for clocksource
msm: timer: Cleanup #includes and #defines
msm: timer: Tighten #ifdef for local timer support
Diffstat (limited to 'arch/arm/mach-msm')
-rw-r--r-- | arch/arm/mach-msm/timer.c | 347 |
1 files changed, 124 insertions, 223 deletions
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index afeeca52fc6..11d0d8f2656 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* linux/arch/arm/mach-msm/timer.c | 1 | /* |
2 | * | 2 | * |
3 | * Copyright (C) 2007 Google, Inc. | 3 | * Copyright (C) 2007 Google, Inc. |
4 | * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. | ||
4 | * | 5 | * |
5 | * This software is licensed under the terms of the GNU General Public | 6 | * This software is licensed under the terms of the GNU General Public |
6 | * License version 2, as published by the Free Software Foundation, and | 7 | * License version 2, as published by the Free Software Foundation, and |
@@ -13,306 +14,207 @@ | |||
13 | * | 14 | * |
14 | */ | 15 | */ |
15 | 16 | ||
17 | #include <linux/clocksource.h> | ||
18 | #include <linux/clockchips.h> | ||
16 | #include <linux/init.h> | 19 | #include <linux/init.h> |
17 | #include <linux/time.h> | ||
18 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
19 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
20 | #include <linux/clk.h> | ||
21 | #include <linux/clockchips.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/io.h> | 22 | #include <linux/io.h> |
24 | 23 | ||
25 | #include <asm/mach/time.h> | 24 | #include <asm/mach/time.h> |
26 | #include <asm/hardware/gic.h> | 25 | #include <asm/hardware/gic.h> |
26 | #include <asm/localtimer.h> | ||
27 | 27 | ||
28 | #include <mach/msm_iomap.h> | 28 | #include <mach/msm_iomap.h> |
29 | #include <mach/cpu.h> | 29 | #include <mach/cpu.h> |
30 | #include <mach/board.h> | ||
30 | 31 | ||
31 | #define TIMER_MATCH_VAL 0x0000 | 32 | #define TIMER_MATCH_VAL 0x0000 |
32 | #define TIMER_COUNT_VAL 0x0004 | 33 | #define TIMER_COUNT_VAL 0x0004 |
33 | #define TIMER_ENABLE 0x0008 | 34 | #define TIMER_ENABLE 0x0008 |
34 | #define TIMER_ENABLE_CLR_ON_MATCH_EN 2 | 35 | #define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) |
35 | #define TIMER_ENABLE_EN 1 | 36 | #define TIMER_ENABLE_EN BIT(0) |
36 | #define TIMER_CLEAR 0x000C | 37 | #define TIMER_CLEAR 0x000C |
37 | #define DGT_CLK_CTL 0x0034 | 38 | #define DGT_CLK_CTL 0x0034 |
38 | enum { | 39 | #define DGT_CLK_CTL_DIV_4 0x3 |
39 | DGT_CLK_CTL_DIV_1 = 0, | ||
40 | DGT_CLK_CTL_DIV_2 = 1, | ||
41 | DGT_CLK_CTL_DIV_3 = 2, | ||
42 | DGT_CLK_CTL_DIV_4 = 3, | ||
43 | }; | ||
44 | #define CSR_PROTECTION 0x0020 | ||
45 | #define CSR_PROTECTION_EN 1 | ||
46 | 40 | ||
47 | #define GPT_HZ 32768 | 41 | #define GPT_HZ 32768 |
48 | 42 | ||
49 | enum timer_location { | 43 | #define MSM_DGT_SHIFT 5 |
50 | LOCAL_TIMER = 0, | ||
51 | GLOBAL_TIMER = 1, | ||
52 | }; | ||
53 | |||
54 | #define MSM_GLOBAL_TIMER MSM_CLOCK_DGT | ||
55 | |||
56 | /* TODO: Remove these ifdefs */ | ||
57 | #if defined(CONFIG_ARCH_QSD8X50) | ||
58 | #define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */ | ||
59 | #define MSM_DGT_SHIFT (0) | ||
60 | #elif defined(CONFIG_ARCH_MSM7X30) | ||
61 | #define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */ | ||
62 | #define MSM_DGT_SHIFT (0) | ||
63 | #elif defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) | ||
64 | #define DGT_HZ (27000000 / 4) /* 27 MHz (PXO) / 4 by default */ | ||
65 | #define MSM_DGT_SHIFT (0) | ||
66 | #else | ||
67 | #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ | ||
68 | #define MSM_DGT_SHIFT (5) | ||
69 | #endif | ||
70 | 44 | ||
71 | struct msm_clock { | 45 | static void __iomem *event_base; |
72 | struct clock_event_device clockevent; | ||
73 | struct clocksource clocksource; | ||
74 | unsigned int irq; | ||
75 | void __iomem *regbase; | ||
76 | uint32_t freq; | ||
77 | uint32_t shift; | ||
78 | void __iomem *global_counter; | ||
79 | void __iomem *local_counter; | ||
80 | union { | ||
81 | struct clock_event_device *evt; | ||
82 | struct clock_event_device __percpu **percpu_evt; | ||
83 | }; | ||
84 | }; | ||
85 | |||
86 | enum { | ||
87 | MSM_CLOCK_GPT, | ||
88 | MSM_CLOCK_DGT, | ||
89 | NR_TIMERS, | ||
90 | }; | ||
91 | |||
92 | |||
93 | static struct msm_clock msm_clocks[]; | ||
94 | 46 | ||
95 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) | 47 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) |
96 | { | 48 | { |
97 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | 49 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; |
98 | if (evt->event_handler == NULL) | 50 | /* Stop the timer tick */ |
99 | return IRQ_HANDLED; | 51 | if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { |
52 | u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); | ||
53 | ctrl &= ~TIMER_ENABLE_EN; | ||
54 | writel_relaxed(ctrl, event_base + TIMER_ENABLE); | ||
55 | } | ||
100 | evt->event_handler(evt); | 56 | evt->event_handler(evt); |
101 | return IRQ_HANDLED; | 57 | return IRQ_HANDLED; |
102 | } | 58 | } |
103 | 59 | ||
104 | static cycle_t msm_read_timer_count(struct clocksource *cs) | ||
105 | { | ||
106 | struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource); | ||
107 | |||
108 | /* | ||
109 | * Shift timer count down by a constant due to unreliable lower bits | ||
110 | * on some targets. | ||
111 | */ | ||
112 | return readl(clk->global_counter) >> clk->shift; | ||
113 | } | ||
114 | |||
115 | static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt) | ||
116 | { | ||
117 | #ifdef CONFIG_SMP | ||
118 | int i; | ||
119 | for (i = 0; i < NR_TIMERS; i++) | ||
120 | if (evt == &(msm_clocks[i].clockevent)) | ||
121 | return &msm_clocks[i]; | ||
122 | return &msm_clocks[MSM_GLOBAL_TIMER]; | ||
123 | #else | ||
124 | return container_of(evt, struct msm_clock, clockevent); | ||
125 | #endif | ||
126 | } | ||
127 | |||
128 | static int msm_timer_set_next_event(unsigned long cycles, | 60 | static int msm_timer_set_next_event(unsigned long cycles, |
129 | struct clock_event_device *evt) | 61 | struct clock_event_device *evt) |
130 | { | 62 | { |
131 | struct msm_clock *clock = clockevent_to_clock(evt); | 63 | u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); |
132 | uint32_t now = readl(clock->local_counter); | ||
133 | uint32_t alarm = now + (cycles << clock->shift); | ||
134 | 64 | ||
135 | writel(alarm, clock->regbase + TIMER_MATCH_VAL); | 65 | writel_relaxed(0, event_base + TIMER_CLEAR); |
66 | writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); | ||
67 | writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); | ||
136 | return 0; | 68 | return 0; |
137 | } | 69 | } |
138 | 70 | ||
139 | static void msm_timer_set_mode(enum clock_event_mode mode, | 71 | static void msm_timer_set_mode(enum clock_event_mode mode, |
140 | struct clock_event_device *evt) | 72 | struct clock_event_device *evt) |
141 | { | 73 | { |
142 | struct msm_clock *clock = clockevent_to_clock(evt); | 74 | u32 ctrl; |
75 | |||
76 | ctrl = readl_relaxed(event_base + TIMER_ENABLE); | ||
77 | ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); | ||
143 | 78 | ||
144 | switch (mode) { | 79 | switch (mode) { |
145 | case CLOCK_EVT_MODE_RESUME: | 80 | case CLOCK_EVT_MODE_RESUME: |
146 | case CLOCK_EVT_MODE_PERIODIC: | 81 | case CLOCK_EVT_MODE_PERIODIC: |
147 | break; | 82 | break; |
148 | case CLOCK_EVT_MODE_ONESHOT: | 83 | case CLOCK_EVT_MODE_ONESHOT: |
149 | writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); | 84 | /* Timer is enabled in set_next_event */ |
150 | break; | 85 | break; |
151 | case CLOCK_EVT_MODE_UNUSED: | 86 | case CLOCK_EVT_MODE_UNUSED: |
152 | case CLOCK_EVT_MODE_SHUTDOWN: | 87 | case CLOCK_EVT_MODE_SHUTDOWN: |
153 | writel(0, clock->regbase + TIMER_ENABLE); | ||
154 | break; | 88 | break; |
155 | } | 89 | } |
90 | writel_relaxed(ctrl, event_base + TIMER_ENABLE); | ||
156 | } | 91 | } |
157 | 92 | ||
158 | static struct msm_clock msm_clocks[] = { | 93 | static struct clock_event_device msm_clockevent = { |
159 | [MSM_CLOCK_GPT] = { | 94 | .name = "gp_timer", |
160 | .clockevent = { | 95 | .features = CLOCK_EVT_FEAT_ONESHOT, |
161 | .name = "gp_timer", | 96 | .rating = 200, |
162 | .features = CLOCK_EVT_FEAT_ONESHOT, | 97 | .set_next_event = msm_timer_set_next_event, |
163 | .shift = 32, | 98 | .set_mode = msm_timer_set_mode, |
164 | .rating = 200, | 99 | }; |
165 | .set_next_event = msm_timer_set_next_event, | 100 | |
166 | .set_mode = msm_timer_set_mode, | 101 | static union { |
167 | }, | 102 | struct clock_event_device *evt; |
168 | .clocksource = { | 103 | struct clock_event_device __percpu **percpu_evt; |
169 | .name = "gp_timer", | 104 | } msm_evt; |
170 | .rating = 200, | 105 | |
171 | .read = msm_read_timer_count, | 106 | static void __iomem *source_base; |
172 | .mask = CLOCKSOURCE_MASK(32), | 107 | |
173 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 108 | static cycle_t msm_read_timer_count(struct clocksource *cs) |
174 | }, | 109 | { |
175 | .irq = INT_GP_TIMER_EXP, | 110 | return readl_relaxed(source_base + TIMER_COUNT_VAL); |
176 | .freq = GPT_HZ, | 111 | } |
177 | }, | 112 | |
178 | [MSM_CLOCK_DGT] = { | 113 | static cycle_t msm_read_timer_count_shift(struct clocksource *cs) |
179 | .clockevent = { | 114 | { |
180 | .name = "dg_timer", | 115 | /* |
181 | .features = CLOCK_EVT_FEAT_ONESHOT, | 116 | * Shift timer count down by a constant due to unreliable lower bits |
182 | .shift = 32 + MSM_DGT_SHIFT, | 117 | * on some targets. |
183 | .rating = 300, | 118 | */ |
184 | .set_next_event = msm_timer_set_next_event, | 119 | return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; |
185 | .set_mode = msm_timer_set_mode, | 120 | } |
186 | }, | 121 | |
187 | .clocksource = { | 122 | static struct clocksource msm_clocksource = { |
188 | .name = "dg_timer", | 123 | .name = "dg_timer", |
189 | .rating = 300, | 124 | .rating = 300, |
190 | .read = msm_read_timer_count, | 125 | .read = msm_read_timer_count, |
191 | .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), | 126 | .mask = CLOCKSOURCE_MASK(32), |
192 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 127 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
193 | }, | ||
194 | .irq = INT_DEBUG_TIMER_EXP, | ||
195 | .freq = DGT_HZ >> MSM_DGT_SHIFT, | ||
196 | .shift = MSM_DGT_SHIFT, | ||
197 | } | ||
198 | }; | 128 | }; |
199 | 129 | ||
200 | static void __init msm_timer_init(void) | 130 | static void __init msm_timer_init(void) |
201 | { | 131 | { |
202 | int i; | 132 | struct clock_event_device *ce = &msm_clockevent; |
133 | struct clocksource *cs = &msm_clocksource; | ||
203 | int res; | 134 | int res; |
204 | int global_offset = 0; | 135 | u32 dgt_hz; |
205 | 136 | ||
206 | if (cpu_is_msm7x01()) { | 137 | if (cpu_is_msm7x01()) { |
207 | msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE; | 138 | event_base = MSM_CSR_BASE; |
208 | msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10; | 139 | source_base = MSM_CSR_BASE + 0x10; |
140 | dgt_hz = 19200000 >> MSM_DGT_SHIFT; /* 600 KHz */ | ||
141 | cs->read = msm_read_timer_count_shift; | ||
142 | cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); | ||
209 | } else if (cpu_is_msm7x30()) { | 143 | } else if (cpu_is_msm7x30()) { |
210 | msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE + 0x04; | 144 | event_base = MSM_CSR_BASE + 0x04; |
211 | msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x24; | 145 | source_base = MSM_CSR_BASE + 0x24; |
146 | dgt_hz = 24576000 / 4; | ||
212 | } else if (cpu_is_qsd8x50()) { | 147 | } else if (cpu_is_qsd8x50()) { |
213 | msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE; | 148 | event_base = MSM_CSR_BASE; |
214 | msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10; | 149 | source_base = MSM_CSR_BASE + 0x10; |
150 | dgt_hz = 19200000 / 4; | ||
215 | } else if (cpu_is_msm8x60() || cpu_is_msm8960()) { | 151 | } else if (cpu_is_msm8x60() || cpu_is_msm8960()) { |
216 | msm_clocks[MSM_CLOCK_GPT].regbase = MSM_TMR_BASE + 0x04; | 152 | event_base = MSM_TMR_BASE + 0x04; |
217 | msm_clocks[MSM_CLOCK_DGT].regbase = MSM_TMR_BASE + 0x24; | 153 | /* Use CPU0's timer as the global clock source. */ |
218 | 154 | source_base = MSM_TMR0_BASE + 0x24; | |
219 | /* Use CPU0's timer as the global timer. */ | 155 | dgt_hz = 27000000 / 4; |
220 | global_offset = MSM_TMR0_BASE - MSM_TMR_BASE; | 156 | writel_relaxed(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); |
221 | } else | 157 | } else |
222 | BUG(); | 158 | BUG(); |
223 | 159 | ||
224 | #ifdef CONFIG_ARCH_MSM_SCORPIONMP | 160 | writel_relaxed(0, event_base + TIMER_ENABLE); |
225 | writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); | 161 | writel_relaxed(0, event_base + TIMER_CLEAR); |
226 | #endif | 162 | writel_relaxed(~0, event_base + TIMER_MATCH_VAL); |
227 | 163 | ce->cpumask = cpumask_of(0); | |
228 | for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) { | 164 | |
229 | struct msm_clock *clock = &msm_clocks[i]; | 165 | ce->irq = INT_GP_TIMER_EXP; |
230 | struct clock_event_device *ce = &clock->clockevent; | 166 | clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff); |
231 | struct clocksource *cs = &clock->clocksource; | 167 | if (cpu_is_msm8x60() || cpu_is_msm8960()) { |
232 | 168 | msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); | |
233 | clock->local_counter = clock->regbase + TIMER_COUNT_VAL; | 169 | if (!msm_evt.percpu_evt) { |
234 | clock->global_counter = clock->local_counter + global_offset; | 170 | pr_err("memory allocation failed for %s\n", ce->name); |
235 | 171 | goto err; | |
236 | writel(0, clock->regbase + TIMER_ENABLE); | ||
237 | writel(0, clock->regbase + TIMER_CLEAR); | ||
238 | writel(~0, clock->regbase + TIMER_MATCH_VAL); | ||
239 | |||
240 | ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); | ||
241 | /* allow at least 10 seconds to notice that the timer wrapped */ | ||
242 | ce->max_delta_ns = | ||
243 | clockevent_delta2ns(0xf0000000 >> clock->shift, ce); | ||
244 | /* 4 gets rounded down to 3 */ | ||
245 | ce->min_delta_ns = clockevent_delta2ns(4, ce); | ||
246 | ce->cpumask = cpumask_of(0); | ||
247 | |||
248 | res = clocksource_register_hz(cs, clock->freq); | ||
249 | if (res) | ||
250 | printk(KERN_ERR "msm_timer_init: clocksource_register " | ||
251 | "failed for %s\n", cs->name); | ||
252 | |||
253 | ce->irq = clock->irq; | ||
254 | if (cpu_is_msm8x60() || cpu_is_msm8960()) { | ||
255 | clock->percpu_evt = alloc_percpu(struct clock_event_device *); | ||
256 | if (!clock->percpu_evt) { | ||
257 | pr_err("msm_timer_init: memory allocation " | ||
258 | "failed for %s\n", ce->name); | ||
259 | continue; | ||
260 | } | ||
261 | |||
262 | *__this_cpu_ptr(clock->percpu_evt) = ce; | ||
263 | res = request_percpu_irq(ce->irq, msm_timer_interrupt, | ||
264 | ce->name, clock->percpu_evt); | ||
265 | if (!res) | ||
266 | enable_percpu_irq(ce->irq, 0); | ||
267 | } else { | ||
268 | clock->evt = ce; | ||
269 | res = request_irq(ce->irq, msm_timer_interrupt, | ||
270 | IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, | ||
271 | ce->name, &clock->evt); | ||
272 | } | 172 | } |
273 | 173 | *__this_cpu_ptr(msm_evt.percpu_evt) = ce; | |
274 | if (res) | 174 | res = request_percpu_irq(ce->irq, msm_timer_interrupt, |
275 | pr_err("msm_timer_init: request_irq failed for %s\n", | 175 | ce->name, msm_evt.percpu_evt); |
276 | ce->name); | 176 | if (!res) |
277 | 177 | enable_percpu_irq(ce->irq, 0); | |
278 | clockevents_register_device(ce); | 178 | } else { |
179 | msm_evt.evt = ce; | ||
180 | res = request_irq(ce->irq, msm_timer_interrupt, | ||
181 | IRQF_TIMER | IRQF_NOBALANCING | | ||
182 | IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt); | ||
279 | } | 183 | } |
184 | |||
185 | if (res) | ||
186 | pr_err("request_irq failed for %s\n", ce->name); | ||
187 | err: | ||
188 | writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); | ||
189 | res = clocksource_register_hz(cs, dgt_hz); | ||
190 | if (res) | ||
191 | pr_err("clocksource_register failed\n"); | ||
280 | } | 192 | } |
281 | 193 | ||
282 | #ifdef CONFIG_SMP | 194 | #ifdef CONFIG_LOCAL_TIMERS |
283 | int __cpuinit local_timer_setup(struct clock_event_device *evt) | 195 | int __cpuinit local_timer_setup(struct clock_event_device *evt) |
284 | { | 196 | { |
285 | static bool local_timer_inited; | ||
286 | struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER]; | ||
287 | |||
288 | /* Use existing clock_event for cpu 0 */ | 197 | /* Use existing clock_event for cpu 0 */ |
289 | if (!smp_processor_id()) | 198 | if (!smp_processor_id()) |
290 | return 0; | 199 | return 0; |
291 | 200 | ||
292 | writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); | 201 | writel_relaxed(0, event_base + TIMER_ENABLE); |
293 | 202 | writel_relaxed(0, event_base + TIMER_CLEAR); | |
294 | if (!local_timer_inited) { | 203 | writel_relaxed(~0, event_base + TIMER_MATCH_VAL); |
295 | writel(0, clock->regbase + TIMER_ENABLE); | 204 | evt->irq = msm_clockevent.irq; |
296 | writel(0, clock->regbase + TIMER_CLEAR); | ||
297 | writel(~0, clock->regbase + TIMER_MATCH_VAL); | ||
298 | local_timer_inited = true; | ||
299 | } | ||
300 | evt->irq = clock->irq; | ||
301 | evt->name = "local_timer"; | 205 | evt->name = "local_timer"; |
302 | evt->features = CLOCK_EVT_FEAT_ONESHOT; | 206 | evt->features = msm_clockevent.features; |
303 | evt->rating = clock->clockevent.rating; | 207 | evt->rating = msm_clockevent.rating; |
304 | evt->set_mode = msm_timer_set_mode; | 208 | evt->set_mode = msm_timer_set_mode; |
305 | evt->set_next_event = msm_timer_set_next_event; | 209 | evt->set_next_event = msm_timer_set_next_event; |
306 | evt->shift = clock->clockevent.shift; | 210 | evt->shift = msm_clockevent.shift; |
307 | evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift); | 211 | evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift); |
308 | evt->max_delta_ns = | 212 | evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt); |
309 | clockevent_delta2ns(0xf0000000 >> clock->shift, evt); | ||
310 | evt->min_delta_ns = clockevent_delta2ns(4, evt); | 213 | evt->min_delta_ns = clockevent_delta2ns(4, evt); |
311 | 214 | ||
312 | *__this_cpu_ptr(clock->percpu_evt) = evt; | 215 | *__this_cpu_ptr(msm_evt.percpu_evt) = evt; |
313 | enable_percpu_irq(evt->irq, 0); | ||
314 | |||
315 | clockevents_register_device(evt); | 216 | clockevents_register_device(evt); |
217 | enable_percpu_irq(evt->irq, 0); | ||
316 | return 0; | 218 | return 0; |
317 | } | 219 | } |
318 | 220 | ||
@@ -321,8 +223,7 @@ void local_timer_stop(struct clock_event_device *evt) | |||
321 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); | 223 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); |
322 | disable_percpu_irq(evt->irq); | 224 | disable_percpu_irq(evt->irq); |
323 | } | 225 | } |
324 | 226 | #endif /* CONFIG_LOCAL_TIMERS */ | |
325 | #endif | ||
326 | 227 | ||
327 | struct sys_timer msm_timer = { | 228 | struct sys_timer msm_timer = { |
328 | .init = msm_timer_init | 229 | .init = msm_timer_init |