Root/
1 | /* |
2 | * (C) Copyright 2009 Intel Corporation |
3 | * Author: Jacob Pan (jacob.jun.pan@intel.com) |
4 | * |
5 | * Shared with ARM platforms, Jamie Iles, Picochip 2011 |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. |
10 | * |
11 | * Support for the Synopsys DesignWare APB Timers. |
12 | */ |
13 | #include <linux/dw_apb_timer.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/irq.h> |
18 | #include <linux/io.h> |
19 | #include <linux/slab.h> |
20 | |
21 | #define APBT_MIN_PERIOD 4 |
22 | #define APBT_MIN_DELTA_USEC 200 |
23 | |
24 | #define APBTMR_N_LOAD_COUNT 0x00 |
25 | #define APBTMR_N_CURRENT_VALUE 0x04 |
26 | #define APBTMR_N_CONTROL 0x08 |
27 | #define APBTMR_N_EOI 0x0c |
28 | #define APBTMR_N_INT_STATUS 0x10 |
29 | |
30 | #define APBTMRS_INT_STATUS 0xa0 |
31 | #define APBTMRS_EOI 0xa4 |
32 | #define APBTMRS_RAW_INT_STATUS 0xa8 |
33 | #define APBTMRS_COMP_VERSION 0xac |
34 | |
35 | #define APBTMR_CONTROL_ENABLE (1 << 0) |
36 | /* 1: periodic, 0:free running. */ |
37 | #define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) |
38 | #define APBTMR_CONTROL_INT (1 << 2) |
39 | |
40 | static inline struct dw_apb_clock_event_device * |
41 | ced_to_dw_apb_ced(struct clock_event_device *evt) |
42 | { |
43 | return container_of(evt, struct dw_apb_clock_event_device, ced); |
44 | } |
45 | |
46 | static inline struct dw_apb_clocksource * |
47 | clocksource_to_dw_apb_clocksource(struct clocksource *cs) |
48 | { |
49 | return container_of(cs, struct dw_apb_clocksource, cs); |
50 | } |
51 | |
52 | static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs) |
53 | { |
54 | return readl(timer->base + offs); |
55 | } |
56 | |
57 | static void apbt_writel(struct dw_apb_timer *timer, unsigned long val, |
58 | unsigned long offs) |
59 | { |
60 | writel(val, timer->base + offs); |
61 | } |
62 | |
63 | static void apbt_disable_int(struct dw_apb_timer *timer) |
64 | { |
65 | unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); |
66 | |
67 | ctrl |= APBTMR_CONTROL_INT; |
68 | apbt_writel(timer, ctrl, APBTMR_N_CONTROL); |
69 | } |
70 | |
71 | /** |
72 | * dw_apb_clockevent_pause() - stop the clock_event_device from running |
73 | * |
74 | * @dw_ced: The APB clock to stop generating events. |
75 | */ |
76 | void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) |
77 | { |
78 | disable_irq(dw_ced->timer.irq); |
79 | apbt_disable_int(&dw_ced->timer); |
80 | } |
81 | |
82 | static void apbt_eoi(struct dw_apb_timer *timer) |
83 | { |
84 | apbt_readl(timer, APBTMR_N_EOI); |
85 | } |
86 | |
87 | static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) |
88 | { |
89 | struct clock_event_device *evt = data; |
90 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
91 | |
92 | if (!evt->event_handler) { |
93 | pr_info("Spurious APBT timer interrupt %d", irq); |
94 | return IRQ_NONE; |
95 | } |
96 | |
97 | if (dw_ced->eoi) |
98 | dw_ced->eoi(&dw_ced->timer); |
99 | |
100 | evt->event_handler(evt); |
101 | return IRQ_HANDLED; |
102 | } |
103 | |
104 | static void apbt_enable_int(struct dw_apb_timer *timer) |
105 | { |
106 | unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); |
107 | /* clear pending intr */ |
108 | apbt_readl(timer, APBTMR_N_EOI); |
109 | ctrl &= ~APBTMR_CONTROL_INT; |
110 | apbt_writel(timer, ctrl, APBTMR_N_CONTROL); |
111 | } |
112 | |
113 | static void apbt_set_mode(enum clock_event_mode mode, |
114 | struct clock_event_device *evt) |
115 | { |
116 | unsigned long ctrl; |
117 | unsigned long period; |
118 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
119 | |
120 | pr_debug("%s CPU %d mode=%d\n", __func__, first_cpu(*evt->cpumask), |
121 | mode); |
122 | |
123 | switch (mode) { |
124 | case CLOCK_EVT_MODE_PERIODIC: |
125 | period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); |
126 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); |
127 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; |
128 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
129 | /* |
130 | * DW APB p. 46, have to disable timer before load counter, |
131 | * may cause sync problem. |
132 | */ |
133 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
134 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
135 | udelay(1); |
136 | pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); |
137 | apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); |
138 | ctrl |= APBTMR_CONTROL_ENABLE; |
139 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
140 | break; |
141 | |
142 | case CLOCK_EVT_MODE_ONESHOT: |
143 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); |
144 | /* |
145 | * set free running mode, this mode will let timer reload max |
146 | * timeout which will give time (3min on 25MHz clock) to rearm |
147 | * the next event, therefore emulate the one-shot mode. |
148 | */ |
149 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
150 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; |
151 | |
152 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
153 | /* write again to set free running mode */ |
154 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
155 | |
156 | /* |
157 | * DW APB p. 46, load counter with all 1s before starting free |
158 | * running mode. |
159 | */ |
160 | apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); |
161 | ctrl &= ~APBTMR_CONTROL_INT; |
162 | ctrl |= APBTMR_CONTROL_ENABLE; |
163 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
164 | break; |
165 | |
166 | case CLOCK_EVT_MODE_UNUSED: |
167 | case CLOCK_EVT_MODE_SHUTDOWN: |
168 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); |
169 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
170 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
171 | break; |
172 | |
173 | case CLOCK_EVT_MODE_RESUME: |
174 | apbt_enable_int(&dw_ced->timer); |
175 | break; |
176 | } |
177 | } |
178 | |
179 | static int apbt_next_event(unsigned long delta, |
180 | struct clock_event_device *evt) |
181 | { |
182 | unsigned long ctrl; |
183 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
184 | |
185 | /* Disable timer */ |
186 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); |
187 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
188 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
189 | /* write new count */ |
190 | apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); |
191 | ctrl |= APBTMR_CONTROL_ENABLE; |
192 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); |
193 | |
194 | return 0; |
195 | } |
196 | |
197 | /** |
198 | * dw_apb_clockevent_init() - use an APB timer as a clock_event_device |
199 | * |
200 | * @cpu: The CPU the events will be targeted at. |
201 | * @name: The name used for the timer and the IRQ for it. |
202 | * @rating: The rating to give the timer. |
203 | * @base: I/O base for the timer registers. |
204 | * @irq: The interrupt number to use for the timer. |
205 | * @freq: The frequency that the timer counts at. |
206 | * |
207 | * This creates a clock_event_device for using with the generic clock layer |
208 | * but does not start and register it. This should be done with |
209 | * dw_apb_clockevent_register() as the next step. If this is the first time |
210 | * it has been called for a timer then the IRQ will be requested, if not it |
211 | * just be enabled to allow CPU hotplug to avoid repeatedly requesting and |
212 | * releasing the IRQ. |
213 | */ |
214 | struct dw_apb_clock_event_device * |
215 | dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, |
216 | void __iomem *base, int irq, unsigned long freq) |
217 | { |
218 | struct dw_apb_clock_event_device *dw_ced = |
219 | kzalloc(sizeof(*dw_ced), GFP_KERNEL); |
220 | int err; |
221 | |
222 | if (!dw_ced) |
223 | return NULL; |
224 | |
225 | dw_ced->timer.base = base; |
226 | dw_ced->timer.irq = irq; |
227 | dw_ced->timer.freq = freq; |
228 | |
229 | clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD); |
230 | dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff, |
231 | &dw_ced->ced); |
232 | dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); |
233 | dw_ced->ced.cpumask = cpumask_of(cpu); |
234 | dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; |
235 | dw_ced->ced.set_mode = apbt_set_mode; |
236 | dw_ced->ced.set_next_event = apbt_next_event; |
237 | dw_ced->ced.irq = dw_ced->timer.irq; |
238 | dw_ced->ced.rating = rating; |
239 | dw_ced->ced.name = name; |
240 | |
241 | dw_ced->irqaction.name = dw_ced->ced.name; |
242 | dw_ced->irqaction.handler = dw_apb_clockevent_irq; |
243 | dw_ced->irqaction.dev_id = &dw_ced->ced; |
244 | dw_ced->irqaction.irq = irq; |
245 | dw_ced->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | |
246 | IRQF_NOBALANCING | |
247 | IRQF_DISABLED; |
248 | |
249 | dw_ced->eoi = apbt_eoi; |
250 | err = setup_irq(irq, &dw_ced->irqaction); |
251 | if (err) { |
252 | pr_err("failed to request timer irq\n"); |
253 | kfree(dw_ced); |
254 | dw_ced = NULL; |
255 | } |
256 | |
257 | return dw_ced; |
258 | } |
259 | |
260 | /** |
261 | * dw_apb_clockevent_resume() - resume a clock that has been paused. |
262 | * |
263 | * @dw_ced: The APB clock to resume. |
264 | */ |
265 | void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) |
266 | { |
267 | enable_irq(dw_ced->timer.irq); |
268 | } |
269 | |
270 | /** |
271 | * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. |
272 | * |
273 | * @dw_ced: The APB clock to stop generating the events. |
274 | */ |
275 | void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) |
276 | { |
277 | free_irq(dw_ced->timer.irq, &dw_ced->ced); |
278 | } |
279 | |
280 | /** |
281 | * dw_apb_clockevent_register() - register the clock with the generic layer |
282 | * |
283 | * @dw_ced: The APB clock to register as a clock_event_device. |
284 | */ |
285 | void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced) |
286 | { |
287 | apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL); |
288 | clockevents_register_device(&dw_ced->ced); |
289 | apbt_enable_int(&dw_ced->timer); |
290 | } |
291 | |
292 | /** |
293 | * dw_apb_clocksource_start() - start the clocksource counting. |
294 | * |
295 | * @dw_cs: The clocksource to start. |
296 | * |
297 | * This is used to start the clocksource before registration and can be used |
298 | * to enable calibration of timers. |
299 | */ |
300 | void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) |
301 | { |
302 | /* |
303 | * start count down from 0xffff_ffff. this is done by toggling the |
304 | * enable bit then load initial load count to ~0. |
305 | */ |
306 | unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); |
307 | |
308 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
309 | apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); |
310 | apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT); |
311 | /* enable, mask interrupt */ |
312 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; |
313 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); |
314 | apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); |
315 | /* read it once to get cached counter value initialized */ |
316 | dw_apb_clocksource_read(dw_cs); |
317 | } |
318 | |
319 | static cycle_t __apbt_read_clocksource(struct clocksource *cs) |
320 | { |
321 | unsigned long current_count; |
322 | struct dw_apb_clocksource *dw_cs = |
323 | clocksource_to_dw_apb_clocksource(cs); |
324 | |
325 | current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); |
326 | |
327 | return (cycle_t)~current_count; |
328 | } |
329 | |
330 | static void apbt_restart_clocksource(struct clocksource *cs) |
331 | { |
332 | struct dw_apb_clocksource *dw_cs = |
333 | clocksource_to_dw_apb_clocksource(cs); |
334 | |
335 | dw_apb_clocksource_start(dw_cs); |
336 | } |
337 | |
338 | /** |
339 | * dw_apb_clocksource_init() - use an APB timer as a clocksource. |
340 | * |
341 | * @rating: The rating to give the clocksource. |
342 | * @name: The name for the clocksource. |
343 | * @base: The I/O base for the timer registers. |
344 | * @freq: The frequency that the timer counts at. |
345 | * |
346 | * This creates a clocksource using an APB timer but does not yet register it |
347 | * with the clocksource system. This should be done with |
348 | * dw_apb_clocksource_register() as the next step. |
349 | */ |
350 | struct dw_apb_clocksource * |
351 | dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base, |
352 | unsigned long freq) |
353 | { |
354 | struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); |
355 | |
356 | if (!dw_cs) |
357 | return NULL; |
358 | |
359 | dw_cs->timer.base = base; |
360 | dw_cs->timer.freq = freq; |
361 | dw_cs->cs.name = name; |
362 | dw_cs->cs.rating = rating; |
363 | dw_cs->cs.read = __apbt_read_clocksource; |
364 | dw_cs->cs.mask = CLOCKSOURCE_MASK(32); |
365 | dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; |
366 | dw_cs->cs.resume = apbt_restart_clocksource; |
367 | |
368 | return dw_cs; |
369 | } |
370 | |
371 | /** |
372 | * dw_apb_clocksource_register() - register the APB clocksource. |
373 | * |
374 | * @dw_cs: The clocksource to register. |
375 | */ |
376 | void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs) |
377 | { |
378 | clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq); |
379 | } |
380 | |
381 | /** |
382 | * dw_apb_clocksource_read() - read the current value of a clocksource. |
383 | * |
384 | * @dw_cs: The clocksource to read. |
385 | */ |
386 | cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs) |
387 | { |
388 | return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); |
389 | } |
390 | |
391 | /** |
392 | * dw_apb_clocksource_unregister() - unregister and free a clocksource. |
393 | * |
394 | * @dw_cs: The clocksource to unregister/free. |
395 | */ |
396 | void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs) |
397 | { |
398 | clocksource_unregister(&dw_cs->cs); |
399 | |
400 | kfree(dw_cs); |
401 | } |
402 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9