diff options
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 225 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.h | 4 |
2 files changed, 95 insertions, 134 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 09b1661b8a3a..738b3b634d74 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -49,7 +49,7 @@ | |||
49 | #include "tlv320aic3x.h" | 49 | #include "tlv320aic3x.h" |
50 | 50 | ||
51 | #define AUDIO_NAME "aic3x" | 51 | #define AUDIO_NAME "aic3x" |
52 | #define AIC3X_VERSION "0.1" | 52 | #define AIC3X_VERSION "0.2" |
53 | 53 | ||
54 | /* codec private data */ | 54 | /* codec private data */ |
55 | struct aic3x_priv { | 55 | struct aic3x_priv { |
@@ -648,81 +648,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) | |||
648 | return 0; | 648 | return 0; |
649 | } | 649 | } |
650 | 650 | ||
651 | struct aic3x_rate_divs { | ||
652 | u32 mclk; | ||
653 | u32 rate; | ||
654 | u32 fsref_reg; | ||
655 | u8 sr_reg:4; | ||
656 | u8 pllj_reg; | ||
657 | u16 plld_reg; | ||
658 | }; | ||
659 | |||
660 | /* AIC3X codec mclk clock divider coefficients */ | ||
661 | static const struct aic3x_rate_divs aic3x_divs[] = { | ||
662 | /* 8k */ | ||
663 | {12000000, 8000, 48000, 0xa, 16, 3840}, | ||
664 | {19200000, 8000, 48000, 0xa, 10, 2400}, | ||
665 | {22579200, 8000, 48000, 0xa, 8, 7075}, | ||
666 | {33868800, 8000, 48000, 0xa, 5, 8049}, | ||
667 | /* 11.025k */ | ||
668 | {12000000, 11025, 44100, 0x6, 15, 528}, | ||
669 | {19200000, 11025, 44100, 0x6, 9, 4080}, | ||
670 | {22579200, 11025, 44100, 0x6, 8, 0}, | ||
671 | {33868800, 11025, 44100, 0x6, 5, 3333}, | ||
672 | /* 16k */ | ||
673 | {12000000, 16000, 48000, 0x4, 16, 3840}, | ||
674 | {19200000, 16000, 48000, 0x4, 10, 2400}, | ||
675 | {22579200, 16000, 48000, 0x4, 8, 7075}, | ||
676 | {33868800, 16000, 48000, 0x4, 5, 8049}, | ||
677 | /* 22.05k */ | ||
678 | {12000000, 22050, 44100, 0x2, 15, 528}, | ||
679 | {19200000, 22050, 44100, 0x2, 9, 4080}, | ||
680 | {22579200, 22050, 44100, 0x2, 8, 0}, | ||
681 | {33868800, 22050, 44100, 0x2, 5, 3333}, | ||
682 | /* 32k */ | ||
683 | {12000000, 32000, 48000, 0x1, 16, 3840}, | ||
684 | {19200000, 32000, 48000, 0x1, 10, 2400}, | ||
685 | {22579200, 32000, 48000, 0x1, 8, 7075}, | ||
686 | {33868800, 32000, 48000, 0x1, 5, 8049}, | ||
687 | /* 44.1k */ | ||
688 | {12000000, 44100, 44100, 0x0, 15, 528}, | ||
689 | {19200000, 44100, 44100, 0x0, 9, 4080}, | ||
690 | {22579200, 44100, 44100, 0x0, 8, 0}, | ||
691 | {33868800, 44100, 44100, 0x0, 5, 3333}, | ||
692 | /* 48k */ | ||
693 | {12000000, 48000, 48000, 0x0, 16, 3840}, | ||
694 | {19200000, 48000, 48000, 0x0, 10, 2400}, | ||
695 | {22579200, 48000, 48000, 0x0, 8, 7075}, | ||
696 | {33868800, 48000, 48000, 0x0, 5, 8049}, | ||
697 | /* 64k */ | ||
698 | {12000000, 64000, 96000, 0x1, 16, 3840}, | ||
699 | {19200000, 64000, 96000, 0x1, 10, 2400}, | ||
700 | {22579200, 64000, 96000, 0x1, 8, 7075}, | ||
701 | {33868800, 64000, 96000, 0x1, 5, 8049}, | ||
702 | /* 88.2k */ | ||
703 | {12000000, 88200, 88200, 0x0, 15, 528}, | ||
704 | {19200000, 88200, 88200, 0x0, 9, 4080}, | ||
705 | {22579200, 88200, 88200, 0x0, 8, 0}, | ||
706 | {33868800, 88200, 88200, 0x0, 5, 3333}, | ||
707 | /* 96k */ | ||
708 | {12000000, 96000, 96000, 0x0, 16, 3840}, | ||
709 | {19200000, 96000, 96000, 0x0, 10, 2400}, | ||
710 | {22579200, 96000, 96000, 0x0, 8, 7075}, | ||
711 | {33868800, 96000, 96000, 0x0, 5, 8049}, | ||
712 | }; | ||
713 | |||
714 | static inline int aic3x_get_divs(int mclk, int rate) | ||
715 | { | ||
716 | int i; | ||
717 | |||
718 | for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { | ||
719 | if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) | ||
720 | return i; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static int aic3x_hw_params(struct snd_pcm_substream *substream, | 651 | static int aic3x_hw_params(struct snd_pcm_substream *substream, |
727 | struct snd_pcm_hw_params *params) | 652 | struct snd_pcm_hw_params *params) |
728 | { | 653 | { |
@@ -730,49 +655,107 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
730 | struct snd_soc_device *socdev = rtd->socdev; | 655 | struct snd_soc_device *socdev = rtd->socdev; |
731 | struct snd_soc_codec *codec = socdev->codec; | 656 | struct snd_soc_codec *codec = socdev->codec; |
732 | struct aic3x_priv *aic3x = codec->private_data; | 657 | struct aic3x_priv *aic3x = codec->private_data; |
733 | int i; | 658 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
734 | u8 data, pll_p, pll_r, pll_j; | 659 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
735 | u16 pll_d; | 660 | u16 pll_d = 1; |
736 | |||
737 | i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); | ||
738 | 661 | ||
739 | /* Route Left DAC to left channel input and | 662 | /* select data word length */ |
740 | * right DAC to right channel input */ | 663 | data = |
741 | data = (LDAC2LCH | RDAC2RCH); | 664 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); |
742 | switch (aic3x_divs[i].fsref_reg) { | 665 | switch (params_format(params)) { |
743 | case 44100: | 666 | case SNDRV_PCM_FORMAT_S16_LE: |
744 | data |= FSREF_44100; | ||
745 | break; | 667 | break; |
746 | case 48000: | 668 | case SNDRV_PCM_FORMAT_S20_3LE: |
747 | data |= FSREF_48000; | 669 | data |= (0x01 << 4); |
748 | break; | 670 | break; |
749 | case 88200: | 671 | case SNDRV_PCM_FORMAT_S24_LE: |
750 | data |= FSREF_44100 | DUAL_RATE_MODE; | 672 | data |= (0x02 << 4); |
751 | break; | 673 | break; |
752 | case 96000: | 674 | case SNDRV_PCM_FORMAT_S32_LE: |
753 | data |= FSREF_48000 | DUAL_RATE_MODE; | 675 | data |= (0x03 << 4); |
754 | break; | 676 | break; |
755 | } | 677 | } |
678 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
679 | |||
680 | /* Fsref can be 44100 or 48000 */ | ||
681 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; | ||
682 | |||
683 | /* Try to find a value for Q which allows us to bypass the PLL and | ||
684 | * generate CODEC_CLK directly. */ | ||
685 | for (pll_q = 2; pll_q < 18; pll_q++) | ||
686 | if (aic3x->sysclk / (128 * pll_q) == fsref) { | ||
687 | bypass_pll = 1; | ||
688 | break; | ||
689 | } | ||
690 | |||
691 | if (bypass_pll) { | ||
692 | pll_q &= 0xf; | ||
693 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); | ||
694 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); | ||
695 | } else | ||
696 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); | ||
697 | |||
698 | /* Route Left DAC to left channel input and | ||
699 | * right DAC to right channel input */ | ||
700 | data = (LDAC2LCH | RDAC2RCH); | ||
701 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; | ||
702 | if (params_rate(params) >= 64000) | ||
703 | data |= DUAL_RATE_MODE; | ||
756 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | 704 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); |
757 | 705 | ||
758 | /* codec sample rate select */ | 706 | /* codec sample rate select */ |
759 | data = aic3x_divs[i].sr_reg; | 707 | data = (fsref * 20) / params_rate(params); |
708 | if (params_rate(params) < 64000) | ||
709 | data /= 2; | ||
710 | data /= 5; | ||
711 | data -= 2; | ||
760 | data |= (data << 4); | 712 | data |= (data << 4); |
761 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | 713 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); |
762 | 714 | ||
763 | /* Use PLL for generation Fsref by equation: | 715 | if (bypass_pll) |
764 | * Fsref = (MCLK * K * R)/(2048 * P); | 716 | return 0; |
765 | * Fix P = 2 and R = 1 and calculate K, if | 717 | |
766 | * K = J.D, i.e. J - an interger portion of K and D is the fractional | 718 | /* Use PLL |
767 | * one with 4 digits of precision; | 719 | * find an apropriate setup for j, d, r and p by iterating over |
768 | * Example: | 720 | * p and r - j and d are calculated for each fraction. |
769 | * For MCLK = 22.5792 MHz and Fsref = 48kHz: | 721 | * Up to 128 values are probed, the closest one wins the game. |
770 | * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 | 722 | * The sysclk is divided by 1000 to prevent integer overflows. |
771 | */ | 723 | */ |
772 | pll_p = 2; | 724 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); |
773 | pll_r = 1; | 725 | |
774 | pll_j = aic3x_divs[i].pllj_reg; | 726 | for (r = 1; r <= 16; r++) |
775 | pll_d = aic3x_divs[i].plld_reg; | 727 | for (p = 1; p <= 8; p++) { |
728 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; | ||
729 | u8 j = tmp / 10000; | ||
730 | u16 d = tmp % 10000; | ||
731 | |||
732 | if (j > 63) | ||
733 | continue; | ||
734 | |||
735 | if (d != 0 && aic3x->sysclk < 10000000) | ||
736 | continue; | ||
737 | |||
738 | /* This is actually 1000 * ((j + (d/10000)) * r) / p | ||
739 | * The term had to be converted to get rid of the | ||
740 | * division by 10000 */ | ||
741 | clk = ((10000 * j * r) + (d * r)) / (10 * p); | ||
742 | |||
743 | /* check whether this values get closer than the best | ||
744 | * ones we had before */ | ||
745 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { | ||
746 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; | ||
747 | last_clk = clk; | ||
748 | } | ||
749 | |||
750 | /* Early exit for exact matches */ | ||
751 | if (clk == codec_clk) | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | if (last_clk == 0) { | ||
756 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); | ||
757 | return -EINVAL; | ||
758 | } | ||
776 | 759 | ||
777 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 760 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
778 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | 761 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); |
@@ -782,24 +765,6 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
782 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | 765 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, |
783 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | 766 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); |
784 | 767 | ||
785 | /* select data word length */ | ||
786 | data = | ||
787 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | ||
788 | switch (params_format(params)) { | ||
789 | case SNDRV_PCM_FORMAT_S16_LE: | ||
790 | break; | ||
791 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
792 | data |= (0x01 << 4); | ||
793 | break; | ||
794 | case SNDRV_PCM_FORMAT_S24_LE: | ||
795 | data |= (0x02 << 4); | ||
796 | break; | ||
797 | case SNDRV_PCM_FORMAT_S32_LE: | ||
798 | data |= (0x03 << 4); | ||
799 | break; | ||
800 | } | ||
801 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
802 | |||
803 | return 0; | 768 | return 0; |
804 | } | 769 | } |
805 | 770 | ||
@@ -826,16 +791,8 @@ static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
826 | struct snd_soc_codec *codec = codec_dai->codec; | 791 | struct snd_soc_codec *codec = codec_dai->codec; |
827 | struct aic3x_priv *aic3x = codec->private_data; | 792 | struct aic3x_priv *aic3x = codec->private_data; |
828 | 793 | ||
829 | switch (freq) { | 794 | aic3x->sysclk = freq; |
830 | case 12000000: | 795 | return 0; |
831 | case 19200000: | ||
832 | case 22579200: | ||
833 | case 33868800: | ||
834 | aic3x->sysclk = freq; | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | return -EINVAL; | ||
839 | } | 796 | } |
840 | 797 | ||
841 | static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 798 | static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d0cdeeb629de..d49d001e6e4c 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -109,6 +109,7 @@ | |||
109 | #define LLOPM_CTRL 86 | 109 | #define LLOPM_CTRL 86 |
110 | #define RLOPM_CTRL 93 | 110 | #define RLOPM_CTRL 93 |
111 | /* Clock generation control register */ | 111 | /* Clock generation control register */ |
112 | #define AIC3X_GPIOB_REG 101 | ||
112 | #define AIC3X_CLKGEN_CTRL_REG 102 | 113 | #define AIC3X_CLKGEN_CTRL_REG 102 |
113 | 114 | ||
114 | /* Page select register bits */ | 115 | /* Page select register bits */ |
@@ -128,12 +129,15 @@ | |||
128 | 129 | ||
129 | /* PLL registers bitfields */ | 130 | /* PLL registers bitfields */ |
130 | #define PLLP_SHIFT 0 | 131 | #define PLLP_SHIFT 0 |
132 | #define PLLQ_SHIFT 3 | ||
131 | #define PLLR_SHIFT 0 | 133 | #define PLLR_SHIFT 0 |
132 | #define PLLJ_SHIFT 2 | 134 | #define PLLJ_SHIFT 2 |
133 | #define PLLD_MSB_SHIFT 0 | 135 | #define PLLD_MSB_SHIFT 0 |
134 | #define PLLD_LSB_SHIFT 2 | 136 | #define PLLD_LSB_SHIFT 2 |
135 | 137 | ||
136 | /* Clock generation register bits */ | 138 | /* Clock generation register bits */ |
139 | #define CODEC_CLKIN_PLLDIV 0 | ||
140 | #define CODEC_CLKIN_CLKDIV 1 | ||
137 | #define PLL_CLKIN_SHIFT 4 | 141 | #define PLL_CLKIN_SHIFT 4 |
138 | #define MCLK_SOURCE 0x0 | 142 | #define MCLK_SOURCE 0x0 |
139 | #define PLL_CLKDIV_SHIFT 0 | 143 | #define PLL_CLKDIV_SHIFT 0 |