Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / arch / arm / plat-omap / dmtimer.c
index eba3cb5..bcbb8d7 100644 (file)
@@ -4,7 +4,8 @@
  * OMAP Dual-Mode Timers
  *
  * Copyright (C) 2005 Nokia Corporation
- * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * OMAP2 support by Juha Yrjola
+ * API improvements and OMAP2 clock framework support by Timo Teras
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  */
 
 #include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <asm/hardware.h>
 #include <asm/arch/dmtimer.h>
 #include <asm/io.h>
 #include <asm/arch/irqs.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-
-#define OMAP_TIMER_COUNT               8
 
+/* register offsets */
 #define OMAP_TIMER_ID_REG              0x00
 #define OMAP_TIMER_OCP_CFG_REG         0x10
 #define OMAP_TIMER_SYS_STAT_REG                0x14
 #define OMAP_TIMER_CAPTURE_REG         0x3c
 #define OMAP_TIMER_IF_CTRL_REG         0x40
 
+/* timer control reg bits */
+#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               /* how much to shift the prescaler value */
+#define OMAP_TIMER_CTRL_AR             (1 << 1)        /* auto-reload enable */
+#define OMAP_TIMER_CTRL_ST             (1 << 0)        /* start timer */
+
+struct omap_dm_timer {
+       unsigned long phys_base;
+       int irq;
+#ifdef CONFIG_ARCH_OMAP2
+       struct clk *iclk, *fclk;
+#endif
+       void __iomem *io_base;
+       unsigned reserved:1;
+       unsigned enabled:1;
+};
+
+#ifdef CONFIG_ARCH_OMAP1
 
