aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-integrator
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-01-15 16:49:23 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-04-29 13:04:16 -0400
commit13edd86d7a8b64735c60c308faac785a6f2257b2 (patch)
tree94fefea5ea04b46a005154981ffcb66cd50e12b7 /arch/arm/mach-integrator
parentb9cedda230793cbf58eb012ddadedd490cc8e129 (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.c107
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
279static 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 */
281static irqreturn_t 284static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
282integrator_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
296static 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
311static 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
322static 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
294static struct irqaction integrator_timer_irq = { 332static 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/* 339static void integrator_clockevent_init(u32 khz, unsigned int ctrl)
301 * Set up timer interrupt, and return the current time in seconds.
302 */
303void __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 */
366void __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}