Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Zidan Wang and committed by
Mark Brown
3176bf2d bc0195aa

+180 -41
+179 -41
sound/soc/codecs/wm8960.c
··· 48 48 #define WM8960_DISOP 0x40 49 49 #define WM8960_DRES_MASK 0x30 50 50 51 + static bool is_pll_freq_available(unsigned int source, unsigned int target); 52 + static int wm8960_set_pll(struct snd_soc_codec *codec, 53 + unsigned int freq_in, unsigned int freq_out); 51 54 /* 52 55 * wm8960 register cache 53 56 * We can't read the WM8960 register space when we are ··· 129 126 struct snd_soc_dapm_widget *rout1; 130 127 struct snd_soc_dapm_widget *out3; 131 128 bool deemph; 132 - int playback_fs; 129 + int lrclk; 133 130 int bclk; 134 131 int sysclk; 132 + int clk_id; 133 + int freq_in; 134 + bool is_stream_in_use[2]; 135 135 struct wm8960_data pdata; 136 136 }; 137 137 ··· 170 164 if (wm8960->deemph) { 171 165 best = 1; 172 166 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { 173 - if (abs(deemph_settings[i] - wm8960->playback_fs) < 174 - abs(deemph_settings[best] - wm8960->playback_fs)) 167 + if (abs(deemph_settings[i] - wm8960->lrclk) < 168 + abs(deemph_settings[best] - wm8960->lrclk)) 175 169 best = i; 176 170 } 177 171 ··· 571 565 { 8000, 5 }, 572 566 }; 573 567 568 + /* -1 for reserved value */ 569 + static const int sysclk_divs[] = { 1, -1, 2, -1 }; 570 + 574 571 /* Multiply 256 for internal 256 div */ 575 572 static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; 576 573 ··· 583 574 120, 160, 220, 240, 320, 320, 320 584 575 }; 585 576 586 - static void wm8960_configure_clocking(struct snd_soc_codec *codec, 587 - bool tx, int lrclk) 577 + static int wm8960_configure_clocking(struct snd_soc_codec *codec) 588 578 { 589 579 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 580 + int sysclk, bclk, lrclk, freq_out, freq_in; 590 581 u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); 591 - u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); 592 - u32 sysclk; 593 - int i, j; 582 + int i, j, k; 594 583 595 584 if (!(iface1 & (1<<6))) { 596 585 dev_dbg(codec->dev, 597 586 "Codec is slave mode, no need to configure clock\n"); 598 - return; 587 + return 0; 599 588 } 600 589 601 - if (!wm8960->sysclk) { 602 - dev_dbg(codec->dev, "No SYSCLK configured\n"); 603 - return; 590 + if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) { 591 + dev_err(codec->dev, "No MCLK configured\n"); 592 + return -EINVAL; 604 593 } 605 594 606 - if (!wm8960->bclk || !lrclk) { 607 - dev_dbg(codec->dev, "No audio clocks configured\n"); 608 - return; 595 + freq_in = wm8960->freq_in; 596 + bclk = wm8960->bclk; 597 + lrclk = wm8960->lrclk; 598 + /* 599 + * If it's sysclk auto mode, check if the MCLK can provide sysclk or 600 + * not. If MCLK can provide sysclk, using MCLK to provide sysclk 601 + * directly. Otherwise, auto select a available pll out frequency 602 + * and set PLL. 603 + */ 604 + if (wm8960->clk_id == WM8960_SYSCLK_AUTO) { 605 + /* disable the PLL and using MCLK to provide sysclk */ 606 + wm8960_set_pll(codec, 0, 0); 607 + freq_out = freq_in; 608 + } else if (wm8960->sysclk) { 609 + freq_out = wm8960->sysclk; 610 + } else { 611 + dev_err(codec->dev, "No SYSCLK configured\n"); 612 + return -EINVAL; 609 613 } 610 614 611 - for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { 612 - if (wm8960->sysclk == lrclk * dac_divs[i]) { 613 - for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { 614 - sysclk = wm8960->bclk * bclk_divs[j] / 10; 615 - if (wm8960->sysclk == sysclk) 615 + /* check if the sysclk frequency is available. */ 616 + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { 617 + if (sysclk_divs[i] == -1) 618 + continue; 619 + sysclk = freq_out / sysclk_divs[i]; 620 + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { 621 + if (sysclk == dac_divs[j] * lrclk) { 622 + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) 623 + if (sysclk == bclk * bclk_divs[k] / 10) 624 + break; 625 + if (k != ARRAY_SIZE(bclk_divs)) 616 626 break; 617 627 } 618 - if(j != ARRAY_SIZE(bclk_divs)) 628 + } 629 + if (j != ARRAY_SIZE(dac_divs)) 630 + break; 631 + } 632 + 633 + if (i != ARRAY_SIZE(sysclk_divs)) { 634 + goto configure_clock; 635 + } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { 636 + dev_err(codec->dev, "failed to configure clock\n"); 637 + return -EINVAL; 638 + } 639 + /* get a available pll out frequency and set pll */ 640 + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { 641 + if (sysclk_divs[i] == -1) 642 + continue; 643 + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { 644 + sysclk = lrclk * dac_divs[j]; 645 + freq_out = sysclk * sysclk_divs[i]; 646 + 647 + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { 648 + if (sysclk == bclk * bclk_divs[k] / 10 && 649 + is_pll_freq_available(freq_in, freq_out)) { 650 + wm8960_set_pll(codec, 651 + freq_in, freq_out); 652 + break; 653 + } else { 654 + continue; 655 + } 656 + } 657 + if (k != ARRAY_SIZE(bclk_divs)) 619 658 break; 620 659 } 660 + if (j != ARRAY_SIZE(dac_divs)) 661 + break; 621 662 } 622 663 623 - if (i == ARRAY_SIZE(dac_divs)) { 624 - dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); 625 - return; 664 + if (i == ARRAY_SIZE(sysclk_divs)) { 665 + dev_err(codec->dev, "failed to configure clock\n"); 666 + return -EINVAL; 626 667 } 627 668 628 - /* 629 - * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC 630 - * pin is used as a frame clock for ADCs and DACs. 631 - */ 632 - if (iface2 & (1<<6)) 633 - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); 634 - else if (tx) 635 - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); 636 - else if (!tx) 637 - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6); 669 + configure_clock: 670 + /* configure sysclk clock */ 671 + snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1); 672 + 673 + /* configure frame clock */ 674 + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3); 675 + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6); 638 676 639 677 /* configure bit clock */ 640 - snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); 678 + snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k); 679 + 680 + return 0; 641 681 } 642 682 643 683 static int wm8960_hw_params(struct snd_pcm_substream *substream, ··· 725 667 return -EINVAL; 726 668 } 727 669 670 + wm8960->lrclk = params_rate(params); 728 671 /* Update filters for the new rate */ 729 - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 730 - wm8960->playback_fs = params_rate(params); 672 + if (tx) { 731 673 wm8960_set_deemph(codec); 732 674 } else { 733 675 for (i = 0; i < ARRAY_SIZE(alc_rates); i++) ··· 740 682 /* set iface */ 741 683 snd_soc_write(codec, WM8960_IFACE1, iface); 742 684 743 - wm8960_configure_clocking(codec, tx, params_rate(params)); 685 + wm8960->is_stream_in_use[tx] = true; 686 + 687 + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON && 688 + !wm8960->is_stream_in_use[!tx]) 689 + return wm8960_configure_clocking(codec); 690 + 691 + return 0; 692 + } 693 + 694 + static int wm8960_hw_free(struct snd_pcm_substream *substream, 695 + struct snd_soc_dai *dai) 696 + { 697 + struct snd_soc_codec *codec = dai->codec; 698 + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 699 + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 700 + 701 + wm8960->is_stream_in_use[tx] = false; 744 702 745 703 return 0; 746 704 } ··· 776 702 enum snd_soc_bias_level level) 777 703 { 778 704 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 705 + u16 pm2 = snd_soc_read(codec, WM8960_POWER2); 779 706 int ret; 780 707 781 708 switch (level) { ··· 796 721 } 797 722 } 798 723 724 + ret = wm8960_configure_clocking(codec); 725 + if (ret) 726 + return ret; 727 + 799 728 /* Set VMID to 2x50k */ 800 729 snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); 801 730 break; 802 731 803 732 case SND_SOC_BIAS_ON: 733 + /* 734 + * If it's sysclk auto mode, and the pll is enabled, 735 + * disable the pll 736 + */ 737 + if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) 738 + wm8960_set_pll(codec, 0, 0); 739 + 804 740 if (!IS_ERR(wm8960->mclk)) 805 741 clk_disable_unprepare(wm8960->mclk); 806 742 break; ··· 866 780 enum snd_soc_bias_level level) 867 781 { 868 782 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 783 + u16 pm2 = snd_soc_read(codec, WM8960_POWER2); 869 784 int reg, ret; 870 785 871 786 switch (level) { ··· 918 831 return ret; 919 832 } 920 833 } 834 + 835 + ret = wm8960_configure_clocking(codec); 836 + if (ret) 837 + return ret; 838 + 921 839 break; 922 840 923 841 case SND_SOC_BIAS_ON: 842 + /* 843 + * If it's sysclk auto mode, and the pll is enabled, 844 + * disable the pll 845 + */ 846 + if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) 847 + wm8960_set_pll(codec, 0, 0); 848 + 924 849 if (!IS_ERR(wm8960->mclk)) 925 850 clk_disable_unprepare(wm8960->mclk); 926 851 ··· 991 892 u32 k:24; 992 893 }; 993 894 895 + static bool is_pll_freq_available(unsigned int source, unsigned int target) 896 + { 897 + unsigned int Ndiv; 898 + 899 + if (source == 0 || target == 0) 900 + return false; 901 + 902 + /* Scale up target to PLL operating frequency */ 903 + target *= 4; 904 + Ndiv = target / source; 905 + 906 + if (Ndiv < 6) { 907 + source >>= 1; 908 + Ndiv = target / source; 909 + } 910 + 911 + if ((Ndiv < 6) || (Ndiv > 12)) 912 + return false; 913 + 914 + return true; 915 + } 916 + 994 917 /* The size in bits of the pll divide multiplied by 10 995 918 * to allow rounding later */ 996 919 #define FIXED_PLL_SIZE ((1 << 24) * 10) ··· 1064 943 return 0; 1065 944 } 1066 945 1067 - static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 1068 - int source, unsigned int freq_in, unsigned int freq_out) 946 + static int wm8960_set_pll(struct snd_soc_codec *codec, 947 + unsigned int freq_in, unsigned int freq_out) 1069 948 { 1070 - struct snd_soc_codec *codec = codec_dai->codec; 1071 949 u16 reg; 1072 950 static struct _pll_div pll_div; 1073 951 int ret; ··· 1104 984 snd_soc_update_bits(codec, WM8960_CLOCK1, 0x1, 0x1); 1105 985 1106 986 return 0; 987 + } 988 + 989 + static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 990 + int source, unsigned int freq_in, unsigned int freq_out) 991 + { 992 + struct snd_soc_codec *codec = codec_dai->codec; 993 + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 994 + 995 + wm8960->freq_in = freq_in; 996 + 997 + if (pll_id == WM8960_SYSCLK_AUTO) 998 + return 0; 999 + 1000 + return wm8960_set_pll(codec, freq_in, freq_out); 1107 1001 } 1108 1002 1109 1003 static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, ··· 1177 1043 snd_soc_update_bits(codec, WM8960_CLOCK1, 1178 1044 0x1, WM8960_SYSCLK_PLL); 1179 1045 break; 1046 + case WM8960_SYSCLK_AUTO: 1047 + break; 1180 1048 default: 1181 1049 return -EINVAL; 1182 1050 } 1183 1051 1184 1052 wm8960->sysclk = freq; 1053 + wm8960->clk_id = clk_id; 1185 1054 1186 1055 return 0; 1187 1056 } ··· 1197 1060 1198 1061 static const struct snd_soc_dai_ops wm8960_dai_ops = { 1199 1062 .hw_params = wm8960_hw_params, 1063 + .hw_free = wm8960_hw_free, 1200 1064 .digital_mute = wm8960_mute, 1201 1065 .set_fmt = wm8960_set_dai_fmt, 1202 1066 .set_clkdiv = wm8960_set_dai_clkdiv,
+1
sound/soc/codecs/wm8960.h
··· 82 82 83 83 #define WM8960_SYSCLK_MCLK (0 << 0) 84 84 #define WM8960_SYSCLK_PLL (1 << 0) 85 + #define WM8960_SYSCLK_AUTO (2 << 0) 85 86 86 87 #define WM8960_DAC_DIV_1 (0 << 3) 87 88 #define WM8960_DAC_DIV_1_5 (1 << 3)