Merge branch 'at91/cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[pandora-kernel.git] / arch / arm / plat-omap / dmtimer.c
index ee9f6eb..75a847d 100644 (file)
 #include <plat/dmtimer.h>
 #include <mach/irqs.h>
 
-/* register offsets */
-#define _OMAP_TIMER_ID_OFFSET          0x00
-#define _OMAP_TIMER_OCP_CFG_OFFSET     0x10
-#define _OMAP_TIMER_SYS_STAT_OFFSET    0x14
-#define _OMAP_TIMER_STAT_OFFSET                0x18
-#define _OMAP_TIMER_INT_EN_OFFSET      0x1c
-#define _OMAP_TIMER_WAKEUP_EN_OFFSET   0x20
-#define _OMAP_TIMER_CTRL_OFFSET                0x24
-#define                OMAP_TIMER_CTRL_GPOCFG          (1 << 14)
-#define                OMAP_TIMER_CTRL_CAPTMODE        (1 << 13)
-#define                OMAP_TIMER_CTRL_PT              (1 << 12)
-#define                OMAP_TIMER_CTRL_TCM_LOWTOHIGH   (0x1 << 8)
-#define                OMAP_TIMER_CTRL_TCM_HIGHTOLOW   (0x2 << 8)
-#define                OMAP_TIMER_CTRL_TCM_BOTHEDGES   (0x3 << 8)
-#define                OMAP_TIMER_CTRL_SCPWM           (1 << 7)
-#define                OMAP_TIMER_CTRL_CE              (1 << 6) /* compare enable */
-#define                OMAP_TIMER_CTRL_PRE             (1 << 5) /* prescaler enable */
-#define                OMAP_TIMER_CTRL_PTV_SHIFT       2 /* prescaler value shift */
-#define                OMAP_TIMER_CTRL_POSTED          (1 << 2)
-#define                OMAP_TIMER_CTRL_AR              (1 << 1) /* auto-reload enable */
-#define                OMAP_TIMER_CTRL_ST              (1 << 0) /* start timer */
-#define _OMAP_TIMER_COUNTER_OFFSET     0x28
-#define _OMAP_TIMER_LOAD_OFFSET                0x2c
-#define _OMAP_TIMER_TRIGGER_OFFSET     0x30
-#define _OMAP_TIMER_WRITE_PEND_OFFSET  0x34
-#define                WP_NONE                 0       /* no write pending bit */
-#define                WP_TCLR                 (1 << 0)
-#define                WP_TCRR                 (1 << 1)
-#define                WP_TLDR                 (1 << 2)
-#define                WP_TTGR                 (1 << 3)
-#define                WP_TMAR                 (1 << 4)
-#define                WP_TPIR                 (1 << 5)
-#define                WP_TNIR                 (1 << 6)
-#define                WP_TCVR                 (1 << 7)
-#define                WP_TOCR                 (1 << 8)
-#define                WP_TOWR                 (1 << 9)
-#define _OMAP_TIMER_MATCH_OFFSET       0x38
-#define _OMAP_TIMER_CAPTURE_OFFSET     0x3c
-#define _OMAP_TIMER_IF_CTRL_OFFSET     0x40
-#define _OMAP_TIMER_CAPTURE2_OFFSET            0x44    /* TCAR2, 34xx only */
-#define _OMAP_TIMER_TICK_POS_OFFSET            0x48    /* TPIR, 34xx only */
-#define _OMAP_TIMER_TICK_NEG_OFFSET            0x4c    /* TNIR, 34xx only */
-#define _OMAP_TIMER_TICK_COUNT_OFFSET          0x50    /* TCVR, 34xx only */
-#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET   0x54    /* TOCR, 34xx only */
-#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58    /* TOWR, 34xx only */
-
-/* register offsets with the write pending bit encoded */
-#define        WPSHIFT                                 16
-
-#define OMAP_TIMER_ID_REG                      (_OMAP_TIMER_ID_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_OCP_CFG_REG                 (_OMAP_TIMER_OCP_CFG_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_SYS_STAT_REG                        (_OMAP_TIMER_SYS_STAT_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_STAT_REG                    (_OMAP_TIMER_STAT_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_INT_EN_REG                  (_OMAP_TIMER_INT_EN_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_WAKEUP_EN_REG               (_OMAP_TIMER_WAKEUP_EN_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_CTRL_REG                    (_OMAP_TIMER_CTRL_OFFSET \
-                                                       | (WP_TCLR << WPSHIFT))
-
-#define OMAP_TIMER_COUNTER_REG                 (_OMAP_TIMER_COUNTER_OFFSET \
-                                                       | (WP_TCRR << WPSHIFT))
-
-#define OMAP_TIMER_LOAD_REG                    (_OMAP_TIMER_LOAD_OFFSET \
-                                                       | (WP_TLDR << WPSHIFT))
-
-#define OMAP_TIMER_TRIGGER_REG                 (_OMAP_TIMER_TRIGGER_OFFSET \
-                                                       | (WP_TTGR << WPSHIFT))
-
-#define OMAP_TIMER_WRITE_PEND_REG              (_OMAP_TIMER_WRITE_PEND_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_MATCH_REG                   (_OMAP_TIMER_MATCH_OFFSET \
-                                                       | (WP_TMAR << WPSHIFT))
-
-#define OMAP_TIMER_CAPTURE_REG                 (_OMAP_TIMER_CAPTURE_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_IF_CTRL_REG                 (_OMAP_TIMER_IF_CTRL_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_CAPTURE2_REG                        (_OMAP_TIMER_CAPTURE2_OFFSET \
-                                                       | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_TICK_POS_REG                        (_OMAP_TIMER_TICK_POS_OFFSET \
-                                                       | (WP_TPIR << WPSHIFT))
-
-#define OMAP_TIMER_TICK_NEG_REG                        (_OMAP_TIMER_TICK_NEG_OFFSET \
-                                                       | (WP_TNIR << WPSHIFT))
-
-#define OMAP_TIMER_TICK_COUNT_REG              (_OMAP_TIMER_TICK_COUNT_OFFSET \
-                                                       | (WP_TCVR << WPSHIFT))
-
-#define OMAP_TIMER_TICK_INT_MASK_SET_REG                               \
-               (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
-
-#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG                             \
-               (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
-
-struct omap_dm_timer {
-       unsigned long phys_base;
-       int irq;
-#ifdef CONFIG_ARCH_OMAP2PLUS
-       struct clk *iclk, *fclk;
-#endif
-       void __iomem *io_base;
-       unsigned reserved:1;
-       unsigned enabled:1;
-       unsigned posted:1;
-};
-
 static int dm_timer_count;
 
 #ifdef CONFIG_ARCH_OMAP1
@@ -291,11 +170,7 @@ static spinlock_t dm_timer_lock;
  */
 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 {
-       if (timer->posted)
-               while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
-                               & (reg >> WPSHIFT))
-                       cpu_relax();
-       return readl(timer->io_base + (reg & 0xff));
+       return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
 }
 
 /*
@@ -307,11 +182,7 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
                                                u32 value)
 {
-       if (timer->posted)
-               while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
-                               & (reg >> WPSHIFT))
-                       cpu_relax();
-       writel(value, timer->io_base + (reg & 0xff));
+       __omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
 }
 
 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
@@ -330,7 +201,7 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
-       u32 l;
+       int autoidle = 0, wakeup = 0;
 
        if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
                omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
@@ -338,28 +209,21 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
        }
        omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
-       l |= 0x02 << 3;  /* Set to smart-idle mode */
-       l |= 0x2 << 8;   /* Set clock activity to perserve f-clock on idle */
-
-       /* Enable autoidle on OMAP2 / OMAP3 */
-       if (cpu_is_omap24xx() || cpu_is_omap34xx())
-               l |= 0x1 << 0;
+       /* Enable autoidle on OMAP2+ */
+       if (cpu_class_is_omap2())
+               autoidle = 1;
 
        /*
         * Enable wake-up on OMAP2 CPUs.
         */
        if (cpu_class_is_omap2())
-               l |= 1 << 2;
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
+               wakeup = 1;
 
-       /* Match hardware reset default of posted mode */
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
-                       OMAP_TIMER_CTRL_POSTED);
+       __omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
        timer->posted = 1;
 }
 
