]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'omap-clks3' into devel
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Thu, 19 Mar 2009 12:39:58 +0000 (12:39 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 19 Mar 2009 12:39:58 +0000 (12:39 +0000)
Conflicts:

arch/arm/mach-omap2/clock.c

1  2 
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/clock.c
drivers/mmc/host/omap_hsmmc.c

index 6031e179926bf66a5a45b8e560df5f63cb0d884c,61f7c365a28cb3082db7f4dc2f335a916b24e946..73e3fdb2d20a1ddf441ad930fa3e0cf701bed74c
@@@ -81,7 -81,7 +81,7 @@@ static inline void __init ldp_init_smc9
        }
  
        ldp_smc911x_resources[0].start = cs_mem_base + 0x0;
 -      ldp_smc911x_resources[0].end   = cs_mem_base + 0xf;
 +      ldp_smc911x_resources[0].end   = cs_mem_base + 0xff;
        udelay(100);
  
        eth_gpio = LDP_SMC911X_GPIO;
@@@ -98,7 -98,7 +98,7 @@@
  
  static void __init omap_ldp_init_irq(void)
  {
-       omap2_init_common_hw();
+       omap2_init_common_hw(NULL);
        omap_init_irq();
        omap_gpio_init();
        ldp_init_smc911x();
index ce4d46a4a8381d2bd2b0cff19f840ae16ac2c153,f49bce997a0b7ffd9c0fc9194057a7759c08d029..4247a1534411ba9f9cf5bfd23c9abf94bcd799c0
  
  #include <mach/clock.h>
  #include <mach/clockdomain.h>
- #include <mach/sram.h>
  #include <mach/cpu.h>
  #include <asm/div64.h>
  
- #include "memory.h"
+ #include <mach/sdrc.h>
  #include "sdrc.h"
  #include "clock.h"
  #include "prm.h"
@@@ -46,7 -45,7 +45,7 @@@
  #define DPLL_MIN_DIVIDER              1
  
  /* Possible error results from _dpll_test_mult */
- #define DPLL_MULT_UNDERFLOW           (1 << 0)
+ #define DPLL_MULT_UNDERFLOW           -1
  
  /*
   * Scale factor to mitigate roundoff errors in DPLL rate rounding.
  #define DPLL_ROUNDING_VAL             ((DPLL_SCALE_BASE / 2) * \
                                         (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
  
+ /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
+ #define DPLL_FINT_BAND1_MIN           750000
+ #define DPLL_FINT_BAND1_MAX           2100000
+ #define DPLL_FINT_BAND2_MIN           7500000
+ #define DPLL_FINT_BAND2_MAX           21000000
+ /* _dpll_test_fint() return codes */
+ #define DPLL_FINT_UNDERFLOW           -1
+ #define DPLL_FINT_INVALID             -2
  u8 cpu_mask;
  
  /*-------------------------------------------------------------------------
   * OMAP2/3 specific clock functions
   *-------------------------------------------------------------------------*/
  
+ /**
+  * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware
+  * @clk: struct clk *
+  *
+  * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes
+  * don't take effect until the VALID_CONFIG bit is written, write the
+  * VALID_CONFIG bit and wait for the write to complete.  No return value.
+  */
+ static void _omap2xxx_clk_commit(struct clk *clk)
+ {
+       if (!cpu_is_omap24xx())
+               return;
+       if (!(clk->flags & DELAYED_APP))
+               return;
+       prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
+               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+       /* OCP barrier */
+       prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+ }
+ /*
+  * _dpll_test_fint - test whether an Fint value is valid for the DPLL
+  * @clk: DPLL struct clk to test
+  * @n: divider value (N) to test
+  *
+  * Tests whether a particular divider @n will result in a valid DPLL
+  * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
+  * Correction".  Returns 0 if OK, -1 if the enclosing loop can terminate
+  * (assuming that it is counting N upwards), or -2 if the enclosing loop
+  * should skip to the next iteration (again assuming N is increasing).
+  */
+ static int _dpll_test_fint(struct clk *clk, u8 n)
+ {
+       struct dpll_data *dd;
+       long fint;
+       int ret = 0;
+       dd = clk->dpll_data;
+       /* DPLL divider must result in a valid jitter correction val */
+       fint = clk->parent->rate / (n + 1);
+       if (fint < DPLL_FINT_BAND1_MIN) {
+               pr_debug("rejecting n=%d due to Fint failure, "
+                        "lowering max_divider\n", n);
+               dd->max_divider = n;
+               ret = DPLL_FINT_UNDERFLOW;
+       } else if (fint > DPLL_FINT_BAND1_MAX &&
+                  fint < DPLL_FINT_BAND2_MIN) {
+               pr_debug("rejecting n=%d due to Fint failure\n", n);
+               ret = DPLL_FINT_INVALID;
+       } else if (fint > DPLL_FINT_BAND2_MAX) {
+               pr_debug("rejecting n=%d due to Fint failure, "
+                        "boosting min_divider\n", n);
+               dd->min_divider = n;
+               ret = DPLL_FINT_INVALID;
+       }
+       return ret;
+ }
  /**
   * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
   * @clk: OMAP clock struct ptr to use
@@@ -120,7 -197,7 +197,7 @@@ void omap2_init_clksel_parent(struct cl
                                                 clk->name, clks->parent->name,
                                                 ((clk->parent) ?
                                                  clk->parent->name : "NULL"));
-                                       clk->parent = clks->parent;
+                                       clk_reparent(clk, clks->parent);
                                };
                                found = 1;
                        }
        return;
  }
  
- /* Returns the DPLL rate */
+ /**
+  * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
+  * @clk: struct clk * of a DPLL
+  *
+  * DPLLs can be locked or bypassed - basically, enabled or disabled.
+  * When locked, the DPLL output depends on the M and N values.  When
+  * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
+  * or sys_clk.  Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
+  * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
+  * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
+  * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
+  * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
+  * if the clock @clk is not a DPLL.
+  */
  u32 omap2_get_dpll_rate(struct clk *clk)
  {
        long long dpll_clk;
-       u32 dpll_mult, dpll_div, dpll;
+       u32 dpll_mult, dpll_div, v;
        struct dpll_data *dd;
  
        dd = clk->dpll_data;
-       /* REVISIT: What do we return on error? */
        if (!dd)
                return 0;
  
-       dpll = __raw_readl(dd->mult_div1_reg);
-       dpll_mult = dpll & dd->mult_mask;
+       /* Return bypass rate if DPLL is bypassed */
+       v = __raw_readl(dd->control_reg);
+       v &= dd->enable_mask;
+       v >>= __ffs(dd->enable_mask);
+       if (cpu_is_omap24xx()) {
+               if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
+                   v == OMAP2XXX_EN_DPLL_FRBYPASS)
+                       return dd->clk_bypass->rate;
+       } else if (cpu_is_omap34xx()) {
+               if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
+                   v == OMAP3XXX_EN_DPLL_FRBYPASS)
+                       return dd->clk_bypass->rate;
+       }
+       v = __raw_readl(dd->mult_div1_reg);
+       dpll_mult = v & dd->mult_mask;
        dpll_mult >>= __ffs(dd->mult_mask);
