diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts index f68ddafbae5d..427b738b7990 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts @@ -319,6 +319,51 @@ sound-dai = <&dummy_codec>; }; }; + +#if 0 + aml-audio-card,dai-link@7 { + format = "i2s"; + mclk-fs = <256>; + //continuous-clock; + //bitclock-inversion; + //frame-inversion; + bitclock-master = <&tdmlb>; + frame-master = <&tdmlb>; + cpu { + sound-dai = <&tdmlb>; + dai-tdm-slot-rx-mask = <1 1>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; +#endif + aml-audio-card,dai-link@8 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; + aml-audio-card,dai-link@9 { + mclk-fs = <256>; + suffix-name = "alsaPORT-loopbackb"; + cpu { + sound-dai = <&loopbackb>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -975,6 +1020,8 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; /* !!!For --TV platform-- ONLY */ @@ -996,6 +1043,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1014,6 +1063,57 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + + status = "okay"; + }; + + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + status = "okay"; }; @@ -1209,10 +1309,120 @@ * 0: in user space * 1: in kernel space */ - level = <0>; + level = <1>; status = "disabled"; }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts index bff7e8ad6452..3b8c7f65e4da 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts @@ -423,6 +423,29 @@ }; }; + aml-audio-card,dai-link@7 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; + aml-audio-card,dai-link@8 { + mclk-fs = <256>; + suffix-name = "alsaPORT-loopbackb"; + cpu { + sound-dai = <&loopbackb>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -1273,6 +1296,7 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ status = "okay"; @@ -1295,6 +1319,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1313,9 +1339,60 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + + status = "disabled"; + }; + spdifa:spdif@0 { compatible = "amlogic, tl1-snd-spdif-a"; #sound-dai-cells = <0>; @@ -1475,6 +1552,151 @@ status = "disabled"; }; + vad:vad { + compatible = "amlogic, snd-vad"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_TOVAD + &clkc CLKID_FCLK_DIV5 + &clkaudio CLKID_AUDIO_VAD>; + clock-names = "gate", "pll", "clk"; + + interrupts = ; + interrupt-names = "irq_wakeup", "irq_frame_sync"; + + /* + * Data src sel: + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + * 5: loopback_b; + * 6: tdmin_lb; + * 7: loopback_a; + */ + src = <4>; + + /* + * deal with hot word in user space or kernel space + * 0: in user space + * 1: in kernel space + */ + level = <1>; + + status = "disabled"; + }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts index 2c549e5a022e..335693f4414a 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts @@ -323,6 +323,18 @@ }; }; + aml-audio-card,dai-link@7 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -977,6 +989,7 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ status = "okay"; @@ -999,6 +1012,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1017,9 +1032,60 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + + status = "disabled"; + }; + spdifa:spdif@0 { compatible = "amlogic, tl1-snd-spdif-a"; #sound-dai-cells = <0>; @@ -1213,6 +1279,116 @@ status = "disabled"; }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index 19c56f5caf82..b216cad48907 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -443,6 +443,18 @@ }; }; + aml-audio-card,dai-link@7 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -1542,6 +1554,7 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ status = "okay"; @@ -1564,6 +1577,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1582,9 +1597,60 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + + status = "disabled"; + }; + spdifa:spdif@0 { compatible = "amlogic, tl1-snd-spdif-a"; #sound-dai-cells = <0>; @@ -1777,6 +1843,116 @@ status = "disabled"; }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts index 8d38c242e824..af480feec2f1 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts @@ -433,6 +433,29 @@ }; }; + aml-audio-card,dai-link@7 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; + aml-audio-card,dai-link@8 { + mclk-fs = <256>; + suffix-name = "alsaPORT-loopbackb"; + cpu { + sound-dai = <&loopbackb>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -1464,6 +1487,7 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ status = "okay"; @@ -1486,6 +1510,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1504,9 +1530,60 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + + status = "disabled"; + }; + spdifa:spdif@0 { compatible = "amlogic, tl1-snd-spdif-a"; #sound-dai-cells = <0>; @@ -1665,6 +1742,151 @@ status = "disabled"; }; + vad:vad { + compatible = "amlogic, snd-vad"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_TOVAD + &clkc CLKID_FCLK_DIV5 + &clkaudio CLKID_AUDIO_VAD>; + clock-names = "gate", "pll", "clk"; + + interrupts = ; + interrupt-names = "irq_wakeup", "irq_frame_sync"; + + /* + * Data src sel: + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + * 5: loopback_b; + * 6: tdmin_lb; + * 7: loopback_a; + */ + src = <4>; + + /* + * deal with hot word in user space or kernel space + * 0: in user space + * 1: in kernel space + */ + level = <1>; + + status = "disabled"; + }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index 3aeec02c1fd4..8c330b0f7b0b 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -440,6 +440,18 @@ }; }; + aml-audio-card,dai-link@7 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -1350,6 +1362,7 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ status = "okay"; @@ -1372,6 +1385,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1390,9 +1405,60 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + + status = "disabled"; + }; + spdifa:spdif@0 { compatible = "amlogic, tl1-snd-spdif-a"; #sound-dai-cells = <0>; @@ -1550,6 +1616,151 @@ status = "disabled"; }; + vad:vad { + compatible = "amlogic, snd-vad"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_TOVAD + &clkc CLKID_FCLK_DIV5 + &clkaudio CLKID_AUDIO_VAD>; + clock-names = "gate", "pll", "clk"; + + interrupts = ; + interrupt-names = "irq_wakeup", "irq_frame_sync"; + + /* + * Data src sel: + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + * 5: loopback_b; + * 6: tdmin_lb; + * 7: loopback_a; + */ + src = <4>; + + /* + * deal with hot word in user space or kernel space + * 0: in user space + * 1: in kernel space + */ + level = <1>; + + status = "disabled"; + }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts index 5fa557706c13..cbf731244c6c 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts @@ -434,6 +434,18 @@ }; }; + aml-audio-card,dai-link@7 { + mclk-fs = <256>; + continuous-clock; + suffix-name = "alsaPORT-loopback"; + cpu { + sound-dai = <&loopbacka>; + system-clock-frequency = <12288000>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; /* Audio Related end */ @@ -1344,6 +1356,7 @@ /* In for ACODEC_ADC */ acodec_adc = <1>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ status = "okay"; @@ -1366,6 +1379,8 @@ &clkc CLKID_MPLL1>; clock-names = "mclk", "clk_srcpll"; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; @@ -1384,9 +1399,60 @@ pinctrl-names = "tdm_pins"; pinctrl-0 = <&tdmout_c &tdmin_c>; + mclk_pad = <0>; /* 0: mclk_0; 1: mclk_1 */ + status = "okay"; }; + tdmlb:tdm@3 { + compatible = "amlogic, tl1-snd-tdmlb"; + #sound-dai-cells = <0>; + + dai-tdm-lane-lb-slot-mask-in = <1 0 0 0>; + dai-tdm-clk-sel = <1>; + + clocks = <&clkaudio CLKID_AUDIO_MCLK_B + &clkc CLKID_MPLL1>; + clock-names = "mclk", "clk_srcpll"; + + /* + * select tdmin_lb src; + * AXG + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA + * 4: PAD_TDMINB + * 5: PAD_TDMINC + * + * G12A/G12B + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D*, oe pin + * 7: PAD_TDMINB_D*, oe pin + * + * TL1 + * 0: TDMOUTA + * 1: TDMOUTB + * 2: TDMOUTC + * 3: PAD_TDMINA_DIN* + * 4: PAD_TDMINB_DIN* + * 5: PAD_TDMINC_DIN* + * 6: PAD_TDMINA_D* + * 7: PAD_TDMINB_D* + * 8: PAD_TDMINC_D* + * 9: HDMIRX_I2S + * 10: ACODEC_ADC + */ + lb-src-sel = <1>; + + status = "disabled"; + }; + spdifa:spdif@0 { compatible = "amlogic, tl1-snd-spdif-a"; #sound-dai-cells = <0>; @@ -1545,6 +1611,151 @@ status = "disabled"; }; + vad:vad { + compatible = "amlogic, snd-vad"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_TOVAD + &clkc CLKID_FCLK_DIV5 + &clkaudio CLKID_AUDIO_VAD>; + clock-names = "gate", "pll", "clk"; + + interrupts = ; + interrupt-names = "irq_wakeup", "irq_frame_sync"; + + /* + * Data src sel: + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + * 5: loopback_b; + * 6: tdmin_lb; + * 7: loopback_a; + */ + src = <4>; + + /* + * deal with hot word in user space or kernel space + * 0: in user space + * 1: in kernel space + */ + level = <1>; + + status = "disabled"; + }; + + loopbacka:loopback@0 { + compatible = "amlogic, tl1-loopbacka"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* calc mclk for datalb */ + mclk-fs = <256>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <0>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "okay"; + }; + + loopbackb:loopback@1 { + compatible = "amlogic, tl1-loopbackb"; + #sound-dai-cells = <0>; + + clocks = <&clkaudio CLKID_AUDIO_GATE_PDM + &clkc CLKID_FCLK_DIV3 + &clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_PDMIN0 + &clkaudio CLKID_AUDIO_PDMIN1 + &clkc CLKID_MPLL0 + &clkaudio CLKID_AUDIO_MCLK_A>; + clock-names = "pdm_gate", + "pdm_sysclk_srcpll", + "pdm_dclk_srcpll", + "pdm_dclk", + "pdm_sysclk", + "tdminlb_mpll", + "tdminlb_mclk"; + + /* calc mclk for datain_lb */ + mclk-fs = <256>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <4>; + datain_chmask = <0xf>; + /* config which data pin for loopback */ + datain-lane-mask-in = <1 0 1 0>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_TDMINA_DIN*, refer to core pinmux + * 4: PAD_TDMINB_DIN*, refer to core pinmux + * 5: PAD_TDMINC_DIN*, refer to core pinmux + * 6: PAD_TDMINA_D*, oe, refer to core pinmux + * 7: PAD_TDMINB_D*, oe, refer to core pinmux + */ + /* if tdmin_lb >= 3, use external loopback */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + /* config which data pin as loopback */ + datalb-lane-mask-in = <1 0 0 0>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/sound/soc/amlogic/auge/Makefile b/sound/soc/amlogic/auge/Makefile index b8d6cc8eb8e8..fb7a97342ce9 100644 --- a/sound/soc/amlogic/auge/Makefile +++ b/sound/soc/amlogic/auge/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \ pdm_hw_coeff.o \ iomap.o \ ddr_mngr.o \ + loopback.o \ loopback_hw.o \ audio_utils.o \ locker.o \ diff --git a/sound/soc/amlogic/auge/audio_utils.c b/sound/soc/amlogic/auge/audio_utils.c index 505f9944bf75..f5205a11de21 100644 --- a/sound/soc/amlogic/auge/audio_utils.c +++ b/sound/soc/amlogic/auge/audio_utils.c @@ -14,24 +14,18 @@ * more details. * */ - #include "audio_utils.h" #include "regs.h" #include "iomap.h" -#include "loopback_hw.h" #include "spdif_hw.h" -#include "pdm_hw.h" -#include "tdm_hw.h" -#include "ddr_mngr.h" #include "resample.h" #include "effects_v2.h" #include "vad.h" +#include "ddr_mngr.h" #include #include -#include - struct snd_elem_info { struct soc_enum *ee; int reg; @@ -39,132 +33,8 @@ struct snd_elem_info { u32 mask; }; -static unsigned int loopback_enable; -static unsigned int loopback_is_running; -static unsigned int datain_datalb_total; static unsigned int audio_inskew; -static const char *const loopback_enable_texts[] = { - "Disable", - "Enable", -}; - -static const struct soc_enum loopback_enable_enum = - SOC_ENUM_SINGLE(EE_AUDIO_LB_CTRL0, - 31, - ARRAY_SIZE(loopback_enable_texts), - loopback_enable_texts); - - -static int loopback_enable_get_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = loopback_enable; - - return 0; -} - -static int loopback_enable_set_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - loopback_enable = ucontrol->value.enumerated.item[0]; - - return 0; -} - -static int datain_datalb_total_get_param( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.bytes.data[0] = datain_datalb_total; - - return 0; -} - -static int datain_datalb_total_set_param( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - datain_datalb_total = ucontrol->value.bytes.data[0]; - - return 0; -} - -static unsigned int loopback_datain; - -static const char *const loopback_datain_texts[] = { - "TDMIN_A", - "TDMIN_B", - "TDMIN_C", - "SPDIFIN", - "PDMIN", -}; - -static const struct soc_enum loopback_datain_enum = - SOC_ENUM_SINGLE(EE_AUDIO_LB_CTRL0, 0, ARRAY_SIZE(loopback_datain_texts), - loopback_datain_texts); - - -static int loopback_datain_get_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = loopback_datain; - - return 0; -} - -static int loopback_datain_set_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - loopback_datain = ucontrol->value.enumerated.item[0]; - audiobus_update_bits(EE_AUDIO_LB_CTRL0, 0, loopback_datain); - - return 0; -} - -static unsigned int loopback_tdminlb; - -static const char *const loopback_tdminlb_texts[] = { - "TDMOUT_A", - "TDMOUT_B", - "TDMOUT_C", - "TDMIN_A", - "TDMIN_B", - "TDMIN_C", -}; - -static const struct soc_enum loopback_tdminlb_enum = - SOC_ENUM_SINGLE(EE_AUDIO_TDMIN_LB_CTRL, - 20, - ARRAY_SIZE(loopback_tdminlb_texts), - loopback_tdminlb_texts); - - -static int loopback_tdminlb_get_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = loopback_tdminlb; - - return 0; -} - -static int loopback_tdminlb_set_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - loopback_tdminlb = ucontrol->value.enumerated.item[0]; - audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, - 0xf << 20, - loopback_datain); - - return 0; -} - #if 0 static int snd_int_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -726,27 +596,6 @@ static int tdmout_c_binv_set_enum( SND_BYTE(xname, type, func, xshift, xmask) static const struct snd_kcontrol_new snd_auge_controls[] = { - /* loopback enable */ - SOC_ENUM_EXT("Loopback Enable", - loopback_enable_enum, - loopback_enable_get_enum, - loopback_enable_set_enum), - - SND_SOC_BYTES_EXT("datain_datalb_total", 1, - datain_datalb_total_get_param, - datain_datalb_total_set_param), - - /* loopback data in source */ - SOC_ENUM_EXT("Loopback datain source", - loopback_datain_enum, - loopback_datain_get_enum, - loopback_datain_set_enum), - - /* loopback data tdmin lb */ - SOC_ENUM_EXT("Loopback tmdin lb source", - loopback_tdminlb_enum, - loopback_tdminlb_get_enum, - loopback_tdminlb_set_enum), #if 0 /*TDMIN_A swap*/ SND_SWAP("TDMIN_A Ch0 Swap", TDMIN_A, in_swap_channel_enum, 0, 0x7), @@ -1058,519 +907,6 @@ int snd_card_add_kcontrols(struct snd_soc_card *card) } -int loopback_parse_of(struct device_node *node, - struct loopback_cfg *lb_cfg) -{ - struct platform_device *pdev; - const __be32 *of_slot_mask; - unsigned int lane_mask = 0; - int i, ret, set_num = 0; - u32 val; - - pdev = of_find_device_by_node(node); - if (!pdev) { - dev_err(&pdev->dev, "failed to find platform device\n"); - ret = -EINVAL; - goto fail; - } - - /*mpll used for tdmin*/ - lb_cfg->tdmin_mpll = devm_clk_get(&pdev->dev, "datalb_mpll"); - if (IS_ERR(lb_cfg->tdmin_mpll)) { - dev_err(&pdev->dev, - "Can't retrieve tdmin_mpll clock\n"); - lb_cfg->tdmin_mpll = NULL; - } - - ret = of_property_read_u32(node, "lb_mode", - &lb_cfg->lb_mode); - if (ret) { - pr_err("failed to get lb_mode, set it default\n"); - lb_cfg->lb_mode = 0; - ret = 0; - } - - ret = of_property_read_u32(node, "datain_src", - &lb_cfg->datain_src); - if (ret) { - pr_err("failed to get datain_src\n"); - ret = -EINVAL; - goto fail; - } - ret = of_property_read_u32(node, "datain_chnum", - &lb_cfg->datain_chnum); - if (ret) { - pr_err("failed to get datain_chnum\n"); - ret = -EINVAL; - goto fail; - } - ret = of_property_read_u32(node, "datain_chmask", - &lb_cfg->datain_chmask); - if (ret) { - pr_err("failed to get datain_chmask\n"); - ret = -EINVAL; - goto fail; - } - - ret = of_property_read_u32(node, "datalb_src", - &lb_cfg->datalb_src); - if (ret) { - pr_err("failed to get datalb_src\n"); - ret = -EINVAL; - goto fail; - } - ret = of_property_read_u32(node, "datalb_chnum", - &lb_cfg->datalb_chnum); - if (ret) { - pr_err("failed to get datalb_chnum\n"); - ret = -EINVAL; - goto fail; - } - ret = of_property_read_u32(node, "datalb_chmask", - &lb_cfg->datalb_chmask); - if (ret) { - pr_err("failed to get datalb_chmask\n"); - ret = -EINVAL; - goto fail; - } - - of_slot_mask = of_get_property(node, "datalb-lane-mask-in", &val); - if (!of_slot_mask) { - pr_err("if use extern loopback, pls set datalb-lane-mask-in\n"); - } else { - val /= sizeof(u32); - for (i = 0; i < val; i++) - if (be32_to_cpup(&of_slot_mask[i])) - lane_mask |= (1 << i); - for (i = 0; i < 4; i++) { - if ((1 << i) & lane_mask) { - /*each lane only L/R masked*/ - lb_cfg->datalb_chswap |= - (i * 2) << (set_num++ * 4); - lb_cfg->datalb_chswap |= - (i * 2 + 1) << (set_num++ * 4); - } - } - } - ret = of_property_read_u32(node, "datalb_clk", - &lb_cfg->datalb_clk); - if (ret) { - pr_err("if no datalb_clk on dts, it equal is datalb_src\n"); - lb_cfg->datalb_clk = lb_cfg->datalb_src; - } - - ret = of_property_read_u32(node, "datain_datalb_total", - &lb_cfg->datain_datalb_total); - if (ret) { - pr_err("no register datain_datalb_total,it also can work\n"); - lb_cfg->datain_datalb_total = 0; - } else { - if (lb_cfg->datain_datalb_total > 8) { - lb_cfg->datain_chnum = 8; - lb_cfg->datain_chmask = 0xff; - lb_cfg->datalb_chnum = 8; - lb_cfg->datalb_chmask = 0xff; - lb_cfg->datalb_chswap = 0x76543210; - } - } - datain_datalb_total = lb_cfg->datain_datalb_total; - - loopback_datain = lb_cfg->datain_src; - loopback_tdminlb = lb_cfg->datalb_src; - - pr_info("parse loopback:, \tlb mode:%d\n", - lb_cfg->lb_mode); - pr_info("\tdatain_src:%d, datain_chnum:%d, datain_chumask:%x\n", - lb_cfg->datain_src, - lb_cfg->datain_chnum, - lb_cfg->datain_chmask); - pr_info("\tdatalb_src:%d, datalb_chnum:%d\n", - lb_cfg->datalb_src, - lb_cfg->datalb_chnum); - pr_info("\tdatalb_chswap:0x%x,datalb_chmask:%x\n", - lb_cfg->datalb_chswap, - lb_cfg->datalb_chmask); - -fail: - return ret; -} - -int loopback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct loopback_cfg *lb_cfg, - unsigned int mclk) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int bclk_sel, fsclk_sel; - int bit_depth; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return 0; - bit_depth = snd_pcm_format_width(runtime->format); - - if (lb_cfg->datalb_src >= 3) { - /*tdm in*/ - /*for i2s mode*/ - unsigned int sclk_div = 4 - 1; - unsigned int ratio = params_channels(params) * bit_depth - 1; - unsigned int fsclk_hi; - unsigned int clk_id = lb_cfg->datalb_src - 3; - unsigned int mul = 2; - unsigned int mpll_freq, offset, reg; - - /*lrclk sclk depend on default 8ch setting,*/ - /* so if num of channels is 4, to change ratio*/ - if (params_channels(params) == 4) - ratio = ratio*2; - - fsclk_hi = ratio/2; - - pr_info("%s, channels:%d, format:%d, ratio:%d\n", - __func__, - params_channels(params), - bit_depth, - ratio); - - bclk_sel = clk_id; - fsclk_sel = clk_id; - - /*mclk*/ - mpll_freq = mclk * mul; - clk_set_rate(lb_cfg->tdmin_mpll, mpll_freq); - pr_info("mpll freq:%d, %lu\n", mpll_freq, - clk_get_rate(lb_cfg->tdmin_mpll)); - offset = EE_AUDIO_MCLK_B_CTRL(0) - EE_AUDIO_MCLK_A_CTRL(0); - reg = EE_AUDIO_MCLK_A_CTRL(0) + offset * clk_id; - audiobus_write(reg, - 1 << 31 | /*clk enable*/ - clk_id << 24 | /*clk src*/ - (mul - 1)); /*clk_div mclk*/ - - /*sclk, lrclk*/ - offset = EE_AUDIO_MST_B_SCLK_CTRL0 - EE_AUDIO_MST_A_SCLK_CTRL0; - reg = EE_AUDIO_MST_A_SCLK_CTRL0 + offset * clk_id; - audiobus_update_bits(reg, - 0x3 << 30 | 0x3ff << 20 | 0x3ff<<10 | 0x3ff, - 0x3 << 30 | sclk_div << 20 | fsclk_hi << 10 - | ratio); - - audiobus_update_bits( - EE_AUDIO_CLK_TDMIN_LB_CTRL, - 0x3 << 30 | 1 << 29 | 0xf << 24 | 0xf << 20, - 0x3 << 30 | 1 << 29 | bclk_sel << 24 | fsclk_sel << 20); - } - return 0; -} - -int loopback_prepare( - struct snd_pcm_substream *substream, - struct loopback_cfg *lb_cfg) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int bitwidth; - unsigned int datain_toddr_type, datalb_toddr_type; - unsigned int datain_msb, datain_lsb, datalb_msb, datalb_lsb; - struct lb_cfg datain_cfg; - struct lb_cfg datalb_cfg; - struct audio_data ddrdata; - struct data_in datain; - struct data_lb datalb; - - if (!lb_cfg) - return -EINVAL; - - pr_info("%s\n", __func__); - - bitwidth = snd_pcm_format_width(runtime->format); - switch (lb_cfg->datain_src) { - case DATAIN_TDMA: - case DATAIN_TDMB: - case DATAIN_TDMC: - case DATAIN_PDM: - datain_toddr_type = 0; - datain_msb = 32 - 1; - datain_lsb = 0; - break; - case DATAIN_SPDIF: - datain_toddr_type = 3; - datain_msb = 27; - datain_lsb = 4; - if (bitwidth <= 24) - datain_lsb = 28 - bitwidth; - else - datain_lsb = 4; - break; - default: - pr_err("unsupport data in source:%d\n", - lb_cfg->datain_src); - return -EINVAL; - } - - switch (lb_cfg->datalb_src) { - case TDMINLB_TDMOUTA: - case TDMINLB_TDMOUTB: - case TDMINLB_TDMOUTC: - case TDMINLB_PAD_TDMINA: - case TDMINLB_PAD_TDMINB: - case TDMINLB_PAD_TDMINC: - if (bitwidth == 24) { - datalb_toddr_type = 4; - datalb_msb = 32 - 1; - datalb_lsb = 32 - bitwidth; - } else { - datalb_toddr_type = 0; - datalb_msb = 32 - 1; - datalb_lsb = 0; - } - break; - default: - pr_err("unsupport data lb source:%d\n", - lb_cfg->datalb_src); - return -EINVAL; - } - - datain_cfg.ext_signed = 0; - datain_cfg.chnum = lb_cfg->datain_chnum; - datain_cfg.chmask = lb_cfg->datain_chmask; - ddrdata.combined_type = datain_toddr_type; - ddrdata.msb = datain_msb; - ddrdata.lsb = datain_lsb; - ddrdata.src = lb_cfg->datain_src; - datain.config = &datain_cfg; - datain.ddrdata = &ddrdata; - - datalb_cfg.ext_signed = 0; - datalb_cfg.chnum = lb_cfg->datalb_chnum; - datalb_cfg.chmask = lb_cfg->datalb_chmask; - datalb.config = &datalb_cfg; - datalb.ddr_type = datalb_toddr_type; - datalb.msb = datalb_msb; - datalb.lsb = datalb_lsb; - - datain_config(&datain); - datalb_config(&datalb); - - lb_cfg->datain_datalb_total = datain_datalb_total; - - if (lb_cfg->datain_datalb_total > 8) { - lb_cfg->datain_chnum = 8; - lb_cfg->datain_chmask = 0xff; - lb_cfg->datalb_chnum = 8; - lb_cfg->datalb_chmask = 0xff; - lb_cfg->datalb_chswap = 0x76543210; - } - datalb_ctrl(lb_cfg); - lb_mode(lb_cfg->lb_mode); - - return 0; -} - -void toddr_enable(int is_enable, int toddr_index) -{ - int offset = EE_AUDIO_TODDR_B_CTRL0 - EE_AUDIO_TODDR_A_CTRL0; - int reg = EE_AUDIO_TODDR_A_CTRL0 + offset * toddr_index; - - audiobus_update_bits( - reg, - 0x1 << 31, - is_enable << 31); -} - -void frddr_enable(int is_enable, int frddr_index) -{ - int offset = EE_AUDIO_FRDDR_B_CTRL0 - EE_AUDIO_FRDDR_A_CTRL0; - int reg = EE_AUDIO_FRDDR_A_CTRL0 + offset * frddr_index; - - audiobus_update_bits( - reg, - 0x1 << 31, - is_enable << 31); -} - -static void loopback_modules_disable( - struct loopback_cfg *lb_cfg, - int tdm_index, - int frddr_index, int toddr_index) -{ - /* tdminLB */ - tdmin_lb_fifo_enable(0); - tdmin_lb_enable(tdm_index, 0); - - /* datain src */ - switch (lb_cfg->datain_src) { - case 0: - case 1: - case 2: - /*tdm in*/ - break; - case 3: - /*spdif in*/ - break; - case 4: - /*pdm in*/ - pdm_enable(0); - break; - default: - pr_err("unsupport datain source!!\n"); - return; - } - /* loopback */ - lb_enable(0); - - /* toddr */ - if (toddr_index >= 0) - toddr_enable(0, toddr_index); - - /* frddr */ - if (frddr_index >= 3) - toddr_enable(0, frddr_index - 3); - else if (frddr_index >= 0) - frddr_enable(0, frddr_index); - - /* tdmout */ - if (frddr_index >= 0) { - tdm_fifo_enable(tdm_index, 0); - tdm_enable(tdm_index, 0); - } -} - -static void loopback_modules_enable( - struct loopback_cfg *lb_cfg, - int tdm_index, - int frddr_index, int toddr_index) -{ - /* - * Loopback enable in sequence: - * tdmout->frddr->toddr->loopback->pdmin->tdminLB - */ - - /* tdmout */ - if (frddr_index >= 0) { - tdm_fifo_enable(tdm_index, 1); - tdm_enable(tdm_index, 1); - } - - /* frddr */ - if (frddr_index >= 3) - toddr_enable(1, frddr_index - 3); - else if (frddr_index >= 0) - frddr_enable(1, frddr_index); - - tdm_fifo_enable(tdm_index, 1); - tdm_enable(tdm_index, 1); - frddr_enable(1, frddr_index); - /* toddr */ - if (toddr_index >= 0) - toddr_enable(1, toddr_index); - - /* loopback */ - lb_enable(1); - - /* datain src */ - switch (lb_cfg->datain_src) { - case 0: - case 1: - case 2: - /*tdm in*/ - break; - case 3: - /*spdif in*/ - break; - case 4: - /*pdm in*/ - pdm_enable(1); - break; - default: - pr_err("unsupport datain source!!\n"); - return; - } - /*tdminLB*/ - tdmin_lb_fifo_enable(1); - tdmin_lb_enable(tdm_index, 1); -} - -int loopback_trigger( - struct snd_pcm_substream *substream, - int cmd, - struct loopback_cfg *lb_cfg) -{ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (loopback_enable && loopback_is_running) { - pr_info("loopback enable\n"); - - /* - * toddr/frdd is selected in dai_prepare already. - * check toddr index of datain - * check frddr index of datalb - */ - lb_cfg->toddr_index = fetch_toddr_index_by_src( - lb_cfg->datain_src); - /* check datalb is from tdmout or tdmin */ - if (lb_cfg->datalb_src >= 3) - lb_cfg->frddr_index = fetch_toddr_index_by_src( - lb_cfg->datalb_src - 3); - else - lb_cfg->frddr_index = fetch_frddr_index_by_src( - lb_cfg->datalb_src); - - pr_info("loopback toddr index:%d, frddr index:%d\n", - lb_cfg->toddr_index, - lb_cfg->frddr_index); - - pr_info("loopback modules in sequence!\n"); - /*if pdm overrun, re-set up the sequence*/ - if (lb_cfg->frddr_index >= 0) - loopback_modules_disable( - lb_cfg, - lb_cfg->datalb_src, - lb_cfg->frddr_index, - lb_cfg->toddr_index); - - loopback_modules_enable( - lb_cfg, - lb_cfg->datalb_src, - lb_cfg->frddr_index, - lb_cfg->toddr_index); - } - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (loopback_enable) { - pr_info("loopback disable\n"); - lb_enable(0); - tdmin_lb_enable(lb_cfg->datalb_src, 0); - } - } - break; - default: - return -EINVAL; - } - - return 0; -} - -void loopback_set_status(int is_running) -{ - loopback_is_running = is_running; -} - -int loopback_is_enable(void) -{ - return (loopback_enable == 1); -} - -int loopback_check_enable(int src) -{ - return (src <= PDMIN) - && (loopback_datain == src) - && (loopback_enable == 1); -} - void auge_acodec_reset(void) { audioreset_update_bits(EE_RESET1, 1 << 29, 1 << 29); diff --git a/sound/soc/amlogic/auge/audio_utils.h b/sound/soc/amlogic/auge/audio_utils.h index d0444473a788..26981818541c 100644 --- a/sound/soc/amlogic/auge/audio_utils.h +++ b/sound/soc/amlogic/auge/audio_utils.h @@ -18,144 +18,10 @@ #ifndef __AML_AUDIO_UTILS_H__ #define __AML_AUDIO_UTILS_H__ -#include -#include #include -#include - -/* datain src - * [4]: pdmin; - * [3]: spdifin; - * [2]: tdmin_c; - * [1]: tdmin_b; - * [0]: tdmin_a; - */ -enum datain_src { - DATAIN_TDMA = 0, - DATAIN_TDMB, - DATAIN_TDMC, - DATAIN_SPDIF, - DATAIN_PDM, -}; - -/* datalb src/tdmlb src - * [0]: tdmoutA - * [1]: tdmoutB - * [2]: tdmoutC - * [3]: PAD_tdminA - * [4]: PAD_tdminB - * [5]: PAD_tdminC - */ -enum tdmin_lb_src { - TDMINLB_TDMOUTA = 0, - TDMINLB_TDMOUTB, - TDMINLB_TDMOUTC, - TDMINLB_PAD_TDMINA, - TDMINLB_PAD_TDMINB, - TDMINLB_PAD_TDMINC, -}; - -/* toddr_src_sel - * [7]: loopback; - * [6]: tdmin_lb; - * [5]: reserved; - * [4]: pdmin; - * [3]: spdifin; - * [2]: tdmin_c; - * [1]: tdmin_b; - * [0]: tdmin_a; - */ -enum fifoin_src { - FIFOIN_TDMINA = 0, - FIFOIN_TDMINB = 1, - FIFOIN_TDMINC = 2, - FIFOIN_SPDIF = 3, - FIFOIN_PDM = 4, - FIFOIN_TDMINLB = 6, - FIFOIN_LOOPBACK = 7 -}; - -/* audio data selected to ddr */ -struct audio_data { - unsigned int resample; - /* reg_dat_sel - * 0: combined data[m:n] without gap; - * like S0[m:n],S1[m:n],S2[m:n], - * 1: combined data[m:n] as 16bits; - * like {S0[11:0],4'd0},{S1[11:0],4'd0} - * 2: combined data[m:n] as 16bits; - * like {4'd0,S0[11:0]},{4'd0,{S1[11:0]} - * 3: combined data[m:n] as 32bits; - * like {S0[27:4],8'd0},{S1[27:4],8'd0} - * 4: combined data[m:n] as 32bits; - * like {8'd0,S0[27:4]},{8'd0,{S1[27:4]} - */ - unsigned int combined_type; - /* the msb positioin in data */ - unsigned int msb; - /* the lsb position in data */ - unsigned int lsb; - /* toddr_src_sel - * [7]: loopback; - * [6]: tdmin_lb; - * [5]: reserved; - * [4]: pdmin; - * [3]: spdifin; - * [2]: tdmin_c; - * [1]: tdmin_b; - * [0]: tdmin_a; - */ - unsigned int src; -}; - -/**/ -struct loopback_cfg { - struct clk *tdmin_mpll; - /* lb_mode - * 0: out rate = in data rate; - * 1: out rate = loopback data rate; - */ - unsigned int lb_mode; - - enum datain_src datain_src; - unsigned int datain_chnum; - unsigned int datain_chmask; - int toddr_index; - - enum tdmin_lb_src datalb_src; - enum tdmin_lb_src datalb_clk; - unsigned int datalb_chnum; - unsigned int datalb_chswap; - unsigned int datalb_chmask; - int frddr_index; - unsigned int datain_datalb_total; -}; - -extern void loopback_set_status(int is_running); - -extern int loopback_is_enable(void); - -extern int loopback_check_enable(int src); extern int snd_card_add_kcontrols(struct snd_soc_card *card); -extern int loopback_parse_of(struct device_node *node, - struct loopback_cfg *lb_cfg); - -extern int loopback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct loopback_cfg *lb_cfg, - unsigned int mclk); - -extern int loopback_prepare( - struct snd_pcm_substream *substream, - struct loopback_cfg *lb_cfg); - -extern int loopback_trigger( - struct snd_pcm_substream *substream, - int cmd, - struct loopback_cfg *lb_cfg); - extern void audio_locker_set(int enable); extern int audio_locker_get(void); diff --git a/sound/soc/amlogic/auge/card.c b/sound/soc/amlogic/auge/card.c index feb1dbf67e78..8ba494927289 100644 --- a/sound/soc/amlogic/auge/card.c +++ b/sound/soc/amlogic/auge/card.c @@ -69,7 +69,6 @@ struct aml_card_data { int spk_mute_gpio; bool spk_mute_active_low; struct gpio_desc *avout_mute_desc; - struct loopback_cfg lb_cfg; struct timer_list timer; struct work_struct work; struct work_struct init_work; @@ -466,8 +465,6 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream, goto err; } - if (loopback_is_enable() && mclk) - loopback_hw_params(substream, params, &priv->lb_cfg, mclk); return 0; err: return ret; @@ -475,23 +472,11 @@ err: int aml_card_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - - if (loopback_is_enable()) - loopback_prepare(substream, &priv->lb_cfg); - return 0; } int aml_card_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - - if (loopback_is_enable()) - loopback_trigger(substream, cmd, &priv->lb_cfg); - return 0; } @@ -802,7 +787,6 @@ static int aml_card_parse_of(struct device_node *node, { struct device *dev = aml_priv_to_dev(priv); struct device_node *dai_link; - struct device_node *lb_link; int ret; if (!node) @@ -829,14 +813,6 @@ static int aml_card_parse_of(struct device_node *node, /* Factor to mclk, used in hw_params() */ of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); - /* Loopback */ - lb_link = of_parse_phandle(node, PREFIX "loopback", 0); - if (lb_link) { - ret = loopback_parse_of(lb_link, &priv->lb_cfg); - if (ret < 0) - pr_err("failed parse loopback, ignore it\n"); - } - /* Single/Muti DAI link(s) & New style of DT node */ if (dai_link) { struct device_node *np = NULL; @@ -867,12 +843,10 @@ static int aml_card_parse_of(struct device_node *node, card_parse_end: of_node_put(dai_link); - of_node_put(lb_link); return ret; } - static struct aml_chipset_info g12a_chipset_info = { .spdif_b = true, .eqdrc_fn = true, @@ -922,6 +896,13 @@ static int aml_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + /* chipset related */ + priv->chipinfo = (struct aml_chipset_info *) + of_device_get_match_data(&pdev->dev); + + if (!priv->chipinfo) + pr_warn_once("check whether to update sound card init data\n"); + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); if (!dai_props || !dai_link) @@ -979,13 +960,6 @@ static int aml_card_probe(struct platform_device *pdev) sizeof(priv->dai_props->codec_dai)); } - - priv->chipinfo = (struct aml_chipset_info *) - of_device_get_match_data(&pdev->dev); - - if (!priv->chipinfo) - pr_warn_once("check whether to update sound card init data\n"); - snd_soc_card_set_drvdata(&priv->snd_card, priv); ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); diff --git a/sound/soc/amlogic/auge/ddr_mngr.c b/sound/soc/amlogic/auge/ddr_mngr.c index 8cd7392e88d4..5d20f725943c 100644 --- a/sound/soc/amlogic/auge/ddr_mngr.c +++ b/sound/soc/amlogic/auge/ddr_mngr.c @@ -29,7 +29,6 @@ #include "regs.h" #include "ddr_mngr.h" -#include "audio_utils.h" #include "resample.h" #include "resample_hw.h" @@ -134,12 +133,6 @@ static int unregister_toddr_l(struct device *dev, void *data) to = &toddrs[i]; - /* check for loopback */ - if (to->is_lb) { - loopback_set_status(0); - to->is_lb = 0; - } - /* disable audio ddr arb */ mask_bit = i; actrl = to->actrl; @@ -366,13 +359,6 @@ void aml_toddr_select_src(struct toddr *to, enum toddr_src src) /* store to check toddr num */ to->src = src; - /* check whether loopback enable */ - if (loopback_check_enable(src)) { - loopback_set_status(1); - to->is_lb = 1; /* in loopback */ - src = LOOPBACK_A; - } - if (to->chipinfo && to->chipinfo->src_sel_ctrl) { reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL1, reg_base); @@ -456,6 +442,29 @@ void aml_toddr_set_format(struct toddr *to, struct toddr_fmt *fmt) fmt->msb << 8 | fmt->lsb << 3); } +unsigned int aml_toddr_get_status(struct toddr *to) +{ + struct aml_audio_controller *actrl = to->actrl; + unsigned int reg_base = to->reg_base; + unsigned int reg; + + reg = calc_toddr_address(EE_AUDIO_TODDR_A_STATUS1, reg_base); + + return aml_audiobus_read(actrl, reg); +} + +void aml_toddr_ack_irq(struct toddr *to, int status) +{ + struct aml_audio_controller *actrl = to->actrl; + unsigned int reg_base = to->reg_base; + unsigned int reg; + + reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL1, reg_base); + + aml_audiobus_update_bits(actrl, reg, MEMIF_INT_MASK, status); + aml_audiobus_update_bits(actrl, reg, MEMIF_INT_MASK, 0); +} + void aml_toddr_insert_chanum(struct toddr *to) { struct aml_audio_controller *actrl = to->actrl; diff --git a/sound/soc/amlogic/auge/ddr_mngr.h b/sound/soc/amlogic/auge/ddr_mngr.h index c787662707d0..dc7dca26d29f 100644 --- a/sound/soc/amlogic/auge/ddr_mngr.h +++ b/sound/soc/amlogic/auge/ddr_mngr.h @@ -23,6 +23,14 @@ #include #include "audio_io.h" +#define MEMIF_INT_ADDR_FINISH BIT(0) +#define MEMIF_INT_ADDR_INT BIT(1) +#define MEMIF_INT_COUNT_REPEAT BIT(2) +#define MEMIF_INT_COUNT_ONCE BIT(3) +#define MEMIF_INT_FIFO_ZERO BIT(4) +#define MEMIF_INT_FIFO_DEPTH BIT(5) +#define MEMIF_INT_MASK GENMASK(7, 0) + enum ddr_num { DDR_A, DDR_B, @@ -104,27 +112,6 @@ struct toddr_fmt { unsigned int rate; }; -#if 0 -struct ddr_desc { - /* start address of DDR */ - unsigned int start; - /* finish address of DDR */ - unsigned int finish; - /* interrupt address or counts of DDR blocks */ - unsigned int intrpt; - /* fifo total counts */ - unsigned int fifo_depth; - /* fifo start threshold */ - unsigned int fifo_thr; - enum ddr_types data_type; - unsigned int edian; - unsigned int pp_mode; - //unsigned int reg_base; - struct clk *ddr; - struct clk *ddr_arb; -}; -#endif - struct ddr_chipinfo { /* INT and Start address is same or separated */ bool int_start_same_addr; @@ -170,7 +157,6 @@ struct ddr_chipinfo { }; struct toddr { - //struct ddr_desc dscrpt; struct device *dev; unsigned int resample: 1; unsigned int ext_signed: 1; @@ -222,7 +208,6 @@ struct frddr_attach { }; struct frddr { - //struct ddr_desc dscrpt; struct device *dev; enum frddr_dest dest; @@ -244,7 +229,6 @@ struct frddr { }; /* to ddrs */ -int fetch_toddr_index_by_src(int toddr_src); struct toddr *fetch_toddr_by_src(int toddr_src); struct toddr *aml_audio_register_toddr(struct device *dev, struct aml_audio_controller *actrl, @@ -264,6 +248,10 @@ void aml_toddr_set_fifos(struct toddr *to, unsigned int thresh); void aml_toddr_update_fifos_rd_th(struct toddr *to, int th); void aml_toddr_force_finish(struct toddr *to); void aml_toddr_set_format(struct toddr *to, struct toddr_fmt *fmt); + +unsigned int aml_toddr_get_status(struct toddr *to); +void aml_toddr_ack_irq(struct toddr *to, int status); + void aml_toddr_insert_chanum(struct toddr *to); unsigned int aml_toddr_read(struct toddr *to); void aml_toddr_write(struct toddr *to, unsigned int val); @@ -280,7 +268,6 @@ void aml_pwrdet_enable(bool enable, int pwrdet_module); void aml_set_vad(bool enable, int module); /* from ddrs */ -int fetch_frddr_index_by_src(int frddr_src); struct frddr *fetch_frddr_by_src(int frddr_src); struct frddr *aml_audio_register_frddr(struct device *dev, diff --git a/sound/soc/amlogic/auge/loopback.c b/sound/soc/amlogic/auge/loopback.c new file mode 100644 index 000000000000..95178bd1e949 --- /dev/null +++ b/sound/soc/amlogic/auge/loopback.c @@ -0,0 +1,1433 @@ +/* + * sound/soc/amlogic/auge/loopback.c + * + * Copyright (C) 2018 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include +#include +#include +#include + +#include + +#include "loopback.h" +#include "loopback_hw.h" +#include "loopback_match_table.c" +#include "ddr_mngr.h" +#include "tdm_hw.h" +#include "pdm_hw.h" + +#define DRV_NAME "loopback" + +/*#define __PTM_PDM_CLK__*/ +/*#define __PTM_TDM_CLK__*/ + +struct loopback { + struct device *dev; + struct aml_audio_controller *actrl; + unsigned int id; + + /* + * datain + */ + + /* PDM clocks */ + struct clk *pdm_clk_gate; + struct clk *pdm_sysclk_srcpll; + struct clk *pdm_dclk_srcpll; + struct clk *pdm_sysclk; + struct clk *pdm_dclk; + unsigned int dclk_idx; + /* TDM clocks */ + struct clk *tdmin_mpll; + struct clk *tdmin_mclk; + + /* datain info */ + enum datain_src datain_src; + unsigned int datain_chnum; + unsigned int datain_chmask; + unsigned int datain_lane_mask; /* related with data lane */ + + /* + * datalb + */ + + /* TDMIN_LB clocks */ + struct clk *tdminlb_mpll; + struct clk *tdminlb_mclk; + unsigned int mclk_fs_ratio; + + /* datalb info */ + enum datalb_src datalb_src; + unsigned int datalb_chnum; + unsigned int datalb_chmask; + unsigned int datalb_lane_mask; /* related with data lane */ + + unsigned int sysclk_freq; + + struct toddr *tddr; + + struct loopback_chipinfo *chipinfo; +}; + +#define LOOPBACK_RATES (SNDRV_PCM_RATE_8000_192000) +#define LOOPBACK_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_pcm_hardware loopback_hardware = { + .info = + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE, + + .formats = LOOPBACK_FORMATS, + + .period_bytes_max = 256 * 64, + .buffer_bytes_max = 512 * 1024, + .period_bytes_min = 64, + .periods_min = 1, + .periods_max = 1024, + + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 32, +}; + +static irqreturn_t loopback_ddr_isr(int irq, void *data) +{ + struct snd_pcm_substream *ss = (struct snd_pcm_substream *)data; + struct snd_soc_pcm_runtime *rtd = ss->private_data; + struct device *dev = rtd->platform->dev; + struct loopback *p_loopback = (struct loopback *)dev_get_drvdata(dev); + unsigned int status; + + if (!snd_pcm_running(ss)) + return IRQ_NONE; + + status = aml_toddr_get_status(p_loopback->tddr) & MEMIF_INT_MASK; + if (status & MEMIF_INT_COUNT_REPEAT) { + snd_pcm_period_elapsed(ss); + + aml_toddr_ack_irq(p_loopback->tddr, MEMIF_INT_COUNT_REPEAT); + } else + dev_dbg(dev, "unexpected irq - STS 0x%02x\n", + status); + + return !status ? IRQ_NONE : IRQ_HANDLED; +} + +static int loopback_open(struct snd_pcm_substream *ss) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct snd_soc_pcm_runtime *rtd = ss->private_data; + struct device *dev = rtd->platform->dev; + struct loopback *p_loopback = (struct loopback *)dev_get_drvdata(dev); + + snd_soc_set_runtime_hwparams(ss, &loopback_hardware); + + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { + p_loopback->tddr = aml_audio_register_toddr(dev, + p_loopback->actrl, + loopback_ddr_isr, ss); + if (p_loopback->tddr == NULL) { + dev_err(dev, "failed to claim to ddr\n"); + return -ENXIO; + } + } + + runtime->private_data = p_loopback; + + return 0; +} + +static int loopback_close(struct snd_pcm_substream *ss) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct loopback *p_loopback = runtime->private_data; + + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) + aml_audio_unregister_toddr(p_loopback->dev, ss); + + runtime->private_data = NULL; + + return 0; +} + +static int loopback_hw_params( + struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); +} + +static int loopback_hw_free(struct snd_pcm_substream *ss) +{ + snd_pcm_lib_free_pages(ss); + + return 0; +} + +static int loopback_trigger( + struct snd_pcm_substream *ss, + int cmd) +{ + return 0; +} + +static int loopback_prepare(struct snd_pcm_substream *ss) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct loopback *p_loopback = runtime->private_data; + unsigned int start_addr, end_addr, int_addr; + + start_addr = runtime->dma_addr; + end_addr = start_addr + runtime->dma_bytes - 8; + int_addr = frames_to_bytes(runtime, runtime->period_size) / 8; + + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { + struct toddr *to = p_loopback->tddr; + + aml_toddr_set_buf(to, start_addr, end_addr); + aml_toddr_set_intrpt(to, int_addr); + } + + return 0; +} + +static snd_pcm_uframes_t loopback_pointer( + struct snd_pcm_substream *ss) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct loopback *p_loopback = runtime->private_data; + unsigned int addr, start_addr; + snd_pcm_uframes_t frames = 0; + + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { + start_addr = runtime->dma_addr; + addr = aml_toddr_get_position(p_loopback->tddr); + + frames = bytes_to_frames(runtime, addr - start_addr); + } + if (frames > runtime->buffer_size) + frames = 0; + + return frames; +} + +int loopback_silence( + struct snd_pcm_substream *ss, + int channel, + snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + char *ppos; + int n; + + n = frames_to_bytes(runtime, count); + ppos = runtime->dma_area + frames_to_bytes(runtime, pos); + memset(ppos, 0, n); + + return 0; +} + +static int loopback_mmap(struct snd_pcm_substream *ss, + struct vm_area_struct *vma) +{ + return snd_pcm_lib_default_mmap(ss, vma); +} + +static struct snd_pcm_ops loopback_ops = { + .open = loopback_open, + .close = loopback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = loopback_hw_params, + .hw_free = loopback_hw_free, + .prepare = loopback_prepare, + .trigger = loopback_trigger, + .pointer = loopback_pointer, + .silence = loopback_silence, + .mmap = loopback_mmap, +}; + +static int loopback_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_pcm *pcm = rtd->pcm; + struct snd_pcm_substream *ss; + int size = loopback_hardware.buffer_bytes_max; + int ret = -EINVAL; + + /* only capture */ + ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (ss) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + rtd->platform->dev, + size, &ss->dma_buffer); + if (ret) { + dev_err(rtd->dev, "Cannot allocate buffer(s)\n"); + return ret; + } + } + + return ret; +} + +static void loopback_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *ss; + + ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (ss) { + snd_dma_free_pages(&ss->dma_buffer); + ss->dma_buffer.area = NULL; + ss->dma_buffer.addr = 0; + } +} + +struct snd_soc_platform_driver loopback_platform_drv = { + .pcm_new = loopback_pcm_new, + .pcm_free = loopback_pcm_free, + .ops = &loopback_ops, +}; + +static int loopback_dai_probe(struct snd_soc_dai *dai) +{ + return 0; +} + +static int loopback_dai_remove(struct snd_soc_dai *dai) +{ + return 0; +} + +static int datain_pdm_startup(struct loopback *p_loopback) +{ + int ret; + + /* enable clock gate */ + ret = clk_prepare_enable(p_loopback->pdm_clk_gate); + + /* enable clock */ + ret = clk_prepare_enable(p_loopback->pdm_sysclk_srcpll); + if (ret) { + pr_err("Can't enable pcm pdm_sysclk_srcpll clock: %d\n", ret); + goto err; + } + + ret = clk_prepare_enable(p_loopback->pdm_dclk_srcpll); + if (ret) { + pr_err("Can't enable pcm pdm_dclk_srcpll clock: %d\n", ret); + goto err; + } + + ret = clk_prepare_enable(p_loopback->pdm_sysclk); + if (ret) { + pr_err("Can't enable pcm pdm_sysclk clock: %d\n", ret); + goto err; + } + + ret = clk_prepare_enable(p_loopback->pdm_dclk); + if (ret) { + pr_err("Can't enable pcm pdm_dclk clock: %d\n", ret); + goto err; + } + + return 0; +err: + pr_err("failed enable pdm clock\n"); + return -EINVAL; +} + +static void datain_pdm_shutdown(struct loopback *p_loopback) +{ + /* disable clock and gate */ + clk_disable_unprepare(p_loopback->pdm_dclk); + clk_disable_unprepare(p_loopback->pdm_sysclk); + clk_disable_unprepare(p_loopback->pdm_sysclk_srcpll); + clk_disable_unprepare(p_loopback->pdm_dclk_srcpll); + clk_disable_unprepare(p_loopback->pdm_clk_gate); +} + +static int tdminlb_startup(struct loopback *p_loopback) +{ + int ret; + + /* enable clock */ + ret = clk_prepare_enable(p_loopback->tdminlb_mpll); + if (ret) { + pr_err("Can't enable tdminlb_mpll clock: %d\n", ret); + goto err; + } + + ret = clk_prepare_enable(p_loopback->tdminlb_mclk); + if (ret) { + pr_err("Can't enable tdminlb_mclk clock: %d\n", ret); + goto err; + } + + return 0; +err: + pr_err("failed enable pdm clock\n"); + return -EINVAL; +} + +static void tdminlb_shutdown(struct loopback *p_loopback) +{ + /* disable clock and gate */ + clk_disable_unprepare(p_loopback->tdminlb_mclk); + clk_disable_unprepare(p_loopback->tdminlb_mpll); +} + +static int loopback_dai_startup( + struct snd_pcm_substream *ss, + struct snd_soc_dai *dai) +{ + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + if (ss->stream != SNDRV_PCM_STREAM_CAPTURE) { + ret = -EINVAL; + goto err; + } + + pr_info("%s\n", __func__); + + /* datain */ + switch (p_loopback->datain_src) { + case DATAIN_TDMA: + case DATAIN_TDMB: + case DATAIN_TDMC: + break; + case DATAIN_SPDIF: + break; + case DATAIN_PDM: + ret = datain_pdm_startup(p_loopback); + if (ret < 0) + goto err; + break; + case DATAIN_LOOPBACK: + break; + default: + break; + } + + /* datalb */ + switch (p_loopback->datalb_src) { + case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC: + tdminlb_startup(p_loopback); + break; + case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB: + break; + default: + break; + } + + return ret; +err: + pr_err("Failed to enable datain clock\n"); + return ret; +} + +static void loopback_dai_shutdown( + struct snd_pcm_substream *ss, + struct snd_soc_dai *dai) +{ + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + + pr_info("%s\n", __func__); + + /* datain */ + switch (p_loopback->datain_src) { + case DATAIN_TDMA: + case DATAIN_TDMB: + case DATAIN_TDMC: + break; + case DATAIN_SPDIF: + break; + case DATAIN_PDM: + datain_pdm_shutdown(p_loopback); + break; + case DATAIN_LOOPBACK: + break; + default: + break; + } + + /* datalb */ + switch (p_loopback->datalb_src) { + case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC: + tdminlb_shutdown(p_loopback); + break; + case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB: + break; + default: + break; + } + +} + +static void loopback_set_clk(struct loopback *p_loopback, + int rate, bool enable) +{ + unsigned int mul = 2; + unsigned int mpll_freq, mclk_freq; + /* assume datain_lb in i2s format, 2ch, 32bit */ + unsigned int bit_depth = 32, i2s_ch = 2; + unsigned int sclk_div = 4 - 1; + unsigned int ratio = i2s_ch * bit_depth - 1; + + /* lb_datain clk is set + * prepare clocks for tdmin_lb + */ + + /* mpll, mclk */ + if (p_loopback->datalb_src >= 3) { + mclk_freq = rate * p_loopback->mclk_fs_ratio; + mpll_freq = mclk_freq * mul; + clk_set_rate(p_loopback->tdminlb_mpll, mpll_freq); + clk_set_rate(p_loopback->tdminlb_mclk, mclk_freq); + pr_info("%s, rate:%d mclk:%d, mpll:%d, get mclk:%lu mpll:%lu\n", + __func__, + rate, + mclk_freq, + mpll_freq, + clk_get_rate(p_loopback->tdminlb_mclk), + clk_get_rate(p_loopback->tdminlb_mpll)); + } + +#ifdef __PTM_TDM_CLK__ + ratio = 18 * 2; +#endif + + tdminlb_set_clk(p_loopback->datalb_src, sclk_div, ratio, enable); +} + +static int loopback_set_ctrl(struct loopback *p_loopback, int bitwidth) +{ + unsigned int datain_toddr_type, datalb_toddr_type; + unsigned int datain_msb, datain_lsb, datalb_msb, datalb_lsb; + struct data_cfg datain_cfg; + struct data_cfg datalb_cfg; + + if (!p_loopback) + return -EINVAL; + + switch (p_loopback->datain_src) { + case DATAIN_TDMA: + case DATAIN_TDMB: + case DATAIN_TDMC: + case DATAIN_PDM: + datain_toddr_type = 0; + datain_msb = 32 - 1; + datain_lsb = 0; + break; + case DATAIN_SPDIF: + datain_toddr_type = 3; + datain_msb = 27; + datain_lsb = 4; + if (bitwidth <= 24) + datain_lsb = 28 - bitwidth; + else + datain_lsb = 4; + break; + default: + pr_err("unsupport data in source:%d\n", + p_loopback->datain_src); + return -EINVAL; + } + + switch (p_loopback->datalb_src) { + case TDMINLB_TDMOUTA: + case TDMINLB_TDMOUTB: + case TDMINLB_TDMOUTC: + case TDMINLB_PAD_TDMINA: + case TDMINLB_PAD_TDMINB: + case TDMINLB_PAD_TDMINC: + if (bitwidth == 24) { + datalb_toddr_type = 4; + datalb_msb = 32 - 1; + datalb_lsb = 32 - bitwidth; + } else { + datalb_toddr_type = 0; + datalb_msb = 32 - 1; + datalb_lsb = 0; + } + break; + default: + pr_err("unsupport data lb source:%d\n", + p_loopback->datalb_src); + return -EINVAL; + } + + datain_cfg.ext_signed = 0; + datain_cfg.chnum = p_loopback->datain_chnum; + datain_cfg.chmask = p_loopback->datain_chmask; + datain_cfg.type = datain_toddr_type; + datain_cfg.m = datain_msb; + datain_cfg.n = datain_lsb; + datain_cfg.src = p_loopback->datain_src; + + datalb_cfg.ext_signed = 0; + datalb_cfg.chnum = p_loopback->datalb_chnum; + datalb_cfg.chmask = p_loopback->datalb_chmask; + datalb_cfg.type = datalb_toddr_type; + datalb_cfg.m = datalb_msb; + datalb_cfg.n = datalb_lsb; + datalb_cfg.datalb_src = p_loopback->datalb_src; + + if (p_loopback->chipinfo) { + datain_cfg.ch_ctrl_switch = p_loopback->chipinfo->ch_ctrl; + datalb_cfg.ch_ctrl_switch = p_loopback->chipinfo->ch_ctrl; + } else { + datain_cfg.ch_ctrl_switch = 0; + datalb_cfg.ch_ctrl_switch = 0; + } + + lb_set_datain_cfg(p_loopback->id, &datain_cfg); + lb_set_datalb_cfg(p_loopback->id, &datalb_cfg); + + tdminlb_set_format(1); /* tdmin_lb i2s mode */ + tdminlb_set_lanemask_and_chswap(0x76543210, + p_loopback->datalb_lane_mask); + tdminlb_set_ctrl(p_loopback->datalb_src); + + return 0; +} + +static void datatin_pdm_cfg( + struct snd_pcm_runtime *runtime, + struct loopback *p_loopback) +{ + unsigned int bit_depth = snd_pcm_format_width(runtime->format); + unsigned int osr; + struct pdm_info info; + + info.bitdepth = bit_depth; + info.channels = p_loopback->datain_chnum; + info.lane_masks = p_loopback->datain_lane_mask; + info.dclk_idx = p_loopback->dclk_idx; + info.bypass = 0; + info.sample_count = pdm_get_sample_count(0, p_loopback->dclk_idx); + aml_pdm_ctrl(&info); + + /* filter for pdm */ + osr = pdm_get_ors(p_loopback->dclk_idx, runtime->rate); + + aml_pdm_filter_ctrl(osr, 1); +} + +static int loopback_dai_prepare( + struct snd_pcm_substream *ss, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + unsigned int bit_depth = snd_pcm_format_width(runtime->format); + + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { + struct toddr *to = p_loopback->tddr; + unsigned int msb = 32 - 1; + unsigned int lsb = 32 - bit_depth; + unsigned int toddr_type; + struct toddr_fmt fmt; + unsigned int src; + + if (p_loopback->id == 0) + src = LOOPBACK_A; + else + src = LOOPBACK_B; + + pr_info("%s Expected toddr src:%s\n", + __func__, + toddr_src_get_str(src)); + + switch (bit_depth) { + case 8: + case 16: + case 32: + toddr_type = 0; + break; + case 24: + toddr_type = 4; + break; + default: + dev_err(p_loopback->dev, + "invalid bit_depth: %d\n", + bit_depth); + return -EINVAL; + } + + fmt.type = toddr_type; + fmt.msb = msb; + fmt.lsb = lsb; + fmt.endian = 0; + fmt.bit_depth = bit_depth; + fmt.ch_num = runtime->channels; + fmt.rate = runtime->rate; + + aml_toddr_select_src(to, src); + aml_toddr_set_format(to, &fmt); + aml_toddr_set_fifos(to, 0x40); + + switch (p_loopback->datain_src) { + case DATAIN_TDMA: + case DATAIN_TDMB: + case DATAIN_TDMC: + break; + case DATAIN_SPDIF: + break; + case DATAIN_PDM: + datatin_pdm_cfg(runtime, p_loopback); + break; + case DATAIN_LOOPBACK: + break; + default: + dev_err(p_loopback->dev, + "unexpected datain src 0x%02x\n", + p_loopback->datain_src); + return -EINVAL; + } + + switch (p_loopback->datalb_src) { + case TDMINLB_TDMOUTA: + case TDMINLB_TDMOUTB: + case TDMINLB_TDMOUTC: + break; + case TDMINLB_PAD_TDMINA: + case TDMINLB_PAD_TDMINB: + case TDMINLB_PAD_TDMINC: + break; + case SPDIFINLB_SPDIFOUTA: + case SPDIFINLB_SPDIFOUTB: + break; + default: + dev_err(p_loopback->dev, + "unexpected datalb src 0x%02x\n", + p_loopback->datalb_src); + return -EINVAL; + } + + /* config for loopback, datain, datalb */ + loopback_set_ctrl(p_loopback, bit_depth); + } + + return 0; +} + +static int loopback_dai_trigger( + struct snd_pcm_substream *ss, + int cmd, + struct snd_soc_dai *dai) +{ + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + + pr_info("%s\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { + dev_info(ss->pcm->card->dev, "Loopback Capture enable\n"); + + pdm_fifo_reset(); + tdminlb_fifo_enable(true); + + aml_toddr_enable(p_loopback->tddr, true); + /* loopback */ + lb_enable(p_loopback->id, true); + /* tdminLB */ + tdminlb_enable(p_loopback->datalb_src, true); + /* pdm */ + pdm_enable(1); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (ss->stream == SNDRV_PCM_STREAM_CAPTURE) { + dev_info(ss->pcm->card->dev, "Loopback Capture disable\n"); + pdm_enable(0); + + /* loopback */ + lb_enable(p_loopback->id, false); + /* tdminLB */ + tdminlb_fifo_enable(false); + tdminlb_enable(p_loopback->datalb_src, false); + + aml_toddr_enable(p_loopback->tddr, false); + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static void datain_pdm_set_clk(struct loopback *p_loopback) +{ + unsigned int pdm_sysclk_srcpll_freq, pdm_dclk_srcpll_freq; + + pdm_sysclk_srcpll_freq = clk_get_rate(p_loopback->pdm_sysclk_srcpll); + pdm_dclk_srcpll_freq = clk_get_rate(p_loopback->pdm_dclk_srcpll); + +#ifdef __PTM_PDM_CLK__ + clk_set_rate(p_loopback->pdm_sysclk, 133333351); + clk_set_rate(p_loopback->pdm_dclk_srcpll, 24576000 * 15); /* 350m */ + clk_set_rate(p_loopback->pdm_dclk, 3072000); +#else + clk_set_rate(p_loopback->pdm_sysclk, 133333351); + + if (pdm_dclk_srcpll_freq == 0) + clk_set_rate(p_loopback->pdm_dclk_srcpll, 24576000); + else + pr_info("pdm pdm_dclk_srcpll:%lu\n", + clk_get_rate(p_loopback->pdm_dclk_srcpll)); +#endif + + clk_set_rate(p_loopback->pdm_dclk, + pdm_dclkidx2rate(p_loopback->dclk_idx)); + + pr_info("pdm pdm_sysclk:%lu pdm_dclk:%lu\n", + clk_get_rate(p_loopback->pdm_sysclk), + clk_get_rate(p_loopback->pdm_dclk)); +} + +static void datalb_tdminlb_set_clk(struct loopback *p_loopback) +{ + int mpll_freq = p_loopback->sysclk_freq * 2; + + clk_set_rate(p_loopback->tdminlb_mpll, mpll_freq); + clk_set_rate(p_loopback->tdminlb_mclk, p_loopback->sysclk_freq); + + pr_info("tdmin lb mpll:%lu mclk:%lu\n", + clk_get_rate(p_loopback->tdminlb_mpll), + clk_get_rate(p_loopback->tdminlb_mclk)); +} + +static int loopback_dai_hw_params( + struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels; + snd_pcm_format_t format; + int ret = 0; + + rate = params_rate(params); + channels = params_channels(params); + format = params_format(params); + + pr_info("%s:rate:%d, sysclk:%d\n", + __func__, + rate, + p_loopback->sysclk_freq); + + switch (p_loopback->datain_src) { + case DATAIN_TDMA: + case DATAIN_TDMB: + case DATAIN_TDMC: + break; + case DATAIN_SPDIF: + break; + case DATAIN_PDM: + datain_pdm_set_clk(p_loopback); + break; + case DATAIN_LOOPBACK: + break; + default: + break; + } + + /* datalb */ + switch (p_loopback->datalb_src) { + case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC: + datalb_tdminlb_set_clk(p_loopback); + break; + case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB: + break; + default: + break; + } + + loopback_set_clk(p_loopback, runtime->rate, true); + + return ret; +} + +int loopback_dai_hw_free( + struct snd_pcm_substream *ss, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = ss->runtime; + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + + pr_info("%s\n", __func__); + + if (0) + loopback_set_clk(p_loopback, runtime->rate, false); + + return 0; +} + +static int loopback_dai_set_fmt( + struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + + pr_info("asoc loopback_dai_set_fmt, %#x, %p\n", fmt, p_loopback); + + return 0; +} + +static int loopback_dai_set_sysclk( + struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct loopback *p_loopback = snd_soc_dai_get_drvdata(dai); + + p_loopback->sysclk_freq = freq; + pr_info("\n%s, %d, %d, %d\n", + __func__, + clk_id, freq, dir); + + return 0; +} + +static struct snd_soc_dai_ops loopback_dai_ops = { + .startup = loopback_dai_startup, + .shutdown = loopback_dai_shutdown, + .prepare = loopback_dai_prepare, + .trigger = loopback_dai_trigger, + .hw_params = loopback_dai_hw_params, + .hw_free = loopback_dai_hw_free, + .set_fmt = loopback_dai_set_fmt, + .set_sysclk = loopback_dai_set_sysclk, +}; + +static struct snd_soc_dai_driver loopback_dai[] = { + { + .name = "LOOPBACK-A", + .id = 0, + .probe = loopback_dai_probe, + .remove = loopback_dai_remove, + + .capture = { + .channels_min = 1, + .channels_max = 32, + .rates = LOOPBACK_RATES, + .formats = LOOPBACK_FORMATS, + }, + .ops = &loopback_dai_ops, + }, + { + .name = "LOOPBACK-B", + .id = 1, + .probe = loopback_dai_probe, + .remove = loopback_dai_remove, + + .capture = { + .channels_min = 1, + .channels_max = 32, + .rates = LOOPBACK_RATES, + .formats = LOOPBACK_FORMATS, + }, + .ops = &loopback_dai_ops, + }, +}; + +static const char *const datain_src_texts[] = { + "TDMIN_A", + "TDMIN_B", + "TDMIN_C", + "SPDIFIN", + "PDMIN", +}; + +static const struct soc_enum datain_src_enum = + SOC_ENUM_SINGLE(EE_AUDIO_LB_CTRL0, 0, ARRAY_SIZE(datain_src_texts), + datain_src_texts); + +static int datain_src_get_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct loopback *p_loopback = dev_get_drvdata(component->dev); + + if (!p_loopback) + return 0; + + ucontrol->value.enumerated.item[0] = p_loopback->datain_src; + + return 0; +} + +static int datain_src_set_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct loopback *p_loopback = dev_get_drvdata(component->dev); + + if (!p_loopback) + return 0; + + p_loopback->datain_src = ucontrol->value.enumerated.item[0]; + + lb_set_datain_src(p_loopback->id, p_loopback->datain_src); + + return 0; +} + +static const char *const datalb_tdminlb_texts[] = { + "TDMOUT_A", + "TDMOUT_B", + "TDMOUT_C", + "TDMIN_A", + "TDMIN_B", + "TDMIN_C", +}; + +static const struct soc_enum datalb_tdminlb_enum = + SOC_ENUM_SINGLE(EE_AUDIO_TDMIN_LB_CTRL, + 20, + ARRAY_SIZE(datalb_tdminlb_texts), + datalb_tdminlb_texts); + +static int datalb_tdminlb_get_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct loopback *p_loopback = dev_get_drvdata(component->dev); + + if (!p_loopback) + return 0; + + ucontrol->value.enumerated.item[0] = p_loopback->datalb_src; + + return 0; +} + +static int datalb_tdminlb_set_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct loopback *p_loopback = dev_get_drvdata(component->dev); + + if (!p_loopback) + return 0; + + p_loopback->datalb_src = ucontrol->value.enumerated.item[0]; + + tdminlb_set_src(p_loopback->datalb_src); + + return 0; +} + +static const struct snd_kcontrol_new snd_loopback_controls[] = { + /* loopback data in source */ + SOC_ENUM_EXT("Loopback datain source", + datain_src_enum, + datain_src_get_enum, + datain_src_set_enum), + + /* loopback data tdmin lb */ + SOC_ENUM_EXT("Loopback tdmin lb source", + datalb_tdminlb_enum, + datalb_tdminlb_get_enum, + datalb_tdminlb_set_enum), +}; + +static const struct snd_soc_component_driver loopback_component = { + .name = DRV_NAME, + .controls = snd_loopback_controls, + .num_controls = ARRAY_SIZE(snd_loopback_controls), +}; + +static int snd_soc_of_get_slot_mask( + struct device_node *np, + const char *prop_name, + unsigned int *mask) +{ + u32 val; + const __be32 *of_slot_mask = of_get_property(np, prop_name, &val); + int i; + + if (!of_slot_mask) + return -EINVAL; + + val /= sizeof(u32); + for (i = 0; i < val; i++) + if (be32_to_cpup(&of_slot_mask[i])) + *mask |= (1 << i); + + return val; +} + +static int datain_pdm_parse_of( + struct device *dev, + struct loopback *p_loopback) +{ + int ret; + + /* clock gate */ + p_loopback->pdm_clk_gate = devm_clk_get(dev, "pdm_gate"); + if (IS_ERR(p_loopback->pdm_clk_gate)) { + dev_err(dev, + "Can't get pdm gate\n"); + return PTR_ERR(p_loopback->pdm_clk_gate); + } + + p_loopback->pdm_sysclk_srcpll = devm_clk_get(dev, "pdm_sysclk_srcpll"); + if (IS_ERR(p_loopback->pdm_sysclk_srcpll)) { + dev_err(dev, + "Can't retrieve pll clock\n"); + ret = PTR_ERR(p_loopback->pdm_sysclk_srcpll); + goto err; + } + + p_loopback->pdm_dclk_srcpll = devm_clk_get(dev, "pdm_dclk_srcpll"); + if (IS_ERR(p_loopback->pdm_dclk_srcpll)) { + dev_err(dev, + "Can't retrieve data src clock\n"); + ret = PTR_ERR(p_loopback->pdm_dclk_srcpll); + goto err; + } + + p_loopback->pdm_sysclk = devm_clk_get(dev, "pdm_sysclk"); + if (IS_ERR(p_loopback->pdm_sysclk)) { + dev_err(dev, + "Can't retrieve pdm_sysclk clock\n"); + ret = PTR_ERR(p_loopback->pdm_sysclk); + goto err; + } + + p_loopback->pdm_dclk = devm_clk_get(dev, "pdm_dclk"); + if (IS_ERR(p_loopback->pdm_dclk)) { + dev_err(dev, + "Can't retrieve pdm_dclk clock\n"); + ret = PTR_ERR(p_loopback->pdm_dclk); + goto err; + } + + ret = clk_set_parent(p_loopback->pdm_sysclk, + p_loopback->pdm_sysclk_srcpll); + if (ret) { + dev_err(dev, + "Can't set pdm_sysclk parent clock\n"); + ret = PTR_ERR(p_loopback->pdm_sysclk); + goto err; + } + + ret = clk_set_parent(p_loopback->pdm_dclk, + p_loopback->pdm_dclk_srcpll); + if (ret) { + dev_err(dev, + "Can't set pdm_dclk parent clock\n"); + ret = PTR_ERR(p_loopback->pdm_dclk); + goto err; + } + + return 0; + +err: + return ret; +} + +static int datain_parse_of( + struct device_node *node, + struct loopback *p_loopback) +{ + struct platform_device *pdev; + int ret; + + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(&pdev->dev, + "failed to find platform device\n"); + return -EINVAL; + } + + switch (p_loopback->datain_src) { + case DATAIN_TDMA: + case DATAIN_TDMB: + case DATAIN_TDMC: + break; + case DATAIN_SPDIF: + break; + case DATAIN_PDM: + ret = datain_pdm_parse_of(&pdev->dev, p_loopback); + if (ret < 0) + goto err; + break; + case DATAIN_LOOPBACK: + break; + default: + break; + } + + return 0; +err: + pr_err("%s, error:%d\n", __func__, ret); + return -EINVAL; +} + +static int datalb_tdminlb_parse_of( + struct device_node *node, + struct loopback *p_loopback) +{ + struct platform_device *pdev; + int ret; + + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(&pdev->dev, + "failed to find platform device\n"); + return -EINVAL; + } + + /* mpll used for tdmin_lb */ + p_loopback->tdminlb_mpll = devm_clk_get(&pdev->dev, "tdminlb_mpll"); + if (IS_ERR(p_loopback->tdminlb_mpll)) { + dev_err(&pdev->dev, + "Can't retrieve tdminlb_mpll clock\n"); + return PTR_ERR(p_loopback->tdminlb_mpll); + } + p_loopback->tdminlb_mclk = devm_clk_get(&pdev->dev, "tdminlb_mclk"); + if (IS_ERR(p_loopback->tdminlb_mclk)) { + dev_err(&pdev->dev, + "Can't retrieve tdminlb_mclk clock\n"); + return PTR_ERR(p_loopback->tdminlb_mclk); + } + + ret = clk_set_parent(p_loopback->tdminlb_mclk, + p_loopback->tdminlb_mpll); + if (ret) { + dev_err(&pdev->dev, + "Can't set tdminlb_mclk parent clock\n"); + ret = PTR_ERR(p_loopback->tdminlb_mpll); + goto err; + } + + ret = of_property_read_u32(node, "mclk-fs", + &p_loopback->mclk_fs_ratio); + if (ret) { + pr_warn_once("failed to get mclk-fs node, set it default\n"); + p_loopback->mclk_fs_ratio = 256; + ret = 0; + } + + return 0; +err: + pr_err("%s, error:%d\n", __func__, ret); + return -EINVAL; +} + +static int loopback_parse_of( + struct device_node *node, + struct loopback *p_loopback) +{ + struct platform_device *pdev; + int ret; + + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(&pdev->dev, "failed to find platform device\n"); + ret = -EINVAL; + goto fail; + } + + ret = of_property_read_u32(node, "datain_src", + &p_loopback->datain_src); + if (ret) { + pr_err("failed to get datain_src\n"); + ret = -EINVAL; + goto fail; + } + ret = of_property_read_u32(node, "datain_chnum", + &p_loopback->datain_chnum); + if (ret) { + pr_err("failed to get datain_chnum\n"); + ret = -EINVAL; + goto fail; + } + ret = of_property_read_u32(node, "datain_chmask", + &p_loopback->datain_chmask); + if (ret) { + pr_err("failed to get datain_chmask\n"); + ret = -EINVAL; + goto fail; + } + ret = snd_soc_of_get_slot_mask(node, "datain-lane-mask-in", + &p_loopback->datain_lane_mask); + if (ret < 0) { + ret = -EINVAL; + dev_err(&pdev->dev, "datain lane-slot-mask should be set\n"); + goto fail; + } + + ret = of_property_read_u32(node, "datalb_src", + &p_loopback->datalb_src); + if (ret) { + pr_err("failed to get datalb_src\n"); + ret = -EINVAL; + goto fail; + } + ret = of_property_read_u32(node, "datalb_chnum", + &p_loopback->datalb_chnum); + if (ret) { + pr_err("failed to get datalb_chnum\n"); + ret = -EINVAL; + goto fail; + } + ret = of_property_read_u32(node, "datalb_chmask", + &p_loopback->datalb_chmask); + if (ret) { + pr_err("failed to get datalb_chmask\n"); + ret = -EINVAL; + goto fail; + } + + ret = snd_soc_of_get_slot_mask(node, "datalb-lane-mask-in", + &p_loopback->datalb_lane_mask); + if (ret < 0) { + ret = -EINVAL; + pr_err("datalb lane-slot-mask should be set\n"); + goto fail; + } + + pr_info("\tdatain_src:%d, datain_chnum:%d, datain_chumask:%x\n", + p_loopback->datain_src, + p_loopback->datain_chnum, + p_loopback->datain_chmask); + pr_info("\tdatalb_src:%d, datalb_chnum:%d, datalb_chmask:%x\n", + p_loopback->datalb_src, + p_loopback->datalb_chnum, + p_loopback->datalb_chmask); + pr_info("\tdatain_lane_mask:0x%x, datalb_lane_mask:0x%x\n", + p_loopback->datain_lane_mask, + p_loopback->datalb_lane_mask); + + ret = datain_parse_of(node, p_loopback); + if (ret) { + dev_err(&pdev->dev, + "failed to parse datain\n"); + return ret; + } + ret = datalb_tdminlb_parse_of(node, p_loopback); + if (ret) { + dev_err(&pdev->dev, + "failed to parse datalb\n"); + return ret; + } + + return 0; + +fail: + return ret; +} + +static int loopback_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + struct loopback *p_loopback = NULL; + struct loopback_chipinfo *p_chipinfo = NULL; + struct device_node *node_prt = NULL; + struct platform_device *pdev_parent = NULL; + struct aml_audio_controller *actrl = NULL; + int ret = 0; + + p_loopback = devm_kzalloc(&pdev->dev, + sizeof(struct loopback), + GFP_KERNEL); + if (!p_loopback) + return -ENOMEM; + + /* match data */ + p_chipinfo = (struct loopback_chipinfo *) + of_device_get_match_data(dev); + if (p_chipinfo) { + p_loopback->chipinfo = p_chipinfo; + p_loopback->id = p_chipinfo->id; + } else + dev_warn_once(dev, + "check whether to update loopback chipinfo\n"); + + /* get audio controller */ + node_prt = of_get_parent(node); + if (node_prt == NULL) + return -ENXIO; + + pdev_parent = of_find_device_by_node(node_prt); + of_node_put(node_prt); + actrl = (struct aml_audio_controller *) + platform_get_drvdata(pdev_parent); + p_loopback->actrl = actrl; + + ret = loopback_parse_of(dev->of_node, p_loopback); + if (ret) { + dev_err(&pdev->dev, + "failed to parse loopback info\n"); + return ret; + } + + p_loopback->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, p_loopback); + + ret = devm_snd_soc_register_component(&pdev->dev, + &loopback_component, + &loopback_dai[p_loopback->id], + 1); + if (ret) { + dev_err(&pdev->dev, + "snd_soc_register_component failed\n"); + return ret; + } + + pr_info("%s, p_loopback->id:%d register soc platform\n", + __func__, + p_loopback->id); + + return devm_snd_soc_register_platform(dev, + &loopback_platform_drv); +} + +static struct platform_driver loopback_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(loopback_device_id), + }, + .probe = loopback_platform_probe, +}; +module_platform_driver(loopback_platform_driver); + +MODULE_AUTHOR("AMLogic, Inc."); +MODULE_DESCRIPTION("Amlogic Loopback driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amlogic/auge/loopback.h b/sound/soc/amlogic/auge/loopback.h new file mode 100644 index 000000000000..bc0c075974a1 --- /dev/null +++ b/sound/soc/amlogic/auge/loopback.h @@ -0,0 +1,61 @@ +/* + * sound/soc/amlogic/auge/loopback.h + * + * Copyright (C) 2018 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#ifndef __AML_AUDIO_LOOPBACK_H__ +#define __AML_AUDIO_LOOPBACK_H__ +#include +#include + +/* datain src + * [4]: pdmin; + * [3]: spdifin; + * [2]: tdmin_c; + * [1]: tdmin_b; + * [0]: tdmin_a; + */ +enum datain_src { + DATAIN_TDMA = 0, + DATAIN_TDMB, + DATAIN_TDMC, + DATAIN_SPDIF, + DATAIN_PDM, + DATAIN_LOOPBACK, +}; + +/* datalb src + * /tdmin_lb src + * [0]: tdmoutA + * [1]: tdmoutB + * [2]: tdmoutC + * [3]: PAD_tdminA + * [4]: PAD_tdminB + * [5]: PAD_tdminC + * /spdifin_lb src + * spdifout_a + * spdifout_b + */ +enum datalb_src { + TDMINLB_TDMOUTA = 0, + TDMINLB_TDMOUTB, + TDMINLB_TDMOUTC, + TDMINLB_PAD_TDMINA, + TDMINLB_PAD_TDMINB, + TDMINLB_PAD_TDMINC, + + SPDIFINLB_SPDIFOUTA, + SPDIFINLB_SPDIFOUTB, +}; +#endif diff --git a/sound/soc/amlogic/auge/loopback_hw.c b/sound/soc/amlogic/auge/loopback_hw.c index 15144b9dde7e..0508769c9475 100644 --- a/sound/soc/amlogic/auge/loopback_hw.c +++ b/sound/soc/amlogic/auge/loopback_hw.c @@ -14,193 +14,80 @@ * more details. * */ -#include +#define DEBUG + +#include "linux/kernel.h" -#include "regs.h" #include "loopback_hw.h" +#include "regs.h" #include "iomap.h" -void datain_config(struct data_in *datain) -{ - audiobus_update_bits( - EE_AUDIO_LB_CTRL0, - 1 << 29 | 0x7 << 24 | 0xff << 16 | - 0x7 << 13 | 0x1f << 8 | 0x1f << 3 | - 0x7 << 0, - datain->config->ext_signed << 29 | - (datain->config->chnum - 1) << 24 | - datain->config->chmask << 16 | - datain->ddrdata->combined_type << 13 | - datain->ddrdata->msb << 8 | - datain->ddrdata->lsb << 3 | - datain->ddrdata->src << 0 - ); -} -void datalb_config(struct data_lb *datalb) +void tdminlb_set_clk(int datatlb_src, int sclk_div, int ratio, bool enable) { - audiobus_write( - EE_AUDIO_LB_CTRL1, - datalb->config->ext_signed << 29 | - (datalb->config->chnum - 1) << 24 | - datalb->config->chmask << 16 | - datalb->ddr_type << 13 | - datalb->msb << 8 | - datalb->lsb << 3 - ); -} + unsigned int bclk_sel, fsclk_sel; + unsigned int tdmin_src; -void datalb_ctrl(struct loopback_cfg *lb_cfg) -{ - int id = lb_cfg->datalb_src; - int offset = 0; - int reg, reg_base; + /* config for external codec */ + if (datatlb_src >= 3) { + unsigned int clk_id = datatlb_src - 3; + unsigned int offset, reg; + unsigned int fsclk_hi; + + fsclk_hi = ratio / 2; + bclk_sel = clk_id; + fsclk_sel = clk_id; + + /*sclk, lrclk*/ + offset = EE_AUDIO_MST_B_SCLK_CTRL0 - EE_AUDIO_MST_A_SCLK_CTRL0; + reg = EE_AUDIO_MST_A_SCLK_CTRL0 + offset * clk_id; + audiobus_update_bits(reg, + 0x3 << 30 | 0x3ff << 20 | 0x3ff<<10 | 0x3ff, + (enable ? 0x3 : 0x0) << 30 + | sclk_div << 20 | fsclk_hi << 10 + | ratio); + + + tdmin_src = datatlb_src - 3; + } else + tdmin_src = datatlb_src; audiobus_update_bits( - EE_AUDIO_TDMIN_LB_CTRL, - 0xf << 28 | 0xf << 20 | 0x7 << 16 | 0x1f << 0, - 1 << 31 | - /*0:tdm mode; 1: i2s mode;*/ - 1 << 30 | - 1 << 29 | - 1 << 28 | - lb_cfg->datalb_src << 20 | - 3 << 16| - 31 << 0 - ); - - if (id >= 0 && id <= 2) { - /* tdmout_a, tdmout_b, tdmout_c */ - reg_base = EE_AUDIO_TDMOUT_A_SWAP0; - offset = EE_AUDIO_TDMOUT_B_SWAP0 - EE_AUDIO_TDMOUT_A_SWAP0; - } else if (id < 6) { - /*lb_cfg->datalb_src for pad tdm in, - *pad from tdmin_a, tdmin_b, tdmin_c - */ - /* id offset from tdmin_a */ - id -= 3; - - reg_base = EE_AUDIO_TDMIN_A_CTRL; - offset = EE_AUDIO_TDMIN_B_CTRL - EE_AUDIO_TDMIN_A_CTRL; - reg = reg_base + offset * id; - audiobus_update_bits(reg, 3<<28, 0); - audiobus_update_bits(reg, 1<<29, 1<<29); - audiobus_update_bits(reg, 1<<28, 1<<28); - - /* just assume lb from tdm in is i2s mode */ - audiobus_update_bits( - reg, - 0xf << 28 | 0xf << 20 | 0x7 << 16 | 0x1f << 0, - 1 << 31 | - /* 0:tdm mode; 1: i2s mode */ - 1 << 30 | - 1 << 29 | - 1 << 28 | - id << 20 | - 3 << 16| - 31 << 0 - ); - - pr_info("reg:0x%x, EE_AUDIO_TDMIN_A_CTRL:0x%x\n", - reg, - audiobus_read(EE_AUDIO_TDMIN_A_CTRL)); - /* swap */ - reg += 1; - audiobus_write( - reg, - lb_cfg->datalb_chswap); - - /* mask 0 */ - reg += 1; - audiobus_write( - reg, - lb_cfg->datalb_chmask); - reg_base = EE_AUDIO_TDMIN_A_SWAP0; - offset = EE_AUDIO_TDMIN_B_SWAP0 - EE_AUDIO_TDMIN_A_SWAP0; - } else { - pr_err("unsupport datalb_src\n"); - return; - } - - if (lb_cfg->datain_datalb_total > 8) { - audiobus_write( - EE_AUDIO_TDMIN_LB_SWAP0, - lb_cfg->datalb_chswap); - - audiobus_write(EE_AUDIO_TDMIN_LB_MASK0, 3); - audiobus_write(EE_AUDIO_TDMIN_LB_MASK1, 3); - audiobus_write(EE_AUDIO_TDMIN_LB_MASK2, 3); - audiobus_write(EE_AUDIO_TDMIN_LB_MASK3, 3); - } else { - /*swap same as tdmout */ - reg = reg_base + offset * id; - audiobus_write(EE_AUDIO_TDMIN_LB_SWAP0, - audiobus_read(reg)); - - /*mask same as datalb*/ - /* mask 0 */ - reg += 1; - audiobus_write( - EE_AUDIO_TDMIN_LB_MASK0, - audiobus_read(reg)); - - /* mask 1 */ - reg += 1; - audiobus_write( - EE_AUDIO_TDMIN_LB_MASK1, - audiobus_read(reg)); - - /* mask 2 */ - reg += 1; - audiobus_write( - EE_AUDIO_TDMIN_LB_MASK2, - audiobus_read(reg)); - - /* mask 3 */ - reg += 1; - audiobus_write( - EE_AUDIO_TDMIN_LB_MASK3, - audiobus_read(reg)); - } + EE_AUDIO_CLK_TDMIN_LB_CTRL, + 0x3 << 30 | 1 << 29 | 0xf << 24 | 0xf << 20, + (enable ? 0x3 : 0x0) << 30 | + 1 << 29 | tdmin_src << 24 | tdmin_src << 20 + ); } -void lb_mode(int mode) +void tdminlb_enable(int tdm_index, int is_enable) { -// TODO: - return; -#if 0 - audiobus_update_bits( - EE_AUDIO_LB_CTRL0, - 0x1 << 30, - mode << 30 - ); -#endif -} - -static void tdmin_lb_clk_enalbe(int tdm_src, int is_enable) -{ - if (tdm_src <= 2) - audiobus_update_bits( - EE_AUDIO_CLK_TDMIN_LB_CTRL, - 0x3 << 30 | 1 << 29 | 0xf << 24 | 0xf << 20, - 0x3 << 30 | 1 << 29 | tdm_src << 24 | tdm_src << 20 - ); - else - pr_warn_once("pad from tdmin_a, tdmin_b, tdmin_c needs clks\n"); -} - -void tdmin_lb_enable(int tdm_index, int is_enable) -{ - if (is_enable) - tdmin_lb_clk_enalbe(tdm_index, is_enable); - audiobus_update_bits( EE_AUDIO_TDMIN_LB_CTRL, 0x1 << 31, is_enable << 31); } -void tdmin_lb_fifo_enable(int is_enable) +void tdminlb_set_format(int i2s_fmt) +{ + audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, + 0x1 << 30, + i2s_fmt << 30 /* 0:tdm mode; 1: i2s mode; */ + ); +} + +void tdminlb_set_ctrl(int src) +{ + audiobus_update_bits( + EE_AUDIO_TDMIN_LB_CTRL, + 0xf << 20 | 0x7 << 16 | 0x1f << 0, + src << 20 | /* in src */ + 3 << 16 | /* skew */ + 31 << 0 /* bit width */ + ); +} + +void tdminlb_fifo_enable(int is_enable) { if (is_enable) { audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, 1<<29, 1<<29); @@ -209,39 +96,123 @@ void tdmin_lb_fifo_enable(int is_enable) audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, 3<<28, 0); } - -void lb_set_datain_src(int src) +static void tdminlb_set_lane_mask(int lane, int mask) { + audiobus_write(EE_AUDIO_TDMIN_LB_MASK0 + lane, mask); } -void lb_set_tdminlb_src(int src) +void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask) { + unsigned int mask; + unsigned int i; + + pr_debug("tdmin_lb lane swap:0x%x mask:0x%x\n", swap, lane_mask); + + mask = 0x3; /* i2s format */ + + /* channel swap */ + audiobus_write(EE_AUDIO_TDMIN_LB_SWAP0, swap); + + /* lane mask */ + for (i = 0; i < 4; i++) + if ((1 << i) & lane_mask) + tdminlb_set_lane_mask(i, mask); } -void lb_set_tdminlb_enable(bool is_enable) +void tdminlb_set_src(int src) { + audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, 0xf << 20, src); } -int lb_is_enable(void) +void lb_set_datain_src(int id, int src) { - return (audiobus_read(EE_AUDIO_LB_CTRL0) & 0x80000000) >> 31; + int offset = EE_AUDIO_LB_B_CTRL0 - EE_AUDIO_LB_A_CTRL0; + int reg = EE_AUDIO_LB_A_CTRL0 + offset * id; + + audiobus_update_bits(reg, 0x7 << 0, src); } -void lb_enable(bool is_enable) +void lb_set_datain_cfg(int id, struct data_cfg *datain_cfg) { - audiobus_update_bits( - EE_AUDIO_LB_CTRL0, - 0x1 << 31, - is_enable << 31 + int offset = EE_AUDIO_LB_B_CTRL0 - EE_AUDIO_LB_A_CTRL0; + int reg = EE_AUDIO_LB_A_CTRL0 + offset * id; + + if (!datain_cfg) + return; + + if (datain_cfg->ch_ctrl_switch) { + audiobus_update_bits(reg, + 1 << 29 | 0x7 << 13 | 0x1f << 8 | 0x1f << 3 | 0x7 << 0, + datain_cfg->ext_signed << 29 | + datain_cfg->type << 13 | + datain_cfg->m << 8 | + datain_cfg->n << 3 | + datain_cfg->src << 0 + ); + + /* channel and mask */ + offset = EE_AUDIO_LB_B_CTRL2 - EE_AUDIO_LB_A_CTRL2; + reg = EE_AUDIO_LB_A_CTRL2 + offset * id; + audiobus_write(reg, + (datain_cfg->chnum - 1) << 16 | + datain_cfg->chmask << 0 + ); + } else + audiobus_update_bits(reg, + 1 << 29 | 0x7 << 24 | 0xff << 16 | + 0x7 << 13 | 0x1f << 8 | 0x1f << 3 | + 0x7 << 0, + datain_cfg->ext_signed << 29 | + (datain_cfg->chnum - 1) << 24 | + datain_cfg->chmask << 16 | + datain_cfg->type << 13 | + datain_cfg->m << 8 | + datain_cfg->n << 3 | + datain_cfg->src << 0 ); } -void lb_set_mode(int mode) +void lb_set_datalb_cfg(int id, struct data_cfg *datalb_cfg) { - audiobus_update_bits( - EE_AUDIO_LB_CTRL0, - 0x1 << 30, - mode << 30 + int offset = EE_AUDIO_LB_B_CTRL1 - EE_AUDIO_LB_A_CTRL1; + int reg = EE_AUDIO_LB_A_CTRL1 + offset * id; + + if (!datalb_cfg) + return; + + if (datalb_cfg->ch_ctrl_switch) { + audiobus_update_bits(reg, + 0x1 << 29 | 0x7 << 13 | 0x1f << 8 + | 0x1f << 3 | 0x1 << 1, + datalb_cfg->ext_signed << 29 | + datalb_cfg->type << 13 | + datalb_cfg->m << 8 | + datalb_cfg->n << 3 | + datalb_cfg->datalb_src << 0 + ); + + /* channel and mask */ + offset = EE_AUDIO_LB_B_CTRL3 - EE_AUDIO_LB_A_CTRL3; + reg = EE_AUDIO_LB_A_CTRL3 + offset * id; + audiobus_write(reg, + (datalb_cfg->chnum - 1) << 16 | + datalb_cfg->chmask << 0 + ); + } else + audiobus_write(reg, + datalb_cfg->ext_signed << 29 | + (datalb_cfg->chnum - 1) << 24 | + datalb_cfg->chmask << 16 | + datalb_cfg->type << 13 | + datalb_cfg->m << 8 | + datalb_cfg->n << 3 ); } +void lb_enable(int id, bool enable) +{ + int offset = EE_AUDIO_LB_B_CTRL0 - EE_AUDIO_LB_A_CTRL0; + int reg = EE_AUDIO_LB_A_CTRL0 + offset * id; + + audiobus_update_bits(reg, 0x1 << 31, enable << 31); +} diff --git a/sound/soc/amlogic/auge/loopback_hw.h b/sound/soc/amlogic/auge/loopback_hw.h index 13115d846f2d..776299a0ea9a 100644 --- a/sound/soc/amlogic/auge/loopback_hw.h +++ b/sound/soc/amlogic/auge/loopback_hw.h @@ -18,54 +18,55 @@ #ifndef __AML_LOOPBACK_HW_H__ #define __AML_LOOPBACK_HW_H__ -#include "audio_utils.h" +#include -struct lb_cfg { +struct data_cfg { /* * 0: extend bits as "0" * 1: extend bits as "msb" */ unsigned int ext_signed; - /* total channel number */ + /* channel number */ unsigned int chnum; - /* which channel is selected for loopback */ + /* channel selected */ unsigned int chmask; + /* combined data */ + unsigned int type; + /* the msb positioin in data */ + unsigned int m; + /* the lsb position in data */ + unsigned int n; + + /* loopback datalb src */ + unsigned int src; + + unsigned int datalb_src; + + /* channel and mask in new ctrol register */ + bool ch_ctrl_switch; }; -struct data_in { - struct lb_cfg *config; - struct audio_data *ddrdata; -}; +extern void tdminlb_set_clk(int datatlb_src, + int sclk_div, int ratio, bool enable); -struct data_lb { - struct lb_cfg *config; - unsigned int ddr_type; - unsigned int msb; - unsigned int lsb; -}; +extern void tdminlb_set_format(int i2s_fmt); -struct loopback { - struct device *dev; - unsigned int lb_mode; +extern void tdminlb_set_ctrl(int src); - struct data_in *datain; - struct data_lb *datalb; -}; +extern void tdminlb_enable(int tdm_index, int in_enable); + +extern void tdminlb_fifo_enable(int is_enable); + +extern void tdminlb_set_format(int i2s_fmt); +extern void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask); -extern void datain_config(struct data_in *datain); +extern void tdminlb_set_src(int src); +extern void lb_set_datain_src(int id, int src); -extern void datalb_config(struct data_lb *datalb); +extern void lb_set_datain_cfg(int id, struct data_cfg *datain_cfg); +extern void lb_set_datalb_cfg(int id, struct data_cfg *datalb_cfg); -extern void datalb_ctrl(struct loopback_cfg *lb_cfg); +extern void lb_enable(int id, bool enable); -extern int lb_is_enable(void); - -extern void lb_enable(bool is_enable); - -extern void lb_mode(int mode); - -extern void tdmin_lb_enable(int tdm_index, int in_enable); - -extern void tdmin_lb_fifo_enable(int is_enable); #endif diff --git a/sound/soc/amlogic/auge/loopback_match_table.c b/sound/soc/amlogic/auge/loopback_match_table.c new file mode 100644 index 000000000000..566e1065dbe6 --- /dev/null +++ b/sound/soc/amlogic/auge/loopback_match_table.c @@ -0,0 +1,104 @@ +/* + * sound/soc/amlogic/auge/loopback_match_table.c + * + * Copyright (C) 2019 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#define LOOPBACKA 0 +#define LOOPBACKB 1 + +struct loopback_chipinfo { + unsigned int id; + + /* reset all modules, after g12a + * it has reset bits control for modules + */ + bool is_reset_all; + + /* channel and mask switch to ctrl2, ctrl3 from tl1 + * for datain, 0: channel and mask is controlled by ctrl0 + * 1: channel and mask is controlled by ctrl2 + * for datalb, 0: channel and mask is controlled by ctrl1 + * 1: channel and mask is controlled by ctrl3 + */ + bool ch_ctrl; +}; + +static struct loopback_chipinfo tl1_loopbacka_chipinfo = { + .id = LOOPBACKA, + .ch_ctrl = true, +}; + +static struct loopback_chipinfo tl1_loopbackb_chipinfo = { + .id = LOOPBACKB, + .ch_ctrl = true, +}; + +static struct loopback_chipinfo sm1_loopbacka_chipinfo = { + .id = LOOPBACKA, + .ch_ctrl = true, +}; + +static struct loopback_chipinfo sm1_loopbackb_chipinfo = { + .id = LOOPBACKB, + .ch_ctrl = true, +}; + +static struct loopback_chipinfo tm2_loopbacka_chipinfo = { + .id = LOOPBACKA, + .ch_ctrl = true, +}; + +static struct loopback_chipinfo tm2_loopbackb_chipinfo = { + .id = LOOPBACKB, + .ch_ctrl = true, +}; + +static const struct of_device_id loopback_device_id[] = { + { + .compatible = "amlogic, snd-loopback", + }, + { + .compatible = "amlogic, axg-loopback", + }, + { + .compatible = "amlogic, g12a-loopback", + }, + { + .compatible = "amlogic, tl1-loopbacka", + .data = &tl1_loopbacka_chipinfo, + }, + { + .compatible = "amlogic, tl1-loopbackb", + .data = &tl1_loopbackb_chipinfo, + }, + { + .compatible = "amlogic, sm1-loopbacka", + .data = &sm1_loopbacka_chipinfo, + }, + { + .compatible = "amlogic, sm1-loopbackb", + .data = &sm1_loopbackb_chipinfo, + }, + { + .compatible = "amlogic, tm2-loopbacka", + .data = &tm2_loopbacka_chipinfo, + }, + { + .compatible = "amlogic, tm2-loopbackb", + .data = &tm2_loopbackb_chipinfo, + }, + {} +}; +MODULE_DEVICE_TABLE(of, loopback_device_id); diff --git a/sound/soc/amlogic/auge/pdm.c b/sound/soc/amlogic/auge/pdm.c index 72540b46961f..3debb3480d26 100644 --- a/sound/soc/amlogic/auge/pdm.c +++ b/sound/soc/amlogic/auge/pdm.c @@ -76,8 +76,6 @@ static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = { .mask = 0 }; -static int s_pdm_filter_mode; - static const char *const pdm_filter_mode_texts[] = { "Filter Mode 0", "Filter Mode 1", @@ -94,7 +92,13 @@ static int aml_pdm_filter_mode_get_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.enumerated.item[0] = s_pdm_filter_mode; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; + + ucontrol->value.enumerated.item[0] = p_pdm->filter_mode; return 0; } @@ -103,7 +107,13 @@ static int aml_pdm_filter_mode_set_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - s_pdm_filter_mode = ucontrol->value.enumerated.item[0]; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; + + p_pdm->filter_mode = ucontrol->value.enumerated.item[0]; return 0; } @@ -137,8 +147,6 @@ static int pdm_hcic_shift_gain_set_enum( return 0; } -int pdm_dclk; - static const char *const pdm_dclk_texts[] = { "PDM Dclk 3.072m, support 8k/16k/32k/48k/64k/96k", "PDM Dclk 1.024m, support 8k/16k", @@ -153,7 +161,13 @@ static int pdm_dclk_get_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.enumerated.item[0] = pdm_dclk; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; + + ucontrol->value.enumerated.item[0] = p_pdm->dclk_idx; return 0; } @@ -162,7 +176,56 @@ static int pdm_dclk_set_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pdm_dclk = ucontrol->value.enumerated.item[0]; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; + + p_pdm->dclk_idx = ucontrol->value.enumerated.item[0]; + + return 0; +} + + +static const char *const pdm_bypass_texts[] = { + "PCM Data", + "Raw Data/Bypass Data", +}; + +static const struct soc_enum pdm_bypass_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(pdm_bypass_texts), + pdm_bypass_texts); + +static int pdm_bypass_get_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; + + ucontrol->value.enumerated.item[0] = p_pdm->bypass; + + return 0; +} + +static int pdm_bypass_set_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; + + p_pdm->bypass = ucontrol->value.enumerated.item[0]; + + if (p_pdm->clk_on) + pdm_set_bypass_data((bool)p_pdm->bypass); return 0; } @@ -180,8 +243,11 @@ static int pdm_train_get_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); - struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); + + if (!p_pdm) + return 0; ucontrol->value.enumerated.item[0] = p_pdm->train_en; @@ -192,10 +258,11 @@ static int pdm_train_set_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); - struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aml_pdm *p_pdm = dev_get_drvdata(component->dev); - if (!p_pdm->chipinfo || + if (!p_pdm || + !p_pdm->chipinfo || !p_pdm->chipinfo->train || (p_pdm->train_en == ucontrol->value.enumerated.item[0])) return 0; @@ -230,6 +297,11 @@ static const struct snd_kcontrol_new snd_pdm_controls[] = { pdm_train_enum, pdm_train_get_enum, pdm_train_set_enum), + + SOC_ENUM_EXT("PDM Bypass", + pdm_bypass_enum, + pdm_bypass_get_enum, + pdm_bypass_set_enum), }; #if 0 @@ -252,7 +324,7 @@ static int pdm_mute_val_get(struct snd_kcontrol *kcontrol, val = pdm_get_mute_value(); ucontrol->value.integer.value[0] = val; - pr_info("%s:get mute_val:0x%x\n", + pr_info("%s, get mute_val:0x%x\n", __func__, val); @@ -264,7 +336,7 @@ static int pdm_mute_val_set(struct snd_kcontrol *kcontrol, { int val = (int)ucontrol->value.integer.value[0]; - pr_info("%s:set mute_val:0x%x\n", + pr_info("%s, set mute_val:0x%x\n", __func__, val); @@ -302,7 +374,7 @@ static int pdm_mute_chmask_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = val; - pr_info("%s:get pdm channel mask val:0x%x\n", + pr_info("%s, get pdm channel mask val:0x%x\n", __func__, val); @@ -319,7 +391,7 @@ static int pdm_mute_chmask_set(struct snd_kcontrol *kcontrol, if (val > 255) val = 255; - pr_info("%s:set pdm channel mask val:0x%x\n", + pr_info("%s, set pdm channel mask val:0x%x\n", __func__, val); @@ -379,11 +451,25 @@ static irqreturn_t aml_pdm_isr_handler(int irq, void *data) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct device *dev = rtd->platform->dev; + struct aml_pdm *p_pdm = (struct aml_pdm *)dev_get_drvdata(dev); + unsigned int status; int train_sts = pdm_train_sts(); pr_debug("%s\n", __func__); - snd_pcm_period_elapsed(substream); + if (!snd_pcm_running(substream)) + return IRQ_NONE; + + status = aml_toddr_get_status(p_pdm->tddr) & MEMIF_INT_MASK; + if (status & MEMIF_INT_COUNT_REPEAT) { + snd_pcm_period_elapsed(substream); + + aml_toddr_ack_irq(p_pdm->tddr, MEMIF_INT_COUNT_REPEAT); + } else + dev_dbg(dev, "unexpected irq - STS 0x%02x\n", + status); if (train_sts) { pr_debug("%s train result:0x%x\n", @@ -392,7 +478,7 @@ static irqreturn_t aml_pdm_isr_handler(int irq, void *data) pdm_train_clr(); } - return IRQ_HANDLED; + return !status ? IRQ_NONE : IRQ_HANDLED; } static int aml_pdm_open(struct snd_pcm_substream *substream) @@ -404,7 +490,7 @@ static int aml_pdm_open(struct snd_pcm_substream *substream) dev_get_drvdata(dev); int ret; - pr_info("%s, stream:%d\n", + pr_debug("%s, stream:%d\n", __func__, substream->stream); snd_soc_set_runtime_hwparams(substream, &aml_pdm_hardware); @@ -453,7 +539,7 @@ static int aml_pdm_close(struct snd_pcm_substream *substream) struct device *dev = rtd->platform->dev; struct aml_pdm *p_pdm = (struct aml_pdm *)dev_get_drvdata(dev); - pr_info("enter %s type: %d\n", + pr_debug("enter %s type: %d\n", __func__, substream->stream); aml_audio_unregister_toddr(p_pdm->dev, substream); @@ -469,7 +555,7 @@ static int aml_pdm_hw_params( struct snd_pcm_runtime *runtime = substream->runtime; int ret = 0; - pr_info("enter %s\n", __func__); + pr_debug("enter %s\n", __func__); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); @@ -480,7 +566,7 @@ static int aml_pdm_hw_params( static int aml_pdm_hw_free(struct snd_pcm_substream *substream) { - pr_info("%s\n", __func__); + pr_debug("%s\n", __func__); snd_pcm_lib_free_pages(substream); return 0; @@ -547,7 +633,7 @@ static int aml_pdm_silence( unsigned char *ppos = NULL; ssize_t n; - pr_info("%s\n", __func__); + pr_debug("%s\n", __func__); n = frames_to_bytes(runtime, count); ppos = runtime->dma_area + frames_to_bytes(runtime, pos); @@ -564,7 +650,7 @@ static int aml_pdm_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) int size = aml_pdm_hardware.buffer_bytes_max; int ret = -EINVAL; - pr_info("%s dai->name: %s dai->id: %d\n", + pr_debug("%s dai->name: %s dai->id: %d\n", __func__, dai->name, dai->id); /* only capture for PDM */ @@ -586,7 +672,7 @@ static void aml_pdm_pcm_free(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; - pr_info("%s\n", __func__); + pr_debug("%s\n", __func__); substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; if (substream) { @@ -611,7 +697,7 @@ static struct snd_pcm_ops aml_pdm_ops = { static int aml_pdm_probe(struct snd_soc_platform *platform) { - pr_info("%s\n", __func__); + pr_debug("%s\n", __func__); return 0; } @@ -638,7 +724,6 @@ static int aml_pdm_dai_set_fmt( return 0; } - static int aml_pdm_dai_prepare( struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) @@ -652,6 +737,8 @@ static int aml_pdm_dai_prepare( && pm_audio_is_suspend()) return 0; + p_pdm->rate = runtime->rate; + /* set bclk */ bitwidth = snd_pcm_format_width(runtime->format); lsb = 32 - bitwidth; @@ -670,17 +757,16 @@ static int aml_pdm_dai_prepare( return -1; } - pr_info("%s rate:%d, bits:%d, channels:%d\n", + pr_debug("%s rate:%d, bits:%d, channels:%d\n", __func__, runtime->rate, bitwidth, runtime->channels); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { struct toddr *to = p_pdm->tddr; struct toddr_fmt fmt; - unsigned int osr = 192; + unsigned int osr = 192, filter_mode; struct pdm_info info; /* to ddr pdmin */ @@ -698,49 +784,27 @@ static int aml_pdm_dai_prepare( info.bitdepth = bitwidth; info.channels = runtime->channels; info.lane_masks = p_pdm->lane_mask_in; - info.dclk_idx = pdm_dclk; + info.dclk_idx = p_pdm->dclk_idx; info.bypass = p_pdm->bypass; + info.sample_count = pdm_get_sample_count(p_pdm->isLowPower, + p_pdm->dclk_idx); aml_pdm_ctrl(&info); + filter_mode = p_pdm->filter_mode; + /* filter for pdm */ - if (pdm_dclk == 1) { - if (runtime->rate == 16000) - osr = 64; - else if (runtime->rate == 8000) - osr = 128; - else { - pr_err("Not support rate:%d\n", runtime->rate); - return -EINVAL; - } - } else if (pdm_dclk == 2) { - if (runtime->rate == 16000) - osr = 48; - else if (runtime->rate == 8000) - osr = 96; - else { - pr_err("Not support rate:%d\n", runtime->rate); - return -EINVAL; - } - } else { - if (runtime->rate == 96000) - osr = 32; - else if (runtime->rate == 64000) - osr = 48; - else if (runtime->rate == 48000) - osr = 64; - else if (runtime->rate == 32000) - osr = 96; - else if (runtime->rate == 16000) - osr = 192; - else if (runtime->rate == 8000) - osr = 384; - else { - pr_err("Not support rate:%d\n", runtime->rate); - return -EINVAL; - } - } - p_pdm->filter_mode = s_pdm_filter_mode; - aml_pdm_filter_ctrl(osr, p_pdm->filter_mode); + osr = pdm_get_ors(p_pdm->dclk_idx, runtime->rate); + if (!osr) + return -EINVAL; + + pr_info("%s, pdm_dclk:%d, osr:%d, rate:%d filter mode:%d\n", + __func__, + pdm_dclkidx2rate(p_pdm->dclk_idx), + osr, + runtime->rate, + p_pdm->filter_mode); + + aml_pdm_filter_ctrl(osr, filter_mode); if (p_pdm->chipinfo && p_pdm->chipinfo->truncate_data) pdm_init_truncate_data(runtime->rate); @@ -755,7 +819,7 @@ static int aml_pdm_dai_trigger( { struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai); - pr_info("%s, cmd:%d\n", __func__, cmd); + pr_debug("%s\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -773,7 +837,7 @@ static int aml_pdm_dai_trigger( pdm_fifo_reset(); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - dev_info(substream->pcm->card->dev, "pdm capture start\n"); + dev_info(substream->pcm->card->dev, "PDM Capture start\n"); aml_toddr_enable(p_pdm->tddr, 1); pdm_enable(1); } @@ -820,37 +884,21 @@ static int aml_pdm_dai_set_sysclk(struct snd_soc_dai *cpu_dai, if (dclk_srcpll_freq == 0) clk_set_rate(p_pdm->dclk_srcpll, 24576000); - else - pr_info("pdm dclk_srcpll:%lu\n", - clk_get_rate(p_pdm->dclk_srcpll)); #endif - if (pdm_dclk == 1) - clk_set_rate(p_pdm->clk_pdm_dclk, 1024000); - else if (pdm_dclk == 2) - clk_set_rate(p_pdm->clk_pdm_dclk, 768000); - else - clk_set_rate(p_pdm->clk_pdm_dclk, 3072000); + clk_set_rate(p_pdm->clk_pdm_dclk, + pdm_dclkidx2rate(p_pdm->dclk_idx)); - pr_info("pdm pdm_sysclk:%lu clk_pdm_dclk:%lu\n", + pr_info("\n%s, pdm_sysclk:%lu pdm_dclk:%lu, dclk_srcpll:%lu\n", + __func__, clk_get_rate(p_pdm->clk_pdm_sysclk), - clk_get_rate(p_pdm->clk_pdm_dclk)); + clk_get_rate(p_pdm->clk_pdm_dclk), + clk_get_rate(p_pdm->dclk_srcpll)); return 0; } static int aml_pdm_dai_probe(struct snd_soc_dai *cpu_dai) { - int ret = 0; - - ret = snd_soc_add_dai_controls(cpu_dai, snd_pdm_controls, - ARRAY_SIZE(snd_pdm_controls)); - if (ret < 0) { - pr_err("%s, failed add snd pdm controls\n", __func__); - return ret; - } - - pr_info("%s\n", __func__); - return 0; } @@ -919,6 +967,7 @@ void aml_pdm_dai_shutdown(struct snd_pcm_substream *substream, #endif p_pdm->clk_on = false; + p_pdm->rate = 0; /* disable clock and gate */ clk_disable_unprepare(p_pdm->clk_pdm_dclk); @@ -955,6 +1004,8 @@ EXPORT_SYMBOL_GPL(aml_pdm_dai); static const struct snd_soc_component_driver aml_pdm_component = { .name = DRV_NAME, + .controls = snd_pdm_controls, + .num_controls = ARRAY_SIZE(snd_pdm_controls), }; static int snd_soc_of_get_slot_mask( @@ -1094,9 +1145,6 @@ static int aml_pdm_platform_probe(struct platform_device *pdev) /* defulat set 1 */ p_pdm->filter_mode = 1; } - s_pdm_filter_mode = p_pdm->filter_mode; - pr_info("%s pdm filter mode from dts:%d\n", - __func__, p_pdm->filter_mode); p_pdm->dev = dev; dev_set_drvdata(&pdev->dev, p_pdm); @@ -1126,10 +1174,10 @@ err: static int aml_pdm_platform_remove(struct platform_device *pdev) { - struct aml_pdm *pdm_priv = dev_get_drvdata(&pdev->dev); + struct aml_pdm *p_pdm = dev_get_drvdata(&pdev->dev); - clk_disable_unprepare(pdm_priv->sysclk_srcpll); - clk_disable_unprepare(pdm_priv->clk_pdm_dclk); + clk_disable_unprepare(p_pdm->sysclk_srcpll); + clk_disable_unprepare(p_pdm->clk_pdm_dclk); snd_soc_unregister_component(&pdev->dev); diff --git a/sound/soc/amlogic/auge/pdm.h b/sound/soc/amlogic/auge/pdm.h index 39bf6ab11efb..877a2fb3eeab 100644 --- a/sound/soc/amlogic/auge/pdm.h +++ b/sound/soc/amlogic/auge/pdm.h @@ -30,7 +30,6 @@ /* 8ch pdm in, 8 ch tdmin_lb */ #define PDM_CHANNELS_LB_MAX (PDM_CHANNELS_MAX + 8) - #define PDM_RATES (SNDRV_PCM_RATE_96000 |\ SNDRV_PCM_RATE_64000 |\ SNDRV_PCM_RATE_48000 |\ @@ -70,6 +69,8 @@ struct aml_pdm { struct clk *clk_pdm_sysclk; struct clk *clk_pdm_dclk; struct toddr *tddr; + /* sample rate */ + int rate; /* * filter mode:0~4, * from mode 0 to 4, the performance is from high to low, @@ -90,6 +91,9 @@ struct aml_pdm { /* train */ bool train_en; + /* low power mode, for dclk_sycpll to 24m */ + bool isLowPower; + struct pdm_chipinfo *chipinfo; struct snd_kcontrol *controls[PDM_RUN_MAX]; }; diff --git a/sound/soc/amlogic/auge/pdm_hw.c b/sound/soc/amlogic/auge/pdm_hw.c index 49841f4b5ed6..617a07bd9bc6 100644 --- a/sound/soc/amlogic/auge/pdm_hw.c +++ b/sound/soc/amlogic/auge/pdm_hw.c @@ -70,22 +70,28 @@ void pdm_fifo_reset(void) 0x1 << 16); } +void pdm_set_channel_ctrl(int sample_count) +{ + aml_pdm_write(PDM_CHAN_CTRL, ((sample_count << 24) | + (sample_count << 16) | + (sample_count << 8) | + (sample_count << 0) + )); + aml_pdm_write(PDM_CHAN_CTRL1, ((sample_count << 24) | + (sample_count << 16) | + (sample_count << 8) | + (sample_count << 0) + )); +} + void aml_pdm_ctrl(struct pdm_info *info) { - int mode, i, ch_mask = 0, sample_count; + int mode, i, ch_mask = 0; int pdm_chs, lane_chs = 0; if (!info) return; - /* sameple count */ - if (info->dclk_idx == 1) - sample_count = 38; - else if (info->dclk_idx == 2) - sample_count = 48; - else - sample_count = 18; - if (info->bitdepth == 32) mode = 0; else @@ -124,7 +130,6 @@ void aml_pdm_ctrl(struct pdm_info *info) /* must be sure that clk and pdm is enable */ aml_pdm_update_bits(PDM_CTRL, (0x7 << 28 | 0xff << 8 | 0xff << 0), - /*(1 << 31) |*/ /* invert the PDM_DCLK or not */ (0 << 30) | /* output mode: 1: 24bits. 0: 32 bits */ @@ -139,16 +144,7 @@ void aml_pdm_ctrl(struct pdm_info *info) (ch_mask << 0) ); - aml_pdm_write(PDM_CHAN_CTRL, ((sample_count << 24) | - (sample_count << 16) | - (sample_count << 8) | - (sample_count << 0) - )); - aml_pdm_write(PDM_CHAN_CTRL1, ((sample_count << 24) | - (sample_count << 16) | - (sample_count << 8) | - (sample_count << 0) - )); + pdm_set_channel_ctrl(info->sample_count); } void aml_pdm_arb_config(struct aml_audio_controller *actrl) @@ -351,9 +347,6 @@ void aml_pdm_filter_ctrl(int osr, int mode) int lpf1_len, lpf2_len, lpf3_len; const int *lpf1_coeff, *lpf2_coeff, *lpf3_coeff; - pr_info("%s, osr:%d, mode:%d\n", - __func__, osr, mode); - /* select LPF coefficent * For filter 1 and filter 3, * it's only relative with coefficent mode @@ -489,6 +482,11 @@ void pdm_set_mute_channel(int mute_chmask) (mute_chmask << 20 | mute_en << 17)); } +void pdm_set_bypass_data(bool bypass) +{ + aml_pdm_update_bits(PDM_CTRL, 0x1 << 28, bypass << 28); +} + void pdm_init_truncate_data(int freq) { int mask_val; @@ -519,3 +517,71 @@ int pdm_train_sts(void) return ((val >> 4) & 0xff); } + +int pdm_dclkidx2rate(int idx) +{ + int rate; + + if (idx == 2) + rate = 768000; + else if (idx == 1) + rate = 1024000; + else + rate = 3072000; + + return rate; +} + +int pdm_get_sample_count(int isLowPower, int dclk_idx) +{ + int count = 0; + + if (isLowPower) + count = 0; + else if (dclk_idx == 1) + count = 38; + else if (dclk_idx == 2) + count = 48; + else + count = 18; + + return count; +} + +int pdm_get_ors(int dclk_idx, int sample_rate) +{ + int osr = 0; + + if (dclk_idx == 1) { + if (sample_rate == 16000) + osr = 64; + else if (sample_rate == 8000) + osr = 128; + else + pr_err("Not support rate:%d\n", sample_rate); + } else if (dclk_idx == 2) { + if (sample_rate == 16000) + osr = 48; + else if (sample_rate == 8000) + osr = 96; + else + pr_err("Not support rate:%d\n", sample_rate); + } else { + if (sample_rate == 96000) + osr = 32; + else if (sample_rate == 64000) + osr = 48; + else if (sample_rate == 48000) + osr = 64; + else if (sample_rate == 32000) + osr = 96; + else if (sample_rate == 16000) + osr = 192; + else if (sample_rate == 8000) + osr = 384; + else + pr_err("Not support rate:%d\n", sample_rate); + } + + return osr; +} diff --git a/sound/soc/amlogic/auge/pdm_hw.h b/sound/soc/amlogic/auge/pdm_hw.h index b1d8424e8e7a..893e0a07627d 100644 --- a/sound/soc/amlogic/auge/pdm_hw.h +++ b/sound/soc/amlogic/auge/pdm_hw.h @@ -29,6 +29,7 @@ struct pdm_info { int dclk_idx; /* mapping for dclk value */ int bypass; /* bypass all filter, capture raw data */ + int sample_count; }; extern void aml_pdm_ctrl(struct pdm_info *info); @@ -47,14 +48,20 @@ extern int pdm_get_mute_value(void); extern void pdm_set_mute_value(int val); extern int pdm_get_mute_channel(void); extern void pdm_set_mute_channel(int mute_chmask); - +extern void pdm_set_bypass_data(bool bypass); extern void pdm_init_truncate_data(int freq); +extern void pdm_train_en(bool en); +extern void pdm_train_clr(void); +extern int pdm_train_sts(void); + +extern int pdm_dclkidx2rate(int idx); +extern int pdm_get_sample_count(int isLowPower, int dclk_idx); +extern int pdm_get_ors(int dclk_idx, int sample_rate); extern void pdm_train_en(bool en); extern void pdm_train_clr(void); extern int pdm_train_sts(void); extern int pdm_hcic_shift_gain; -extern int pdm_dclk; #endif /*__AML_PDM_HW_H__*/ diff --git a/sound/soc/amlogic/auge/regs.h b/sound/soc/amlogic/auge/regs.h index 2a97ec10431b..c6ae28f443ca 100644 --- a/sound/soc/amlogic/auge/regs.h +++ b/sound/soc/amlogic/auge/regs.h @@ -197,16 +197,41 @@ enum clk_sel { #define EE_AUDIO_ARB_CTRL 0x0a0 /* - * AUDIO TDM + * AUDIO LOOPBACK */ #define EE_AUDIO_LB_CTRL0 0x0b0 -#define EE_AUDIO_LB_CTRL1 0x0b1 -#define EE_AUDIO_DAT_ID0 0x0b2 -#define EE_AUDIO_DAT_ID1 0x0b3 -#define EE_AUDIO_LB_ID0 0x0b4 -#define EE_AUDIO_LB_ID1 0x0b5 -#define EE_AUDIO_LB_STS 0x0b6 +#define EE_AUDIO_LB_A_CTRL0 0xb0 +#define EE_AUDIO_LB_A_CTRL1 0xb1 +#define EE_AUDIO_LB_A_CTRL2 0xb2 +#define EE_AUDIO_LB_A_CTRL3 0xb3 +#define EE_AUDIO_LB_A_DAT_CH_ID0 0xb4 +#define EE_AUDIO_LB_A_DAT_CH_ID1 0xb5 +#define EE_AUDIO_LB_A_DAT_CH_ID2 0xb6 +#define EE_AUDIO_LB_A_DAT_CH_ID3 0xb7 +#define EE_AUDIO_LB_A_LB_CH_ID0 0xb8 +#define EE_AUDIO_LB_A_LB_CH_ID1 0xb9 +#define EE_AUDIO_LB_A_LB_CH_ID2 0xba +#define EE_AUDIO_LB_A_LB_CH_ID3 0xbb +#define EE_AUDIO_LB_A_STS 0xbc + +#define EE_AUDIO_LB_B_CTRL0 0x230 +#define EE_AUDIO_LB_B_CTRL1 0x231 +#define EE_AUDIO_LB_B_CTRL2 0x232 +#define EE_AUDIO_LB_B_CTRL3 0x233 +#define EE_AUDIO_LB_B_DAT_CH_ID0 0x234 +#define EE_AUDIO_LB_B_DAT_CH_ID1 0x235 +#define EE_AUDIO_LB_B_DAT_CH_ID2 0x236 +#define EE_AUDIO_LB_B_DAT_CH_ID3 0x237 +#define EE_AUDIO_LB_B_LB_CH_ID0 0x238 +#define EE_AUDIO_LB_B_LB_CH_ID1 0x239 +#define EE_AUDIO_LB_B_LB_CH_ID2 0x23a +#define EE_AUDIO_LB_B_LB_CH_ID3 0x23b +#define EE_AUDIO_LB_B_STS 0x23c + +/* + * AUDIO TDM + */ #define EE_AUDIO_TDMIN_A_CTRL 0x0c0 #define EE_AUDIO_TDMIN_A_SWAP0 0x0c1 #define EE_AUDIO_TDMIN_A_SWAP1 0x260 @@ -544,20 +569,6 @@ enum clk_sel { #define EE_AUDIO_FRDDR_D_INIT_ADDR 0x229 #define EE_AUDIO_FRDDR_D_CTRL2 0x22a -#define EE_AUDIO_LB_B_CTRL0 0x230 -#define EE_AUDIO_LB_B_CTRL1 0x231 -#define EE_AUDIO_LB_B_CTRL2 0x232 -#define EE_AUDIO_LB_B_CTRL3 0x233 -#define EE_AUDIO_LB_B_DAT_CH_ID0 0x234 -#define EE_AUDIO_LB_B_DAT_CH_ID1 0x235 -#define EE_AUDIO_LB_B_DAT_CH_ID2 0x236 -#define EE_AUDIO_LB_B_DAT_CH_ID3 0x237 -#define EE_AUDIO_LB_B_LB_CH_ID0 0x238 -#define EE_AUDIO_LB_B_LB_CH_ID1 0x239 -#define EE_AUDIO_LB_B_LB_CH_ID2 0x23a -#define EE_AUDIO_LB_B_LB_CH_ID3 0x23b -#define EE_AUDIO_LB_B_STS 0x23c - /* * AUDIO LOCKER */ diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c index ab6523a39b42..e4e42fbd9647 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -36,7 +36,6 @@ #include "ddr_mngr.h" #include "spdif_hw.h" #include "spdif_match_table.c" -#include "audio_utils.h" #include "resample.h" #include "resample_hw.h" @@ -1163,50 +1162,30 @@ static int aml_dai_spdif_prepare( struct toddr_fmt fmt; unsigned int msb, lsb, toddr_type; - if (loopback_is_enable()) { - switch (bit_depth) { - case 8: - case 16: - case 32: - toddr_type = 0; - break; - case 24: - toddr_type = 4; - break; - default: - pr_err( - "runtime format invalid bit_depth: %d\n", - bit_depth); - return -EINVAL; - } - msb = 32 - 1; - lsb = 32 - bit_depth; - } else { - switch (bit_depth) { - case 8: - case 16: - toddr_type = 0; - break; - case 24: - toddr_type = 4; - break; - case 32: - toddr_type = 3; - break; - default: - dev_err(p_spdif->dev, - "runtime format invalid bit_depth: %d\n", - bit_depth); - return -EINVAL; - } - - msb = 28 - 1; - if (bit_depth <= 24) - lsb = 28 - bit_depth; - else - lsb = 4; + switch (bit_depth) { + case 8: + case 16: + toddr_type = 0; + break; + case 24: + toddr_type = 4; + break; + case 32: + toddr_type = 3; + break; + default: + dev_err(p_spdif->dev, + "runtime format invalid bit_depth: %d\n", + bit_depth); + return -EINVAL; } + msb = 28 - 1; + if (bit_depth <= 24) + lsb = 28 - bit_depth; + else + lsb = 4; + // to ddr spdifin fmt.type = toddr_type; fmt.msb = msb; diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index 5bf2933b4bea..4ebe2de7a735 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -107,6 +107,9 @@ struct aml_tdm { bool en_share; unsigned int lane_cnt; + + /* tdmin_lb src sel */ + int tdmin_lb_src; }; static const struct snd_pcm_hardware aml_tdm_hardware = { @@ -537,6 +540,9 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream, case 2: src = TDMIN_C; break; + case 3: + src = TDMIN_LB; + break; default: dev_err(p_tdm->dev, "invalid id: %d\n", p_tdm->id); @@ -935,7 +941,7 @@ static int aml_dai_tdm_hw_free(struct snd_pcm_substream *substream, struct frddr *fr = p_tdm->fddr; int i; - for (i = 0; i < 4; i++) + for (i = 0; i < p_tdm->lane_cnt; i++) aml_tdm_set_channel_mask(p_tdm->actrl, substream->stream, p_tdm->id, i, 0); @@ -1178,20 +1184,15 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, oe_val = p_tdm->setting.lane_oe_mask_out; } - if (lanes_lb_cnt) { - in_src = p_tdm->id + 6; - if (in_src > 7) { - pr_err("unknown src(%d) for tdmin\n", in_src); - return -EINVAL; - } - } + if (lanes_lb_cnt) + in_src = p_tdm->tdmin_lb_src; if (lanes_oe_in_cnt) in_src = p_tdm->id + 3; if (lanes_in_cnt) in_src = p_tdm->id; } else { if (lanes_lb_cnt) - in_src = p_tdm->id + 3; + in_src = p_tdm->tdmin_lb_src; if (lanes_in_cnt && lanes_in_cnt <= 4) in_src = p_tdm->id; if (in_src > 5) { @@ -1310,69 +1311,85 @@ static struct snd_soc_dai_ops aml_dai_tdm_ops = { static struct snd_soc_dai_driver aml_tdm_dai[] = { { - .name = "TDM-A", - .id = 1, - .probe = aml_dai_tdm_probe, - .remove = aml_dai_tdm_remove, - .playback = { - .channels_min = 1, - .channels_max = 32, - .rates = AML_DAI_TDM_RATES, - .formats = AML_DAI_TDM_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - .rates = AML_DAI_TDM_RATES, - .formats = AML_DAI_TDM_FORMATS, - }, - .ops = &aml_dai_tdm_ops, - .symmetric_rates = 1, + .name = "TDM-A", + .id = 1, + .probe = aml_dai_tdm_probe, + .remove = aml_dai_tdm_remove, + .playback = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .ops = &aml_dai_tdm_ops, + .symmetric_rates = 1, }, { - .name = "TDM-B", - .id = 2, - .probe = aml_dai_tdm_probe, - .remove = aml_dai_tdm_remove, - .playback = { - .channels_min = 1, - .channels_max = 32, - .rates = AML_DAI_TDM_RATES, - .formats = AML_DAI_TDM_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - .rates = AML_DAI_TDM_RATES, - .formats = AML_DAI_TDM_FORMATS, - }, - .ops = &aml_dai_tdm_ops, - .symmetric_rates = 1, + + .name = "TDM-B", + .id = 2, + .probe = aml_dai_tdm_probe, + .remove = aml_dai_tdm_remove, + .playback = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .ops = &aml_dai_tdm_ops, + .symmetric_rates = 1, }, { - .name = "TDM-C", - .id = 3, - .probe = aml_dai_tdm_probe, - .remove = aml_dai_tdm_remove, - .playback = { - .channels_min = 1, - .channels_max = 32, - .rates = AML_DAI_TDM_RATES, - .formats = AML_DAI_TDM_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - .rates = AML_DAI_TDM_RATES, - .formats = AML_DAI_TDM_FORMATS, - }, - .ops = &aml_dai_tdm_ops, - .symmetric_rates = 1, + .name = "TDM-C", + .id = 3, + .probe = aml_dai_tdm_probe, + .remove = aml_dai_tdm_remove, + .playback = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .ops = &aml_dai_tdm_ops, + .symmetric_rates = 1, }, + { + .name = "TDMIN-LB", + .id = 4, + .probe = aml_dai_tdm_probe, + .remove = aml_dai_tdm_remove, + + .capture = { + .channels_min = 1, + .channels_max = 32, + .rates = AML_DAI_TDM_RATES, + .formats = AML_DAI_TDM_FORMATS, + }, + .ops = &aml_dai_tdm_ops, + .symmetric_rates = 1, + } }; static const struct snd_soc_component_driver aml_tdm_component = { - .name = DRV_NAME, + .name = DRV_NAME, }; static int check_channel_mask(const char *str) @@ -1520,9 +1537,23 @@ static int aml_tdm_platform_probe(struct platform_device *pdev) &p_tdm->i2s2hdmitx); if (ret < 0) p_tdm->i2s2hdmitx = 0; - pr_info("TDM id %d i2s2hdmi:%d\n", - p_tdm->id, - p_tdm->i2s2hdmitx); + else + pr_info("TDM id %d i2s2hdmi:%d\n", + p_tdm->id, + p_tdm->i2s2hdmitx); + + if (p_tdm->id == TDM_LB) { + ret = of_property_read_u32(node, "lb-src-sel", + &p_tdm->tdmin_lb_src); + if (ret < 0 || (p_tdm->tdmin_lb_src > 7)) { + dev_err(&pdev->dev, "invalid lb-src-sel:%d\n", + p_tdm->tdmin_lb_src); + return -EINVAL; + } + pr_info("TDM id %d lb-src-sel:%d\n", + p_tdm->id, + p_tdm->tdmin_lb_src); + } /* get tdm lanes info. if not, set to default 0 */ ret = of_parse_tdm_lane_slot_in(node, @@ -1594,6 +1625,12 @@ static int aml_tdm_platform_probe(struct platform_device *pdev) /*set default clk for output*/ aml_set_default_tdm_clk(p_tdm); + /* mclk pad ctrl */ + ret = of_property_read_u32(node, "mclk_pad", + &p_tdm->mclk_pad); + if (ret < 0) + p_tdm->mclk_pad = -1; /* not use mclk in defalut. */ + p_tdm->dev = dev; /* For debug to disable share buffer */ p_tdm->en_share = 1; diff --git a/sound/soc/amlogic/auge/tdm_hw.h b/sound/soc/amlogic/auge/tdm_hw.h index b47bf1e7c793..bb9b9bd51079 100644 --- a/sound/soc/amlogic/auge/tdm_hw.h +++ b/sound/soc/amlogic/auge/tdm_hw.h @@ -24,6 +24,7 @@ #define TDM_A 0 #define TDM_B 1 #define TDM_C 2 +#define TDM_LB 3 #define LANE_MAX0 2 #define LANE_MAX1 4 diff --git a/sound/soc/amlogic/auge/tdm_match_table.c b/sound/soc/amlogic/auge/tdm_match_table.c index 4fb318c38857..7b45f00420b4 100644 --- a/sound/soc/amlogic/auge/tdm_match_table.c +++ b/sound/soc/amlogic/auge/tdm_match_table.c @@ -60,6 +60,11 @@ struct tdm_chipinfo axg_tdmc_chipinfo = { .no_mclkpad_ctrl = true, }; +struct tdm_chipinfo axg_tdminlb_chipinfo = { + .id = TDM_LB, + .no_mclkpad_ctrl = true, +}; + struct tdm_chipinfo g12a_tdma_chipinfo = { .id = TDM_A, .sclk_ws_inv = true, @@ -84,6 +89,14 @@ struct tdm_chipinfo g12a_tdmc_chipinfo = { .mclkpad_no_offset = true, }; +struct tdm_chipinfo g12a_tdminlb_chipinfo = { + .id = TDM_LB, + .sclk_ws_inv = true, + .oe_fn = true, + .same_src_fn = true, + .mclkpad_no_offset = true, +}; + struct tdm_chipinfo tl1_tdma_chipinfo = { .id = TDM_A, .sclk_ws_inv = true, @@ -108,6 +121,14 @@ struct tdm_chipinfo tl1_tdmc_chipinfo = { .adc_fn = true, }; +struct tdm_chipinfo tl1_tdminlb_chipinfo = { + .id = TDM_LB, + .sclk_ws_inv = true, + .oe_fn = true, + .same_src_fn = true, + .adc_fn = true, +}; + struct tdm_chipinfo sm1_tdma_chipinfo = { .id = TDM_A, .sclk_ws_inv = true, @@ -132,6 +153,14 @@ struct tdm_chipinfo sm1_tdmc_chipinfo = { .lane_cnt = LANE_MAX1, }; +struct tdm_chipinfo sm1_tdminlb_chipinfo = { + .id = TDM_LB, + .sclk_ws_inv = true, + .oe_fn = true, + .same_src_fn = true, + .lane_cnt = LANE_MAX3, +}; + struct tdm_chipinfo tm2_tdma_chipinfo = { .id = TDM_A, .sclk_ws_inv = true, @@ -159,6 +188,14 @@ struct tdm_chipinfo tm2_tdmc_chipinfo = { .lane_cnt = LANE_MAX1, }; +struct tdm_chipinfo tm2_tdminlb_chipinfo = { + .id = TDM_LB, + .sclk_ws_inv = true, + .oe_fn = true, + .same_src_fn = true, + .lane_cnt = LANE_MAX3, +}; + static const struct of_device_id aml_tdm_device_id[] = { { .compatible = "amlogic, axg-snd-tdma", @@ -172,6 +209,10 @@ static const struct of_device_id aml_tdm_device_id[] = { .compatible = "amlogic, axg-snd-tdmc", .data = &axg_tdmc_chipinfo, }, + { + .compatible = "amlogic, axg-snd-tdmlb", + .data = &axg_tdminlb_chipinfo, + }, { .compatible = "amlogic, g12a-snd-tdma", .data = &g12a_tdma_chipinfo, @@ -184,6 +225,10 @@ static const struct of_device_id aml_tdm_device_id[] = { .compatible = "amlogic, g12a-snd-tdmc", .data = &g12a_tdmc_chipinfo, }, + { + .compatible = "amlogic, g12a-snd-tdmlb", + .data = &g12a_tdminlb_chipinfo, + }, { .compatible = "amlogic, tl1-snd-tdma", .data = &tl1_tdma_chipinfo, @@ -196,29 +241,41 @@ static const struct of_device_id aml_tdm_device_id[] = { .compatible = "amlogic, tl1-snd-tdmc", .data = &tl1_tdmc_chipinfo, }, + { + .compatible = "amlogic, tl1-snd-tdmlb", + .data = &tl1_tdminlb_chipinfo, + }, { .compatible = "amlogic, sm1-snd-tdma", - .data = &sm1_tdma_chipinfo, + .data = &sm1_tdma_chipinfo, }, { .compatible = "amlogic, sm1-snd-tdmb", - .data = &sm1_tdmb_chipinfo, + .data = &sm1_tdmb_chipinfo, }, { .compatible = "amlogic, sm1-snd-tdmc", - .data = &sm1_tdmc_chipinfo, + .data = &sm1_tdmc_chipinfo, + }, + { + .compatible = "amlogic, sm1-snd-tdmlb", + .data = &sm1_tdminlb_chipinfo, }, { .compatible = "amlogic, tm2-snd-tdma", - .data = &tm2_tdma_chipinfo, + .data = &tm2_tdma_chipinfo, }, { .compatible = "amlogic, tm2-snd-tdmb", - .data = &tm2_tdmb_chipinfo, + .data = &tm2_tdmb_chipinfo, }, { .compatible = "amlogic, tm2-snd-tdmc", - .data = &tm2_tdmc_chipinfo, + .data = &tm2_tdmc_chipinfo, + }, + { + .compatible = "amlogic, tm2-snd-tdmlb", + .data = &tm2_tdminlb_chipinfo, }, {}, }; diff --git a/sound/soc/codecs/amlogic/ad82584f.c b/sound/soc/codecs/amlogic/ad82584f.c index 52954182268f..f76a2f9c07f6 100644 --- a/sound/soc/codecs/amlogic/ad82584f.c +++ b/sound/soc/codecs/amlogic/ad82584f.c @@ -34,18 +34,19 @@ static void ad82584f_early_suspend(struct early_suspend *h); static void ad82584f_late_resume(struct early_suspend *h); #endif -#define AD82584F_RATES (SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_64000 | \ - SNDRV_PCM_RATE_88200 | \ - SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_176400 | \ - SNDRV_PCM_RATE_192000) +#define AD82584F_RATES (SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) #define AD82584F_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static const DECLARE_TLV_DB_SCALE(mvol_tlv, -10300, 50, 1); static const DECLARE_TLV_DB_SCALE(chvol_tlv, -10300, 50, 1);