summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baluta <daniel.baluta@nxp.com>2017-03-21 11:03:25 -0400
committerMark Brown <broonie@kernel.org>2017-03-24 14:53:06 -0400
commit3c01b9ee2ab9d0dffe837c12ed93740516a673d7 (patch)
tree7b3b9e7f860491d72b6ad8a8cdc2b297b13e09e5
parent3ddc97211cbb61a5f59882c26f8e3158c86e34bb (diff)
ASoC: codec: wm8960: Relax bit clock computation
WM8960 derives bit clock from sysclock using BCLKDIV[3:0] of R8 clocking register (See WM8960 datasheet, page 71). There are use cases, like this: aplay -Dhw:0,0 -r 48000 -c 1 -f S20_3LE -t raw audio48k20b_3LE1c.pcm where no BCLKDIV applied to sysclock can give us the exact requested bitclk, so driver fails to configure clocking and aplay fails to run. Fix this by relaxing bitclk computation, so that when no exact value can be derived from sysclk pick the closest value greater than expected bitclk. Suggested-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com> Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/wm8960.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 25a4a11929fe..ce159f13e7a4 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -611,6 +611,10 @@ static const int bclk_divs[] = {
611 * - lrclk = sysclk / dac_divs 611 * - lrclk = sysclk / dac_divs
612 * - 10 * bclk = sysclk / bclk_divs 612 * - 10 * bclk = sysclk / bclk_divs
613 * 613 *
614 * If we cannot find an exact match for (sysclk, lrclk, bclk)
615 * triplet, we relax the bclk such that bclk is chosen as the
616 * closest available frequency greater than expected bclk.
617 *
614 * @wm8960_priv: wm8960 codec private data 618 * @wm8960_priv: wm8960 codec private data
615 * @mclk: MCLK used to derive sysclk 619 * @mclk: MCLK used to derive sysclk
616 * @sysclk_idx: sysclk_divs index for found sysclk 620 * @sysclk_idx: sysclk_divs index for found sysclk
@@ -618,8 +622,9 @@ static const int bclk_divs[] = {
618 * @bclk_idx: bclk_divs index for found bclk 622 * @bclk_idx: bclk_divs index for found bclk
619 * 623 *
620 * Returns: 624 * Returns:
621 * -1, in case no sysclk frequency available found 625 * -1, in case no sysclk frequency available found
622 * 0, in case an exact (@sysclk_idx, @dac_idx, @bclk_idx) match is found 626 * >=0, in case we could derive bclk and lrclk from sysclk using
627 * (@sysclk_idx, @dac_idx, @bclk_idx) dividers
623 */ 628 */
624static 629static
625int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, 630int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
@@ -627,7 +632,10 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
627{ 632{
628 int sysclk, bclk, lrclk; 633 int sysclk, bclk, lrclk;
629 int i, j, k; 634 int i, j, k;
630 int diff; 635 int diff, closest = mclk;
636
637 /* marker for no match */
638 *bclk_idx = -1;
631 639
632 bclk = wm8960->bclk; 640 bclk = wm8960->bclk;
633 lrclk = wm8960->lrclk; 641 lrclk = wm8960->lrclk;
@@ -648,6 +656,12 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
648 *bclk_idx = k; 656 *bclk_idx = k;
649 break; 657 break;
650 } 658 }
659 if (diff > 0 && closest > diff) {
660 *sysclk_idx = i;
661 *dac_idx = j;
662 *bclk_idx = k;
663 closest = diff;
664 }
651 } 665 }
652 if (k != ARRAY_SIZE(bclk_divs)) 666 if (k != ARRAY_SIZE(bclk_divs))
653 break; 667 break;
@@ -655,11 +669,7 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
655 if (j != ARRAY_SIZE(dac_divs)) 669 if (j != ARRAY_SIZE(dac_divs))
656 break; 670 break;
657 } 671 }
658 672 return *bclk_idx;
659 if (i != ARRAY_SIZE(sysclk_divs))
660 return 0;
661
662 return -1;
663} 673}
664 674
665static int wm8960_configure_clocking(struct snd_soc_codec *codec) 675static int wm8960_configure_clocking(struct snd_soc_codec *codec)
@@ -703,7 +713,7 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
703 713
704 if (wm8960->clk_id != WM8960_SYSCLK_PLL) { 714 if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
705 ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k); 715 ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k);
706 if (ret == 0) { 716 if (ret >= 0) {
707 goto configure_clock; 717 goto configure_clock;
708 } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { 718 } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
709 dev_err(codec->dev, "failed to configure clock\n"); 719 dev_err(codec->dev, "failed to configure clock\n");