diff options
Diffstat (limited to 'arch/arm/mach-integrator/integrator_ap.c')
-rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 86 |
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 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/mtd/physmap.h> +#include <linux/clk.h> #include <video/vga.h> #include <mach/hardware.h> @@ -322,27 +323,16 @@ static void __init ap_init(void) #define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE) #define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE) -/* - * How long is the timer interval? - */ -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) -#if TIMER_INTERVAL >= 0x100000 -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) -#elif TIMER_INTERVAL >= 0x10000 -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) -#else -#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) -#endif - static unsigned long timer_reload; -static void integrator_clocksource_init(u32 khz) +static void integrator_clocksource_init(unsigned long inrate) { void __iomem *base = (void __iomem *)TIMER2_VA_BASE; u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; + unsigned long rate = inrate; - if (khz >= 1500) { - khz /= 16; + if (rate >= 1500000) { + rate /= 16; ctrl |= TIMER_CTRL_DIV16; } @@ -350,7 +340,7 @@ static void integrator_clocksource_init(u32 khz) writel(ctrl, base + TIMER_CTRL); clocksource_mmio_init(base + TIMER_VALUE, "timer2", - khz * 1000, 200, 16, clocksource_mmio_readl_down); + rate, 200, 16, clocksource_mmio_readl_down); } static 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 { u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; - BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT); + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); - if (mode == CLOCK_EVT_MODE_PERIODIC) { - writel(ctrl, clkevt_base + TIMER_CTRL); + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* Enable the timer and start the periodic tick */ writel(timer_reload, clkevt_base + TIMER_LOAD); ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Leave the timer disabled, .set_next_event will enable it */ + ctrl &= ~TIMER_CTRL_PERIODIC; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + default: + /* Just leave in disabled state */ + break; } - writel(ctrl, clkevt_base + TIMER_CTRL); } static 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 * static struct clock_event_device integrator_clockevent = { .name = "timer1", - .shift = 34, - .features = CLOCK_EVT_FEAT_PERIODIC, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = clkevt_set_mode, .set_next_event = clkevt_set_next_event, .rating = 300, - .cpumask = cpu_all_mask, }; static struct irqaction integrator_timer_irq = { @@ -413,29 +415,27 @@ static struct irqaction integrator_timer_irq = { .dev_id = &integrator_clockevent, }; -static void integrator_clockevent_init(u32 khz) +static void integrator_clockevent_init(unsigned long inrate) { - struct clock_event_device *evt = &integrator_clockevent; + unsigned long rate = inrate; unsigned int ctrl = 0; - if (khz * 1000 > 0x100000 * HZ) { - khz /= 256; + /* Calculate and program a divisor */ + if (rate > 0x100000 * HZ) { + rate /= 256; ctrl |= TIMER_CTRL_DIV256; - } else if (khz * 1000 > 0x10000 * HZ) { - khz /= 16; + } else if (rate > 0x10000 * HZ) { + rate /= 16; ctrl |= TIMER_CTRL_DIV16; } - - timer_reload = khz * 1000 / HZ; + timer_reload = rate / HZ; writel(ctrl, clkevt_base + TIMER_CTRL); - evt->irq = IRQ_TIMERINT1; - evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift); - evt->max_delta_ns = clockevent_delta2ns(0xffff, evt); - evt->min_delta_ns = clockevent_delta2ns(0xf, evt); - setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); - clockevents_register_device(evt); + clockevents_config_and_register(&integrator_clockevent, + rate, + 1, + 0xffffU); } /* @@ -443,14 +443,20 @@ static void integrator_clockevent_init(u32 khz) */ static void __init ap_init_timer(void) { - u32 khz = TICKS_PER_uSEC * 1000; + struct clk *clk; + unsigned long rate; + + clk = clk_get_sys("ap_timer", NULL); + BUG_ON(IS_ERR(clk)); + clk_enable(clk); + rate = clk_get_rate(clk); writel(0, TIMER0_VA_BASE + TIMER_CTRL); writel(0, TIMER1_VA_BASE + TIMER_CTRL); writel(0, TIMER2_VA_BASE + TIMER_CTRL); - integrator_clocksource_init(khz); - integrator_clockevent_init(khz); + integrator_clocksource_init(rate); + integrator_clockevent_init(rate); } static struct sys_timer ap_timer = { |