-       dpll_div = dpll & dd->div1_mask;
+       dpll_div = v & dd->div1_mask;
        dpll_div >>= __ffs(dd->div1_mask);
  
-       dpll_clk = (long long)clk->parent->rate * dpll_mult;
+       dpll_clk = (long long)dd->clk_ref->rate * dpll_mult;
        do_div(dpll_clk, dpll_div + 1);
  
        return dpll_clk;
   * Used for clocks that have the same value as the parent clock,
   * divided by some factor
   */
void omap2_fixed_divisor_recalc(struct clk *clk)
unsigned long omap2_fixed_divisor_recalc(struct clk *clk)
  {
        WARN_ON(!clk->fixed_div);
  
-       clk->rate = clk->parent->rate / clk->fixed_div;
-       if (clk->flags & RATE_PROPAGATES)
-               propagate_rate(clk);
+       return clk->parent->rate / clk->fixed_div;
  }
  
  /**
@@@ -190,11 -291,10 +291,10 @@@ int omap2_wait_clock_ready(void __iome
         * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
         * 34xx reverses this, just to keep us on our toes
         */
-       if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) {
+       if (cpu_mask & (RATE_IN_242X | RATE_IN_243X))
                ena = mask;
-       } else if (cpu_mask & RATE_IN_343X) {
+       else if (cpu_mask & RATE_IN_343X)
                ena = 0;
-       }
  
        /* Wait for lock */
        while (((__raw_readl(reg) & mask) != ena) &&
@@@ -228,31 -328,12 +328,12 @@@ static void omap2_clk_wait_ready(struc
         * it and pull it into struct clk itself somehow.
         */
        reg = clk->enable_reg;
-       if ((((u32)reg & 0xff) >= CM_FCLKEN1) &&
-           (((u32)reg & 0xff) <= OMAP24XX_CM_FCLKEN2))
-               other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x10); /* CM_ICLKEN* */
-       else if ((((u32)reg & 0xff) >= CM_ICLKEN1) &&
-                (((u32)reg & 0xff) <= OMAP24XX_CM_ICLKEN4))
-               other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x00); /* CM_FCLKEN* */
-       else
-               return;
  