-static struct dmtimer_info_struct {
-       struct list_head        unused_timers;
-       struct list_head        reserved_timers;
-} dm_timer_info;
+#define omap_dm_clk_enable(x)
+#define omap_dm_clk_disable(x)
 
 static struct omap_dm_timer dm_timers[] = {
-       { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
-       { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
-       { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
-       { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
-       { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
-       { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
-       { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
-       { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
-       { .base=0x0 },
+       { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
+       { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
+       { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
+       { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
+       { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
+       { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
+       { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 },
+       { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 },
 };
 
+#elif defined(CONFIG_ARCH_OMAP2)
+
+#define omap_dm_clk_enable(x) clk_enable(x)
+#define omap_dm_clk_disable(x) clk_disable(x)
+
+static struct omap_dm_timer dm_timers[] = {
+       { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
+       { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
+       { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
+       { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
+       { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
+       { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
+       { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
+       { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
+       { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
+       { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
+       { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
+       { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
+};
 
+static const char *dm_source_names[] = {
+       "sys_ck",
+       "func_32k_ck",
+       "alt_ck"
+};
+
+static struct clk *dm_source_clocks[3];
+
+#else
+
+#error OMAP architecture not supported!
+
+#endif
+
+static const int dm_timer_count = ARRAY_SIZE(dm_timers);
 static spinlock_t dm_timer_lock;
 
+static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
+{
+       return readl(timer->io_base + reg);
+}
 
-inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
+static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
 {
-       omap_writel(value, timer->base + reg);
+       writel(value, timer->io_base + reg);
        while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
                ;
 }
 
-u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
+static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 {
-       return omap_readl(timer->base + reg);
+       int c;
+
+       c = 0;
+       while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
+               c++;
+               if (c > 100000) {
+                       printk(KERN_ERR "Timer failed to reset\n");
+                       return;
+               }
+       }
 }
 
-int omap_dm_timers_active(void)
+static void omap_dm_timer_reset(struct omap_dm_timer *timer)
+{
+       u32 l;
+
+       if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
+               omap_dm_timer_wait_for_reset(timer);
+       }
+       omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+       /* Set to smart-idle mode */
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
+       l |= 0x02 << 3;
+
+       if (cpu_class_is_omap2() && timer == &dm_timers[0]) {
+               /* Enable wake-up only for GPT1 on OMAP2 CPUs*/
+               l |= 1 << 2;
+               /* Non-posted mode */
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0);
+       }
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
+}
+
+static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
+{
+       omap_dm_timer_enable(timer);
+       omap_dm_timer_reset(timer);
+}
+
+struct omap_dm_timer *omap_dm_timer_request(void)
+{
+       struct omap_dm_timer *timer = NULL;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       for (i = 0; i < dm_timer_count; i++) {
+               if (dm_timers[i].reserved)
+                       continue;
+
+               timer = &dm_timers[i];
+               timer->reserved = 1;
+               break;
+       }
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+       if (timer != NULL)
+               omap_dm_timer_prepare(timer);
+
+       return timer;
+}
+
+struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
        struct omap_dm_timer *timer;
+       unsigned long flags;
 
-       for (timer = &dm_timers[0]; timer->base; ++timer)
-               if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
-                   OMAP_TIMER_CTRL_ST)
-                       return 1;
+       spin_lock_irqsave(&dm_timer_lock, flags);
+       if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
+               spin_unlock_irqrestore(&dm_timer_lock, flags);
+               printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
+                      __FILE__, __LINE__, __FUNCTION__, id);
+               dump_stack();
+               return NULL;
+       }
 
-       return 0;
+       timer = &dm_timers[id-1];
+       timer->reserved = 1;
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+       omap_dm_timer_prepare(timer);
+
+       return timer;
 }
 
+void omap_dm_timer_free(struct omap_dm_timer *timer)
+{
+       omap_dm_timer_enable(timer);
+       omap_dm_timer_reset(timer);
+       omap_dm_timer_disable(timer);
+
+       WARN_ON(!timer->reserved);
+       timer->reserved = 0;
+}
+
+void omap_dm_timer_enable(struct omap_dm_timer *timer)
+{
+       if (timer->enabled)
+               return;
+
+       omap_dm_clk_enable(timer->fclk);
+       omap_dm_clk_enable(timer->iclk);
+
+       timer->enabled = 1;
+}
+
+void omap_dm_timer_disable(struct omap_dm_timer *timer)
+{
+       if (!timer->enabled)
+               return;
+
+       omap_dm_clk_disable(timer->iclk);
+       omap_dm_clk_disable(timer->fclk);
+
+       timer->enabled = 0;
+}
+
+int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
+{
+       return timer->irq;
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+
+struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
+{
+       BUG();
+}
 
 /**
  * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
@@ -103,184 +282,243 @@ int omap_dm_timers_active(void)
  */
 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 {
-       int n;
+       int i;
 
        /* If ARMXOR cannot be idled this function call is unnecessary */
        if (!(inputmask & (1 << 1)))
                return inputmask;
 
        /* If any active timer is using ARMXOR return modified mask */
-       for (n = 0; dm_timers[n].base; ++n)
-               if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)&
-                   OMAP_TIMER_CTRL_ST) {
-                       if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0)
+       for (i = 0; i < dm_timer_count; i++) {
+               u32 l;
+
+               l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
+               if (l & OMAP_TIMER_CTRL_ST) {
+                       if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
                                inputmask &= ~(1 << 1);
                        else
                                inputmask &= ~(1 << 2);
                }
+       }
 
        return inputmask;
 }
 
+#elif defined(CONFIG_ARCH_OMAP2)
 
-void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
+struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
-       int n = (timer - dm_timers) << 1;
-       u32 l;
+       return timer->fclk;
+}
 
-       l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
-       l |= source << n;
-       omap_writel(l, MOD_CONF_CTRL_1);
+__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
+{
+       BUG();
 }
 
+#endif
 
-static void omap_dm_timer_reset(struct omap_dm_timer *timer)
+void omap_dm_timer_trigger(struct omap_dm_timer *timer)
 {
-       /* Reset and set posted mode */
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
-
-       omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 
+void omap_dm_timer_start(struct omap_dm_timer *timer)
+{
+       u32 l;
 
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       if (!(l & OMAP_TIMER_CTRL_ST)) {
+               l |= OMAP_TIMER_CTRL_ST;
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+       }
+}
 
-struct omap_dm_timer * omap_dm_timer_request(void)
+void omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
-       struct omap_dm_timer *timer = NULL;
-       unsigned long flags;
+       u32 l;
 
-       spin_lock_irqsave(&dm_timer_lock, flags);
-       if (!list_empty(&dm_timer_info.unused_timers)) {
-               timer = (struct omap_dm_timer *)
-                               dm_timer_info.unused_timers.next;
-               list_move_tail((struct list_head *)timer,
-                               &dm_timer_info.reserved_timers);
+       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);
        }
-       spin_unlock_irqrestore(&dm_timer_lock, flags);
-
-       return timer;
 }
 
+#ifdef CONFIG_ARCH_OMAP1
 
-void omap_dm_timer_free(struct omap_dm_timer *timer)
+void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
-       unsigned long flags;
-
-       omap_dm_timer_reset(timer);
+       int n = (timer - dm_timers) << 1;
+       u32 l;
 
-       spin_lock_irqsave(&dm_timer_lock, flags);
-       list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
-       spin_unlock_irqrestore(&dm_timer_lock, flags);
+       l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+       l |= source << n;
+       omap_writel(l, MOD_CONF_CTRL_1);
 }
 
-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);
-}
+#else
 
-unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
+void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
-       return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
-}
+       if (source < 0 || source >= 3)
+               return;
 
-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);
+       clk_disable(timer->fclk);
+       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. */
+       __delay(15000);
 }
 
-void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
+#endif
+
+void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+                           unsigned int load)
 {
        u32 l;
+
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       l |= OMAP_TIMER_CTRL_AR;
+       if (autoreload)
+               l |= OMAP_TIMER_CTRL_AR;
+       else
+               l &= ~OMAP_TIMER_CTRL_AR;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 
-void omap_dm_timer_trigger(struct omap_dm_timer *timer)
-{
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
-}
-
-void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
+void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
+                            unsigned int match)
 {
        u32 l;
 
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       l |= value & 0x3;
+       if (enable)
+               l |= OMAP_TIMER_CTRL_CE;
+       else
+               l &= ~OMAP_TIMER_CTRL_CE;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
 }
 
-void omap_dm_timer_start(struct omap_dm_timer *timer)
+
+void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
+                          int toggle, int trigger)
 {
        u32 l;
 
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       l |= OMAP_TIMER_CTRL_ST;
+       l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
+              OMAP_TIMER_CTRL_PT | (0x03 << 10));
+       if (def_on)
+               l |= OMAP_TIMER_CTRL_SCPWM;
+       if (toggle)
+               l |= OMAP_TIMER_CTRL_PT;
+       l |= trigger << 10;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 }
 
-void omap_dm_timer_stop(struct omap_dm_timer *timer)
+void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
        u32 l;
 
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       l &= ~0x1;
+       l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
+       if (prescaler >= 0x00 && prescaler <= 0x07) {
+               l |= OMAP_TIMER_CTRL_PRE;
+               l |= prescaler << 2;
+       }
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 }
 
-unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
+void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
+                                 unsigned int value)
 {
-       return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
 }
 
-void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
+unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
+       unsigned int l;
+
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+
+       return l;
 }
 
-void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
+void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
 }
 
-void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
+unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+       unsigned int l;
+
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+
+       return l;
 }
 
-void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
+void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
-       u32 l;
-
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       l |= OMAP_TIMER_CTRL_CE;
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+       omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
 }
 
+int omap_dm_timers_active(void)
+{
+       int i;
+
+       for (i = 0; i < dm_timer_count; i++) {
+               struct omap_dm_timer *timer;
+
+               timer = &dm_timers[i];
+
+               if (!timer->enabled)
+                       continue;
+
+               if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
+                   OMAP_TIMER_CTRL_ST) {
+                       return 1;
+               }
+       }
+       return 0;
+}
 
