diff options
-rw-r--r-- | sound/soc/codecs/pcm512x.c | 119 | ||||
-rw-r--r-- | sound/soc/codecs/pcm512x.h | 4 |
2 files changed, 96 insertions, 27 deletions
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 66dd036f0141..8b474196d52a 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -105,6 +105,7 @@ static const struct reg_default pcm512x_reg_defaults[] = { | |||
105 | { PCM512x_VCOM_CTRL_2, 0x01 }, | 105 | { PCM512x_VCOM_CTRL_2, 0x01 }, |
106 | { PCM512x_BCLK_LRCLK_CFG, 0x00 }, | 106 | { PCM512x_BCLK_LRCLK_CFG, 0x00 }, |
107 | { PCM512x_MASTER_MODE, 0x7c }, | 107 | { PCM512x_MASTER_MODE, 0x7c }, |
108 | { PCM512x_GPIO_DACIN, 0x00 }, | ||
108 | { PCM512x_GPIO_PLLIN, 0x00 }, | 109 | { PCM512x_GPIO_PLLIN, 0x00 }, |
109 | { PCM512x_SYNCHRONIZE, 0x10 }, | 110 | { PCM512x_SYNCHRONIZE, 0x10 }, |
110 | { PCM512x_PLL_COEFF_0, 0x00 }, | 111 | { PCM512x_PLL_COEFF_0, 0x00 }, |
@@ -138,6 +139,7 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg) | |||
138 | case PCM512x_MASTER_MODE: | 139 | case PCM512x_MASTER_MODE: |
139 | case PCM512x_PLL_REF: | 140 | case PCM512x_PLL_REF: |
140 | case PCM512x_DAC_REF: | 141 | case PCM512x_DAC_REF: |
142 | case PCM512x_GPIO_DACIN: | ||
141 | case PCM512x_GPIO_PLLIN: | 143 | case PCM512x_GPIO_PLLIN: |
142 | case PCM512x_SYNCHRONIZE: | 144 | case PCM512x_SYNCHRONIZE: |
143 | case PCM512x_PLL_COEFF_0: | 145 | case PCM512x_PLL_COEFF_0: |
@@ -659,6 +661,37 @@ done: | |||
659 | return 0; | 661 | return 0; |
660 | } | 662 | } |
661 | 663 | ||
664 | static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, | ||
665 | unsigned long osr_rate, | ||
666 | unsigned long pllin_rate) | ||
667 | { | ||
668 | struct snd_soc_codec *codec = dai->codec; | ||
669 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
670 | unsigned long dac_rate; | ||
671 | |||
672 | if (!pcm512x->pll_out) | ||
673 | return 0; /* no PLL to bypass, force SCK as DAC input */ | ||
674 | |||
675 | if (pllin_rate % osr_rate) | ||
676 | return 0; /* futile, quit early */ | ||
677 | |||
678 | /* run DAC no faster than 6144000 Hz */ | ||
679 | for (dac_rate = rounddown(6144000, osr_rate); | ||
680 | dac_rate; | ||
681 | dac_rate -= osr_rate) { | ||
682 | |||
683 | if (pllin_rate / dac_rate > 128) | ||
684 | return 0; /* DAC divider would be too big */ | ||
685 | |||
686 | if (!(pllin_rate % dac_rate)) | ||
687 | return dac_rate; | ||
688 | |||
689 | dac_rate -= osr_rate; | ||
690 | } | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
662 | static int pcm512x_set_dividers(struct snd_soc_dai *dai, | 695 | static int pcm512x_set_dividers(struct snd_soc_dai *dai, |
663 | struct snd_pcm_hw_params *params) | 696 | struct snd_pcm_hw_params *params) |
664 | { | 697 | { |
@@ -672,6 +705,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
672 | unsigned long bclk_rate; | 705 | unsigned long bclk_rate; |
673 | unsigned long sample_rate; | 706 | unsigned long sample_rate; |
674 | unsigned long osr_rate; | 707 | unsigned long osr_rate; |
708 | unsigned long dacsrc_rate; | ||
675 | int bclk_div; | 709 | int bclk_div; |
676 | int lrclk_div; | 710 | int lrclk_div; |
677 | int dsp_div; | 711 | int dsp_div; |
@@ -679,11 +713,10 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
679 | unsigned long dac_rate; | 713 | unsigned long dac_rate; |
680 | int ncp_div; | 714 | int ncp_div; |
681 | int osr_div; | 715 | int osr_div; |
682 | unsigned long dac_mul; | ||
683 | unsigned long sck_mul; | ||
684 | int ret; | 716 | int ret; |
685 | int idac; | 717 | int idac; |
686 | int fssp; | 718 | int fssp; |
719 | int gpio; | ||
687 | 720 | ||
688 | lrclk_div = snd_soc_params_to_frame_size(params); | 721 | lrclk_div = snd_soc_params_to_frame_size(params); |
689 | if (lrclk_div == 0) { | 722 | if (lrclk_div == 0) { |
@@ -772,31 +805,72 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
772 | /* run DSP no faster than 50 MHz */ | 805 | /* run DSP no faster than 50 MHz */ |
773 | dsp_div = mck_rate > 50000000 ? 2 : 1; | 806 | dsp_div = mck_rate > 50000000 ? 2 : 1; |
774 | 807 | ||
775 | /* run DAC no faster than 6144000 Hz */ | 808 | dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); |
776 | dac_mul = 6144000 / osr_rate; | 809 | if (dac_rate) { |
777 | sck_mul = sck_rate / osr_rate; | 810 | /* the desired clock rate is "compatible" with the pll input |
778 | for (; dac_mul; dac_mul--) { | 811 | * clock, so use that clock as dac input instead of the pll |
779 | if (!(sck_mul % dac_mul)) | 812 | * output clock since the pll will introduce jitter and thus |
780 | break; | 813 | * noise. |
781 | } | 814 | */ |
782 | if (!dac_mul) { | 815 | dev_dbg(dev, "using pll input as dac input\n"); |
783 | dev_err(dev, "Failed to find DAC rate\n"); | 816 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, |
784 | return -EINVAL; | 817 | PCM512x_SDAC, PCM512x_SDAC_GPIO); |
785 | } | 818 | if (ret != 0) { |
819 | dev_err(codec->dev, | ||
820 | "Failed to set gpio as dacref: %d\n", ret); | ||
821 | return ret; | ||
822 | } | ||
786 | 823 | ||
787 | dac_rate = dac_mul * osr_rate; | 824 | gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1; |
788 | dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", dac_rate, sample_rate); | 825 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN, |
826 | PCM512x_GREF, gpio); | ||
827 | if (ret != 0) { | ||
828 | dev_err(codec->dev, | ||
829 | "Failed to set gpio %d as dacin: %d\n", | ||
830 | pcm512x->pll_in, ret); | ||
831 | return ret; | ||
832 | } | ||
833 | |||
834 | dacsrc_rate = pllin_rate; | ||
835 | } else { | ||
836 | /* run DAC no faster than 6144000 Hz */ | ||
837 | unsigned long dac_mul = 6144000 / osr_rate; | ||
838 | unsigned long sck_mul = sck_rate / osr_rate; | ||
839 | |||
840 | for (; dac_mul; dac_mul--) { | ||
841 | if (!(sck_mul % dac_mul)) | ||
842 | break; | ||
843 | } | ||
844 | if (!dac_mul) { | ||
845 | dev_err(dev, "Failed to find DAC rate\n"); | ||
846 | return -EINVAL; | ||
847 | } | ||
789 | 848 | ||
790 | dac_div = DIV_ROUND_CLOSEST(sck_rate, dac_rate); | 849 | dac_rate = dac_mul * osr_rate; |
850 | dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", | ||
851 | dac_rate, sample_rate); | ||
852 | |||
853 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, | ||
854 | PCM512x_SDAC, PCM512x_SDAC_SCK); | ||
855 | if (ret != 0) { | ||
856 | dev_err(codec->dev, | ||
857 | "Failed to set sck as dacref: %d\n", ret); | ||
858 | return ret; | ||
859 | } | ||
860 | |||
861 | dacsrc_rate = sck_rate; | ||
862 | } | ||
863 | |||
864 | dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); | ||
791 | if (dac_div > 128) { | 865 | if (dac_div > 128) { |
792 | dev_err(dev, "Failed to find DAC divider\n"); | 866 | dev_err(dev, "Failed to find DAC divider\n"); |
793 | return -EINVAL; | 867 | return -EINVAL; |
794 | } | 868 | } |
795 | 869 | ||
796 | ncp_div = DIV_ROUND_CLOSEST(sck_rate / dac_div, 1536000); | 870 | ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); |
797 | if (ncp_div > 128 || sck_rate / dac_div / ncp_div > 2048000) { | 871 | if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { |
798 | /* run NCP no faster than 2048000 Hz, but why? */ | 872 | /* run NCP no faster than 2048000 Hz, but why? */ |
799 | ncp_div = DIV_ROUND_UP(sck_rate / dac_div, 2048000); | 873 | ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); |
800 | if (ncp_div > 128) { | 874 | if (ncp_div > 128) { |
801 | dev_err(dev, "Failed to find NCP divider\n"); | 875 | dev_err(dev, "Failed to find NCP divider\n"); |
802 | return -EINVAL; | 876 | return -EINVAL; |
@@ -1011,13 +1085,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, | |||
1011 | if (ret != 0) | 1085 | if (ret != 0) |
1012 | return ret; | 1086 | return ret; |
1013 | 1087 | ||
1014 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, | ||
1015 | PCM512x_SDAC, PCM512x_SDAC_SCK); | ||
1016 | if (ret != 0) { | ||
1017 | dev_err(codec->dev, "Failed to set sck as dacref: %d\n", ret); | ||
1018 | return ret; | ||
1019 | } | ||
1020 | |||
1021 | if (pcm512x->pll_out) { | 1088 | if (pcm512x->pll_out) { |
1022 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF, | 1089 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF, |
1023 | PCM512x_SREF, PCM512x_SREF_GPIO); | 1090 | PCM512x_SREF, PCM512x_SREF_GPIO); |
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h index eba5adc2cdb1..b7c310207223 100644 --- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) | 38 | #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) |
39 | #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) | 39 | #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) |
40 | #define PCM512x_DAC_REF (PCM512x_PAGE_BASE(0) + 14) | 40 | #define PCM512x_DAC_REF (PCM512x_PAGE_BASE(0) + 14) |
41 | #define PCM512x_GPIO_DACIN (PCM512x_PAGE_BASE(0) + 16) | ||
41 | #define PCM512x_GPIO_PLLIN (PCM512x_PAGE_BASE(0) + 18) | 42 | #define PCM512x_GPIO_PLLIN (PCM512x_PAGE_BASE(0) + 18) |
42 | #define PCM512x_SYNCHRONIZE (PCM512x_PAGE_BASE(0) + 19) | 43 | #define PCM512x_SYNCHRONIZE (PCM512x_PAGE_BASE(0) + 19) |
43 | #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) | 44 | #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) |
@@ -162,8 +163,9 @@ | |||
162 | #define PCM512x_SDAC_PLL (1 << 4) | 163 | #define PCM512x_SDAC_PLL (1 << 4) |
163 | #define PCM512x_SDAC_SCK (3 << 4) | 164 | #define PCM512x_SDAC_SCK (3 << 4) |
164 | #define PCM512x_SDAC_BCK (4 << 4) | 165 | #define PCM512x_SDAC_BCK (4 << 4) |
166 | #define PCM512x_SDAC_GPIO (5 << 4) | ||
165 | 167 | ||
166 | /* Page 0, Register 18 - GPIO source for PLL */ | 168 | /* Page 0, Register 16, 18 - GPIO source for DAC, PLL */ |
167 | #define PCM512x_GREF (7 << 0) | 169 | #define PCM512x_GREF (7 << 0) |
168 | #define PCM512x_GREF_SHIFT 0 | 170 | #define PCM512x_GREF_SHIFT 0 |
169 | #define PCM512x_GREF_GPIO1 (0 << 0) | 171 | #define PCM512x_GREF_GPIO1 (0 << 0) |