-       /* REVISIT: What are the appropriate exclusions for 34XX? */
-       /* No check for DSS or cam clocks */
-       if (cpu_is_omap24xx() && ((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
-               if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT ||
-                   clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT ||
-                   clk->enable_bit == OMAP24XX_EN_CAM_SHIFT)
-                       return;
-       }
-       /* REVISIT: What are the appropriate exclusions for 34XX? */
-       /* OMAP3: ignore DSS-mod clocks */
-       if (cpu_is_omap34xx() &&
-           (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0) ||
-            ((((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(CORE_MOD, 0)) &&
-            clk->enable_bit == OMAP3430_EN_SSI_SHIFT)))
-               return;
+       /*
+        * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes
+        * it's just a matter of XORing the bits.
+        */
+       other_reg = (void __iomem *)((u32)reg ^ (CM_FCLKEN ^ CM_ICLKEN));
  
        /* Check if both functional and interface clocks
         * are running. */
        omap2_wait_clock_ready(st_reg, bit, clk->name);
  }
  
- /* Enables clock without considering parent dependencies or use count
-  * REVISIT: Maybe change this to use clk->enable like on omap1?
-  */
- int _omap2_clk_enable(struct clk *clk)
+ static int omap2_dflt_clk_enable(struct clk *clk)
  {
-       u32 regval32;
-       if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
-               return 0;
-       if (clk->enable)
-               return clk->enable(clk);
+       u32 v;
  
        if (unlikely(clk->enable_reg == NULL)) {
                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
                return 0; /* REVISIT: -EINVAL */
        }
  
-       regval32 = __raw_readl(clk->enable_reg);
+       v = __raw_readl(clk->enable_reg);
        if (clk->flags & INVERT_ENABLE)
-               regval32 &= ~(1 << clk->enable_bit);
+               v &= ~(1 << clk->enable_bit);
        else
-               regval32 |= (1 << clk->enable_bit);
-       __raw_writel(regval32, clk->enable_reg);
-       wmb();
-       omap2_clk_wait_ready(clk);
+               v |= (1 << clk->enable_bit);
+       __raw_writel(v, clk->enable_reg);
+       v = __raw_readl(clk->enable_reg); /* OCP barrier */
  
        return 0;
  }
  
- /* Disables clock without considering parent dependencies or use count */
- void _omap2_clk_disable(struct clk *clk)
+ static int omap2_dflt_clk_enable_wait(struct clk *clk)
  {
-       u32 regval32;
-       if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
-               return;
+       int ret;
  
-       if (clk->disable) {
-               clk->disable(clk);
-               return;
+       if (!clk->enable_reg) {
+               printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+                      clk->name);
+               return 0; /* REVISIT: -EINVAL */
        }
  
-       if (clk->enable_reg == NULL) {
+       ret = omap2_dflt_clk_enable(clk);
+       if (ret == 0)
+               omap2_clk_wait_ready(clk);
+       return ret;
+ }
+ static void omap2_dflt_clk_disable(struct clk *clk)
+ {
+       u32 v;
+       if (!clk->enable_reg) {
                /*
                 * 'Independent' here refers to a clock which is not
                 * controlled by its parent.
                return;
        }
  
-       regval32 = __raw_readl(clk->enable_reg);
+       v = __raw_readl(clk->enable_reg);
        if (clk->flags & INVERT_ENABLE)
-               regval32 |= (1 << clk->enable_bit);
+               v |= (1 << clk->enable_bit);
        else
-               regval32 &= ~(1 << clk->enable_bit);
-       __raw_writel(regval32, clk->enable_reg);
-       wmb();
+               v &= ~(1 << clk->enable_bit);
+       __raw_writel(v, clk->enable_reg);
+       /* No OCP barrier needed here since it is a disable operation */
+ }
+ const struct clkops clkops_omap2_dflt_wait = {
+       .enable         = omap2_dflt_clk_enable_wait,
+       .disable        = omap2_dflt_clk_disable,
+ };
+ const struct clkops clkops_omap2_dflt = {
+       .enable         = omap2_dflt_clk_enable,
+       .disable        = omap2_dflt_clk_disable,
+ };
+ /* Enables clock without considering parent dependencies or use count
+  * REVISIT: Maybe change this to use clk->enable like on omap1?
+  */
+ static int _omap2_clk_enable(struct clk *clk)
+ {
+       return clk->ops->enable(clk);
+ }
+ /* Disables clock without considering parent dependencies or use count */
+ static void _omap2_clk_disable(struct clk *clk)
+ {
+       clk->ops->disable(clk);
  }
  
  void omap2_clk_disable(struct clk *clk)
  {
        if (clk->usecount > 0 && !(--clk->usecount)) {
                _omap2_clk_disable(clk);
-               if (likely((u32)clk->parent))
+               if (clk->parent)
                        omap2_clk_disable(clk->parent);
                if (clk->clkdm)
                        omap2_clkdm_clk_disable(clk->clkdm, clk);
@@@ -345,30 -446,29 +446,29 @@@ int omap2_clk_enable(struct clk *clk
        int ret = 0;
  
        if (clk->usecount++ == 0) {
-               if (likely((u32)clk->parent))
-                       ret = omap2_clk_enable(clk->parent);
-               if (unlikely(ret != 0)) {
-                       clk->usecount--;
-                       return ret;
-               }
                if (clk->clkdm)
                        omap2_clkdm_clk_enable(clk->clkdm, clk);
  
-               ret = _omap2_clk_enable(clk);
-               if (unlikely(ret != 0)) {
-                       if (clk->clkdm)
-                               omap2_clkdm_clk_disable(clk->clkdm, clk);
+               if (clk->parent) {
+                       ret = omap2_clk_enable(clk->parent);
+                       if (ret)
+                               goto err;
+               }
  
-                       if (clk->parent) {
+               ret = _omap2_clk_enable(clk);
+               if (ret) {
+                       if (clk->parent)
                                omap2_clk_disable(clk->parent);
-                               clk->usecount--;
-                       }
+                       goto err;
                }
        }
+       return ret;
  
+ err:
+       if (clk->clkdm)
+               omap2_clkdm_clk_disable(clk->clkdm, clk);
+       clk->usecount--;
        return ret;
  }
  
   * Used for clocks that are part of CLKSEL_xyz governed clocks.
   * REVISIT: Maybe change to use clk->enable() functions like on omap1?
   */
void omap2_clksel_recalc(struct clk *clk)
unsigned long omap2_clksel_recalc(struct clk *clk)
  {
+       unsigned long rate;
        u32 div = 0;
  
        pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
  
        div = omap2_clksel_get_divisor(clk);
        if (div == 0)
-               return;
+               return clk->rate;
  
-       if (unlikely(clk->rate == clk->parent->rate / div))
-               return;
-       clk->rate = clk->parent->rate / div;
+       rate = clk->parent->rate / div;
  
-       pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
+       pr_debug("clock: new clock rate is %ld (div %d)\n", rate, div);
  
-       if (unlikely(clk->flags & RATE_PROPAGATES))
-               propagate_rate(clk);
+       return rate;
  }
  
  /**
   * the element associated with the supplied parent clock address.
   * Returns a pointer to the struct clksel on success or NULL on error.
   */
- const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
-                                               struct clk *src_clk)
static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
+                                                      struct clk *src_clk)
  {
        const struct clksel *clks;
  
@@@ -455,7 -553,7 +553,7 @@@ u32 omap2_clksel_round_rate_div(struct 
        *new_div = 1;
  
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return ~0;
  
        for (clkr = clks->rates; clkr->div; clkr++) {
@@@ -514,7 -612,7 +612,7 @@@ long omap2_clksel_round_rate(struct cl
  /* Given a clock and a rate apply a clock specific rounding function */
  long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
  {
-       if (clk->round_rate != NULL)
+       if (clk->round_rate)
                return clk->round_rate(clk, rate);
  
        if (clk->flags & RATE_FIXED)
@@@ -540,7 -638,7 +638,7 @@@ u32 omap2_clksel_to_divisor(struct clk 
        const struct clksel_rate *clkr;
  
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return 0;
  
        for (clkr = clks->rates; clkr->div; clkr++) {
   *
   * Given a struct clk of a rate-selectable clksel clock, and a clock divisor,
   * find the corresponding register field value.  The return register value is
 - * the value before left-shifting.  Returns 0xffffffff on error
 + * the value before left-shifting.  Returns ~0 on error
   */
  u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
  {
        WARN_ON(div == 0);
  
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
 -              return 0;
 +              return ~0;
  
        for (clkr = clks->rates; clkr->div; clkr++) {
                if ((clkr->flags & cpu_mask) && (clkr->div == div))
                printk(KERN_ERR "clock: Could not find divisor %d for "
                       "clock %s parent %s\n", div, clk->name,
                       clk->parent->name);
 -              return 0;
 +              return ~0;
        }
  
        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.
-  */
- 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.
   */
  u32 omap2_clksel_get_divisor(struct clk *clk)
  {
-       u32 field_mask, field_val;
-       void __iomem *div_addr;
+       u32 v;
  
-       div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == NULL)
+       if (!clk->clksel_mask)
                return 0;
  
-       field_val = __raw_readl(div_addr) & field_mask;
-       field_val >>= __ffs(field_mask);
+       v = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
+       v >>= __ffs(clk->clksel_mask);
  
-       return omap2_clksel_to_divisor(clk, field_val);
+       return omap2_clksel_to_divisor(clk, v);
  }
  
  int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
  {
-       u32 field_mask, field_val, reg_val, validrate, new_div = 0;
-       void __iomem *div_addr;
+       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)
+       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;
  
-       reg_val = __raw_readl(div_addr);
-       reg_val &= ~field_mask;
-       reg_val |= (field_val << __ffs(field_mask));
-       __raw_writel(reg_val, div_addr);
-       wmb();
+       v = __raw_readl(clk->clksel_reg);
+       v &= ~clk->clksel_mask;
+       v |= field_val << __ffs(clk->clksel_mask);
+       __raw_writel(v, clk->clksel_reg);
+       v = __raw_readl(clk->clksel_reg); /* OCP barrier */
  
        clk->rate = clk->parent->rate / new_div;
  
-       if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
-               prm_write_mod_reg(OMAP24XX_VALID_CONFIG,
-                       OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
-               wmb();
-       }
+       _omap2xxx_clk_commit(clk);
  
        return 0;
  }
@@@ -680,35 -753,28 +753,28 @@@ int omap2_clk_set_rate(struct clk *clk
                return -EINVAL;
  
        /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
-       if (clk->set_rate != NULL)
+       if (clk->set_rate)
                ret = clk->set_rate(clk, rate);
  
-       if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
-               propagate_rate(clk);
        return ret;
  }
  
  /*
   * 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 == NULL)
+       if (!clks)
                return 0;
  
        for (clkr = clks->rates; clkr->div; clkr++) {
 -              if (clkr->flags & (cpu_mask | DEFAULT_RATE))
 +              if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE)
                        break; /* Found the default rate for this platform */
        }
  
        /* 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, reg_val, parent_div;
+       u32 field_val, v, parent_div;
  
-       if (unlikely(clk->flags & CONFIG_PARTICIPANT))
+       if (clk->flags & CONFIG_PARTICIPANT)
                return -EINVAL;
  
        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) */
-       reg_val = __raw_readl(src_addr) & ~field_mask;
-       reg_val |= (field_val << __ffs(field_mask));
-       __raw_writel(reg_val, src_addr);
-       wmb();
-       if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
-               __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
-               wmb();
-       }
+       v = __raw_readl(clk->clksel_reg);
+       v &= ~clk->clksel_mask;
+       v |= field_val << __ffs(clk->clksel_mask);
+       __raw_writel(v, clk->clksel_reg);
+       v = __raw_readl(clk->clksel_reg);    /* OCP barrier */
  
-       clk->parent = new_parent;
+       _omap2xxx_clk_commit(clk);
  
-       if (clk->usecount > 0)
-               omap2_clk_enable(clk);
+       clk_reparent(clk, new_parent);
  
        /* CLKSEL clocks follow their parents' rates, divided by a divisor */
        clk->rate = new_parent->rate;
        pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
                 clk->name, clk->parent->name, clk->rate);
  
-       if (unlikely(clk->flags & RATE_PROPAGATES))
-               propagate_rate(clk);
        return 0;
  }
  
@@@ -805,7 -856,8 +856,8 @@@ int omap2_dpll_set_rate_tolerance(struc
        return 0;
  }
  
- static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, unsigned int m, unsigned int n)
+ static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
+                                           unsigned int m, unsigned int n)
  {
        unsigned long long num;
  
@@@ -838,7 -890,7 +890,7 @@@ static int _dpll_test_mult(int *m, int 
                           unsigned long target_rate,
                           unsigned long parent_rate)
  {
-       int flags = 0, carry = 0;
+       int r = 0, carry = 0;
  
        /* Unscale m and round if necessary */
        if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
        if (*m < DPLL_MIN_MULTIPLIER) {
                *m = DPLL_MIN_MULTIPLIER;
                *new_rate = 0;
-               flags = DPLL_MULT_UNDERFLOW;
+               r = DPLL_MULT_UNDERFLOW;
        }
  
        if (*new_rate == 0)
                *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
  
-       return flags;
+       return r;
  }
  
  /**
@@@ -889,54 -941,65 +941,65 @@@ long omap2_dpll_round_rate(struct clk *
        int m, n, r, e, scaled_max_m;
        unsigned long scaled_rt_rp, new_rate;
        int min_e = -1, min_e_m = -1, min_e_n = -1;
+       struct dpll_data *dd;
  
        if (!clk || !clk->dpll_data)
                return ~0;
  
+       dd = clk->dpll_data;
        pr_debug("clock: starting DPLL round_rate for clock %s, target rate "
                 "%ld\n", clk->name, target_rate);
  
-       scaled_rt_rp = target_rate / (clk->parent->rate / DPLL_SCALE_FACTOR);
-       scaled_max_m = clk->dpll_data->max_multiplier * DPLL_SCALE_FACTOR;
+       scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR);
+       scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
  
-       clk->dpll_data->last_rounded_rate = 0;
+       dd->last_rounded_rate = 0;
  
-       for (n = clk->dpll_data->max_divider; n >= DPLL_MIN_DIVIDER; n--) {
+       for (n = dd->min_divider; n <= dd->max_divider; n++) {
+               /* Is the (input clk, divider) pair valid for the DPLL? */
+               r = _dpll_test_fint(clk, n);
+               if (r == DPLL_FINT_UNDERFLOW)
+                       break;
+               else if (r == DPLL_FINT_INVALID)
+                       continue;
  
                /* Compute the scaled DPLL multiplier, based on the divider */
                m = scaled_rt_rp * n;
  
                /*
-                * Since we're counting n down, a m overflow means we can
-                * can immediately skip to the next n
+                * Since we're counting n up, a m overflow means we
+                * can bail out completely (since as n increases in
+                * the next iteration, there's no way that m can
+                * increase beyond the current m)
                 */
                if (m > scaled_max_m)
-                       continue;
+                       break;
  
                r = _dpll_test_mult(&m, n, &new_rate, target_rate,
-                                   clk->parent->rate);
+                                   dd->clk_ref->rate);
+               /* m can't be set low enough for this n - try with a larger n */
+               if (r == DPLL_MULT_UNDERFLOW)
+                       continue;
  
                e = target_rate - new_rate;
                pr_debug("clock: n = %d: m = %d: rate error is %d "
                         "(new_rate = %ld)\n", n, m, e, new_rate);
  
                if (min_e == -1 ||
-                   min_e >= (int)(abs(e) - clk->dpll_data->rate_tolerance)) {
+                   min_e >= (int)(abs(e) - dd->rate_tolerance)) {
                        min_e = e;
                        min_e_m = m;
                        min_e_n = n;
  
                        pr_debug("clock: found new least error %d\n", min_e);
-               }
  
-               /*
-                * Since we're counting n down, a m underflow means we
-                * can bail out completely (since as n decreases in
-                * the next iteration, there's no way that m can
-                * increase beyond the current m)
-                */
-               if (r & DPLL_MULT_UNDERFLOW)
-                       break;
+                       /* We found good settings -- bail out now */
+                       if (min_e <= dd->rate_tolerance)
+                               break;
+               }
        }
  
        if (min_e < 0) {
                return ~0;
        }
  
-       clk->dpll_data->last_rounded_m = min_e_m;
-       clk->dpll_data->last_rounded_n = min_e_n;
-       clk->dpll_data->last_rounded_rate =
-               _dpll_compute_new_rate(clk->parent->rate, min_e_m,  min_e_n);
+       dd->last_rounded_m = min_e_m;
+       dd->last_rounded_n = min_e_n;
+       dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate,
+                                                      min_e_m,  min_e_n);
  
        pr_debug("clock: final least error: e = %d, m = %d, n = %d\n",
                 min_e, min_e_m, min_e_n);
        pr_debug("clock: final rate: %ld  (target rate: %ld)\n",
-                clk->dpll_data->last_rounded_rate, target_rate);
+                dd->last_rounded_rate, target_rate);
  
