]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - arch/arm/plat-nomadik/timer.c
ARM: 6153/1: nomadik MTU to use dynamic shift and mult assignment
[net-next-2.6.git] / arch / arm / plat-nomadik / timer.c
index 0ff3798769abb9a6fe2d03b390c5500c478b5141..ea3ca86c52836ba1ec9fe780da9c1629db91723f 100644 (file)
@@ -13,7 +13,9 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/clockchips.h>
+#include <linux/clk.h>
 #include <linux/jiffies.h>
+#include <linux/err.h>
 #include <asm/mach/time.h>
 
 #include <plat/mtu.h>
@@ -40,7 +42,6 @@ static struct clocksource nmdk_clksrc = {
        .rating         = 200,
        .read           = nmdk_read_timer_dummy,
        .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = 20,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -80,6 +81,12 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_UNUSED:
                /* disable irq */
                writel(0, mtu_base + MTU_IMSC);
+               /* disable timer */
+               cr = readl(mtu_base + MTU_CR(1));
+               cr &= ~MTU_CRn_ENA;
+               writel(cr, mtu_base + MTU_CR(1));
+               /* load some high default value */
+               writel(0xffffffff, mtu_base + MTU_LR(1));
                break;
        case CLOCK_EVT_MODE_RESUME:
                break;
@@ -96,7 +103,6 @@ static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
 static struct clock_event_device nmdk_clkevt = {
        .name           = "mtu_1",
        .features       = CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 32,
        .rating         = 200,
        .set_mode       = nmdk_clkevt_mode,
        .set_next_event = nmdk_clkevt_next,
@@ -124,19 +130,32 @@ static struct irqaction nmdk_timer_irq = {
 void __init nmdk_timer_init(void)
 {
        unsigned long rate;
-       u32 cr = MTU_CRn_32BITS;;
+       struct clk *clk0;
+       struct clk *clk1;
+       u32 cr;
+
+       clk0 = clk_get_sys("mtu0", NULL);
+       BUG_ON(IS_ERR(clk0));
+
+       clk1 = clk_get_sys("mtu1", NULL);
+       BUG_ON(IS_ERR(clk1));
+
+       clk_enable(clk0);
+       clk_enable(clk1);
 
        /*
         * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500:
         * use a divide-by-16 counter if it's more than 16MHz
         */
-       rate = CLOCK_TICK_RATE;
+       cr = MTU_CRn_32BITS;;
+       rate = clk_get_rate(clk0);
        if (rate > 16 << 20) {
                rate /= 16;
                cr |= MTU_CRn_PRESCALE_16;
        } else {
                cr |= MTU_CRn_PRESCALE_1;
        }
+       clocksource_calc_mult_shift(&nmdk_clksrc, rate, MTU_MIN_RANGE);
 
        /* Timer 0 is the free running clocksource */
        writel(cr, mtu_base + MTU_CR(0));
@@ -144,7 +163,6 @@ void __init nmdk_timer_init(void)
        writel(0, mtu_base + MTU_BGLR(0));
        writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
 
-       nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
        /* Now the scheduling clock is ready */
        nmdk_clksrc.read = nmdk_read_timer;
 
@@ -153,8 +171,18 @@ void __init nmdk_timer_init(void)
                       nmdk_clksrc.name);
 
        /* Timer 1 is used for events, fix according to rate */
+       cr = MTU_CRn_32BITS;
+       rate = clk_get_rate(clk1);
+       if (rate > 16 << 20) {
+               rate /= 16;
+               cr |= MTU_CRn_PRESCALE_16;
+       } else {
+               cr |= MTU_CRn_PRESCALE_1;
+       }
+       clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
+
        writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
-       nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
+
        nmdk_clkevt.max_delta_ns =
                clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
        nmdk_clkevt.min_delta_ns =