aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/wm8994.c49
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
2012static int wm8994_get_fll_config(struct fll_div *fll, 2014static 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 |