-       return clk->dpll_data->last_rounded_rate;
+       return dd->last_rounded_rate;
  }
  
  /*-------------------------------------------------------------------------
@@@ -973,6 -1036,10 +1036,10 @@@ void omap2_clk_disable_unused(struct cl
                return;
  
        printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
-       _omap2_clk_disable(clk);
+       if (cpu_is_omap34xx()) {
+               omap2_clk_enable(clk);
+               omap2_clk_disable(clk);
+       } else
+               _omap2_clk_disable(clk);
  }
  #endif
index a631c81dce1243bcb9bacefd26dcd3f0e439073d,65e0743dbdd9028b8322884bf662bc413cb02f3b..3916a5618e288e4cd5680a1127ce025efcc8b387
@@@ -55,7 -55,6 +55,7 @@@
  #define VS30                  (1 << 25)
  #define SDVS18                        (0x5 << 9)
  #define SDVS30                        (0x6 << 9)
 +#define SDVS33                        (0x7 << 9)
  #define SDVSCLR                       0xFFFFF1FF
  #define SDVSDET                       0x00000400
  #define AUTOIDLE              0x1
@@@ -376,32 -375,6 +376,32 @@@ static void mmc_omap_report_irq(struct 
  }
  #endif  /* CONFIG_MMC_DEBUG */
  
 +/*
 + * MMC controller internal state machines reset
 + *
 + * Used to reset command or data internal state machines, using respectively
 + *  SRC or SRD bit of SYSCTL register
 + * Can be called from interrupt context
 + */
 +static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host,
 +              unsigned long bit)
 +{
 +      unsigned long i = 0;
 +      unsigned long limit = (loops_per_jiffy *
 +                              msecs_to_jiffies(MMC_TIMEOUT_MS));
 +
 +      OMAP_HSMMC_WRITE(host->base, SYSCTL,
 +                       OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
 +
 +      while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
 +              (i++ < limit))
 +              cpu_relax();
 +
 +      if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
 +              dev_err(mmc_dev(host->mmc),
 +                      "Timeout waiting on controller reset in %s\n",
 +                      __func__);
 +}
  
  /*
   * MMC controller IRQ handler
@@@ -430,17 -403,21 +430,17 @@@ static irqreturn_t mmc_omap_irq(int irq
                        (status & CMD_CRC)) {
                        if (host->cmd) {
                                if (status & CMD_TIMEOUT) {
 -                                      OMAP_HSMMC_WRITE(host->base, SYSCTL,
 -                                              OMAP_HSMMC_READ(host->base,
 -                                                              SYSCTL) | SRC);
 -                                      while (OMAP_HSMMC_READ(host->base,
 -                                                      SYSCTL) & SRC)
 -                                              ;
 -
 +                                      mmc_omap_reset_controller_fsm(host, SRC);
                                        host->cmd->error = -ETIMEDOUT;
                                } else {
                                        host->cmd->error = -EILSEQ;
                                }
                                end_cmd = 1;
                        }
 -                      if (host->data)
 +                      if (host->data) {
                                mmc_dma_cleanup(host);
 +                              mmc_omap_reset_controller_fsm(host, SRD);
 +                      }
                }
                if ((status & DATA_TIMEOUT) ||
                        (status & DATA_CRC)) {
                                        mmc_dma_cleanup(host);
                                else
                                        host->data->error = -EILSEQ;
 -                              OMAP_HSMMC_WRITE(host->base, SYSCTL,
 -                                      OMAP_HSMMC_READ(host->base,
 -                                                      SYSCTL) | SRD);
 -                              while (OMAP_HSMMC_READ(host->base,
 -                                              SYSCTL) & SRD)
 -                                      ;
 +                              mmc_omap_reset_controller_fsm(host, SRD);
                                end_trans = 1;
                        }
                }
  }
  
  /*
 - * Switch MMC operating voltage
 + * Switch MMC interface voltage ... only relevant for MMC1.
 + *
 + * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
 + * The MMC2 transceiver controls are used instead of DAT4..DAT7.
 + * Some chips, like eMMC ones, use internal transceivers.
   */
  static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
  {
        u32 reg_val = 0;
        int ret;
  
 +      if (host->id != OMAP_MMC1_DEVID)
 +              return 0;
 +
        /* Disable the clocks */
        clk_disable(host->fclk);
        clk_disable(host->iclk);
        OMAP_HSMMC_WRITE(host->base, HCTL,
                OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
        reg_val = OMAP_HSMMC_READ(host->base, HCTL);
 +
        /*
         * If a MMC dual voltage card is detected, the set_ios fn calls
         * this fn with VDD bit set for 1.8V. Upon card removal from the
         * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
         *
 -       * Only MMC1 supports 3.0V.  MMC2 will not function if SDVS30 is
 -       * set in HCTL.
 +       * Cope with a bit of slop in the range ... per data sheets:
 +       *  - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
 +       *    but recommended values are 1.71V to 1.89V
 +       *  - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
 +       *    but recommended values are 2.7V to 3.3V
 +       *
 +       * Board setup code shouldn't permit anything very out-of-range.
 +       * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
 +       * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
         */
 -      if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) ||
 -                              ((1 << vdd) == MMC_VDD_33_34)))
 -              reg_val |= SDVS30;
 -      if ((1 << vdd) == MMC_VDD_165_195)
 +      if ((1 << vdd) <= MMC_VDD_23_24)
                reg_val |= SDVS18;
 +      else
 +              reg_val |= SDVS30;
  
        OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
  
