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

ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible

The PLL introduces jitter, which in turn introduces noice if used
to clock the DAC. Thus, avoid the PLL output, and use the PLL input
to drive the DAC clock, if possible.

This is described for the PCM5142/PCM5242 chips in the answers to the
forum post "PCM5142/PCM5242 DAC clock source" at the TI E2E community
pages (1).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/389994

Signed-off-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Peter Rosin and committed by
Mark Brown
7c4e1119 f086ba9d

+96 -27
+93 -26
sound/soc/codecs/pcm512x.c
··· 105 105 { PCM512x_VCOM_CTRL_2, 0x01 }, 106 106 { PCM512x_BCLK_LRCLK_CFG, 0x00 }, 107 107 { PCM512x_MASTER_MODE, 0x7c }, 108 + { PCM512x_GPIO_DACIN, 0x00 }, 108 109 { PCM512x_GPIO_PLLIN, 0x00 }, 109 110 { PCM512x_SYNCHRONIZE, 0x10 }, 110 111 { PCM512x_PLL_COEFF_0, 0x00 }, ··· 139 138 case PCM512x_MASTER_MODE: 140 139 case PCM512x_PLL_REF: 141 140 case PCM512x_DAC_REF: 141 + case PCM512x_GPIO_DACIN: 142 142 case PCM512x_GPIO_PLLIN: 143 143 case PCM512x_SYNCHRONIZE: 144 144 case PCM512x_PLL_COEFF_0: ··· 661 659 return 0; 662 660 } 663 661 662 + static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, 663 + unsigned long osr_rate, 664 + unsigned long pllin_rate) 665 + { 666 + struct snd_soc_codec *codec = dai->codec; 667 + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); 668 + unsigned long dac_rate; 669 + 670 + if (!pcm512x->pll_out) 671 + return 0; /* no PLL to bypass, force SCK as DAC input */ 672 + 673 + if (pllin_rate % osr_rate) 674 + return 0; /* futile, quit early */ 675 + 676 + /* run DAC no faster than 6144000 Hz */ 677 + for (dac_rate = rounddown(6144000, osr_rate); 678 + dac_rate; 679 + dac_rate -= osr_rate) { 680 + 681 + if (pllin_rate / dac_rate > 128) 682 + return 0; /* DAC divider would be too big */ 683 + 684 + if (!(pllin_rate % dac_rate)) 685 + return dac_rate; 686 + 687 + dac_rate -= osr_rate; 688 + } 689 + 690 + return 0; 691 + } 692 + 664 693 static int pcm512x_set_dividers(struct snd_soc_dai *dai, 665 694 struct snd_pcm_hw_params *params) 666 695 { ··· 705 672 unsigned long bclk_rate; 706 673 unsigned long sample_rate; 707 674 unsigned long osr_rate; 675 + unsigned long dacsrc_rate; 708 676 int bclk_div; 709 677 int lrclk_div; 710 678 int dsp_div; ··· 713 679 unsigned long dac_rate; 714 680 int ncp_div; 715 681 int osr_div; 716 - unsigned long dac_mul; 717 - unsigned long sck_mul; 718 682 int ret; 719 683 int idac; 720 684 int fssp; 685 + int gpio; 721 686 722 687 lrclk_div = snd_soc_params_to_frame_size(params); 723 688 if (lrclk_div == 0) { ··· 805 772 /* run DSP no faster than 50 MHz */ 806 773 dsp_div = mck_rate > 50000000 ? 2 : 1; 807 774 808 - /* run DAC no faster than 6144000 Hz */ 809 - dac_mul = 6144000 / osr_rate; 810 - sck_mul = sck_rate / osr_rate; 811 - for (; dac_mul; dac_mul--) { 812 - if (!(sck_mul % dac_mul)) 813 - break; 814 - } 815 - if (!dac_mul) { 816 - dev_err(dev, "Failed to find DAC rate\n"); 817 - return -EINVAL; 775 + dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); 776 + if (dac_rate) { 777 + /* the desired clock rate is "compatible" with the pll input 778 + * clock, so use that clock as dac input instead of the pll 779 + * output clock since the pll will introduce jitter and thus 780 + * noise. 781 + */ 782 + dev_dbg(dev, "using pll input as dac input\n"); 783 + ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, 784 + PCM512x_SDAC, PCM512x_SDAC_GPIO); 785 + if (ret != 0) { 786 + dev_err(codec->dev, 787 + "Failed to set gpio as dacref: %d\n", ret); 788 + return ret; 789 + } 790 + 791 + gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1; 792 + ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN, 793 + PCM512x_GREF, gpio); 794 + if (ret != 0) { 795 + dev_err(codec->dev, 796 + "Failed to set gpio %d as dacin: %d\n", 797 + pcm512x->pll_in, ret); 798 + return ret; 799 + } 800 + 801 + dacsrc_rate = pllin_rate; 802 + } else { 803 + /* run DAC no faster than 6144000 Hz */ 804 + unsigned long dac_mul = 6144000 / osr_rate; 805 + unsigned long sck_mul = sck_rate / osr_rate; 806 + 807 + for (; dac_mul; dac_mul--) { 808 + if (!(sck_mul % dac_mul)) 809 + break; 810 + } 811 + if (!dac_mul) { 812 + dev_err(dev, "Failed to find DAC rate\n"); 813 + return -EINVAL; 814 + } 815 + 816 + dac_rate = dac_mul * osr_rate; 817 + dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", 818 + dac_rate, sample_rate); 819 + 820 + ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, 821 + PCM512x_SDAC, PCM512x_SDAC_SCK); 822 + if (ret != 0) { 823 + dev_err(codec->dev, 824 + "Failed to set sck as dacref: %d\n", ret); 825 + return ret; 826 + } 827 + 828 + dacsrc_rate = sck_rate; 818 829 } 819 830 820 - dac_rate = dac_mul * osr_rate; 821 - dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", dac_rate, sample_rate); 822 - 823 - dac_div = DIV_ROUND_CLOSEST(sck_rate, dac_rate); 831 + dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); 824 832 if (dac_div > 128) { 825 833 dev_err(dev, "Failed to find DAC divider\n"); 826 834 return -EINVAL; 827 835 } 828 836 829 - ncp_div = DIV_ROUND_CLOSEST(sck_rate / dac_div, 1536000); 830 - if (ncp_div > 128 || sck_rate / dac_div / ncp_div > 2048000) { 837 + ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); 838 + if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { 831 839 /* run NCP no faster than 2048000 Hz, but why? */ 832 - ncp_div = DIV_ROUND_UP(sck_rate / dac_div, 2048000); 840 + ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); 833 841 if (ncp_div > 128) { 834 842 dev_err(dev, "Failed to find NCP divider\n"); 835 843 return -EINVAL; ··· 1084 1010 ret = pcm512x_set_dividers(dai, params); 1085 1011 if (ret != 0) 1086 1012 return ret; 1087 - 1088 - ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, 1089 - PCM512x_SDAC, PCM512x_SDAC_SCK); 1090 - if (ret != 0) { 1091 - dev_err(codec->dev, "Failed to set sck as dacref: %d\n", ret); 1092 - return ret; 1093 - } 1094 1013 1095 1014 if (pcm512x->pll_out) { 1096 1015 ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
+3 -1
sound/soc/codecs/pcm512x.h
··· 38 38 #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) 39 39 #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) 40 40 #define PCM512x_DAC_REF (PCM512x_PAGE_BASE(0) + 14) 41 + #define PCM512x_GPIO_DACIN (PCM512x_PAGE_BASE(0) + 16) 41 42 #define PCM512x_GPIO_PLLIN (PCM512x_PAGE_BASE(0) + 18) 42 43 #define PCM512x_SYNCHRONIZE (PCM512x_PAGE_BASE(0) + 19) 43 44 #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) ··· 163 162 #define PCM512x_SDAC_PLL (1 << 4) 164 163 #define PCM512x_SDAC_SCK (3 << 4) 165 164 #define PCM512x_SDAC_BCK (4 << 4) 165 + #define PCM512x_SDAC_GPIO (5 << 4) 166 166 167 - /* Page 0, Register 18 - GPIO source for PLL */ 167 + /* Page 0, Register 16, 18 - GPIO source for DAC, PLL */ 168 168 #define PCM512x_GREF (7 << 0) 169 169 #define PCM512x_GREF_SHIFT 0 170 170 #define PCM512x_GREF_GPIO1 (0 << 0)