diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-01-15 16:49:23 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-04-29 13:04:16 -0400 |
commit | 13edd86d7a8b64735c60c308faac785a6f2257b2 (patch) | |
tree | 94fefea5ea04b46a005154981ffcb66cd50e12b7 /arch/arm/mach-integrator | |
parent | b9cedda230793cbf58eb012ddadedd490cc8e129 (diff) |
ARM: Integrator: convert to generic clockevent support
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-integrator')
-rw-r--r-- | arch/arm/mach-integrator/core.c | 107 |
1 files changed, 73 insertions, 34 deletions
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 87c6f980944d..b1ccbe3f233f 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/amba/bus.h> | 20 | #include <linux/amba/bus.h> |
21 | #include <linux/amba/serial.h> | 21 | #include <linux/amba/serial.h> |
22 | #include <linux/clocksource.h> | 22 | #include <linux/clocksource.h> |
23 | #include <linux/clockchips.h> | ||
23 | #include <linux/io.h> | 24 | #include <linux/io.h> |
24 | 25 | ||
25 | #include <asm/clkdev.h> | 26 | #include <asm/clkdev.h> |
@@ -275,61 +276,99 @@ static void integrator_clocksource_init(u32 khz) | |||
275 | clocksource_register(cs); | 276 | clocksource_register(cs); |
276 | } | 277 | } |
277 | 278 | ||
279 | static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE; | ||
280 | |||
278 | /* | 281 | /* |
279 | * IRQ handler for the timer | 282 | * IRQ handler for the timer |
280 | */ | 283 | */ |
281 | static irqreturn_t | 284 | static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) |
282 | integrator_timer_interrupt(int irq, void *dev_id) | ||
283 | { | 285 | { |
284 | /* | 286 | struct clock_event_device *evt = dev_id; |
285 | * clear the interrupt | 287 | |
286 | */ | 288 | /* clear the interrupt */ |
287 | writel(1, TIMER1_VA_BASE + TIMER_INTCLR); | 289 | writel(1, clkevt_base + TIMER_INTCLR); |
288 | 290 | ||
289 | timer_tick(); | 291 | evt->event_handler(evt); |
290 | 292 | ||
291 | return IRQ_HANDLED; | 293 | return IRQ_HANDLED; |
292 | } | 294 | } |
293 | 295 | ||
296 | static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) | ||
297 | { | ||
298 | u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; | ||
299 | |||
300 | BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT); | ||
301 | |||
302 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | ||
303 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
304 | writel(timer_reload, clkevt_base + TIMER_LOAD); | ||
305 | ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; | ||
306 | } | ||
307 | |||
308 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
309 | } | ||
310 | |||
311 | static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) | ||
312 | { | ||
313 | unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); | ||
314 | |||
315 | writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); | ||
316 | writel(next, clkevt_base + TIMER_LOAD); | ||
317 | writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static struct clock_event_device integrator_clockevent = { | ||
323 | .name = "timer1", | ||
324 | .shift = 34, | ||
325 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
326 | .set_mode = clkevt_set_mode, | ||
327 | .set_next_event = clkevt_set_next_event, | ||
328 | .rating = 300, | ||
329 | .cpumask = cpu_all_mask, | ||
330 | }; | ||
331 | |||
294 | static struct irqaction integrator_timer_irq = { | 332 | static struct irqaction integrator_timer_irq = { |
295 | .name = "Integrator Timer Tick", | 333 | .name = "timer", |
296 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 334 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
297 | .handler = integrator_timer_interrupt, | 335 | .handler = integrator_timer_interrupt, |
336 | .dev_id = &integrator_clockevent, | ||
298 | }; | 337 | }; |
299 | 338 | ||
300 | /* | 339 | static void integrator_clockevent_init(u32 khz, unsigned int ctrl) |
301 | * Set up timer interrupt, and return the current time in seconds. | ||
302 | */ | ||
303 | void __init integrator_time_init(unsigned long reload, unsigned int ctrl) | ||
304 | { | 340 | { |
305 | unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; | 341 | struct clock_event_device *evt = &integrator_clockevent; |
306 | 342 | ||
307 | integrator_clocksource_init(reload * HZ / 1000); | 343 | if (khz * 1000 > 0x100000 * HZ) { |
344 | khz /= 256; | ||
345 | ctrl |= TIMER_CTRL_DIV256; | ||
346 | } else if (khz * 1000 > 0x10000 * HZ) { | ||
347 | khz /= 16; | ||
348 | ctrl |= TIMER_CTRL_DIV16; | ||
349 | } | ||
308 | 350 | ||
309 | timer_reload = reload; | 351 | timer_reload = khz * 1000 / HZ; |
310 | timer_ctrl |= ctrl; | 352 | writel(ctrl, clkevt_base + TIMER_CTRL); |
311 | 353 | ||
312 | if (timer_reload > 0x100000) { | 354 | evt->irq = IRQ_TIMERINT1; |
313 | timer_reload >>= 8; | 355 | evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift); |
314 | timer_ctrl |= TIMER_CTRL_DIV256; | 356 | evt->max_delta_ns = clockevent_delta2ns(0xffff, evt); |
315 | } else if (timer_reload > 0x010000) { | 357 | evt->min_delta_ns = clockevent_delta2ns(0xf, evt); |
316 | timer_reload >>= 4; | ||
317 | timer_ctrl |= TIMER_CTRL_DIV16; | ||
318 | } | ||
319 | 358 | ||
320 | /* | 359 | setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); |
321 | * Initialise to a known state (all timers off) | 360 | clockevents_register_device(evt); |
322 | */ | 361 | } |
362 | |||
363 | /* | ||
364 | * Set up timer(s). | ||
365 | */ | ||
366 | void __init integrator_time_init(unsigned long reload, unsigned int ctrl) | ||
367 | { | ||
323 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); | 368 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); |
324 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); | 369 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); |
325 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | 370 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); |
326 | 371 | ||
327 | writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD); | 372 | integrator_clocksource_init(reload * HZ / 1000); |
328 | writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE); | 373 | integrator_clockevent_init(reload * HZ / 1000, ctrl); |
329 | writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL); | ||
330 | |||
331 | /* | ||
332 | * Make irqs happen for the system timer | ||
333 | */ | ||
334 | setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); | ||
335 | } | 374 | } |