]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/mach-omap2/clock.c
OMAP2/3 PRCM: convert IDLEST register bit macros to use the _SHIFT/_MASK style
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / clock.c
index 2bdd587f3169bad260be4f2fba014ae2806ea9d8..990da5a0479d82f81d343e7a5c686c38bf38ed0f 100644 (file)
 #define ST_CORE_CLK_REF                        0x1
 #define ST_CORE_CLK_32K                        0x3
 
+/* Bitmask to isolate the register type of clk.enable_reg */
+#define PRCM_REGTYPE_MASK              0xf0
+/* various CM register type options */
+#define CM_FCLKEN_REGTYPE              0x00
+#define CM_ICLKEN_REGTYPE              0x10
+#define CM_IDLEST_REGTYPE              0x20
+
 u8 cpu_mask;
 
 /*-------------------------------------------------------------------------
@@ -153,7 +160,8 @@ void omap2_init_clksel_parent(struct clk *clk)
        if (!clk->clksel)
                return;
 
-       r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
+       r = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       r &= clk->clksel_mask;
        r >>= __ffs(clk->clksel_mask);
 
        for (clks = clk->clksel; clks->parent && !found; clks++) {
@@ -204,7 +212,8 @@ u32 omap2_get_dpll_rate(struct clk *clk)
                return 0;
 
        /* Return bypass rate if DPLL is bypassed */
-       v = __raw_readl(dd->idlest_reg) & dd->idlest_mask;
+       v = cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg);
+       v &= dd->idlest_mask;
        v >>= __ffs(dd->idlest_mask);
        if (cpu_is_omap24xx()) {
 
@@ -220,7 +229,7 @@ u32 omap2_get_dpll_rate(struct clk *clk)
 
        }
 
-       v = __raw_readl(dd->mult_div1_reg);
+       v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
        dpll_mult = v & dd->mult_mask;
        dpll_mult >>= __ffs(dd->mult_mask);
        dpll_div = v & dd->div1_mask;
@@ -248,14 +257,16 @@ void omap2_fixed_divisor_recalc(struct clk *clk)
 
 /**
  * omap2_wait_clock_ready - wait for clock to enable
- * @reg: physical address of clock IDLEST register
+ * @prcm_mod: CM submodule offset from CM_BASE (e.g., "MPU_MOD")
+ * @reg_index: offset of CM register address from prcm_mod
  * @mask: value to mask against to determine if the clock is active
  * @name: name of the clock (for printk)
  *
  * Returns 1 if the clock enabled in time, or 0 if it failed to enable
  * in roughly MAX_CLOCK_ENABLE_WAIT microseconds.
  */
-int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
+int omap2_wait_clock_ready(s16 prcm_mod, u16 reg_index, u32 mask,
+                          const char *name)
 {
        int i = 0, ena = 0;
 
@@ -269,7 +280,7 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
                ena = 0;
 
        /* Wait for lock */
-       while (((__raw_readl(reg) & mask) != ena) &&
+       while (((cm_read_mod_reg(prcm_mod, reg_index) & mask) != ena) &&
               (i++ < MAX_CLOCK_ENABLE_WAIT)) {
                udelay(1);
        }
@@ -280,7 +291,6 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
                printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
                       name, MAX_CLOCK_ENABLE_WAIT);
 
-
        return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0;
 };
 
