aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZidan Wang <zidan.wang@freescale.com>2015-08-11 07:25:15 -0400
committerMark Brown <broonie@kernel.org>2015-08-11 12:11:52 -0400
commit3176bf2d7ccd64da9be7b07036e0ba8293179906 (patch)
treee82349c7447e81c9aa3e7f75f0bfce4bfa7ad33f
parentbc0195aad0daa2ad5b0d76cce22b167bc3435590 (diff)
ASoC: wm8960: update pll and clock setting function
Add sysclk auto mode. When it's sysclk auto mode, if the MCLK is available for clock configure, using MCLK to provide sysclk directly, otherwise, search a available pll out frequcncy and set pll. Configure clock in hw_params may cause problems when using bypass style paths without hw_params in machine driver getting called. So add configure clock to set_bias_level. Signed-off-by: Zidan Wang <zidan.wang@freescale.com> Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/wm8960.c220
-rw-r--r--sound/soc/codecs/wm8960.h1
2 files changed, 180 insertions, 41 deletions
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 94c5c4681ce5..0fc8364b58b9 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -48,6 +48,9 @@
48#define WM8960_DISOP 0x40 48#define WM8960_DISOP 0x40
49#define WM8960_DRES_MASK 0x30 49#define WM8960_DRES_MASK 0x30
50 50
51static bool is_pll_freq_available(unsigned int source, unsigned int target);
52static int wm8960_set_pll(struct snd_soc_codec *codec,
53 unsigned int freq_in, unsigned int freq_out);
51/* 54/*
52 * wm8960 register cache 55 * wm8960 register cache
53 * We can't read the WM8960 register space when we are 56 * We can't read the WM8960 register space when we are
@@ -126,9 +129,12 @@ struct wm8960_priv {
126 struct snd_soc_dapm_widget *rout1; 129 struct snd_soc_dapm_widget *rout1;
127 struct snd_soc_dapm_widget *out3; 130 struct snd_soc_dapm_widget *out3;
128 bool deemph; 131 bool deemph;
129 int playback_fs; 132 int lrclk;
130 int bclk; 133 int bclk;
131 int sysclk; 134 int sysclk;
135 int clk_id;
136 int freq_in;
137 bool is_stream_in_use[2];
132 struct wm8960_data pdata; 138 struct wm8960_data pdata;
133}; 139};
134 140
@@ -164,8 +170,8 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
164 if (wm8960->deemph) { 170 if (wm8960->deemph) {
165 best = 1; 171 best = 1;
166 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { 172 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
167 if (abs(deemph_settings[i] - wm8960->playback_fs) < 173 if (abs(deemph_settings[i] - wm8960->lrclk) <
168 abs(deemph_settings[best] - wm8960->playback_fs)) 174 abs(deemph_settings[best] - wm8960->lrclk))
169 best = i; 175 best = i;
170 } 176 }
171 177
@@ -565,6 +571,9 @@ static struct {
565 { 8000, 5 }, 571 { 8000, 5 },
566}; 572};
567 573
574/* -1 for reserved value */
575static const int sysclk_divs[] = { 1, -1, 2, -1 };
576
568/* Multiply 256 for internal 256 div */ 577/* Multiply 256 for internal 256 div */
569static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; 578static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
570 579
@@ -574,61 +583,110 @@ static const int bclk_divs[] = {
574 120, 160, 220, 240, 320, 320, 320 583 120, 160, 220, 240, 320, 320, 320
575}; 584};
576 585
577static void wm8960_configure_clocking(struct snd_soc_codec *codec, 586static int wm8960_configure_clocking(struct snd_soc_codec *codec)
578 bool tx, int lrclk)
579{ 587{
580 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 588 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
589 int sysclk, bclk, lrclk, freq_out, freq_in;
581 u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); 590 u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
582 u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); 591 int i, j, k;
583 u32 sysclk;
584 int i, j;
585 592
586 if (!(iface1 & (1<<6))) { 593 if (!(iface1 & (1<<6))) {
587 dev_dbg(codec->dev, 594 dev_dbg(codec->dev,
588 "Codec is slave mode, no need to configure clock\n"); 595 "Codec is slave mode, no need to configure clock\n");
589 return; 596 return 0;
597 }
598
599 if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) {
600 dev_err(codec->dev, "No MCLK configured\n");
601 return -EINVAL;
590 } 602 }
591 603
592 if (!wm8960->sysclk) { 604 freq_in = wm8960->freq_in;
593 dev_dbg(codec->dev, "No SYSCLK configured\n"); 605 bclk = wm8960->bclk;
594 return; 606 lrclk = wm8960->lrclk;
607 /*
608 * If it's sysclk auto mode, check if the MCLK can provide sysclk or
609 * not. If MCLK can provide sysclk, using MCLK to provide sysclk
610 * directly. Otherwise, auto select a available pll out frequency
611 * and set PLL.
612 */
613 if (wm8960->clk_id == WM8960_SYSCLK_AUTO) {
614 /* disable the PLL and using MCLK to provide sysclk */
615 wm8960_set_pll(codec, 0, 0);
616 freq_out = freq_in;
617 } else if (wm8960->sysclk) {
618 freq_out = wm8960->sysclk;
619 } else {
620 dev_err(codec->dev, "No SYSCLK configured\n");
621 return -EINVAL;
595 } 622 }
596 623
597 if (!wm8960->bclk || !lrclk) { 624 /* check if the sysclk frequency is available. */
598 dev_dbg(codec->dev, "No audio clocks configured\n"); 625 for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
599 return; 626 if (sysclk_divs[i] == -1)
627 continue;
628 sysclk = freq_out / sysclk_divs[i];
629 for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
630 if (sysclk == dac_divs[j] * lrclk) {
631 for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
632 if (sysclk == bclk * bclk_divs[k] / 10)
633 break;
634 if (k != ARRAY_SIZE(bclk_divs))
635 break;
636 }
637 }
638 if (j != ARRAY_SIZE(dac_divs))
639 break;
600 } 640 }
601 641
602 for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { 642 if (i != ARRAY_SIZE(sysclk_divs)) {
603 if (wm8960->sysclk == lrclk * dac_divs[i]) { 643 goto configure_clock;
604 for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { 644 } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
605 sysclk = wm8960->bclk * bclk_divs[j] / 10; 645 dev_err(codec->dev, "failed to configure clock\n");
606 if (wm8960->sysclk == sysclk) 646 return -EINVAL;
647 }
648 /* get a available pll out frequency and set pll */
649 for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
650 if (sysclk_divs[i] == -1)
651 continue;
652 for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
653 sysclk = lrclk * dac_divs[j];
654 freq_out = sysclk * sysclk_divs[i];
655
656 for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
657 if (sysclk == bclk * bclk_divs[k] / 10 &&
658 is_pll_freq_available(freq_in, freq_out)) {
659 wm8960_set_pll(codec,
660 freq_in, freq_out);
607 break; 661 break;
662 } else {
663 continue;
664 }
608 } 665 }
609 if(j != ARRAY_SIZE(bclk_divs)) 666 if (k != ARRAY_SIZE(bclk_divs))
610 break; 667 break;
611 } 668 }
669 if (j != ARRAY_SIZE(dac_divs))
670 break;
612 } 671 }
613 672
614 if (i == ARRAY_SIZE(dac_divs)) { 673 if (i == ARRAY_SIZE(sysclk_divs)) {
615 dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); 674 dev_err(codec->dev, "failed to configure clock\n");
616 return; 675 return -EINVAL;
617 } 676 }
618 677
619 /* 678configure_clock:
620 * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC 679 /* configure sysclk clock */
621 * pin is used as a frame clock for ADCs and DACs. 680 snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1);
622 */ 681
623 if (iface2 & (1<<6)) 682 /* configure frame clock */
624 snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); 683 snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3);
625 else if (tx) 684 snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6);
626 snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
627 else if (!tx)
628 snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6);
629 685
630 /* configure bit clock */ 686 /* configure bit clock */
631 snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); 687 snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k);
688
689 return 0;
632} 690}
633 691
634static int wm8960_hw_params(struct snd_pcm_substream *substream, 692static int wm8960_hw_params(struct snd_pcm_substream *substream,
@@ -667,9 +725,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
667 return -EINVAL; 725 return -EINVAL;
668 } 726 }
669 727
728 wm8960->lrclk = params_rate(params);
670 /* Update filters for the new rate */ 729 /* Update filters for the new rate */
671 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 730 if (tx) {
672 wm8960->playback_fs = params_rate(params);
673 wm8960_set_deemph(codec); 731 wm8960_set_deemph(codec);
674 } else { 732 } else {
675 for (i = 0; i < ARRAY_SIZE(alc_rates); i++) 733 for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
@@ -682,7 +740,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
682 /* set iface */ 740 /* set iface */
683 snd_soc_write(codec, WM8960_IFACE1, iface); 741 snd_soc_write(codec, WM8960_IFACE1, iface);
684 742
685 wm8960_configure_clocking(codec, tx, params_rate(params)); 743 wm8960->is_stream_in_use[tx] = true;
744
745 if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON &&
746 !wm8960->is_stream_in_use[!tx])
747 return wm8960_configure_clocking(codec);
748
749 return 0;
750}
751
752static int wm8960_hw_free(struct snd_pcm_substream *substream,
753 struct snd_soc_dai *dai)
754{
755 struct snd_soc_codec *codec = dai->codec;
756 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
757 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
758
759 wm8960->is_stream_in_use[tx] = false;
686 760
687 return 0; 761 return 0;
688} 762}
@@ -702,6 +776,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
702 enum snd_soc_bias_level level) 776 enum snd_soc_bias_level level)
703{ 777{
704 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 778 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
779 u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
705 int ret; 780 int ret;
706 781
707 switch (level) { 782 switch (level) {
@@ -721,11 +796,22 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
721 } 796 }
722 } 797 }
723 798
799 ret = wm8960_configure_clocking(codec);
800 if (ret)
801 return ret;
802
724 /* Set VMID to 2x50k */ 803 /* Set VMID to 2x50k */
725 snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); 804 snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
726 break; 805 break;
727 806
728 case SND_SOC_BIAS_ON: 807 case SND_SOC_BIAS_ON:
808 /*
809 * If it's sysclk auto mode, and the pll is enabled,
810 * disable the pll
811 */
812 if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
813 wm8960_set_pll(codec, 0, 0);
814
729 if (!IS_ERR(wm8960->mclk)) 815 if (!IS_ERR(wm8960->mclk))
730 clk_disable_unprepare(wm8960->mclk); 816 clk_disable_unprepare(wm8960->mclk);
731 break; 817 break;
@@ -780,6 +866,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
780 enum snd_soc_bias_level level) 866 enum snd_soc_bias_level level)
781{ 867{
782 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 868 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
869 u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
783 int reg, ret; 870 int reg, ret;
784 871
785 switch (level) { 872 switch (level) {
@@ -831,9 +918,21 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
831 return ret; 918 return ret;
832 } 919 }
833 } 920 }
921
922 ret = wm8960_configure_clocking(codec);
923 if (ret)
924 return ret;
925
834 break; 926 break;
835 927
836 case SND_SOC_BIAS_ON: 928 case SND_SOC_BIAS_ON:
929 /*
930 * If it's sysclk auto mode, and the pll is enabled,
931 * disable the pll
932 */
933 if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
934 wm8960_set_pll(codec, 0, 0);
935
837 if (!IS_ERR(wm8960->mclk)) 936 if (!IS_ERR(wm8960->mclk))
838 clk_disable_unprepare(wm8960->mclk); 937 clk_disable_unprepare(wm8960->mclk);
839 938
@@ -892,6 +991,28 @@ struct _pll_div {
892 u32 k:24; 991 u32 k:24;
893}; 992};
894 993
994static bool is_pll_freq_available(unsigned int source, unsigned int target)
995{
996 unsigned int Ndiv;
997
998 if (source == 0 || target == 0)
999 return false;
1000
1001 /* Scale up target to PLL operating frequency */
1002 target *= 4;
1003 Ndiv = target / source;
1004
1005 if (Ndiv < 6) {
1006 source >>= 1;
1007 Ndiv = target / source;
1008 }
1009
1010 if ((Ndiv < 6) || (Ndiv > 12))
1011 return false;
1012
1013 return true;
1014}
1015
895/* The size in bits of the pll divide multiplied by 10 1016/* The size in bits of the pll divide multiplied by 10
896 * to allow rounding later */ 1017 * to allow rounding later */
897#define FIXED_PLL_SIZE ((1 << 24) * 10) 1018#define FIXED_PLL_SIZE ((1 << 24) * 10)
@@ -943,10 +1064,9 @@ static int pll_factors(unsigned int source, unsigned int target,
943 return 0; 1064 return 0;
944} 1065}
945 1066
946static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 1067static int wm8960_set_pll(struct snd_soc_codec *codec,
947 int source, unsigned int freq_in, unsigned int freq_out) 1068 unsigned int freq_in, unsigned int freq_out)
948{ 1069{
949 struct snd_soc_codec *codec = codec_dai->codec;
950 u16 reg; 1070 u16 reg;
951 static struct _pll_div pll_div; 1071 static struct _pll_div pll_div;
952 int ret; 1072 int ret;
@@ -986,6 +1106,20 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
986 return 0; 1106 return 0;
987} 1107}
988 1108
1109static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
1110 int source, unsigned int freq_in, unsigned int freq_out)
1111{
1112 struct snd_soc_codec *codec = codec_dai->codec;
1113 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
1114
1115 wm8960->freq_in = freq_in;
1116
1117 if (pll_id == WM8960_SYSCLK_AUTO)
1118 return 0;
1119
1120 return wm8960_set_pll(codec, freq_in, freq_out);
1121}
1122
989static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 1123static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
990 int div_id, int div) 1124 int div_id, int div)
991{ 1125{
@@ -1043,11 +1177,14 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
1043 snd_soc_update_bits(codec, WM8960_CLOCK1, 1177 snd_soc_update_bits(codec, WM8960_CLOCK1,
1044 0x1, WM8960_SYSCLK_PLL); 1178 0x1, WM8960_SYSCLK_PLL);
1045 break; 1179 break;
1180 case WM8960_SYSCLK_AUTO:
1181 break;
1046 default: 1182 default:
1047 return -EINVAL; 1183 return -EINVAL;
1048 } 1184 }
1049 1185
1050 wm8960->sysclk = freq; 1186 wm8960->sysclk = freq;
1187 wm8960->clk_id = clk_id;
1051 1188
1052 return 0; 1189 return 0;
1053} 1190}
@@ -1060,6 +1197,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
1060 1197
1061static const struct snd_soc_dai_ops wm8960_dai_ops = { 1198static const struct snd_soc_dai_ops wm8960_dai_ops = {
1062 .hw_params = wm8960_hw_params, 1199 .hw_params = wm8960_hw_params,
1200 .hw_free = wm8960_hw_free,
1063 .digital_mute = wm8960_mute, 1201 .digital_mute = wm8960_mute,
1064 .set_fmt = wm8960_set_dai_fmt, 1202 .set_fmt = wm8960_set_dai_fmt,
1065 .set_clkdiv = wm8960_set_dai_clkdiv, 1203 .set_clkdiv = wm8960_set_dai_clkdiv,
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index 2d8163d7004b..ab3220d3411d 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -82,6 +82,7 @@
82 82
83#define WM8960_SYSCLK_MCLK (0 << 0) 83#define WM8960_SYSCLK_MCLK (0 << 0)
84#define WM8960_SYSCLK_PLL (1 << 0) 84#define WM8960_SYSCLK_PLL (1 << 0)
85#define WM8960_SYSCLK_AUTO (2 << 0)
85 86
86#define WM8960_DAC_DIV_1 (0 << 3) 87#define WM8960_DAC_DIV_1 (0 << 3)
87#define WM8960_DAC_DIV_1_5 (1 << 3) 88#define WM8960_DAC_DIV_1_5 (1 << 3)