diff options
| -rw-r--r-- | sound/soc/codecs/wm8994.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1eb152cb1097..9f32dd8660d5 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
| 19 | #include <linux/gcd.h> | ||
| 19 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
| 20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
| 21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
| @@ -2005,15 +2006,16 @@ struct fll_div { | |||
| 2005 | u16 outdiv; | 2006 | u16 outdiv; |
| 2006 | u16 n; | 2007 | u16 n; |
| 2007 | u16 k; | 2008 | u16 k; |
| 2009 | u16 lambda; | ||
| 2008 | u16 clk_ref_div; | 2010 | u16 clk_ref_div; |
| 2009 | u16 fll_fratio; | 2011 | u16 fll_fratio; |
| 2010 | }; | 2012 | }; |
| 2011 | 2013 | ||
| 2012 | static int wm8994_get_fll_config(struct fll_div *fll, | 2014 | static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll, |
| 2013 | int freq_in, int freq_out) | 2015 | int freq_in, int freq_out) |
| 2014 | { | 2016 | { |
| 2015 | u64 Kpart; | 2017 | u64 Kpart; |
| 2016 | unsigned int K, Ndiv, Nmod; | 2018 | unsigned int K, Ndiv, Nmod, gcd_fll; |
| 2017 | 2019 | ||
| 2018 | pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); | 2020 | pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); |
| 2019 | 2021 | ||
| @@ -2062,20 +2064,30 @@ static int wm8994_get_fll_config(struct fll_div *fll, | |||
| 2062 | Nmod = freq_out % freq_in; | 2064 | Nmod = freq_out % freq_in; |
| 2063 | pr_debug("Nmod=%d\n", Nmod); | 2065 | pr_debug("Nmod=%d\n", Nmod); |
| 2064 | 2066 | ||
| 2065 | /* Calculate fractional part - scale up so we can round. */ | 2067 | switch (control->type) { |
| 2066 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | 2068 | case WM8994: |
| 2069 | /* Calculate fractional part - scale up so we can round. */ | ||
| 2070 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
| 2067 | 2071 | ||
| 2068 | do_div(Kpart, freq_in); | 2072 | do_div(Kpart, freq_in); |
| 2069 | 2073 | ||
| 2070 | K = Kpart & 0xFFFFFFFF; | 2074 | K = Kpart & 0xFFFFFFFF; |
| 2071 | 2075 | ||
| 2072 | if ((K % 10) >= 5) | 2076 | if ((K % 10) >= 5) |
| 2073 | K += 5; | 2077 | K += 5; |
| 2074 | 2078 | ||
| 2075 | /* Move down to proper range now rounding is done */ | 2079 | /* Move down to proper range now rounding is done */ |
| 2076 | fll->k = K / 10; | 2080 | fll->k = K / 10; |
| 2077 | 2081 | ||
| 2078 | pr_debug("N=%x K=%x\n", fll->n, fll->k); | 2082 | pr_debug("N=%x K=%x\n", fll->n, fll->k); |
| 2083 | |||
| 2084 | default: | ||
| 2085 | gcd_fll = gcd(freq_out, freq_in); | ||
| 2086 | |||
| 2087 | fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll; | ||
| 2088 | fll->lambda = freq_in / gcd_fll; | ||
| 2089 | |||
| 2090 | } | ||
| 2079 | 2091 | ||
| 2080 | return 0; | 2092 | return 0; |
| 2081 | } | 2093 | } |
| @@ -2139,9 +2151,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
| 2139 | * analysis bugs spewing warnings. | 2151 | * analysis bugs spewing warnings. |
| 2140 | */ | 2152 | */ |
| 2141 | if (freq_out) | 2153 | if (freq_out) |
| 2142 | ret = wm8994_get_fll_config(&fll, freq_in, freq_out); | 2154 | ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out); |
| 2143 | else | 2155 | else |
| 2144 | ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in, | 2156 | ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in, |
| 2145 | wm8994->fll[id].out); | 2157 | wm8994->fll[id].out); |
| 2146 | if (ret < 0) | 2158 | if (ret < 0) |
| 2147 | return ret; | 2159 | return ret; |
| @@ -2186,6 +2198,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
| 2186 | WM8994_FLL1_N_MASK, | 2198 | WM8994_FLL1_N_MASK, |
| 2187 | fll.n << WM8994_FLL1_N_SHIFT); | 2199 | fll.n << WM8994_FLL1_N_SHIFT); |
| 2188 | 2200 | ||
| 2201 | if (fll.lambda) { | ||
| 2202 | snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset, | ||
| 2203 | WM8958_FLL1_LAMBDA_MASK, | ||
| 2204 | fll.lambda); | ||
| 2205 | snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset, | ||
| 2206 | WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA); | ||
| 2207 | } else { | ||
| 2208 | snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset, | ||
| 2209 | WM8958_FLL1_EFS_ENA, 0); | ||
| 2210 | } | ||
| 2211 | |||
| 2189 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, | 2212 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, |
| 2190 | WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | | 2213 | WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | |
| 2191 | WM8994_FLL1_REFCLK_DIV_MASK | | 2214 | WM8994_FLL1_REFCLK_DIV_MASK | |
