aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Matuschek <info@crazy-audio.com>2014-05-29 10:08:03 -0400
committerMark Brown <broonie@linaro.org>2014-05-29 11:01:56 -0400
commit06109f47f2c33fdd2b10194ee53235e72b8fbfe7 (patch)
tree201d445302475cb34a86b9a51876ff59a36bf4ad
parenta3086791ebe0c50aff0753a24db565ae0da7be18 (diff)
ASoC: wm8804: Allow control of master clock divider in PLL generation
WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an additional mclk_div divider, it is now possible to control the behaviour. This allows using 256xfs PLL frequency on all sample rates up to 96kHz. It should allow lower jitter and better signal quality. The behavior has to be controlled by the sound card driver, because some sample frequency share the same setting. e.g. 192kHz and 96kHz use 24.576MHz master clock. The only difference is the MCLK divider. Signed-off-by: Daniel Matuschek <daniel@matuschek.net> Tested-by: Florian Meier <florian.meier@koalo.de> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--sound/soc/codecs/wm8804.c17
-rw-r--r--sound/soc/codecs/wm8804.h4
2 files changed, 18 insertions, 3 deletions
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index b4c8d6086737..de80d911868e 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -63,6 +63,7 @@ struct wm8804_priv {
63 struct regmap *regmap; 63 struct regmap *regmap;
64 struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; 64 struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
65 struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; 65 struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
66 int mclk_div;
66}; 67};
67 68
68static int txsrc_get(struct snd_kcontrol *kcontrol, 69static int txsrc_get(struct snd_kcontrol *kcontrol,
@@ -318,7 +319,7 @@ static struct {
318 319
319#define FIXED_PLL_SIZE ((1ULL << 22) * 10) 320#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
320static int pll_factors(struct pll_div *pll_div, unsigned int target, 321static int pll_factors(struct pll_div *pll_div, unsigned int target,
321 unsigned int source) 322 unsigned int source, unsigned int mclk_div)
322{ 323{
323 u64 Kpart; 324 u64 Kpart;
324 unsigned long int K, Ndiv, Nmod, tmp; 325 unsigned long int K, Ndiv, Nmod, tmp;
@@ -330,7 +331,8 @@ static int pll_factors(struct pll_div *pll_div, unsigned int target,
330 */ 331 */
331 for (i = 0; i < ARRAY_SIZE(post_table); i++) { 332 for (i = 0; i < ARRAY_SIZE(post_table); i++) {
332 tmp = target * post_table[i].div; 333 tmp = target * post_table[i].div;
333 if (tmp >= 90000000 && tmp <= 100000000) { 334 if ((tmp >= 90000000 && tmp <= 100000000) &&
335 (mclk_div == post_table[i].mclkdiv)) {
334 pll_div->freqmode = post_table[i].freqmode; 336 pll_div->freqmode = post_table[i].freqmode;
335 pll_div->mclkdiv = post_table[i].mclkdiv; 337 pll_div->mclkdiv = post_table[i].mclkdiv;
336 target *= post_table[i].div; 338 target *= post_table[i].div;
@@ -387,8 +389,12 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
387 } else { 389 } else {
388 int ret; 390 int ret;
389 struct pll_div pll_div; 391 struct pll_div pll_div;
392 struct wm8804_priv *wm8804;
390 393
391 ret = pll_factors(&pll_div, freq_out, freq_in); 394 wm8804 = snd_soc_codec_get_drvdata(codec);
395
396 ret = pll_factors(&pll_div, freq_out, freq_in,
397 wm8804->mclk_div);
392 if (ret) 398 if (ret)
393 return ret; 399 return ret;
394 400
@@ -452,6 +458,7 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
452 int div_id, int div) 458 int div_id, int div)
453{ 459{
454 struct snd_soc_codec *codec; 460 struct snd_soc_codec *codec;
461 struct wm8804_priv *wm8804;
455 462
456 codec = dai->codec; 463 codec = dai->codec;
457 switch (div_id) { 464 switch (div_id) {
@@ -459,6 +466,10 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
459 snd_soc_update_bits(codec, WM8804_PLL5, 0x30, 466 snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
460 (div & 0x3) << 4); 467 (div & 0x3) << 4);
461 break; 468 break;
469 case WM8804_MCLK_DIV:
470 wm8804 = snd_soc_codec_get_drvdata(codec);
471 wm8804->mclk_div = div;
472 break;
462 default: 473 default:
463 dev_err(dai->dev, "Unknown clock divider: %d\n", div_id); 474 dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
464 return -EINVAL; 475 return -EINVAL;
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
index 8ec14f5573cb..e72d4f4ba6b1 100644
--- a/sound/soc/codecs/wm8804.h
+++ b/sound/soc/codecs/wm8804.h
@@ -57,5 +57,9 @@
57#define WM8804_CLKOUT_SRC_OSCCLK 4 57#define WM8804_CLKOUT_SRC_OSCCLK 4
58 58
59#define WM8804_CLKOUT_DIV 1 59#define WM8804_CLKOUT_DIV 1
60#define WM8804_MCLK_DIV 2
61
62#define WM8804_MCLKDIV_256FS 0
63#define WM8804_MCLKDIV_128FS 1
60 64
61#endif /* _WM8804_H */ 65#endif /* _WM8804_H */