aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-integrator/integrator_ap.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-10-25 03:19:59 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-10-25 03:19:59 -0400
commitbdf4e9482360a3ddc1619efbd5d1c928ede8c3fa (patch)
treeb02319e809c5b8abfca85409a11472775e27f597 /arch/arm/mach-integrator/integrator_ap.c
parent06afb1a087d49ae0f676b2e5b9ffe5f4b3aba355 (diff)
parenteb0474544bc16a9dab53b26abd846e86ba814eb1 (diff)
Merge branch 'misc' into for-linus
Conflicts: arch/arm/mach-integrator/integrator_ap.c
Diffstat (limited to 'arch/arm/mach-integrator/integrator_ap.c')
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c86
1 files changed, 46 insertions, 40 deletions
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 8cdc730dcb3a..f2119908a0b3 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -32,6 +32,7 @@
32#include <linux/interrupt.h> 32#include <linux/interrupt.h>
33#include <linux/io.h> 33#include <linux/io.h>
34#include <linux/mtd/physmap.h> 34#include <linux/mtd/physmap.h>
35#include <linux/clk.h>
35#include <video/vga.h> 36#include <video/vga.h>
36 37
37#include <mach/hardware.h> 38#include <mach/hardware.h>
@@ -322,27 +323,16 @@ static void __init ap_init(void)
322#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE) 323#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)
323#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE) 324#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)
324 325
325/*
326 * How long is the timer interval?
327 */
328#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
329#if TIMER_INTERVAL >= 0x100000
330#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
331#elif TIMER_INTERVAL >= 0x10000
332#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
333#else
334#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
335#endif
336
337static unsigned long timer_reload; 326static unsigned long timer_reload;
338 327
339static void integrator_clocksource_init(u32 khz) 328static void integrator_clocksource_init(unsigned long inrate)
340{ 329{
341 void __iomem *base = (void __iomem *)TIMER2_VA_BASE; 330 void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
342 u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; 331 u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
332 unsigned long rate = inrate;
343 333
344 if (khz >= 1500) { 334 if (rate >= 1500000) {
345 khz /= 16; 335 rate /= 16;
346 ctrl |= TIMER_CTRL_DIV16; 336 ctrl |= TIMER_CTRL_DIV16;
347 } 337 }
348 338
@@ -350,7 +340,7 @@ static void integrator_clocksource_init(u32 khz)
350 writel(ctrl, base + TIMER_CTRL); 340 writel(ctrl, base + TIMER_CTRL);
351 341
352 clocksource_mmio_init(base + TIMER_VALUE, "timer2", 342 clocksource_mmio_init(base + TIMER_VALUE, "timer2",
353 khz * 1000, 200, 16, clocksource_mmio_readl_down); 343 rate, 200, 16, clocksource_mmio_readl_down);
354} 344}
355 345
356static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE; 346static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
@@ -374,15 +364,29 @@ static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_devic
374{ 364{
375 u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; 365 u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
376 366
377 BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT); 367 /* Disable timer */
368 writel(ctrl, clkevt_base + TIMER_CTRL);
378 369
379 if (mode == CLOCK_EVT_MODE_PERIODIC) { 370 switch (mode) {
380 writel(ctrl, clkevt_base + TIMER_CTRL); 371 case CLOCK_EVT_MODE_PERIODIC:
372 /* Enable the timer and start the periodic tick */
381 writel(timer_reload, clkevt_base + TIMER_LOAD); 373 writel(timer_reload, clkevt_base + TIMER_LOAD);
382 ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; 374 ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
375 writel(ctrl, clkevt_base + TIMER_CTRL);
376 break;
377 case CLOCK_EVT_MODE_ONESHOT:
378 /* Leave the timer disabled, .set_next_event will enable it */
379 ctrl &= ~TIMER_CTRL_PERIODIC;
380 writel(ctrl, clkevt_base + TIMER_CTRL);
381 break;
382 case CLOCK_EVT_MODE_UNUSED:
383 case CLOCK_EVT_MODE_SHUTDOWN:
384 case CLOCK_EVT_MODE_RESUME:
385 default:
386 /* Just leave in disabled state */
387 break;
383 } 388 }
384 389
385 writel(ctrl, clkevt_base + TIMER_CTRL);
386} 390}
387 391
388static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) 392static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
@@ -398,12 +402,10 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device *
398 402
399static struct clock_event_device integrator_clockevent = { 403static struct clock_event_device integrator_clockevent = {
400 .name = "timer1", 404 .name = "timer1",
401 .shift = 34, 405 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
402 .features = CLOCK_EVT_FEAT_PERIODIC,
403 .set_mode = clkevt_set_mode, 406 .set_mode = clkevt_set_mode,
404 .set_next_event = clkevt_set_next_event, 407 .set_next_event = clkevt_set_next_event,
405 .rating = 300, 408 .rating = 300,
406 .cpumask = cpu_all_mask,
407}; 409};
408 410
409static struct irqaction integrator_timer_irq = { 411static struct irqaction integrator_timer_irq = {
@@ -413,29 +415,27 @@ static struct irqaction integrator_timer_irq = {
413 .dev_id = &integrator_clockevent, 415 .dev_id = &integrator_clockevent,
414}; 416};
415 417
416static void integrator_clockevent_init(u32 khz) 418static void integrator_clockevent_init(unsigned long inrate)
417{ 419{
418 struct clock_event_device *evt = &integrator_clockevent; 420 unsigned long rate = inrate;
419 unsigned int ctrl = 0; 421 unsigned int ctrl = 0;
420 422
421 if (khz * 1000 > 0x100000 * HZ) { 423 /* Calculate and program a divisor */
422 khz /= 256; 424 if (rate > 0x100000 * HZ) {
425 rate /= 256;
423 ctrl |= TIMER_CTRL_DIV256; 426 ctrl |= TIMER_CTRL_DIV256;
424 } else if (khz * 1000 > 0x10000 * HZ) { 427 } else if (rate > 0x10000 * HZ) {
425 khz /= 16; 428 rate /= 16;
426 ctrl |= TIMER_CTRL_DIV16; 429 ctrl |= TIMER_CTRL_DIV16;
427 } 430 }
428 431 timer_reload = rate / HZ;
429 timer_reload = khz * 1000 / HZ;
430 writel(ctrl, clkevt_base + TIMER_CTRL); 432 writel(ctrl, clkevt_base + TIMER_CTRL);
431 433
432 evt->irq = IRQ_TIMERINT1;
433 evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift);
434 evt->max_delta_ns = clockevent_delta2ns(0xffff, evt);
435 evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
436
437 setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); 434 setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
438 clockevents_register_device(evt); 435 clockevents_config_and_register(&integrator_clockevent,
436 rate,
437 1,
438 0xffffU);
439} 439}
440 440
441/* 441/*
@@ -443,14 +443,20 @@ static void integrator_clockevent_init(u32 khz)
443 */ 443 */
444static void __init ap_init_timer(void) 444static void __init ap_init_timer(void)
445{ 445{
446 u32 khz = TICKS_PER_uSEC * 1000; 446 struct clk *clk;
447 unsigned long rate;
448
449 clk = clk_get_sys("ap_timer", NULL);
450 BUG_ON(IS_ERR(clk));
451 clk_enable(clk);
452 rate = clk_get_rate(clk);
447 453
448 writel(0, TIMER0_VA_BASE + TIMER_CTRL); 454 writel(0, TIMER0_VA_BASE + TIMER_CTRL);
449 writel(0, TIMER1_VA_BASE + TIMER_CTRL); 455 writel(0, TIMER1_VA_BASE + TIMER_CTRL);
450 writel(0, TIMER2_VA_BASE + TIMER_CTRL); 456 writel(0, TIMER2_VA_BASE + TIMER_CTRL);
451 457
452 integrator_clocksource_init(khz); 458 integrator_clocksource_init(rate);
453 integrator_clockevent_init(khz); 459 integrator_clockevent_init(rate);
454} 460}
455 461
456static struct sys_timer ap_timer = { 462static struct sys_timer ap_timer = {