From: Xing Wang Date: Tue, 3 Apr 2018 06:03:41 +0000 (+0800) Subject: audio: auge: fix spdif in & out work at the same time for ASRC X-Git-Tag: khadas-vims-v0.9.6-release~1334 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bf64bfb4f2b0e28fac85cdd4c7a5995b06362001;p=platform%2Fkernel%2Flinux-amlogic.git audio: auge: fix spdif in & out work at the same time for ASRC PD#163795: audio: auge: fix spdif in & out work at the same time for ASRC 1. fix spdifin toddr as right_j for asrc, not support asrc 32bit now 2. fix clk dir for set_sysclk 3. auto enable/disable asrc when switch raw data and pcm data source 4. fix lr channel swap when replug in 5. detect spdifin sample mode by max_width 6. force to clear spdif in sample rate irq bit for axg 7. enable spdif in for s420 boards Change-Id: I83dc211815068b9d073fb20433c76ce9f129b40e Signed-off-by: Xing Wang --- diff --git a/arch/arm64/boot/dts/amlogic/axg_s400.dts b/arch/arm64/boot/dts/amlogic/axg_s400.dts index 49cfcf9..4c8de29 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400.dts @@ -1158,6 +1158,20 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; status = "okay"; }; aml_pdm: pdm { @@ -1242,7 +1256,7 @@ * TDMIN_LB, * LOOPBACK, */ - resample_module = <4>; + resample_module = <3>; status = "okay"; }; aml_pwrdet: pwrdet { @@ -1266,7 +1280,7 @@ hi_th = <0x70000>; lo_th = <0x16000>; - status = "okay"; + status = "disabled"; }; }; /* end of audiobus */ diff --git a/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts index 69a0f26..5625611 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts @@ -1139,6 +1139,20 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; status = "okay"; }; aml_pdm: pdm { @@ -1206,6 +1220,49 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; + aml_pwrdet: pwrdet { + compatible = "amlogic, axg-power-detect"; + + interrupts = ; + interrupt-names = "pwrdet_irq"; + + /* pwrdet source sel + * 7: loopback; + * 6: tdmin_lb; + * 5: reserved; + * 4: pdmin; + * 3: spdifin; + * 2: tdmin_c; + * 1: tdmin_b; + * 0: tdmin_a; + */ + pwrdet_src = <4>; + + hi_th = <0x70000>; + lo_th = <0x16000>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts b/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts index 77de81d..d414c3d 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts @@ -1016,6 +1016,20 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; status = "okay"; }; aml_pdm: pdm { @@ -1080,6 +1094,49 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; + aml_pwrdet: pwrdet { + compatible = "amlogic, axg-power-detect"; + + interrupts = ; + interrupt-names = "pwrdet_irq"; + + /* pwrdet source sel + * 7: loopback; + * 6: tdmin_lb; + * 5: reserved; + * 4: pdmin; + * 3: spdifin; + * 2: tdmin_c; + * 1: tdmin_b; + * 0: tdmin_a; + */ + pwrdet_src = <4>; + + hi_th = <0x70000>; + lo_th = <0x16000>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts b/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts index 6d88311..9feeb07 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts @@ -1060,6 +1060,20 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; status = "okay"; }; aml_pdm: pdm { @@ -1124,6 +1138,49 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; + aml_pwrdet: pwrdet { + compatible = "amlogic, axg-power-detect"; + + interrupts = ; + interrupt-names = "pwrdet_irq"; + + /* pwrdet source sel + * 7: loopback; + * 6: tdmin_lb; + * 5: reserved; + * 4: pdmin; + * 3: spdifin; + * 2: tdmin_c; + * 1: tdmin_b; + * 0: tdmin_a; + */ + pwrdet_src = <4>; + + hi_th = <0x70000>; + lo_th = <0x16000>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts index 16829a0..aba276d 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts @@ -1026,6 +1026,20 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; status = "okay"; }; aml_pdm: pdm { @@ -1090,6 +1104,49 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; + aml_pwrdet: pwrdet { + compatible = "amlogic, axg-power-detect"; + + interrupts = ; + interrupt-names = "pwrdet_irq"; + + /* pwrdet source sel + * 7: loopback; + * 6: tdmin_lb; + * 5: reserved; + * 4: pdmin; + * 3: spdifin; + * 2: tdmin_c; + * 1: tdmin_b; + * 0: tdmin_a; + */ + pwrdet_src = <4>; + + hi_th = <0x70000>; + lo_th = <0x16000>; + + status = "disabled"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/axg_s420.dts b/arch/arm64/boot/dts/amlogic/axg_s420.dts index 5d4c021..e9470de 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420.dts @@ -434,16 +434,15 @@ }; }; - /*aml-audio-card,dai-link@4 { - * mclk-fs = <128>; - * cpu { - * sound-dai = <&aml_spdif>; - * }; - * codec { - * sound-dai = <&dummy_codec>; - * }; - *}; - */ + aml-audio-card,dai-link@4 { + mclk-fs = <128>; + cpu { + sound-dai = <&aml_spdif>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; bt-dev{ @@ -955,7 +954,21 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; - status = "disabled"; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; + status = "okay"; }; aml_pdm: pdm { @@ -1020,6 +1033,26 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts b/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts index fc52b5e..c47a2bc 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts @@ -425,16 +425,15 @@ }; }; - /*aml-audio-card,dai-link@4 { - * mclk-fs = <128>; - * cpu { - * sound-dai = <&aml_spdif>; - * }; - * codec { - * sound-dai = <&dummy_codec>; - * }; - *}; - */ + aml-audio-card,dai-link@4 { + mclk-fs = <128>; + cpu { + sound-dai = <&aml_spdif>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; bt-dev{ @@ -822,7 +821,21 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; - status = "disabled"; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; + status = "okay"; }; aml_pdm: pdm { @@ -886,6 +899,26 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts index 8e302b6..02eae18 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts @@ -437,16 +437,15 @@ }; }; - /*aml-audio-card,dai-link@4 { - * mclk-fs = <128>; - * cpu { - * sound-dai = <&aml_spdif>; - * }; - * codec { - * sound-dai = <&dummy_codec>; - * }; - *}; - */ + aml-audio-card,dai-link@4 { + mclk-fs = <128>; + cpu { + sound-dai = <&aml_spdif>; + }; + codec { + sound-dai = <&dummy_codec>; + }; + }; }; bt-dev{ @@ -960,7 +959,21 @@ interrupt-names = "irq_spdifin"; pinctrl-names = "spdif_pins"; pinctrl-0 = <&spdifout &spdifin>; - status = "disabled"; + + /* + * whether do asrc for pcm. + * if raw data, asrc is disabled automatically + * 0: "Disable", + * 1: "Enable:32K", + * 2: "Enable:44K", + * 3: "Enable:48K", + * 4: "Enable:88K", + * 5: "Enable:96K", + * 6: "Enable:176K", + * 7: "Enable:192K", + */ + auto_asrc = <0>; + status = "okay"; }; aml_pdm: pdm { @@ -1026,6 +1039,26 @@ status = "okay"; }; + + audioresample: resample { + compatible = "amlogic, axg-resample"; + clocks = <&clkc CLKID_MPLL3 + &clkaudio CLKID_AUDIO_MCLK_F + &clkaudio CLKID_AUDIO_RESAMPLE_CTRL>; + clock-names = "resample_pll", "resample_src", "resample_clk"; + /*same with toddr_src + * TDMIN_A, + * TDMIN_B, + * TDMIN_C, + * SPDIFIN, + * PDMIN, + * NONE, + * TDMIN_LB, + * LOOPBACK, + */ + resample_module = <3>; + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/sound/soc/amlogic/auge/card.c b/sound/soc/amlogic/auge/card.c index 863f789..f916cd6 100644 --- a/sound/soc/amlogic/auge/card.c +++ b/sound/soc/amlogic/auge/card.c @@ -433,6 +433,12 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream, aml_priv_to_props(priv, rtd->num); unsigned int mclk = 0, mclk_fs = 0; int i = 0, ret = 0; + int clk_dir = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + clk_dir = SND_SOC_CLOCK_OUT; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + clk_dir = SND_SOC_CLOCK_IN; if (priv->mclk_fs) mclk_fs = priv->mclk_fs; @@ -444,16 +450,15 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream, for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); + clk_dir); if (ret && ret != -ENOTSUPP) goto err; } ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, - SND_SOC_CLOCK_OUT); + clk_dir); if (ret && ret != -ENOTSUPP) goto err; diff --git a/sound/soc/amlogic/auge/ddr_mngr.c b/sound/soc/amlogic/auge/ddr_mngr.c index dc0159a..3410ed8 100644 --- a/sound/soc/amlogic/auge/ddr_mngr.c +++ b/sound/soc/amlogic/auge/ddr_mngr.c @@ -74,8 +74,9 @@ struct toddr { unsigned int msb_bit; unsigned int lsb_bit; unsigned int reg_base; - unsigned int channels; unsigned int bitdepth; + unsigned int channels; + unsigned int rate; enum toddr_src src; unsigned int fifo_id; @@ -129,14 +130,17 @@ static struct toddr toddrs[DDRMAX]; /* resample */ static struct toddr_attach attach_resample; static void aml_check_resample(bool enable); +static bool aml_check_resample_module(int src); /* power detect */ static struct toddr_attach attach_pwrdet; static void aml_check_pwrdet(bool enable); +static bool aml_check_pwrdet_module(int src); /* Audio EQ DRC */ static struct frddr_attach attach_aed; static void aml_check_aed(bool enable, int dst); +static bool aml_check_aed_module(int dst); /* to DDRS */ static struct toddr *register_toddr_l(struct device *dev, @@ -341,10 +345,15 @@ void aml_toddr_enable(struct toddr *to, bool enable) aml_audiobus_update_bits(actrl, reg, 1<<31, enable<<31); /* check resample */ - aml_check_resample(enable); + if (aml_check_resample_module(to->src)) + aml_check_resample(enable); /* check power detect */ - aml_check_pwrdet(enable); + if (aml_check_pwrdet_module(to->src)) + aml_check_pwrdet(enable); + + if (!enable) + aml_audiobus_write(actrl, reg, 0x0); } void aml_toddr_select_src(struct toddr *to, enum toddr_src src) @@ -377,84 +386,170 @@ void aml_toddr_set_fifos(struct toddr *to, unsigned int thresh) aml_audiobus_write(actrl, reg, (thresh-1)<<16|2<<8); } -void aml_toddr_set_format(struct toddr *to, - unsigned int type, unsigned int msb, unsigned int lsb, - int ch_num, int bit_depth) +void aml_toddr_set_format(struct toddr *to, struct toddr_fmt *fmt) { struct aml_audio_controller *actrl = to->actrl; unsigned int reg_base = to->reg_base; unsigned int reg; - to->channels = ch_num; - to->bitdepth = bit_depth; + to->bitdepth = fmt->bit_depth; + to->channels = fmt->ch_num; + to->rate = fmt->rate; reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base); - aml_audiobus_update_bits(actrl, reg, 0x1fff<<3, - type<<13|msb<<8|lsb<<3); + aml_audiobus_update_bits(actrl, reg, + 0x7 << 24 | 0x1fff << 3, + fmt->endian << 24 | fmt->type << 13 | + fmt->msb << 8 | fmt->lsb << 3); } -static void aml_set_resample(struct toddr *to, - bool enable) +void aml_toddr_insert_chanum(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_CTRL1, reg_base); + aml_audiobus_update_bits(actrl, reg, 1 << 24, 1 << 24); +} + +unsigned int aml_toddr_read(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_CTRL0, reg_base); + + return aml_audiobus_read(actrl, reg); +} + +void aml_toddr_write(struct toddr *to, unsigned int val) +{ + 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_CTRL0, reg_base); + + aml_audiobus_write(actrl, reg, val); +} + +void aml_toddr_set_resample(struct toddr *to, bool enable) { struct aml_audio_controller *actrl = to->actrl; unsigned int reg_base = to->reg_base; unsigned int reg; + pr_info("toddr selects data to %s resample\n", + enable ? "enable" : "disable"); + reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base); + aml_audiobus_update_bits(actrl, reg, 1<<30, enable<<30); +} + +static void aml_set_resample(struct toddr *to, + bool enable) +{ if (enable) { + int bitwidth = to->bitdepth; /* channels and bit depth for resample */ - resample_format_set(to->channels, to->bitdepth); + if ((to->src == SPDIFIN) && (bitwidth == 32)) { + struct aml_audio_controller *actrl = to->actrl; + unsigned int reg_base = to->reg_base; + unsigned int reg; + unsigned int endian, toddr_type; + + /* TODO: fixed me */ + pr_info("Warning: Not support 32bit sample rate for axg chipset\n"); + bitwidth = 24; + endian = 5; + toddr_type = 4; + + /* FIX ME */ + reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, + reg_base); + aml_audiobus_update_bits(actrl, reg, + 0x7 << 24 | 0x7 << 13, + endian << 24 | toddr_type << 13); + } + resample_format_set(to->channels, bitwidth); /* toddr index for resample */ resample_src_select(to->fifo_id); } /* resample enable or not */ - reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base); - aml_audiobus_update_bits(actrl, reg, 0x1 << 30, enable << 30); + resample_enable(enable); + /* select reample data */ + aml_toddr_set_resample(to, enable); } void aml_resample_enable(bool enable, int resample_module) { - /* when try to enable resample, if toddr is not in used, - * set resample status as ready - */ attach_resample.enable = enable; attach_resample.attach_module = resample_module; - if (enable) { - if ((attach_resample.status == DISABLED) - || (attach_resample.status == READY)) { - struct toddr *to = fetch_toddr_by_src(resample_module); - if (!to) { - attach_resample.status = READY; - pr_info("not in capture, resample is ready"); - } else { - attach_resample.status = RUNNING; - aml_set_resample(to, enable); - } - } - } else { - if (attach_resample.status == RUNNING) { - struct toddr *to = fetch_toddr_by_src(resample_module); + aml_check_resample(enable); +} - aml_set_resample(to, enable); - } - attach_resample.status = DISABLED; - } +static bool aml_check_resample_module(int src) +{ + bool is_module_resample = false; + + if (attach_resample.enable + && (src == attach_resample.attach_module)) + is_module_resample = true; + + return is_module_resample; } +/* + * when try to enable resample, if toddr is not in used, + * set resample status as ready + */ static void aml_check_resample(bool enable) { /* resample in enable */ if (attach_resample.enable) { if (enable) { /* check whether ready ? */ - if (attach_resample.status == READY) - aml_resample_enable(true, + if ((attach_resample.status == DISABLED) + || (attach_resample.status == READY)) { + struct toddr *to = fetch_toddr_by_src( attach_resample.attach_module); + + if (!to) { + attach_resample.status = READY; + pr_info("not in capture, Resample is ready\n"); + } else { + attach_resample.status = RUNNING; + aml_set_resample(to, enable); + pr_info("Resample in running, module:%d, toddr:%d\n", + attach_resample.attach_module, + to->fifo_id); + } + } } else { - if (attach_resample.status == RUNNING) - attach_resample.status = READY; + if (attach_resample.status == RUNNING) { + struct toddr *to = fetch_toddr_by_src( + attach_resample.attach_module); + + aml_set_resample(to, enable); + attach_resample.status = DISABLED; + } + } + } else { + /* ensure resample is disabled */ + struct toddr *to = fetch_toddr_by_src( + attach_resample.attach_module); + + if (to) { + pr_info("Resample in running, disable it\n"); + + /* select reample data */ + aml_toddr_set_resample(to, false); + /* update resample status */ + attach_resample.status = DISABLED; } } } @@ -490,7 +585,7 @@ void aml_pwrdet_enable(bool enable, int pwrdet_module) if (!to) { attach_pwrdet.status = READY; - pr_info("not in capture, power detect is ready"); + pr_info("not in capture, power detect is ready\n"); } else { attach_pwrdet.status = RUNNING; aml_set_pwrdet(to, enable); @@ -506,6 +601,17 @@ void aml_pwrdet_enable(bool enable, int pwrdet_module) } } +static bool aml_check_pwrdet_module(int src) +{ + bool is_module_pwrdet = false; + + if (attach_pwrdet.enable + && (src == attach_pwrdet.attach_module)) + is_module_pwrdet = true; + + return is_module_pwrdet; +} + static void aml_check_pwrdet(bool enable) { /* power detect in enable */ @@ -746,7 +852,8 @@ void aml_frddr_enable(struct frddr *fr, bool enable) aml_audiobus_write(actrl, reg, 0x0); /* check for Audio EQ/DRC */ - aml_check_aed(enable, fr->dest); + if (aml_check_aed_module(fr->dest)) + aml_check_aed(enable, fr->dest); } void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest dst) @@ -868,6 +975,17 @@ void aml_aed_enable(bool enable, int aed_module) } } +static bool aml_check_aed_module(int dst) +{ + bool is_module_aed = false; + + if (attach_aed.enable + && (dst == attach_aed.attach_module)) + is_module_aed = true; + + return is_module_aed; +} + static void aml_check_aed(bool enable, int dst) { /* check effect module is sync with crruent frddr dst */ diff --git a/sound/soc/amlogic/auge/ddr_mngr.h b/sound/soc/amlogic/auge/ddr_mngr.h index 8a5d660..5d4aac8 100644 --- a/sound/soc/amlogic/auge/ddr_mngr.h +++ b/sound/soc/amlogic/auge/ddr_mngr.h @@ -55,6 +55,16 @@ enum frddr_dest { SPDIFOUT_B, }; +struct toddr_fmt { + unsigned int type; + unsigned int msb; + unsigned int lsb; + unsigned int endian; + unsigned int bit_depth; + unsigned int ch_num; + unsigned int rate; +}; + /* to ddrs */ int fetch_toddr_index_by_src(int toddr_src); struct toddr *fetch_toddr_by_src(int toddr_src); @@ -69,9 +79,10 @@ unsigned int aml_toddr_get_position(struct toddr *to); void aml_toddr_select_src(struct toddr *to, enum toddr_src); void aml_toddr_enable(struct toddr *to, bool enable); void aml_toddr_set_fifos(struct toddr *to, unsigned int thresh); -void aml_toddr_set_format(struct toddr *to, - unsigned int type, unsigned int msb, unsigned int lsb, - int ch_num, int bit_depth); +void aml_toddr_set_format(struct toddr *to, struct toddr_fmt *fmt); +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); /* resample */ void aml_resample_enable(bool enable, int resample_module); diff --git a/sound/soc/amlogic/auge/pdm.c b/sound/soc/amlogic/auge/pdm.c index 905d920..7434b03 100644 --- a/sound/soc/amlogic/auge/pdm.c +++ b/sound/soc/amlogic/auge/pdm.c @@ -619,13 +619,19 @@ static int aml_pdm_dai_prepare( if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { struct toddr *to = p_pdm->tddr; + struct toddr_fmt fmt; unsigned int osr = 192; /* to ddr pdmin */ + fmt.type = toddr_type; + fmt.msb = 31; + fmt.lsb = lsb; + fmt.endian = 0; + fmt.bit_depth = bitwidth; + fmt.ch_num = runtime->channels; + fmt.rate = runtime->rate; aml_toddr_select_src(to, PDMIN); - aml_toddr_set_format(to, toddr_type, 31, lsb, - runtime->channels, - bitwidth); + aml_toddr_set_format(to, &fmt); aml_toddr_set_fifos(to, 0x40); aml_pdm_ctrl(p_pdm->actrl, diff --git a/sound/soc/amlogic/auge/resample.c b/sound/soc/amlogic/auge/resample.c index be9e2c1..5338294 100644 --- a/sound/soc/amlogic/auge/resample.c +++ b/sound/soc/amlogic/auge/resample.c @@ -20,15 +20,20 @@ #include #include #include +#include #include #include #include "resample.h" #include "resample_hw.h" #include "ddr_mngr.h" +#include "regs.h" +#include "iomap.h" #define DRV_NAME "audioresample" +#define CLK_RATIO 256 + struct resample_chipinfo { bool dividor_fn; }; @@ -50,6 +55,9 @@ struct audioresample { /* resample to the rate */ int out_rate; + /* sync with auge_resample_texts */ + int asr_idx; + bool enable; }; @@ -63,23 +71,30 @@ static int resample_clk_set(struct audioresample *p_resample) if (p_resample->enable) { ret = clk_prepare_enable(p_resample->clk); if (ret) { - pr_err("Can't enable resample_clk clock: %d\n", ret); + pr_err("Can't enable resample_clk clock: %d\n", + ret); return -EINVAL; } + ret = clk_prepare_enable(p_resample->sclk); if (ret) { - pr_err("Can't enable resample_src clock: %d\n", ret); + pr_err("Can't enable resample_src clock: %d\n", + ret); return -EINVAL; } + if (p_resample->out_rate) { + clk_set_rate(p_resample->pll, + p_resample->out_rate * CLK_RATIO * 2); clk_set_rate(p_resample->sclk, - p_resample->out_rate * 256); + p_resample->out_rate * CLK_RATIO); clk_set_rate(p_resample->clk, - p_resample->out_rate * 256); + p_resample->out_rate * CLK_RATIO); } else { /* defaule resample clk */ - clk_set_rate(p_resample->sclk, 48000 * 256); - clk_set_rate(p_resample->clk, 48000 * 256); + clk_set_rate(p_resample->pll, 48000 * CLK_RATIO * 2); + clk_set_rate(p_resample->sclk, 48000 * CLK_RATIO); + clk_set_rate(p_resample->clk, 48000 * CLK_RATIO); } ret = clk_prepare_enable(p_resample->pll); @@ -104,10 +119,10 @@ static int resample_clk_set(struct audioresample *p_resample) static void audio_resample_init(struct audioresample *p_resample) { + resample_clk_set(p_resample); + aml_resample_enable(p_resample->enable, p_resample->resample_module); - - resample_clk_set(p_resample); } static int audio_resample_set(int enable, int rate) @@ -124,8 +139,6 @@ static int audio_resample_set(int enable, int rate) return 0; } -static int auge_resample; - static const char *const auge_resample_texts[] = { "Disable", "Enable:32K", @@ -137,6 +150,30 @@ static const char *const auge_resample_texts[] = { "Enable:192K", }; +static int resample_idx2rate(int index) +{ + int rate = 0; + + if (index == 0) + rate = 0; + else if (index == 1) + rate = 32000; + else if (index == 2) + rate = 44100; + else if (index == 3) + rate = 48000; + else if (index == 4) + rate = 88200; + else if (index == 5) + rate = 96000; + else if (index == 6) + rate = 176400; + else if (index == 7) + rate = 192000; + + return rate; +} + static const struct soc_enum auge_resample_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(auge_resample_texts), auge_resample_texts); @@ -145,60 +182,47 @@ static int resample_get_enum( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.enumerated.item[0] = auge_resample; + struct audioresample *p_resample = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = p_resample->asr_idx; return 0; } -static int resample_set_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +int resample_set(int index) { -/* struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - * struct aml_audio_private_data *p_aml_audio = - * snd_soc_card_get_drvdata(card); - * struct aml_card_info *p_cardinfo = p_aml_audio->cardinfo; - */ - int index = ucontrol->value.enumerated.item[0]; - int resample_rate = 0; + int resample_rate = resample_idx2rate(index); - if (index == 0) - resample_rate = 0; - else if (index == 1) - resample_rate = 32000; - else if (index == 2) - resample_rate = 44100; - else if (index == 3) - resample_rate = 48000; - else if (index == 4) - resample_rate = 88200; - else if (index == 5) - resample_rate = 96000; - else if (index == 6) - resample_rate = 176400; - else if (index == 7) - resample_rate = 192000; - else + if (index == s_resample->asr_idx) return 0; - auge_resample = index; + s_resample->asr_idx = index; + + pr_info("%s %s\n", + __func__, + auge_resample_texts[index]); if (audio_resample_set(index, resample_rate)) return 0; - if (index == 0) + if ((index == 0) || (resample_rate == 0)) resample_disable(); else { - resample_enable(resample_rate); - // TODO: fixe me + resample_init(resample_rate); + resample_set_hw_param(index - 1); } -/* - * if (index > 0 - * && p_aml_audio - * && p_cardinfo) - * p_cardinfo->set_resample_param(index - 1); - */ + + return 0; +} + +static int resample_set_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int index = ucontrol->value.enumerated.item[0]; + + resample_set(index); return 0; } @@ -246,9 +270,61 @@ static int mixer_audiobus_write( return 0; } -static const struct snd_kcontrol_new snd_resample_controls[] = { +/* resample module + * keep sync with enum toddr_src in ddr_mngr.h + */ +static const char *const auge_resample_module_texts[] = { + "TDMIN_A", + "TDMIN_B", + "TDMIN_C", + "SPDIFIN", + "PDMIN", + "NONE", + "TDMIN_LB", + "LOOPBACK", +}; + +static const struct soc_enum auge_resample_module_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(auge_resample_module_texts), + auge_resample_module_texts); + +static int resample_module_get_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct audioresample *p_resample = snd_kcontrol_chip(kcontrol); + + if (!p_resample) { + pr_err("audio resample is not init\n"); + return -EINVAL; + } + + ucontrol->value.enumerated.item[0] = p_resample->resample_module; + + return 0; +} + +static int resample_module_set_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct audioresample *p_resample = snd_kcontrol_chip(kcontrol); + + if (!p_resample) { + pr_err("audio resample is not init\n"); + return -EINVAL; + } - /* resample */ + p_resample->resample_module = ucontrol->value.enumerated.item[0]; + + /* update info to ddr */ + aml_resample_enable(p_resample->enable, + p_resample->resample_module); + + return 0; +} + +static const struct snd_kcontrol_new snd_resample_controls[] = { SOC_ENUM_EXT("Hardware resample enable", auge_resample_enum, resample_get_enum, @@ -261,12 +337,26 @@ static const struct snd_kcontrol_new snd_resample_controls[] = { EE_AUDIO_RESAMPLE_CTRL2, 0, 0xffffff, 0, mixer_audiobus_read, mixer_audiobus_write, NULL), + SOC_ENUM_EXT("Hardware resample module", + auge_resample_module_enum, + resample_module_get_enum, + resample_module_set_enum), }; int card_add_resample_kcontrols(struct snd_soc_card *card) { - return snd_soc_add_card_controls(card, - snd_resample_controls, ARRAY_SIZE(snd_resample_controls)); + unsigned int idx; + int err; + + for (idx = 0; idx < ARRAY_SIZE(snd_resample_controls); idx++) { + err = snd_ctl_add(card->snd_card, + snd_ctl_new1(&snd_resample_controls[idx], + s_resample)); + if (err < 0) + return err; + } + + return 0; } static struct resample_chipinfo g12a_resample_chipinfo = { diff --git a/sound/soc/amlogic/auge/resample.h b/sound/soc/amlogic/auge/resample.h index 6ac94d8..d0bb722 100644 --- a/sound/soc/amlogic/auge/resample.h +++ b/sound/soc/amlogic/auge/resample.h @@ -19,4 +19,5 @@ extern int card_add_resample_kcontrols(struct snd_soc_card *card); +extern int resample_set(int index); #endif diff --git a/sound/soc/amlogic/auge/resample_hw.c b/sound/soc/amlogic/auge/resample_hw.c index f0ee072..0c40fea 100644 --- a/sound/soc/amlogic/auge/resample_hw.c +++ b/sound/soc/amlogic/auge/resample_hw.c @@ -14,8 +14,11 @@ * more details. * */ +#include #include "resample_hw.h" +#include "regs.h" +#include "iomap.h" /*Cnt_ctrl = mclk/fs_out-1 ; fest 256fs */ #define RESAMPLE_CNT_CONTROL 255 @@ -37,22 +40,39 @@ static u32 resample_coef_parameters_table[7][5] = { {0x00800000, 0x0, 0x0, 0x0, 0x0}, }; -int resample_enable(int input_sr) +void resample_enable(bool enable) +{ + audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0, + 0x1 << 31, + 1 << 31); + + audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0, + 0x1 << 31, + 0 << 31); + + audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0, + 0x1 << 28, + enable << 28); +} + +int resample_init(int input_sr) { u16 Avg_cnt_init = 0; unsigned int clk_rate = 167000000;//clk81; - Avg_cnt_init = (u16)(clk_rate * 4 / input_sr); + if (input_sr) + Avg_cnt_init = (u16)(clk_rate * 4 / input_sr); + else + pr_err("unsupport input sample rate:%d\n", input_sr); + pr_info("clk_rate = %u, input_sr = %d, Avg_cnt_init = %u\n", clk_rate, input_sr, Avg_cnt_init); - audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, (1 << 31)); - audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, 0); - audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, - (1 << 28) /* enable */ - | (0 << 26) /* method0 */ - | (RESAMPLE_CNT_CONTROL << 16) - | Avg_cnt_init); + audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0, + 0x3 << 26 | 0x3ff << 16 | 0xffff << 0, + 0x0 << 26 | /* method0 */ + RESAMPLE_CNT_CONTROL << 16 | + Avg_cnt_init << 0); return 0; } @@ -91,3 +111,13 @@ void resample_format_set(int ch_num, int bits) audiobus_write(EE_AUDIO_RESAMPLE_CTRL3, ch_num << 8 | (bits - 1) << 0); } + +int resample_ctrl_read(int idx) +{ + return audiobus_read(EE_AUDIO_RESAMPLE_CTRL0); +} + +void resample_ctrl_write(int idx, int value) +{ + audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, value); +} diff --git a/sound/soc/amlogic/auge/resample_hw.h b/sound/soc/amlogic/auge/resample_hw.h index 021e34b..e78be73 100644 --- a/sound/soc/amlogic/auge/resample_hw.h +++ b/sound/soc/amlogic/auge/resample_hw.h @@ -16,15 +16,15 @@ */ #ifndef __AML_AUDIO_RESAMPLE_HW_H__ #define __AML_AUDIO_RESAMPLE_HW_H__ -#include -#include "regs.h" -#include "iomap.h" - -extern int resample_enable(int input_sr); +extern void resample_enable(bool enable); +extern int resample_init(int input_sr); extern int resample_disable(void); extern int resample_set_hw_param(int index); extern void resample_src_select(int src); extern void resample_format_set(int ch_num, int bits); +extern int resample_ctrl_read(int idx); +extern void resample_ctrl_write(int idx, int value); + #endif diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c index 46182a6..f6bc8ca 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -37,6 +37,8 @@ #include "ddr_mngr.h" #include "spdif_hw.h" #include "audio_utils.h" +#include "resample.h" +#include "resample_hw.h" #define DRV_NAME "aml_spdif" @@ -46,15 +48,22 @@ /* Debug by PTM when bringup */ /* #define G12A_PTM */ +/* for debug */ +/*#define __SPDIFIN_INSERT_CHNUM__*/ + struct spdif_chipinfo { unsigned int id; /* add ch_cnt to ch_num */ bool chnum_en; - /* Reg_clr_interrupt[7:0] for each bit of irq_status[7:0]; */ - bool clr_irq_bits; - /* find PaPb */ - bool irq_papb; + /* + * axg, clear all irq bits + * after axg, such as g12a, clear each bits + * Reg_clr_interrupt[7:0] for each bit of irq_status[7:0]; + */ + bool clr_irq_all_bits; + /* no PaPb irq */ + bool irq_no_papb; /* reg_hold_start_en; 1: add delay to match TDM out when share buff; */ bool hold_start; /* eq/drc */ @@ -83,6 +92,27 @@ struct aml_spdif { unsigned int id; struct spdif_chipinfo *chipinfo; unsigned int clk_cont; /* CONTINUOUS CLOCK */ + + /* spdif in do asrc for pcm, + * if raw data, disable it automatically. + */ + unsigned int auto_asrc; + /* check spdifin channel status for pcm or nonpcm */ + struct timer_list timer; + struct work_struct work; + + /* spdif in reset for l/r channel swap when plug/unplug */ + struct timer_list reset_timer; + /* timer is used */ + int is_reset_timer_used; + /* reset timer counter */ + int timer_counter; + /* 0: default, 1: spdif in firstly enable, 2: spdif in could be reset */ + int sample_rate_detect_start; + /* is spdif in reset */ + int is_reset; + int last_sample_rate_mode; + }; static const struct snd_pcm_hardware aml_spdif_hardware = { @@ -102,7 +132,7 @@ static const struct snd_pcm_hardware aml_spdif_hardware = { .buffer_bytes_max = 256 * 1024, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, .channels_min = 2, .channels_max = 32, }; @@ -114,24 +144,14 @@ static const unsigned int spdifin_extcon[] = { }; /* current sample mode and its sample rate */ -int sample_mode[] = { - 24000, - 32000, - 44100, - 46000, - 48000, - 96000, - 192000, -}; - static const char *const spdifin_samplerate[] = { "N/A", - "24000", "32000", "44100", - "46000", "48000", + "88200", "96000", + "176400", "192000" }; @@ -187,18 +207,17 @@ static const struct sppdif_audio_info type_texts[] = { {6, 0x003, "PAUSE"}, {6, 0x100, "PAUSE"}, }; + static const struct soc_enum spdif_audio_type_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_audio_type_texts), spdif_audio_type_texts); -static int spdifin_audio_type_get_enum( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int spdifin_check_audio_type(void) { - int audio_type = 0; - int i; int total_num = sizeof(type_texts)/sizeof(struct sppdif_audio_info); int pc = spdifin_get_audio_type(); + int audio_type = 0; + int i; for (i = 0; i < total_num; i++) { if (pc == type_texts[i].pc) { @@ -206,7 +225,18 @@ static int spdifin_audio_type_get_enum( break; } } - ucontrol->value.enumerated.item[0] = audio_type; + + pr_info("%s audio type:%d\n", __func__, audio_type); + + return audio_type; +} + +static int spdifin_audio_type_get_enum( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = + spdifin_check_audio_type(); return 0; } @@ -223,54 +253,271 @@ static const struct snd_kcontrol_new snd_spdif_controls[] = { NULL), }; +static bool spdifin_check_audiotype_by_sw(struct aml_spdif *p_spdif) +{ + if (p_spdif + && p_spdif->chipinfo + && p_spdif->chipinfo->irq_no_papb) + return true; + + return false; +} + +static void spdifin_audio_type_start_timer( + struct aml_spdif *p_spdif) +{ + p_spdif->timer.expires = jiffies + 1; + add_timer(&p_spdif->timer); +} + +static void spdifin_audio_type_stop_timer( + struct aml_spdif *p_spdif) +{ + del_timer(&p_spdif->timer); +} + +static void spdifin_audio_type_timer_func(unsigned long data) +{ + struct aml_spdif *p_spdif = (struct aml_spdif *)data; + unsigned long delay = msecs_to_jiffies(1); + + schedule_work(&p_spdif->work); + mod_timer(&p_spdif->timer, jiffies + delay); +} + +static void spdifin_audio_type_work_func(struct work_struct *work) +{ + struct aml_spdif *p_spdif = container_of( + work, struct aml_spdif, work); + + int val = spdifin_get_ch_status0to31(); + + /* auto resample ? */ + if (!p_spdif->auto_asrc) + return; + + if (val & 0x2) + /* nonpcm, resample disable */ + resample_set(0); + else + /* pcm, resample which rate ? */ + resample_set(p_spdif->auto_asrc); +} + +static void spdifin_audio_type_detect_init(struct aml_spdif *p_spdif) +{ + init_timer(&p_spdif->timer); + p_spdif->timer.function = spdifin_audio_type_timer_func; + p_spdif->timer.data = (unsigned long)p_spdif; + + INIT_WORK(&p_spdif->work, spdifin_audio_type_work_func); +} + +static void spdifin_audio_type_detect_deinit(struct aml_spdif *p_spdif) +{ + cancel_work_sync(&p_spdif->work); +} + +static void spdifin_fast_reset(struct aml_spdif *p_spdif) +{ + struct aml_audio_controller *actrl = p_spdif->actrl; + unsigned int tddr_val = aml_toddr_read(p_spdif->tddr); + unsigned int spdifin_ctrl_val = aml_spdif_ctrl_read(actrl, + SNDRV_PCM_STREAM_CAPTURE, p_spdif->id); + unsigned int asr_ctrl_val = 0; + + pr_info("%s\n", __func__); + + /* toddr disable */ + tddr_val &= ~(1 << 31); + aml_toddr_write(p_spdif->tddr, tddr_val); + + /* resample disable and reset */ + if (p_spdif->auto_asrc) { + asr_ctrl_val = resample_ctrl_read(0); + asr_ctrl_val &= ~(1 << 28); + resample_ctrl_write(0, asr_ctrl_val); + asr_ctrl_val |= (1 << 31); + resample_ctrl_write(0, asr_ctrl_val); + asr_ctrl_val &= ~(1 << 31); + resample_ctrl_write(0, asr_ctrl_val); + } + + /* spdif in disable and reset */ + spdifin_ctrl_val &= ~(0x1 << 31); + aml_spdif_ctrl_write(actrl, + SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val); + spdifin_ctrl_val &= ~(0x3 << 28); + aml_spdif_ctrl_write(actrl, + SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val); + spdifin_ctrl_val |= (0x1 << 29); + aml_spdif_ctrl_write(actrl, + SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val); + spdifin_ctrl_val |= (0x1 << 28); + aml_spdif_ctrl_write(actrl, + SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val); + + /* toddr enable */ + tddr_val |= (1 << 31); + aml_toddr_write(p_spdif->tddr, tddr_val); + + /* resample enable */ + if (p_spdif->auto_asrc) { + asr_ctrl_val |= (1 << 28); + resample_ctrl_write(0, asr_ctrl_val); + } + + /* spdif in enable */ + spdifin_ctrl_val |= (0x1 << 31); + aml_spdif_ctrl_write(actrl, + SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val); +} + +#define MAX_TIMER_COUNTER 30 +#define FIRST_DELAY 20 + +static void spdifin_reset_timer(unsigned long data) +{ + struct aml_spdif *p_spdif = (struct aml_spdif *)data; + unsigned long delay = msecs_to_jiffies(1); + int intrpt_status = aml_spdifin_status_check(p_spdif->actrl); + int mode = (intrpt_status >> 28) & 0x7; + + if ((p_spdif->last_sample_rate_mode != mode) || + (p_spdif->last_sample_rate_mode == 0x7)) { + + p_spdif->last_sample_rate_mode = mode; + p_spdif->timer_counter = 0; + mod_timer(&p_spdif->reset_timer, jiffies + delay); + } else if ((p_spdif->last_sample_rate_mode == mode) && + (mode != 0x7)) { + + if (p_spdif->timer_counter > MAX_TIMER_COUNTER) { + p_spdif->timer_counter = 0; + + if (p_spdif->is_reset || + (p_spdif->sample_rate_detect_start == 1)) { + p_spdif->is_reset = 0; + p_spdif->sample_rate_detect_start = 2; + if (p_spdif->is_reset_timer_used) { + p_spdif->is_reset_timer_used = 0; + del_timer(&p_spdif->reset_timer); + } + pr_debug("%s,last sample mode:0x%x, stop timer\n", + __func__, + p_spdif->last_sample_rate_mode); + } else { + p_spdif->last_sample_rate_mode = 0; + + p_spdif->is_reset = 1; + spdifin_fast_reset(p_spdif); + + delay = msecs_to_jiffies(FIRST_DELAY); + mod_timer(&p_spdif->reset_timer, + jiffies + delay); + } + } else { + p_spdif->timer_counter++; + mod_timer(&p_spdif->reset_timer, jiffies + delay); + } + } +} + static void spdifin_status_event(struct aml_spdif *p_spdif) { int intrpt_status; - if (p_spdif == NULL) + if (!p_spdif) return; - /* - * interrupt status, check and clear by reg_clk_interrupt; - */ + /* interrupt status, check and clear by reg_clk_interrupt */ intrpt_status = aml_spdifin_status_check(p_spdif->actrl); + /* clear irq bits immediametely */ + if (p_spdif->chipinfo) + aml_spdifin_clr_irq(p_spdif->actrl, + p_spdif->chipinfo->clr_irq_all_bits, + intrpt_status & 0xff); + if (intrpt_status & 0x1) - pr_warn_once("over flow!!\n"); + pr_info("over flow!!\n"); if (intrpt_status & 0x2) - pr_warn_once("parity error\n"); + pr_info("parity error\n"); if (intrpt_status & 0x4) { int mode = (intrpt_status >> 28) & 0x7; - pr_warn_once("sample mode changed\n"); - if (mode == 0x7) { - pr_debug("Default value, not detect sample rate\n"); + pr_debug("sample rate, mode:%x\n", mode); + if (/*(mode == 0x7) && */(!p_spdif->sample_rate_detect_start)) { + p_spdif->sample_rate_detect_start = 1; + pr_debug("spdif in sample rate started\n"); + } + + if (p_spdif->sample_rate_detect_start) { + + p_spdif->last_sample_rate_mode = mode; + + if (!p_spdif->is_reset_timer_used) { + unsigned long delay = msecs_to_jiffies(1); + + if (p_spdif->sample_rate_detect_start == 1) + delay = msecs_to_jiffies(FIRST_DELAY); + + setup_timer(&p_spdif->reset_timer, + spdifin_reset_timer, + (unsigned long)p_spdif); + mod_timer(&p_spdif->reset_timer, + jiffies + delay); + } + p_spdif->is_reset_timer_used++; + p_spdif->timer_counter = 0; + } + + if ((mode == 0x7) || + (((intrpt_status >> 18) & 0x3ff) == 0x3ff)) { + pr_info("Default value, not detect sample rate\n"); extcon_set_state(p_spdif->edev, EXTCON_SPDIFIN_SAMPLERATE, 0); } else if (mode >= 0) { - pr_debug("Event: EXTCON_SPDIFIN_SAMPLERATE, new sample rate:%d\n", - sample_mode[mode]); + if (p_spdif->last_sample_rate_mode != mode) { + pr_info("Event: EXTCON_SPDIFIN_SAMPLERATE, new sample rate:%s\n", + spdifin_samplerate[mode + 1]); - extcon_set_state(p_spdif->edev, - EXTCON_SPDIFIN_SAMPLERATE, 1); + /* resample enable, by hw */ + if (!spdifin_check_audiotype_by_sw(p_spdif)) + resample_set(p_spdif->auto_asrc); + + extcon_set_state(p_spdif->edev, + EXTCON_SPDIFIN_SAMPLERATE, 1); + } } + p_spdif->last_sample_rate_mode = mode; + } if (intrpt_status & 0x8) { - pr_warn_once("Pc changed, try to read spdifin audio type\n"); + pr_info("Pc changed, try to read spdifin audio type\n"); + extcon_set_state(p_spdif->edev, EXTCON_SPDIFIN_AUDIOTYPE, 1); - } else + + /* resample disable, by hw */ + if (!spdifin_check_audiotype_by_sw(p_spdif)) + resample_set(0); + } + if (intrpt_status & 0x10) + pr_info("Pd changed\n"); + if (intrpt_status & 0x20) { + pr_info("nonpcm to pcm\n"); extcon_set_state(p_spdif->edev, EXTCON_SPDIFIN_AUDIOTYPE, 0); - if (intrpt_status & 0x10) - pr_warn_once("Pd changed\n"); - if (intrpt_status & 0x20) - pr_warn_once("nonpcm to pcm\n"); + /* resample to 48k, by hw */ + if (!spdifin_check_audiotype_by_sw(p_spdif)) + resample_set(p_spdif->auto_asrc); + } if (intrpt_status & 0x40) - pr_warn_once("valid changed\n"); + pr_info("valid changed\n"); } static irqreturn_t aml_spdif_ddr_isr(int irq, void *devid) @@ -291,8 +538,6 @@ static irqreturn_t aml_spdifin_status_isr(int irq, void *devid) { struct aml_spdif *p_spdif = (struct aml_spdif *)devid; - aml_spdifin_status_check(p_spdif->actrl); - spdifin_status_event(p_spdif); return IRQ_HANDLED; @@ -306,7 +551,7 @@ static int aml_spdif_open(struct snd_pcm_substream *substream) struct aml_spdif *p_spdif; int ret = 0; - pr_info("asoc debug: %s-%d\n", __func__, __LINE__); + pr_info("%s\n", __func__); p_spdif = (struct aml_spdif *)dev_get_drvdata(dev); @@ -337,6 +582,10 @@ static int aml_spdif_open(struct snd_pcm_substream *substream) p_spdif->irq_spdifin); return ret; } + if (spdifin_check_audiotype_by_sw(p_spdif)) + spdifin_audio_type_detect_init(p_spdif); + + p_spdif->sample_rate_detect_start = 0; } runtime->private_data = p_spdif; @@ -350,13 +599,30 @@ static int aml_spdif_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct aml_spdif *p_spdif = runtime->private_data; - pr_info("asoc debug: %s-%d\n", __func__, __LINE__); + pr_info("%s\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { aml_audio_unregister_frddr(p_spdif->dev, substream); } else { aml_audio_unregister_toddr(p_spdif->dev, substream); free_irq(p_spdif->irq_spdifin, p_spdif); + + if (spdifin_check_audiotype_by_sw(p_spdif)) + spdifin_audio_type_detect_deinit(p_spdif); + + if (p_spdif->is_reset_timer_used) { + p_spdif->is_reset_timer_used = 0; + del_timer(&p_spdif->reset_timer); + } + + /* clear extcon status */ + if (p_spdif->id == 0) { + extcon_set_state(p_spdif->edev, + EXTCON_SPDIFIN_SAMPLERATE, 0); + + extcon_set_state(p_spdif->edev, + EXTCON_SPDIFIN_AUDIOTYPE, 0); + } } runtime->private_data = NULL; @@ -381,7 +647,30 @@ static int aml_spdif_hw_free(struct snd_pcm_substream *substream) static int aml_spdif_trigger(struct snd_pcm_substream *substream, int cmd) { - return 0; + struct snd_pcm_runtime *runtime = substream->runtime; + struct aml_spdif *p_spdif = runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if ((spdifin_check_audiotype_by_sw(p_spdif)) + && (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) + spdifin_audio_type_start_timer(p_spdif); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + if ((spdifin_check_audiotype_by_sw(p_spdif)) + && (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) + spdifin_audio_type_stop_timer(p_spdif); + break; + default: + ret = -EINVAL; + } + + return ret; } static int aml_spdif_prepare(struct snd_pcm_substream *substream) @@ -475,6 +764,7 @@ static int aml_spdif_new(struct snd_soc_pcm_runtime *rtd) __func__, (p_spdif->id == 0) ? "a":"b", p_spdif->clk_cont); + /* keep frddr when probe, after spdif_frddr_init done * frddr can be released, and spdif outputs zero data * without frddr used. @@ -498,6 +788,8 @@ static int aml_dai_spdif_probe(struct snd_soc_dai *cpu_dai) struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai); int ret = 0; + pr_info("%s\n", __func__); + if (p_spdif->id == SPDIF_A) { ret = snd_soc_add_dai_controls(cpu_dai, snd_spdif_controls, ARRAY_SIZE(snd_spdif_controls)); @@ -505,14 +797,12 @@ static int aml_dai_spdif_probe(struct snd_soc_dai *cpu_dai) pr_err("%s, failed add snd spdif controls\n", __func__); } - pr_info("asoc debug: %s-%d\n", __func__, __LINE__); - return 0; } static int aml_dai_spdif_remove(struct snd_soc_dai *cpu_dai) { - pr_info("asoc debug: %s-%d\n", __func__, __LINE__); + pr_info("%s\n", __func__); return 0; } @@ -524,7 +814,9 @@ static int aml_dai_spdif_startup( struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai); int ret; - pr_info("asoc debug: %s-%d\n", __func__, __LINE__); + pr_info("%s stream:%d\n", + __func__, + substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -579,6 +871,9 @@ static int aml_dai_spdif_startup( pr_err("Can't enable pcm clk_spdifin clock: %d\n", ret); goto err; } + /* resample to 48k in default, by hw */ + if (!spdifin_check_audiotype_by_sw(p_spdif)) + resample_set(p_spdif->auto_asrc); } return 0; @@ -593,6 +888,10 @@ static void aml_dai_spdif_shutdown( { struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai); + pr_info("%s, stream:%d\n", + __func__, + substream->stream); + /* disable clock and gate */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (p_spdif->clk_cont) { @@ -605,6 +904,10 @@ static void aml_dai_spdif_shutdown( clk_disable_unprepare(p_spdif->sysclk); clk_disable_unprepare(p_spdif->gate_spdifout); } else { + /* resample disabled, by hw */ + if (!spdifin_check_audiotype_by_sw(p_spdif)) + resample_set(0); + clk_disable_unprepare(p_spdif->clk_spdifin); clk_disable_unprepare(p_spdif->fixed_clk); clk_disable_unprepare(p_spdif->gate_spdifin); @@ -657,6 +960,7 @@ static int aml_dai_spdif_prepare( } else { struct toddr *to = p_spdif->tddr; + struct toddr_fmt fmt; unsigned int msb, lsb, toddr_type; if (loopback_is_enable()) { @@ -704,16 +1008,30 @@ static int aml_dai_spdif_prepare( } // to ddr spdifin + 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, SPDIFIN); - aml_toddr_set_format(to, toddr_type, msb, lsb, - runtime->channels, - bit_depth); + aml_toddr_set_format(to, &fmt); aml_toddr_set_fifos(to, 0x40); +#ifdef __SPDIFIN_INSERT_CHNUM__ + aml_toddr_insert_chanum(to); +#endif } aml_spdif_fifo_ctrl(p_spdif->actrl, bit_depth, substream->stream, p_spdif->id, fifo_id); +#ifdef __SPDIFIN_INSERT_CHNUM__ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + aml_spdifin_chnum_en(p_spdif->actrl, + p_spdif->id, true); +#endif + return 0; } @@ -741,6 +1059,7 @@ static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd, aml_spdif_enable(p_spdif->actrl, substream->stream, p_spdif->id, true); + break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -769,7 +1088,6 @@ static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } - static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) @@ -778,14 +1096,13 @@ static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream, unsigned int rate = params_rate(params); int ret = 0; - pr_info("%s\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { rate *= 128; snd_soc_dai_set_sysclk(cpu_dai, 0, rate, SND_SOC_CLOCK_OUT); } else { - clk_set_rate(p_spdif->clk_spdifin, 250000000); + clk_set_rate(p_spdif->clk_spdifin, 500000000); } return ret; @@ -793,9 +1110,7 @@ static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream, static int aml_dai_set_spdif_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai); - - pr_info("asoc aml_dai_set_spdif_fmt, %#x, %p\n", fmt, p_spdif); + pr_info("%s , fmt %#x\n", __func__, fmt); return 0; } @@ -804,8 +1119,10 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif) { unsigned int mpll_freq = 0; - pr_info("asoc debug: %s-%d, sys freq:%d\n", __func__, __LINE__, + pr_info("%s, sys freq:%d\n", + __func__, p_spdif->sysclk_freq); + if (p_spdif->sysclk_freq) { unsigned int mul = 4; int ret; @@ -821,6 +1138,10 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif) #ifdef G12A_PTM mpll_freq = p_spdif->sysclk_freq * 57; #endif + pr_info("\t finally sys freq:%d, mpll freq:%d\n", + p_spdif->sysclk_freq, + mpll_freq); + clk_set_rate(p_spdif->sysclk, mpll_freq); clk_set_rate(p_spdif->clk_spdifout, p_spdif->sysclk_freq); @@ -841,13 +1162,18 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif) static int aml_dai_set_spdif_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai); + pr_info("%s, clk_id:%d, freq:%d, dir:%d\n", + __func__, + clk_id, + freq, + dir); - p_spdif->sysclk_freq = freq; - pr_info("aml_dai_set_spdif_sysclk, %d, %d, %d\n", - clk_id, freq, dir); + if (dir == SND_SOC_CLOCK_OUT) { + struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai); - aml_set_spdifclk(p_spdif); + p_spdif->sysclk_freq = freq; + aml_set_spdifclk(p_spdif); + } return 0; } @@ -970,6 +1296,14 @@ static int aml_spdif_parse_of(struct platform_device *pdev) ret = extcon_dev_register(p_spdif->edev); if (ret < 0) pr_err("SPDIF IN extcon failed to register!!, ignore it\n"); + + ret = of_property_read_u32(pdev->dev.of_node, + "auto_asrc", &p_spdif->auto_asrc); + if (ret < 0) + p_spdif->auto_asrc = 0; + pr_info("SPDIF id %d auto_asrc:%d\n", + p_spdif->id, + p_spdif->auto_asrc); } /* clock for spdif out */ @@ -996,14 +1330,14 @@ static int aml_spdif_parse_of(struct platform_device *pdev) } struct spdif_chipinfo axg_spdif_chipinfo = { - .id = SPDIF_A, + .id = SPDIF_A, + .irq_no_papb = true, + .clr_irq_all_bits = true, }; struct spdif_chipinfo g12a_spdif_a_chipinfo = { .id = SPDIF_A, .chnum_en = true, - .clr_irq_bits = true, - .irq_papb = true, .hold_start = true, .eq_drc_en = true, }; @@ -1011,8 +1345,6 @@ struct spdif_chipinfo g12a_spdif_a_chipinfo = { struct spdif_chipinfo g12a_spdif_b_chipinfo = { .id = SPDIF_B, .chnum_en = true, - .clr_irq_bits = true, - .irq_papb = true, .hold_start = true, .eq_drc_en = true, }; @@ -1058,11 +1390,10 @@ static int aml_spdif_platform_probe(struct platform_device *pdev) of_device_get_match_data(dev); if (p_spdif_chipinfo) { aml_spdif->id = p_spdif_chipinfo->id; - /* for spdif_b, clk be continuous, + /* for spdif output zero data, clk be continuous, * and keep silence when no valid data */ - /*if (aml_spdif->id == 1)*/ - aml_spdif->clk_cont = 1; + aml_spdif->clk_cont = 1; aml_spdif->chipinfo = p_spdif_chipinfo; } else diff --git a/sound/soc/amlogic/auge/spdif_hw.c b/sound/soc/amlogic/auge/spdif_hw.c index 5594999..0a0e089 100644 --- a/sound/soc/amlogic/auge/spdif_hw.c +++ b/sound/soc/amlogic/auge/spdif_hw.c @@ -26,6 +26,49 @@ /*#define G12A_PTM*/ /*#define G12A_PTM_LB_INTERNAL*/ +unsigned int aml_spdif_ctrl_read(struct aml_audio_controller *actrl, + int stream, int index) +{ + unsigned int offset, reg; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0; + reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * index; + } else { + reg = EE_AUDIO_SPDIFIN_CTRL0; + } + + return aml_audiobus_read(actrl, reg); +} + +void aml_spdif_ctrl_write(struct aml_audio_controller *actrl, + int stream, int index, int val) +{ + unsigned int offset, reg; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0; + reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * index; + } else { + reg = EE_AUDIO_SPDIFIN_CTRL0; + } + + aml_audiobus_write(actrl, reg, val); +} + +void aml_spdifin_chnum_en(struct aml_audio_controller *actrl, + int index, bool is_enable) +{ + unsigned int reg; + + reg = EE_AUDIO_SPDIFIN_CTRL0; + aml_audiobus_update_bits(actrl, reg, 1 << 26, is_enable << 26); + + pr_info("%s spdifin ctrl0:0x%x\n", + __func__, + aml_audiobus_read(actrl, reg)); +} + void aml_spdif_enable( struct aml_audio_controller *actrl, int stream, @@ -84,23 +127,31 @@ int aml_spdifin_status_check(struct aml_audio_controller *actrl) { unsigned int val; - val = aml_audiobus_read(actrl, - EE_AUDIO_SPDIFIN_STAT0); + val = aml_audiobus_read(actrl, EE_AUDIO_SPDIFIN_STAT0); /* pr_info("\t--- spdif handles status0 %#x\n", val); */ - - aml_audiobus_update_bits(actrl, - EE_AUDIO_SPDIFIN_CTRL0, - 1<<26, - 1<<26); - aml_audiobus_update_bits(actrl, - EE_AUDIO_SPDIFIN_CTRL0, - 1<<26, - 0); - return val; } +void aml_spdifin_clr_irq(struct aml_audio_controller *actrl, + bool is_all_bits, int clr_bits_val) +{ + if (is_all_bits) { + aml_audiobus_update_bits(actrl, + EE_AUDIO_SPDIFIN_CTRL0, + 1 << 26, + 1 << 26); + aml_audiobus_update_bits(actrl, + EE_AUDIO_SPDIFIN_CTRL0, + 1 << 26, + 0); + } else + aml_audiobus_update_bits(actrl, + EE_AUDIO_SPDIFIN_CTRL6, + 0xff << 16, + clr_bits_val << 16); +} + void aml_spdif_fifo_reset( struct aml_audio_controller *actrl, int stream, int index) @@ -161,7 +212,10 @@ void aml_spdif_fifo_ctrl( } pr_info("%s, bit depth:%d, frddr type:%d, toddr:type:%d\n", - __func__, bitwidth, frddr_type, toddr_type); + __func__, + bitwidth, + frddr_type, + toddr_type); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { unsigned int offset, reg; @@ -187,61 +241,65 @@ void aml_spdif_fifo_ctrl( reg, 1<<4); } else { - unsigned int lsb; - - if (bitwidth <= 24) - lsb = 28 - bitwidth; - else - lsb = 4; + unsigned int spdifin_clk = 500000000; + + /* sysclk/rate/32(bit)/2(ch)/2(bmc) */ + unsigned int counter_32k = (spdifin_clk / (32000 * 64)); + unsigned int counter_44k = (spdifin_clk / (44100 * 64)); + unsigned int counter_48k = (spdifin_clk / (48000 * 64)); + unsigned int counter_88k = (spdifin_clk / (88200 * 64)); + unsigned int counter_96k = (spdifin_clk / (96000 * 64)); + unsigned int counter_176k = (spdifin_clk / (176400 * 64)); + unsigned int counter_192k = (spdifin_clk / (192000 * 64)); + unsigned int mode0_th = 3 * (counter_32k + counter_44k) >> 1; + unsigned int mode1_th = 3 * (counter_44k + counter_48k) >> 1; + unsigned int mode2_th = 3 * (counter_48k + counter_88k) >> 1; + unsigned int mode3_th = 3 * (counter_88k + counter_96k) >> 1; + unsigned int mode4_th = 3 * (counter_96k + counter_176k) >> 1; + unsigned int mode5_th = 3 * (counter_176k + counter_192k) >> 1; + unsigned int mode0_timer = counter_32k >> 1; + unsigned int mode1_timer = counter_44k >> 1; + unsigned int mode2_timer = counter_48k >> 1; + unsigned int mode3_timer = counter_88k >> 1; + unsigned int mode4_timer = counter_96k >> 1; + unsigned int mode5_timer = (counter_176k >> 1); + unsigned int mode6_timer = (counter_192k >> 1); - // 250M -#ifdef G12A_PTM - aml_audiobus_write(actrl, - EE_AUDIO_SPDIFIN_CTRL1, - 25000 << 0); -#else aml_audiobus_write(actrl, EE_AUDIO_SPDIFIN_CTRL1, - 0xff << 20 | 25000 << 0); -#endif + 0xff << 20 | (spdifin_clk / 10000) << 0); + aml_audiobus_write(actrl, EE_AUDIO_SPDIFIN_CTRL2, - 140 << 20 | 100 << 10 | 86 << 0); + mode0_th << 20 | + mode1_th << 10 | + mode2_th << 0); aml_audiobus_write(actrl, EE_AUDIO_SPDIFIN_CTRL3, - 83 << 20 | 60 << 10 | 30 << 0); + mode3_th << 20 | + mode4_th << 10 | + mode5_th << 0); aml_audiobus_write(actrl, EE_AUDIO_SPDIFIN_CTRL4, - (81<<24) | /* reg_sample_mode0_timer */ - (61<<16) | /* reg_sample_mode1_timer */ - (44<<8) | /* reg_sample_mode2_timer*/ - (42<<0) + (mode0_timer << 24) | + (mode1_timer << 16) | + (mode2_timer << 8) | + (mode3_timer << 0) ); -#ifdef G12A_PTM - aml_audiobus_write(actrl, - EE_AUDIO_SPDIFIN_CTRL5, - (40<<24) | - (20<<16) | - (10<<8) | - (0<<0) - ); -#else aml_audiobus_write(actrl, EE_AUDIO_SPDIFIN_CTRL5, - (40<<24) | /* reg_sample_mode4_timer = 5[31:24]; */ - (20<<16) | /* reg_sample_mode5_timer = 5[23:16]; */ - (9<<8) | /* reg_sample_mode6_timer = 5[15:8]; */ - (0<<0) /* reg_sample_mode7_timer = 5[7:0]; */ + (mode4_timer << 24) | + (mode5_timer << 16) | + (mode6_timer << 8) ); -#endif aml_audiobus_update_bits(actrl, EE_AUDIO_SPDIFIN_CTRL0, - 0x3<<24|1<<12, - 3<<24|1<<12); + 0x1 << 25 | 0x1 << 24 | 0xfff << 12, + 0x1 << 25 | 0x0 << 24 | 0xff << 12); } } @@ -432,18 +490,37 @@ int spdifin_get_sample_rate(void) val = audiobus_read(EE_AUDIO_SPDIFIN_STAT0); + /* NA when check min width of two edges */ + if (((val >> 18) & 0x3ff) == 0x3ff) + return 0x7; + return (val >> 28) & 0x7; } -int spdifin_get_audio_type(void) +static int spdifin_get_channel_status(int sel) { unsigned int val; - /* set ch_status_sel to read Pc*/ - audiobus_update_bits(EE_AUDIO_SPDIFIN_CTRL0, 0xf << 8, 0x6 << 8); + /* set ch_status_sel to channel status */ + audiobus_update_bits(EE_AUDIO_SPDIFIN_CTRL0, 0xf << 8, sel << 8); val = audiobus_read(EE_AUDIO_SPDIFIN_STAT1); + return val; +} + +int spdifin_get_ch_status0to31(void) +{ + return spdifin_get_channel_status(0x0); +} + +int spdifin_get_audio_type(void) +{ + unsigned int val; + + /* set ch_status_sel to read Pc */ + val = spdifin_get_channel_status(0x6); + return (val >> 16) & 0xff; } @@ -557,7 +634,9 @@ void spdifout_play_with_zerodata(unsigned int spdif_id) void spdifout_play_with_zerodata_free(unsigned int spdif_id) { - pr_info("%s, spdif id:%d\n", __func__, spdif_id); + pr_info("%s, spdif id:%d\n", + __func__, + spdif_id); /* free frddr, then frddr in mngr */ frddr_deinit_without_mngr(spdif_id); diff --git a/sound/soc/amlogic/auge/spdif_hw.h b/sound/soc/amlogic/auge/spdif_hw.h index 005a44b..c2e529c 100644 --- a/sound/soc/amlogic/auge/spdif_hw.h +++ b/sound/soc/amlogic/auge/spdif_hw.h @@ -22,6 +22,12 @@ #include +extern unsigned int aml_spdif_ctrl_read(struct aml_audio_controller *actrl, + int stream, int index); +extern void aml_spdif_ctrl_write(struct aml_audio_controller *actrl, + int stream, int index, int val); +extern void aml_spdifin_chnum_en(struct aml_audio_controller *actrl, + int index, bool is_enable); extern void aml_spdif_enable( struct aml_audio_controller *actrl, int stream, @@ -38,6 +44,8 @@ extern void aml_spdif_arb_config(struct aml_audio_controller *actrl); extern int aml_spdifin_status_check( struct aml_audio_controller *actrl); +extern void aml_spdifin_clr_irq(struct aml_audio_controller *actrl, + bool is_all_bits, int clr_bits_val); extern void aml_spdif_fifo_reset( struct aml_audio_controller *actrl, @@ -69,6 +77,8 @@ extern void spdifout_enable(int spdif_id, bool is_enable); extern int spdifin_get_sample_rate(void); +extern int spdifin_get_ch_status0to31(void); + extern int spdifin_get_audio_type(void); extern void spdif_set_channel_status_info( diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index e567127..c817586 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -451,6 +451,7 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream, enum toddr_src src; unsigned int lsb = 32 - bit_depth; unsigned int toddr_type; + struct toddr_fmt fmt; switch (bit_depth) { case 8: @@ -484,10 +485,15 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream, return -EINVAL; } + fmt.type = toddr_type; + fmt.msb = 31; + 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, toddr_type, 31, lsb, - runtime->channels, - bit_depth); + aml_toddr_set_format(to, &fmt); aml_toddr_set_fifos(to, 0x40); }