Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.git] / sound / soc / codecs / wm8994.c
index 29c4cfc..e84a117 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -1710,6 +1711,8 @@ static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
        if (!wm8994_volatile(reg))
                wm8994->reg_cache[reg] = value;
 
+       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
+
        return wm8994_reg_write(codec->control_data, reg, value);
 }
 
@@ -1769,6 +1772,11 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
                dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n",
                        aif + 1, rate);
        }
+
+       if (rate && rate < 3000000)
+               dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n",
+                        aif + 1, rate);
+
        wm8994->aifclk[aif] = rate;
 
        snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
@@ -2189,13 +2197,13 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
        /* Only support direct DAC->headphone paths */
        reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
        if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
-               dev_dbg(codec->dev, "HPL connected to output mixer\n");
+               dev_vdbg(codec->dev, "HPL connected to output mixer\n");
                enable = 0;
        }
 
        reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
        if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
-               dev_dbg(codec->dev, "HPR connected to output mixer\n");
+               dev_vdbg(codec->dev, "HPR connected to output mixer\n");
                enable = 0;
        }
 
@@ -2203,26 +2211,26 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
        reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
        switch (reg) {
        case WM8994_AIF2DACL_TO_DAC1L:
-               dev_dbg(codec->dev, "Class W source AIF2DAC\n");
+               dev_vdbg(codec->dev, "Class W source AIF2DAC\n");
                source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT;
                break;
        case WM8994_AIF1DAC2L_TO_DAC1L:
-               dev_dbg(codec->dev, "Class W source AIF1DAC2\n");
+               dev_vdbg(codec->dev, "Class W source AIF1DAC2\n");
                source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT;
                break;
        case WM8994_AIF1DAC1L_TO_DAC1L:
-               dev_dbg(codec->dev, "Class W source AIF1DAC1\n");
+               dev_vdbg(codec->dev, "Class W source AIF1DAC1\n");
                source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT;
                break;
        default:
-               dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg);
+               dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
                enable = 0;
                break;
        }
 
        reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
        if (reg_r != reg) {
-               dev_dbg(codec->dev, "Left and right DAC mixers different\n");
+               dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
                enable = 0;
        }
 
@@ -2784,9 +2792,18 @@ static int wm8994_get_fll_config(struct fll_div *fll,
 
        if (freq_in > 1000000) {
                fll->fll_fratio = 0;
-       } else {
+       } else if (freq_in > 256000) {
+               fll->fll_fratio = 1;
+               freq_in *= 2;
+       } else if (freq_in > 128000) {
+               fll->fll_fratio = 2;
+               freq_in *= 4;
+       } else if (freq_in > 64000) {
                fll->fll_fratio = 3;
                freq_in *= 8;
+       } else {
+               fll->fll_fratio = 4;
+               freq_in *= 16;
        }
        pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in);
 
@@ -2843,6 +2860,21 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
                return -EINVAL;
        }
 
+       switch (src) {
+       case 0:
+               /* Allow no source specification when stopping */
+               if (freq_out)
+                       return -EINVAL;
+               break;
+       case WM8994_FLL_SRC_MCLK1:
+       case WM8994_FLL_SRC_MCLK2:
+       case WM8994_FLL_SRC_LRCLK:
+       case WM8994_FLL_SRC_BCLK:
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* Are we changing anything? */
        if (wm8994->fll[id].src == src &&
            wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out)
@@ -2883,8 +2915,10 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
                                    fll.n << WM8994_FLL1_N_SHIFT);
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
-                           WM8994_FLL1_REFCLK_DIV_MASK,
-                           fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT);
+                           WM8994_FLL1_REFCLK_DIV_MASK |
+                           WM8994_FLL1_REFCLK_SRC_MASK,
+                           (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
+                           (src - 1));
 
        /* Enable (with fractional mode if required) */
        if (freq_out) {
@@ -2899,6 +2933,7 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
 
        wm8994->fll[id].in = freq_in;
        wm8994->fll[id].out = freq_out;
+       wm8994->fll[id].src = src;
 
        /* Enable any gated AIF clocks */
        snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
@@ -3514,6 +3549,9 @@ static int wm8994_resume(struct platform_device *pdev)
        wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
+               if (!wm8994->fll_suspend[i].out)
+                       continue;
+
                ret = wm8994_set_fll(&codec->dai[0], i + 1,
                                     wm8994->fll_suspend[i].src,
                                     wm8994->fll_suspend[i].in,