audio: auge: fix spdif in & out work at the same time for ASRC
authorXing Wang <xing.wang@amlogic.com>
Tue, 3 Apr 2018 06:03:41 +0000 (14:03 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Fri, 28 Sep 2018 10:52:00 +0000 (03:52 -0700)
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 <xing.wang@amlogic.com>
20 files changed:
arch/arm64/boot/dts/amlogic/axg_s400.dts
arch/arm64/boot/dts/amlogic/axg_s400_v03.dts
arch/arm64/boot/dts/amlogic/axg_s400emmc.dts
arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts
arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts
arch/arm64/boot/dts/amlogic/axg_s420.dts
arch/arm64/boot/dts/amlogic/axg_s420_128m.dts
arch/arm64/boot/dts/amlogic/axg_s420_v03.dts
sound/soc/amlogic/auge/card.c
sound/soc/amlogic/auge/ddr_mngr.c
sound/soc/amlogic/auge/ddr_mngr.h
sound/soc/amlogic/auge/pdm.c
sound/soc/amlogic/auge/resample.c
sound/soc/amlogic/auge/resample.h
sound/soc/amlogic/auge/resample_hw.c
sound/soc/amlogic/auge/resample_hw.h
sound/soc/amlogic/auge/spdif.c
sound/soc/amlogic/auge/spdif_hw.c
sound/soc/amlogic/auge/spdif_hw.h
sound/soc/amlogic/auge/tdm.c

index 49cfcf9..4c8de29 100644 (file)
                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 {
                 *      TDMIN_LB,
                 *      LOOPBACK,
                 */
-               resample_module = <4>;
+               resample_module = <3>;
                status = "okay";
        };
        aml_pwrdet: pwrdet {
                hi_th = <0x70000>;
                lo_th = <0x16000>;
 
-               status = "okay";
+               status = "disabled";
        };
 }; /* end of audiobus */
 
index 69a0f26..5625611 100644 (file)
                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 {
 
                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 = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
+               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 {
index 77de81d..d414c3d 100644 (file)
                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 {
 
                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 = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
+               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 {
index 6d88311..9feeb07 100644 (file)
                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 {
 
                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 = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
+               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 {
index 16829a0..aba276d 100644 (file)
                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 {
 
                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 = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
+               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 {
index 5d4c021..e9470de 100644 (file)
                        };
                };
 
-               /*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{
                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 {
 
                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 {
index fc52b5e..c47a2bc 100644 (file)
                        };
                };
 
-               /*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{
                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 {
 
                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 {
index 8e302b6..02eae18 100644 (file)
                        };
                };
 
-               /*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{
                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 {
 
                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 {
index 863f789..f916cd6 100644 (file)
@@ -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;
 
index dc0159a..3410ed8 100644 (file)
@@ -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 */
index 8a5d660..5d4aac8 100644 (file)
@@ -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);
index 905d920..7434b03 100644 (file)
@@ -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,
index be9e2c1..5338294 100644 (file)
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
 #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 = {
index 6ac94d8..d0bb722 100644 (file)
@@ -19,4 +19,5 @@
 
 extern int card_add_resample_kcontrols(struct snd_soc_card *card);
 
+extern int resample_set(int index);
 #endif
index f0ee072..0c40fea 100644 (file)
  * more details.
  *
  */
+#include <linux/clk.h>
 
 #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);
+}
index 021e34b..e78be73 100644 (file)
  */
 #ifndef __AML_AUDIO_RESAMPLE_HW_H__
 #define __AML_AUDIO_RESAMPLE_HW_H__
-#include <linux/clk.h>
 
-#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
index 46182a6..f6bc8ca 100644 (file)
@@ -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"
 
 /* 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
index 5594999..0a0e089 100644 (file)
 /*#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);
index 005a44b..c2e529c 100644 (file)
 
 #include <linux/amlogic/media/sound/spdif_info.h>
 
+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(
index e567127..c817586 100644 (file)
@@ -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);
        }