@@ -294,29 +304,28 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
  */
 static void omap2_clk_wait_ready(struct clk *clk)
 {
+       u16 other_reg, idlest_reg;
        u32 other_bit, idlest_bit;
-       unsigned long reg, other_reg, idlest_reg, prcm_mod, prcm_regid;
 
-       reg = (unsigned long)clk->enable_reg;
-       prcm_mod = reg & ~0xff;
-       prcm_regid = reg & 0xff;
+       /* Only CM-controlled clocks affect module IDLEST */
+       if (clk->prcm_mod & ~PRCM_MOD_ADDR_MASK)
+               return;
+
+       other_reg = clk->enable_reg & ~PRCM_REGTYPE_MASK;
 
-       if (prcm_regid >= CM_FCLKEN1 && prcm_regid <= OMAP24XX_CM_FCLKEN2)
-               other_reg = ((reg & ~0xf0) | 0x10); /* CM_ICLKEN* */
-       else if (prcm_regid >= CM_ICLKEN1 && prcm_regid <= OMAP24XX_CM_ICLKEN4)
-               other_reg = ((reg & ~0xf0) | 0x00); /* CM_FCLKEN* */
+       /* If we are enabling an iclk, also test the fclk; and vice versa */
+       if (clk->enable_reg & CM_ICLKEN_REGTYPE)
+               other_reg |= CM_FCLKEN_REGTYPE;
        else
-               return;
+               other_reg |= CM_ICLKEN_REGTYPE;
 
        /* Covers most of the cases - a few exceptions are below */
        other_bit = 1 << clk->enable_bit;
        idlest_bit = other_bit;
 
        /* 24xx: DSS and CAM have no idlest bits for their target agents */
-       if (cpu_is_omap24xx() &&
-           (prcm_mod == OMAP2420_CM_REGADDR(CORE_MOD, 0) ||
-            prcm_mod == OMAP2430_CM_REGADDR(CORE_MOD, 0)) &&
-           (reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
+       if (cpu_is_omap24xx() && clk->prcm_mod == CORE_MOD &&
+           (clk->enable_reg == CM_FCLKEN1 || clk->enable_reg == CM_ICLKEN1)) {
 
                if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT ||
                    clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT ||
@@ -329,18 +338,19 @@ static void omap2_clk_wait_ready(struct clk *clk)
        if (cpu_is_omap34xx()) {
 
                /* SSI */
-               if (prcm_mod == OMAP34XX_CM_REGADDR(CORE_MOD, 0) &&
-                   (reg & 0x0f) == 0 &&
+               if (clk->prcm_mod == CORE_MOD &&
+                   (clk->enable_reg == CM_FCLKEN1 ||
+                    clk->enable_reg == CM_ICLKEN1) &&
                    clk->enable_bit == OMAP3430_EN_SSI_SHIFT) {
 
                        if (system_rev == OMAP3430_REV_ES1_0)
                                return;
 
-                       idlest_bit = OMAP3430ES2_ST_SSI_IDLE;
+                       idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
                }
 
                /* DSS */
-               if (prcm_mod == OMAP34XX_CM_REGADDR(OMAP3430_DSS_MOD, 0)) {
+               if (clk->prcm_mod == OMAP3430_DSS_MOD) {
 
                        /* 3430ES1 DSS has no target idlest bits */
                        if (system_rev == OMAP3430_REV_ES1_0)
@@ -353,12 +363,12 @@ static void omap2_clk_wait_ready(struct clk *clk)
                        if (clk->enable_bit != OMAP3430_EN_DSS1_SHIFT)
                                return;
 
-                       idlest_bit = OMAP3430ES2_ST_DSS_IDLE;
+                       idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT;
                }
 
                /* USBHOST */
                if (system_rev > OMAP3430_REV_ES1_0 &&
-                   prcm_mod == OMAP34XX_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, 0)) {
+                   clk->prcm_mod == OMAP3430ES2_USBHOST_MOD) {
 
                        /*
                         * The 120MHz clock apparently has nothing to do with
@@ -367,19 +377,19 @@ static void omap2_clk_wait_ready(struct clk *clk)
                        if (clk->enable_bit == OMAP3430ES2_EN_USBHOST2_SHIFT)
                                return;
 
-                       idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE;
+                       idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT;
 
                }
        }
 
-       /* Check if both functional and interface clocks
-        * are running. */
-       if (!(__raw_readl((void __iomem *)other_reg) & other_bit))
+       /* Check if both functional and interface clocks are running. */
+       if (!(cm_read_mod_reg(clk->prcm_mod, other_reg) & other_bit))
                return;
 
-       idlest_reg = ((other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */
+       idlest_reg = other_reg & ~PRCM_REGTYPE_MASK;
+       idlest_reg |= CM_IDLEST_REGTYPE;
 
-       omap2_wait_clock_ready((void __iomem *)idlest_reg, idlest_bit,
+       omap2_wait_clock_ready(clk->prcm_mod, idlest_reg, idlest_bit,
                               clk->name);
 }
 
@@ -396,18 +406,12 @@ static int _omap2_clk_enable(struct clk *clk)
        if (clk->enable)
                return clk->enable(clk);
 
-       if (unlikely(clk->enable_reg == NULL)) {
-               printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
-                      clk->name);
-               return 0; /* REVISIT: -EINVAL */
-       }
-
-       v = __raw_readl(clk->enable_reg);
+       v = _omap2_clk_read_reg(clk->enable_reg, clk);
        if (clk->flags & INVERT_ENABLE)
                v &= ~(1 << clk->enable_bit);
        else
                v |= (1 << clk->enable_bit);
-       __raw_writel(v, clk->enable_reg);
+       _omap2_clk_write_reg(v, clk->enable_reg, clk);
        wmb();
 
        omap2_clk_wait_ready(clk);
@@ -428,22 +432,12 @@ static void _omap2_clk_disable(struct clk *clk)
                return;
        }
 
-       if (clk->enable_reg == NULL) {
-               /*
-                * 'Independent' here refers to a clock which is not
-                * controlled by its parent.
-                */
-               printk(KERN_ERR "clock: clk_disable called on independent "
-                      "clock %s which has no enable_reg\n", clk->name);
-               return;
-       }
-
-       v = __raw_readl(clk->enable_reg);
+       v = _omap2_clk_read_reg(clk->enable_reg, clk);
        if (clk->flags & INVERT_ENABLE)
                v |= (1 << clk->enable_bit);
        else
                v &= ~(1 << clk->enable_bit);
-       __raw_writel(v, clk->enable_reg);
+       _omap2_clk_write_reg(v, clk->enable_reg, clk);
        wmb();
 }
 
@@ -713,23 +707,6 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
        return clkr->val;
 }
 
-/**
- * omap2_get_clksel - find clksel register addr & field mask for a clk
- * @clk: struct clk to use
- * @field_mask: ptr to u32 to store the register field mask
- *
- * Returns the address of the clksel register upon success or NULL on error.
- */
-static void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
-{
-       if (unlikely((clk->clksel_reg == NULL) || (clk->clksel_mask == NULL)))
-               return NULL;
-
-       *field_mask = clk->clksel_mask;
-
-       return clk->clksel_reg;
-}
-
 /**
  * omap2_clksel_get_divisor - get current divider applied to parent clock.
  * @clk: OMAP struct clk to use.
@@ -738,41 +715,37 @@ static void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
  */
 u32 omap2_clksel_get_divisor(struct clk *clk)
 {
-       u32 field_mask, v;
-       void __iomem *div_addr;
+       u32 v;
 
-       div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == NULL)
+       if (!clk->clksel_mask)
                return 0;
 
-       v = __raw_readl(div_addr) & field_mask;
-       v >>= __ffs(field_mask);
+       v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       v &= clk->clksel_mask;
+       v >>= __ffs(clk->clksel_mask);
 
        return omap2_clksel_to_divisor(clk, v);
 }
 
 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 field_mask, field_val, validrate, new_div = 0;
-       void __iomem *div_addr;
-       u32 v;
+       u32 v, field_val, validrate, new_div = 0;
 
-       validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
-       if (validrate != rate)
+       if (!clk->clksel_mask)
                return -EINVAL;
 
-       div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == NULL)
-               return -EINVAL;
+       validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+       if (validrate != rate)
+              return -EINVAL;
 
        field_val = omap2_divisor_to_clksel(clk, new_div);
        if (field_val == ~0)
                return -EINVAL;
 
-       v = __raw_readl(div_addr);
-       v &= ~field_mask;
-       v |= field_val << __ffs(field_mask);
-       __raw_writel(v, div_addr);
+       v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       v &= ~clk->clksel_mask;
+       v |= field_val << __ffs(clk->clksel_mask);
+       _omap2_clk_write_reg(v, clk->clksel_reg, clk);
 
        wmb();
 
@@ -812,18 +785,14 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
 
 /*
  * Converts encoded control register address into a full address
- * On error, *src_addr will be returned as 0.
+ * On error, the return value (parent_div) will be 0.
  */
-static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
-                                     struct clk *src_clk, u32 *field_mask,
-                                     struct clk *clk, u32 *parent_div)
+static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
+                                      u32 *field_val)
 {
        const struct clksel *clks;
        const struct clksel_rate *clkr;
 
-       *parent_div = 0;
-       *src_addr = NULL;
-
        clks = omap2_get_clksel_by_parent(clk, src_clk);
        if (!clks)
                return 0;
@@ -843,17 +812,14 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
        /* Should never happen.  Add a clksel mask to the struct clk. */
        WARN_ON(clk->clksel_mask == 0);
 
-       *field_mask = clk->clksel_mask;
-       *src_addr = clk->clksel_reg;
-       *parent_div = clkr->div;
+       *field_val = clkr->val;
 
-       return clkr->val;
+       return clkr->div;
 }
 
 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
 {
-       void __iomem *src_addr;
-       u32 field_val, field_mask, v, parent_div;
+       u32 field_val, v, parent_div;
 
        if (clk->flags & CONFIG_PARTICIPANT)
                return -EINVAL;
@@ -861,18 +827,18 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
        if (!clk->clksel)
                return -EINVAL;
 
-       field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
-                                              &field_mask, clk, &parent_div);
-       if (src_addr == NULL)
+       parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val);
+       if (!parent_div)
                return -EINVAL;
 
        if (clk->usecount > 0)
                _omap2_clk_disable(clk);
 
        /* Set new source value (previous dividers if any in effect) */
-       v = __raw_readl(src_addr) & ~field_mask;
-       v |= (field_val << __ffs(field_mask));
-       __raw_writel(v, src_addr);
+       v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       v &= ~clk->clksel_mask;
+       v |= field_val << __ffs(clk->clksel_mask);
+       _omap2_clk_write_reg(v, clk->clksel_reg, clk);
        wmb();
 
        if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
@@ -1091,7 +1057,7 @@ void omap2_clk_disable_unused(struct clk *clk)
 
        v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
 
-       regval32 = __raw_readl(clk->enable_reg);
+       regval32 = _omap2_clk_read_reg(clk->enable_reg, clk);
        if ((regval32 & (1 << clk->enable_bit)) == v)
                return;