@@@ -549,15 -517,16 +549,15 @@@ static void mmc_omap_detect(struct work
  {
        struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
                                                mmc_carddetect_work);
 +      struct omap_mmc_slot_data *slot = &mmc_slot(host);
 +
 +      host->carddetect = slot->card_detect(slot->card_detect_irq);
  
        sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
        if (host->carddetect) {
                mmc_detect_change(host->mmc, (HZ * 200) / 1000);
        } else {
 -              OMAP_HSMMC_WRITE(host->base, SYSCTL,
 -                      OMAP_HSMMC_READ(host->base, SYSCTL) | SRD);
 -              while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD)
 -                      ;
 -
 +              mmc_omap_reset_controller_fsm(host, SRD);
                mmc_detect_change(host->mmc, (HZ * 50) / 1000);
        }
  }
@@@ -569,6 -538,7 +569,6 @@@ static irqreturn_t omap_mmc_cd_handler(
  {
        struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
  
 -      host->carddetect = mmc_slot(host).card_detect(irq);
        schedule_work(&host->mmc_carddetect_work);
  
        return IRQ_HANDLED;
@@@ -787,14 -757,10 +787,14 @@@ static void omap_mmc_set_ios(struct mmc
        case MMC_POWER_OFF:
                mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
                /*
 -               * Reset bus voltage to 3V if it got set to 1.8V earlier.
 +               * Reset interface voltage to 3V if it's 1.8V now;
 +               * only relevant on MMC-1, the others always use 1.8V.
 +               *
                 * REVISIT: If we are able to detect cards after unplugging
                 * a 1.8V card, this code should not be needed.
                 */
 +              if (host->id != OMAP_MMC1_DEVID)
 +                      break;
                if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
                        int vdd = fls(host->mmc->ocr_avail) - 1;
                        if (omap_mmc_switch_opcond(host, vdd) != 0)
        }
  
        if (host->id == OMAP_MMC1_DEVID) {
 -              /* Only MMC1 can operate at 3V/1.8V */
 +              /* Only MMC1 can interface at 3V without some flavor
 +               * of external transceiver; but they all handle 1.8V.
 +               */
                if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
                        (ios->vdd == DUAL_VOLT_OCR_BIT)) {
                                /*
@@@ -956,13 -920,13 +956,13 @@@ static int __init omap_mmc_probe(struc
  
        sema_init(&host->sem, 1);
  
-       host->iclk = clk_get(&pdev->dev, "mmchs_ick");
+       host->iclk = clk_get(&pdev->dev, "ick");
        if (IS_ERR(host->iclk)) {
                ret = PTR_ERR(host->iclk);
                host->iclk = NULL;
                goto err1;
        }
-       host->fclk = clk_get(&pdev->dev, "mmchs_fck");
+       host->fclk = clk_get(&pdev->dev, "fck");
        if (IS_ERR(host->fclk)) {
                ret = PTR_ERR(host->fclk);
                host->fclk = NULL;
@@@ -1173,9 -1137,7 +1173,9 @@@ static int omap_mmc_suspend(struct plat
                                                " level suspend\n");
                        }
  
 -                      if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
 +                      if (host->id == OMAP_MMC1_DEVID
 +                                      && !(OMAP_HSMMC_READ(host->base, HCTL)
 +                                                      & SDVSDET)) {
                                OMAP_HSMMC_WRITE(host->base, HCTL,
                                        OMAP_HSMMC_READ(host->base, HCTL)
                                        & SDVSCLR);