ASoC: wm8994: Support EFS mode for FLL
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Fri, 10 May 2013 20:40:10 +0000 (21:40 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 13 May 2013 05:40:12 +0000 (09:40 +0400)
Later WM8994 devices support an enhanced accuracy FLL divisor mode called
EFS which allows more precise selection of fractional source to output
ratios. Support this on relevant devices.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/codecs/wm8994.c

index 1eb152cb10970d06a09b98995871581105e6fa51..9f32dd8660d59ca77873725ae256d876ba0d3832 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/gcd.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -2005,15 +2006,16 @@ struct fll_div {
        u16 outdiv;
        u16 n;
        u16 k;
+       u16 lambda;
        u16 clk_ref_div;
        u16 fll_fratio;
 };
 
-static int wm8994_get_fll_config(struct fll_div *fll,
+static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
                                 int freq_in, int freq_out)
 {
        u64 Kpart;
-       unsigned int K, Ndiv, Nmod;
+       unsigned int K, Ndiv, Nmod, gcd_fll;
 
        pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
 
@@ -2062,20 +2064,30 @@ static int wm8994_get_fll_config(struct fll_div *fll,
        Nmod = freq_out % freq_in;
        pr_debug("Nmod=%d\n", Nmod);
 
-       /* Calculate fractional part - scale up so we can round. */
-       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+       switch (control->type) {
+       case WM8994:
+               /* Calculate fractional part - scale up so we can round. */
+               Kpart = FIXED_FLL_SIZE * (long long)Nmod;
 
-       do_div(Kpart, freq_in);
+               do_div(Kpart, freq_in);
 
-       K = Kpart & 0xFFFFFFFF;
+               K = Kpart & 0xFFFFFFFF;
 
-       if ((K % 10) >= 5)
-               K += 5;
+               if ((K % 10) >= 5)
+                       K += 5;
 
-       /* Move down to proper range now rounding is done */
-       fll->k = K / 10;
+               /* Move down to proper range now rounding is done */
+               fll->k = K / 10;
 
-       pr_debug("N=%x K=%x\n", fll->n, fll->k);
+               pr_debug("N=%x K=%x\n", fll->n, fll->k);
+
+       default:
+               gcd_fll = gcd(freq_out, freq_in);
+
+               fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll;
+               fll->lambda = freq_in / gcd_fll;
+               
+       }
 
        return 0;
 }
@@ -2139,9 +2151,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
         * analysis bugs spewing warnings.
         */
        if (freq_out)
-               ret = wm8994_get_fll_config(&fll, freq_in, freq_out);
+               ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out);
        else
-               ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in,
+               ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in,
                                            wm8994->fll[id].out);
        if (ret < 0)
                return ret;
@@ -2186,6 +2198,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                            WM8994_FLL1_N_MASK,
                            fll.n << WM8994_FLL1_N_SHIFT);
 
+       if (fll.lambda) {
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset,
+                                   WM8958_FLL1_LAMBDA_MASK,
+                                   fll.lambda);
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+                                   WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA);
+       } else {
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+                                   WM8958_FLL1_EFS_ENA, 0);
+       }
+
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
                            WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
This page took 0.028515 seconds and 5 git commands to generate.