-static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+void omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
        omap_dm_timer_enable(timer);
        omap_dm_timer_reset(timer);
@@ -531,25 +395,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
 
 void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
-       u32 l;
+       unsigned long rate = 0;
 
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       if (l & OMAP_TIMER_CTRL_ST) {
-               l &= ~0x1;
-               omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 #ifdef CONFIG_ARCH_OMAP2PLUS
-               /* Readback to make sure write has completed */
-               omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-                /*
-                 * Wait for functional clock period x 3.5 to make sure that
-                 * timer is stopped
-                 */
-               udelay(3500000 / clk_get_rate(timer->fclk) + 1);
+       rate = clk_get_rate(timer->fclk);
 #endif
-       }
-       /* Ack possibly pending interrupt */
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
-                       OMAP_TIMER_INT_OVERFLOW);
+
+       __omap_dm_timer_stop(timer->io_base, timer->posted, rate);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
@@ -572,22 +424,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
-       int ret = -EINVAL;
-
        if (source < 0 || source >= 3)
                return -EINVAL;
 
-       clk_disable(timer->fclk);
-       ret = clk_set_parent(timer->fclk, dm_source_clocks[source]);
-       clk_enable(timer->fclk);
-
-       /*
-        * When the functional clock disappears, too quick writes seem
-        * to cause an abort. XXX Is this still necessary?
-        */
-       __delay(300000);
-
-       return ret;
+       return __omap_dm_timer_set_source(timer->fclk,
+                                               dm_source_clocks[source]);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
 
@@ -625,8 +466,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
        }
        l |= OMAP_TIMER_CTRL_ST;
 
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load);
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+       __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -679,8 +519,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
                                  unsigned int value)
 {
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
+       __omap_dm_timer_int_enable(timer->io_base, value);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -696,17 +535,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
 
 void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
+       __omap_dm_timer_write_status(timer->io_base, value);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
-       unsigned int l;
-
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
-
-       return l;
+       return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
@@ -737,7 +572,7 @@ int omap_dm_timers_active(void)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
 
-int __init omap_dm_timer_init(void)
+static int __init omap_dm_timer_init(void)
 {
        struct omap_dm_timer *timer;
        int i, map_size = SZ_8K;        /* Module 4KB + L4 4KB except on omap1 */
@@ -790,8 +625,16 @@ int __init omap_dm_timer_init(void)
                        sprintf(clk_name, "gpt%d_fck", i + 1);
                        timer->fclk = clk_get(NULL, clk_name);
                }
+
+               /* One or two timers may be set up early for sys_timer */
+               if (sys_timer_reserved & (1  << i)) {
+                       timer->reserved = 1;
+                       timer->posted = 1;
+               }
 #endif
        }
 
        return 0;
 }
+
+arch_initcall(omap_dm_timer_init);