-static inline void __dm_timer_init(void)
+int omap_dm_timer_init(void)
 {
        struct omap_dm_timer *timer;
+       int i;
+
+       if (!(cpu_is_omap16xx() || cpu_is_omap24xx()))
+               return -ENODEV;
 
        spin_lock_init(&dm_timer_lock);
-       INIT_LIST_HEAD(&dm_timer_info.unused_timers);
-       INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
-
-       timer = &dm_timers[0];
-       while (timer->base) {
-               list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
-               omap_dm_timer_reset(timer);
-               timer++;
+#ifdef CONFIG_ARCH_OMAP2
+       for (i = 0; i < ARRAY_SIZE(dm_source_names); i++) {
+               dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
+               BUG_ON(dm_source_clocks[i] == NULL);
+       }
+#endif
+
+       for (i = 0; i < dm_timer_count; i++) {
+#ifdef CONFIG_ARCH_OMAP2
+               char clk_name[16];
+#endif
+
+               timer = &dm_timers[i];
+               timer->io_base = (void __iomem *) io_p2v(timer->phys_base);
+#ifdef CONFIG_ARCH_OMAP2
+               sprintf(clk_name, "gpt%d_ick", i + 1);
+               timer->iclk = clk_get(NULL, clk_name);
+               sprintf(clk_name, "gpt%d_fck", i + 1);
+               timer->fclk = clk_get(NULL, clk_name);
+#endif
        }
-}
 
-static int __init omap_dm_timer_init(void)
-{
-       if (cpu_is_omap16xx())
-               __dm_timer_init();
        return 0;
 }
-
-arch_initcall(omap_dm_timer_init);