On Thu, May 12, 2016 at 08:48:54AM +0200, Petr Kulhavy wrote:
The clock calculation has several issues:
- if PLL is used in master mode the BCLK output runs at double the speed
- de-facto only 44.1kHz and 48kHz sampling rates are supported, other rates like 8kHz, 12kHz, 24kHz fail to find the proper BCLK divider
These certainly seem like things that need fixed :-)
- the wm8985->sysclk variable has a misleading name and is used wrongly in the clock calculation in wm8985_hw_params() which is the root cause for (1)
- wm8985->bclk is used only in wm8985_hw_params() and therefore no need to store it in the wm8985_priv structure
Therefore the clock calculation is rewritten in more clean and proper way:
- move wm8985_priv->bclk as a local variable into mw8985_hw_params()
- new variable wm8985_priv->pllout holds the actual frequency that is input to the MCLKDIV post-divider
- move wm8985_priv->sysclk as a local variable into mw8985_hw_params()
- sysclk is now always calculated as 256 * fs
- the MCLKDIV is looked up as pllout/sysclk
- fs_ratios[] is replaced by simpler mclk_divs[] lookup table
With this patch all rates: 8, 11.025, 12, 16, 22.05, 24, 32, 44.1 and 48kHz work properly and generate the correct BCLK.
Signed-off-by: Petr Kulhavy petr@barix.com
sound/soc/codecs/wm8985.c | 59 ++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 29 deletions(-)
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 18f2babe1090..628127aa3c96 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -181,22 +181,11 @@ static const int volume_update_regs[] = { struct wm8985_priv { struct regmap *regmap; struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
- unsigned int sysclk;
- unsigned int bclk;
- unsigned int pllout; /* input rate to the MCLKDIV divider */
};
-static const struct {
- int div;
- int ratio;
-} fs_ratios[] = {
- { 10, 128 },
- { 15, 192 },
- { 20, 256 },
- { 30, 384 },
- { 40, 512 },
- { 60, 768 },
- { 80, 1024 },
- { 120, 1536 }
+static const int mclk_divs[] = {
- 10, 15, 20, 30, 40, 60, 80, 120
};
static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 }; @@ -693,15 +682,18 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec; struct wm8985_priv *wm8985; u16 blen, srate_idx;
- unsigned int tmp; int srate_best;
unsigned int bclk; /* bit clock matching the current params */
unsigned int sysclk; /* the actual sysclk after post division */
codec = dai->codec; wm8985 = snd_soc_codec_get_drvdata(codec);
- wm8985->bclk = snd_soc_params_to_bclk(params);
- if ((int)wm8985->bclk < 0)
return wm8985->bclk;
- /* always use 256 * fs in order to get best filter quality */
- sysclk = 256 * params_rate(params);
Seems quite bold to assume we always want to use 256*fs, I am not super familiar with the part itself but are there good reasons to do that? What if someone wanted to use say a direct MCLK and a lower multiple?
The intent presumably here is that set_sysclk is where we set the target SYSCLK and set_pll should set the PLL output then here we probably should work out the correct MCLKDIV to get those.
bclk = snd_soc_params_to_bclk(params);
if ((int)bclk < 0)
return bclk;
switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE:
@@ -742,29 +734,28 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL, WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
- dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
- dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);
- dev_dbg(dai->dev, "Target BCLK = %uHz\n", bclk);
- dev_dbg(dai->dev, "SYSCLK = %uHz\n", sysclk);
- for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
if (wm8985->sysclk / params_rate(params)
== fs_ratios[i].ratio)
- /* select the appropriate mclk divider */
- for (i = 0; i < ARRAY_SIZE(mclk_divs); ++i) {
if (wm8985->pllout / mclk_divs[i] * 10
}== sysclk) break;
- if (i == ARRAY_SIZE(fs_ratios)) {
- if (i == ARRAY_SIZE(mclk_divs)) { dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
wm8985->sysclk, params_rate(params));
return -EINVAL; }wm8985->pllout, sysclk);
dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio); snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL, WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
/* select the appropriate bclk divider */
tmp = (wm8985->sysclk / fs_ratios[i].div) * 10; for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
if (wm8985->bclk == tmp / bclk_divs[i])
}if (bclk == sysclk / bclk_divs[i]) break;
@@ -786,6 +777,10 @@ struct pll_div { };
#define FIXED_PLL_SIZE ((1ULL << 24) * 10) +/*
- source = MCLK input of the chip
- target = the f2 coming out of the PLL before /4 divider
- */
static int pll_factors(struct pll_div *pll_div, unsigned int target, unsigned int source) { @@ -872,17 +867,23 @@ static int wm8985_set_sysclk(struct snd_soc_dai *dai, WM8985_CLKSEL_MASK, 0); snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1, WM8985_PLLEN_MASK, 0);
break; case WM8985_CLKSRC_PLL: snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL, WM8985_CLKSEL_MASK, WM8985_CLKSEL);wm8985->pllout = freq;
/*
* in order to run the PLL within the recommended 90MHz
* operating range the wm8985_set_pll() configures the PLL
* to output double the required frequency
*/
wm8985->pllout = 2 * freq;
Were does this *2 come from? Is this the PLLPRESCALE?
break;
default: dev_err(dai->dev, "Unknown clock source %d\n", clk_id); return -EINVAL; }
- wm8985->sysclk = freq; return 0;
}
-- 1.9.1
Thanks, Charles