mirror of https://gitee.com/openkylin/linux.git
ASoC: wm8994: Support EFS mode for FLL
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>
This commit is contained in:
parent
f722406faa
commit
d1a0a29958
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
|
#include <linux/gcd.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
@ -2005,15 +2006,16 @@ struct fll_div {
|
||||||
u16 outdiv;
|
u16 outdiv;
|
||||||
u16 n;
|
u16 n;
|
||||||
u16 k;
|
u16 k;
|
||||||
|
u16 lambda;
|
||||||
u16 clk_ref_div;
|
u16 clk_ref_div;
|
||||||
u16 fll_fratio;
|
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)
|
int freq_in, int freq_out)
|
||||||
{
|
{
|
||||||
u64 Kpart;
|
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);
|
pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
|
||||||
|
|
||||||
|
@ -2062,6 +2064,8 @@ static int wm8994_get_fll_config(struct fll_div *fll,
|
||||||
Nmod = freq_out % freq_in;
|
Nmod = freq_out % freq_in;
|
||||||
pr_debug("Nmod=%d\n", Nmod);
|
pr_debug("Nmod=%d\n", Nmod);
|
||||||
|
|
||||||
|
switch (control->type) {
|
||||||
|
case WM8994:
|
||||||
/* Calculate fractional part - scale up so we can round. */
|
/* Calculate fractional part - scale up so we can round. */
|
||||||
Kpart = FIXED_FLL_SIZE * (long long)Nmod;
|
Kpart = FIXED_FLL_SIZE * (long long)Nmod;
|
||||||
|
|
||||||
|
@ -2077,6 +2081,14 @@ static int wm8994_get_fll_config(struct fll_div *fll,
|
||||||
|
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2139,9 +2151,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
|
||||||
* analysis bugs spewing warnings.
|
* analysis bugs spewing warnings.
|
||||||
*/
|
*/
|
||||||
if (freq_out)
|
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
|
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);
|
wm8994->fll[id].out);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -2186,6 +2198,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
|
||||||
WM8994_FLL1_N_MASK,
|
WM8994_FLL1_N_MASK,
|
||||||
fll.n << WM8994_FLL1_N_SHIFT);
|
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,
|
snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
|
||||||
WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
|
WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
|
||||||
WM8994_FLL1_REFCLK_DIV_MASK |
|
WM8994_FLL1_REFCLK_DIV_MASK |
|
||||||
|
|
Loading…
Reference in New Issue