]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/mfd/twl6040-core.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[mv-sheeva.git] / drivers / mfd / twl6040-core.c
index dda86293dc9fc0a3f8baaf678591d764824cfe14..b2d8e512d3cb002b6f3e809e47a12f01f96de588 100644 (file)
@@ -282,6 +282,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
                /* Default PLL configuration after power up */
                twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
                twl6040->sysclk = 19200000;
+               twl6040->mclk = 32768;
        } else {
                /* already powered-down */
                if (!twl6040->power_count) {
@@ -305,6 +306,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
                        twl6040_power_down(twl6040);
                }
                twl6040->sysclk = 0;
+               twl6040->mclk = 0;
        }
 
 out:
@@ -324,23 +326,38 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
        hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL);
        lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
 
+       /* Force full reconfiguration when switching between PLL */
+       if (pll_id != twl6040->pll) {
+               twl6040->sysclk = 0;
+               twl6040->mclk = 0;
+       }
+
        switch (pll_id) {
        case TWL6040_SYSCLK_SEL_LPPLL:
                /* low-power PLL divider */
-               switch (freq_out) {
-               case 17640000:
-                       lppllctl |= TWL6040_LPLLFIN;
-                       break;
-               case 19200000:
-                       lppllctl &= ~TWL6040_LPLLFIN;
-                       break;
-               default:
-                       dev_err(twl6040->dev,
-                               "freq_out %d not supported\n", freq_out);
-                       ret = -EINVAL;
-                       goto pll_out;
+               /* Change the sysclk configuration only if it has been canged */
+               if (twl6040->sysclk != freq_out) {
+                       switch (freq_out) {
+                       case 17640000:
+                               lppllctl |= TWL6040_LPLLFIN;
+                               break;
+                       case 19200000:
+                               lppllctl &= ~TWL6040_LPLLFIN;
+                               break;
+                       default:
+                               dev_err(twl6040->dev,
+                                       "freq_out %d not supported\n",
+                                       freq_out);
+                               ret = -EINVAL;
+                               goto pll_out;
+                       }
+                       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+                                         lppllctl);
                }
-               twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+
+               /* The PLL in use has not been change, we can exit */
+               if (twl6040->pll == pll_id)
+                       break;
 
                switch (freq_in) {
                case 32768:
@@ -371,48 +388,56 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
                        goto pll_out;
                }
 
-               hppllctl &= ~TWL6040_MCLK_MSK;
+               if (twl6040->mclk != freq_in) {
+                       hppllctl &= ~TWL6040_MCLK_MSK;
+
+                       switch (freq_in) {
+                       case 12000000:
+                               /* PLL enabled, active mode */
+                               hppllctl |= TWL6040_MCLK_12000KHZ |
+                                           TWL6040_HPLLENA;
+                               break;
+                       case 19200000:
+                               /*
+                               * PLL disabled
+                               * (enable PLL if MCLK jitter quality
+                               *  doesn't meet specification)
+                               */
+                               hppllctl |= TWL6040_MCLK_19200KHZ;
+                               break;
+                       case 26000000:
+                               /* PLL enabled, active mode */
+                               hppllctl |= TWL6040_MCLK_26000KHZ |
+                                           TWL6040_HPLLENA;
+                               break;
+                       case 38400000:
+                               /* PLL enabled, active mode */
+                               hppllctl |= TWL6040_MCLK_38400KHZ |
+                                           TWL6040_HPLLENA;
+                               break;
+                       default:
+                               dev_err(twl6040->dev,
+                                       "freq_in %d not supported\n", freq_in);
+                               ret = -EINVAL;
+                               goto pll_out;
+                       }
 
-               switch (freq_in) {
-               case 12000000:
-                       /* PLL enabled, active mode */
-                       hppllctl |= TWL6040_MCLK_12000KHZ |
-                                   TWL6040_HPLLENA;
-                       break;
-               case 19200000:
                        /*
-                        * PLL disabled
-                        * (enable PLL if MCLK jitter quality
-                        *  doesn't meet specification)
+                        * enable clock slicer to ensure input waveform is
+                        * square
                         */
-                       hppllctl |= TWL6040_MCLK_19200KHZ;
-                       break;
-               case 26000000:
-                       /* PLL enabled, active mode */
-                       hppllctl |= TWL6040_MCLK_26000KHZ |
-                                   TWL6040_HPLLENA;
-                       break;
-               case 38400000:
-                       /* PLL enabled, active mode */
-                       hppllctl |= TWL6040_MCLK_38400KHZ |
-                                   TWL6040_HPLLENA;
-                       break;
-               default:
-                       dev_err(twl6040->dev,
-                               "freq_in %d not supported\n", freq_in);
-                       ret = -EINVAL;
-                       goto pll_out;
-               }
+                       hppllctl |= TWL6040_HPLLSQRENA;
 
-               /* enable clock slicer to ensure input waveform is square */
-               hppllctl |= TWL6040_HPLLSQRENA;
-
-               twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl);
-               usleep_range(500, 700);
-               lppllctl |= TWL6040_HPLLSEL;
-               twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
-               lppllctl &= ~TWL6040_LPLLENA;
-               twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+                       twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
+                                         hppllctl);
+                       usleep_range(500, 700);
+                       lppllctl |= TWL6040_HPLLSEL;
+                       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+                                         lppllctl);
+                       lppllctl &= ~TWL6040_LPLLENA;
+                       twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+                                         lppllctl);
+               }
                break;
        default:
                dev_err(twl6040->dev, "unknown pll id %d\n", pll_id);
@@ -421,6 +446,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
        }
 
        twl6040->sysclk = freq_out;
+       twl6040->mclk = freq_in;
        twl6040->pll = pll_id;
 
 pll_out: