audio: add asoc auge driver for axg
authorXing Wang <xing.wang@amlogic.com>
Tue, 30 May 2017 13:22:31 +0000 (21:22 +0800)
committerVictor Wan <victor.wan@amlogic.com>
Wed, 31 May 2017 10:51:02 +0000 (03:51 -0700)
PD#142470: audio: new Asoc driver
1) tdm module
2) spdif module
3) pdm module
4) audio clock

Change-Id: I064975f4cb036d013a7ca74d781a91c31e7c2436
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
67 files changed:
Documentation/devicetree/bindings/sound/tlv320adc3101.txt [new file with mode: 0644]
MAINTAINERS
arch/arm64/boot/dts/amlogic/axg_a113d_skt.dts
arch/arm64/boot/dts/amlogic/axg_s400.dts
arch/arm64/boot/dts/amlogic/axg_s420.dts
arch/arm64/boot/dts/amlogic/mesonaxg.dtsi
arch/arm64/configs/meson64_defconfig
drivers/amlogic/pinctrl/pinctrl-mesonaxg.c
include/dt-bindings/clock/amlogic,axg-audio-clk.h [new file with mode: 0644]
sound/soc/amlogic/Kconfig
sound/soc/amlogic/Makefile
sound/soc/amlogic/auge/Kconfig [new file with mode: 0644]
sound/soc/amlogic/auge/Makefile [new file with mode: 0644]
sound/soc/amlogic/auge/audio_controller.c [new file with mode: 0644]
sound/soc/amlogic/auge/audio_controller.h [new file with mode: 0644]
sound/soc/amlogic/auge/audio_io.c [new file with mode: 0644]
sound/soc/amlogic/auge/audio_io.h [new file with mode: 0644]
sound/soc/amlogic/auge/card.c [new file with mode: 0644]
sound/soc/amlogic/auge/card.h [new file with mode: 0644]
sound/soc/amlogic/auge/card_utils.c [new file with mode: 0644]
sound/soc/amlogic/auge/card_utils.h [new file with mode: 0644]
sound/soc/amlogic/auge/clocks.c [new file with mode: 0644]
sound/soc/amlogic/auge/ddr_mngr.c [new file with mode: 0644]
sound/soc/amlogic/auge/ddr_mngr.h [new file with mode: 0644]
sound/soc/amlogic/auge/iomap.c [new file with mode: 0644]
sound/soc/amlogic/auge/iomap.h [new file with mode: 0644]
sound/soc/amlogic/auge/pdm.c [new file with mode: 0644]
sound/soc/amlogic/auge/pdm.h [new file with mode: 0644]
sound/soc/amlogic/auge/pdm_hw.c [new file with mode: 0644]
sound/soc/amlogic/auge/pdm_hw.h [new file with mode: 0644]
sound/soc/amlogic/auge/pdm_hw_coeff.c [new file with mode: 0644]
sound/soc/amlogic/auge/regs.h [new file with mode: 0644]
sound/soc/amlogic/auge/spdif.c [new file with mode: 0644]
sound/soc/amlogic/auge/spdif_hw.c [new file with mode: 0644]
sound/soc/amlogic/auge/spdif_hw.h [new file with mode: 0644]
sound/soc/amlogic/auge/tdm.c [new file with mode: 0644]
sound/soc/amlogic/auge/tdm_hw.c [new file with mode: 0644]
sound/soc/amlogic/auge/tdm_hw.h [new file with mode: 0644]
sound/soc/amlogic/meson/Kconfig [new file with mode: 0644]
sound/soc/amlogic/meson/Makefile [new file with mode: 0644]
sound/soc/amlogic/meson/audio_hw.c [moved from sound/soc/amlogic/aml_audio_hw.c with 99% similarity]
sound/soc/amlogic/meson/audio_hw.h [moved from sound/soc/amlogic/aml_audio_hw.h with 99% similarity]
sound/soc/amlogic/meson/audio_hw_pcm.c [moved from sound/soc/amlogic/aml_audio_hw_pcm.c with 99% similarity]
sound/soc/amlogic/meson/audio_hw_pcm.h [moved from sound/soc/amlogic/aml_audio_hw_pcm.h with 95% similarity]
sound/soc/amlogic/meson/dmic.c [moved from sound/soc/amlogic/aml_dmic.c with 99% similarity]
sound/soc/amlogic/meson/i2s.c [moved from sound/soc/amlogic/aml_i2s.c with 99% similarity]
sound/soc/amlogic/meson/i2s.h [moved from sound/soc/amlogic/aml_i2s.h with 98% similarity]
sound/soc/amlogic/meson/i2s_dai.c [moved from sound/soc/amlogic/aml_i2s_dai.c with 98% similarity]
sound/soc/amlogic/meson/i2s_dai.h [moved from sound/soc/amlogic/aml_i2s_dai.h with 95% similarity]
sound/soc/amlogic/meson/meson.c [moved from sound/soc/amlogic/aml_meson.c with 99% similarity]
sound/soc/amlogic/meson/meson.h [moved from sound/soc/amlogic/aml_meson.h with 98% similarity]
sound/soc/amlogic/meson/notify.c [moved from sound/soc/amlogic/aml_notify.c with 97% similarity]
sound/soc/amlogic/meson/pcm.c [moved from sound/soc/amlogic/aml_pcm.c with 99% similarity]
sound/soc/amlogic/meson/pcm.h [moved from sound/soc/amlogic/aml_pcm.h with 96% similarity]
sound/soc/amlogic/meson/pcm_dai.c [moved from sound/soc/amlogic/aml_pcm_dai.c with 98% similarity]
sound/soc/amlogic/meson/pcm_dai.h [moved from sound/soc/amlogic/aml_pcm_dai.h with 95% similarity]
sound/soc/amlogic/meson/spdif_codec.c [moved from sound/soc/amlogic/aml_spdif_codec.c with 99% similarity]
sound/soc/amlogic/meson/spdif_dai.c [moved from sound/soc/amlogic/aml_spdif_dai.c with 99% similarity]
sound/soc/amlogic/meson/spdif_dai.h [moved from sound/soc/amlogic/aml_spdif_dai.h with 98% similarity]
sound/soc/amlogic/meson/tv.c [moved from sound/soc/amlogic/aml_tv.c with 99% similarity]
sound/soc/amlogic/meson/tv.h [moved from sound/soc/amlogic/aml_tv.h with 97% similarity]
sound/soc/codecs/amlogic/Kconfig
sound/soc/codecs/amlogic/Makefile
sound/soc/codecs/amlogic/pdm_dummy.c [new file with mode: 0644]
sound/soc/codecs/amlogic/tas5707.c
sound/soc/codecs/amlogic/tlv320adc3101.c [new file with mode: 0644]
sound/soc/codecs/amlogic/tlv320adc3101.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/sound/tlv320adc3101.txt b/Documentation/devicetree/bindings/sound/tlv320adc3101.txt
new file mode 100644 (file)
index 0000000..69b6e2a
--- /dev/null
@@ -0,0 +1,20 @@
+Texas Instruments - tlv320adc3101 Codec module
+
+The tlv320adc3101 serial control bus communicates through I2C protocols
+
+Required properties:
+ - compatible: Should be "ti,tlv320adc3101"
+ - reg: I2C slave address
+
+Optional properties:
+ - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
+ - clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
+   See clock/clock-bindings.txt for information about the detailed format.
+
+
+Example:
+
+codec: tlv320adc3101@18 {
+       compatible = "ti,tlv320adc3101";
+       reg = <0x18>;
+};
index ede7736..aa6783e 100644 (file)
@@ -13916,3 +13916,12 @@ M:     Long Yu <long.yu@amlogic.com>
 F:     drivers/amlogic/mmc/aml_sd_emmc_v3.c
 F:     include/linux/amlogic/aml_sd_emmc_internal.h
 F:     include/linux/amlogic/aml_sd_emmc_v3.h
+
+AMLOGIC Asoc driver
+M: shuai li <shuai.li@amlogic.com>
+M: xing wang <xing.wang@amlogic.com>
+F: sound/soc/amlogic/meson/*
+F: sound/soc/amlogic/auge/*
+F: sound/soc/codecs/amlogic/*
+F: include/dt-bindings/clock/amlogic,axg-audio-clk.h
+
index 23484f0..263d6f8 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&b_uart_pins>;
        };
+       /* Sound iomap */
+       aml_snd_iomap {
+               compatible = "amlogic, snd_iomap";
+               status = "okay";
+               #address-cells=<2>;
+               #size-cells=<2>;
+               ranges;
+               pdm_bus {
+                       reg = <0x0 0xFF632000 0x0 0x20>;
+               };
+               audiobus_base {
+                       reg = <0x0 0xFF642000 0x0 0x2000>;
+               };
+       };
+       pdm_codec:dummy{
+               #sound-dai-cells = <0>;
+               compatible = "amlogic, pdm_dummy_codec";
+               status = "okay";
+       };
+       dummy_codec:dummy{
+               #sound-dai-cells = <0>;
+               compatible = "amlogic, aml_dummy_codec";
+               status = "okay";
+       };
 
+       meson_sound {
+               compatible = "amlogic, sound-card";
+               aml-audio-card,name = "AML-AXGSOUND";
+               //aml-audio-card,mclk-fs = <256>;
+
+               aml-audio-card,dai-link@0 {
+                       format = "dsp_a";
+                       mclk-fs = <512>;
+                       continuous-clock;
+                       //bitclock-inversion;
+                       //frame-inversion;
+                       //bitclock-master = <&tdmacodec>;
+                       //frame-master = <&tdmacodec>;
+                       tdmacpu: cpu {
+                               sound-dai = <&aml_tdma>;
+                               dai-tdm-slot-tx-mask =
+                                                       <1 1 1 1 1 1 1 1>;
+                               dai-tdm-slot-rx-mask =
+                                                       <1 1 1 1 1 1 1 1>;
+                               dai-tdm-slot-num = <8>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <24576000>;
+                       };
+                       tdmacodec: codec {
+                               sound-dai = <&dummy_codec &dummy_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@1 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       bitclock-inversion;
+                       frame-inversion;
+                       //bitclock-master = <&aml_tdmb>;
+                       //frame-master = <&aml_tdmb>;
+                       cpu {
+                               sound-dai = <&aml_tdmb>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&dummy_codec &dummy_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@2 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       bitclock-inversion;
+                       frame-inversion;
+                       //bitclock-master = <&aml_tdmc>;
+                       //frame-master = <&aml_tdmc>;
+                       cpu {
+                               sound-dai = <&aml_tdmc>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&tas5707_36 &tas5707_3a>;
+                       };
+               };
+
+               aml-audio-card,dai-link@3 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       //bitclock-inversion;
+                       //frame-inversion;
+                       bitclock-master = <&aml_pdm>;
+                       frame-master = <&aml_pdm>;
+                       cpu {
+                               sound-dai = <&aml_pdm>;
+                       };
+                       codec {
+                               sound-dai = <&pdm_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@4 {
+                       //format = "i2s";
+                       mclk-fs = <128>;
+                       continuous-clock;
+                       cpu {
+                               sound-dai = <&aml_spdif>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&dummy_codec>;
+                       };
+               };
+       };
        sd_emmc_c: emmc@ffe07000 {
                status = "okay";
                compatible = "amlogic, meson-aml-mmc";
 
 }; /* end of / */
 
+/* Audio Related start */
+/* for spk board */
+&i2c_b {
+       status = "okay";
+       //pinctrl-names="default";
+       //pinctrl-0=<&b_i2c_master>;
+       tlv320adc3101_32: tlv320adc3101_32@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x32>;
+               status = "disabled";
+       };
+
+       tas5707_36: tas5707_36@36 {
+               compatible = "ti,tas5707";
+               #sound-dai-cells = <0>;
+               reg = <0x1b>;
+               status = "okay";
+               reset_pin = <&gpio_ao GPIOAO_4 0>;
+       };
+
+       tas5707_3a: tas5707_3a@3a {
+               compatible = "ti,tas5707";
+               #sound-dai-cells = <0>;
+               reg = <0x1d>;
+               status = "okay";
+       };
+};
+
+/* for mic board */
+&i2c_ao {
+       status = "okay";
+       pinctrl-names="default";
+       pinctrl-0=<&ao_i2c_master_pin2>;
+
+       tlv320adc3101_30: tlv320adc3101_30@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x30>;
+               status = "okay";
+       };
+       tlv320adc3101_34: tlv320adc3101_34@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x34>;
+               status = "okay";
+       };
+       tlv320adc3101_36: tlv320adc3101_36@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x36>;
+               status = "okay";
+       };
+};
+
+&audiobus {
+       aml_tdma: tdma {
+               compatible = "amlogic, snd-tdma";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1>;
+               dai-tdm-clk-sel = <0>;
+               tdm_from_ddr = <0>;
+               tdm_to_ddr = <0>;
+               clocks = <&clkc CLKID_MPLL0>;
+                                       //&clkaudio CLKID_AUDIO_TDMOUTA
+                                       //&clkaudio CLKID_AUDIO_MCLK_A>;
+               clock-names = "mpll0", "gate", "mclk";
+               interrupts =
+                       <GIC_SPI 84 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmout_a &tdmin_a>;
+       };
+
+       aml_tdmb: tdmb {
+               compatible = "amlogic, snd-tdmb";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-clk-sel = <1>;
+               tdm_from_ddr = <1>;
+               tdm_to_ddr = <1>;
+               clocks = <&clkc CLKID_MPLL1>;
+               clock-names = "mpll1";
+               interrupts =
+                       <GIC_SPI 85 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmb_mclk &tdmout_b>;
+       };
+
+       aml_tdmc: tdmc {
+               compatible = "amlogic, snd-tdmc";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask-in = <0 1 0 0>;
+               dai-tdm-lane-slot-mask-out = <1 0 1 1>;
+               dai-tdm-clk-sel = <2>;
+               tdm_from_ddr = <2>;
+               tdm_to_ddr = <2>;
+               clocks = <&clkc CLKID_MPLL2>;
+               clock-names = "mpll2";
+               interrupts =
+                       <GIC_SPI 86 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmc_mclk &tdmout_c>;// &tdmin_c>;
+       };
+
+       aml_spdif: spdif {
+               compatible = "amlogic, snd-spdif";
+               #sound-dai-cells = <0>;
+               spdif_from_ddr = <0>;
+               spdif_to_ddr = <0>;
+               clocks = <&clkc CLKID_MPLL0
+                               &clkc CLKID_FCLK_DIV4
+                               &clkaudio CLKID_AUDIO_SPDIFIN
+                               &clkaudio CLKID_AUDIO_SPDIFOUT
+                               &clkaudio CLKID_AUDIO_SPDIFIN_CTRL
+                               &clkaudio CLKID_AUDIO_SPDIFOUT_CTRL>;
+               clock-names = "sysclk", "fixed_clk", "gate_spdifin",
+                               "gate_spdifout", "clk_spdifin", "clk_spdifout";
+               interrupts =
+                               <GIC_SPI 87 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 84 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+
+               interrupt-names = "irq_spdifin", "irq_toddr", "irq_frddr";
+               pinctrl-names = "spdif_pins";
+               pinctrl-0 = <&spdifout &spdifin>;
+               status = "okay";
+       };
+       aml_pdm: pdm {
+               compatible = "amlogic, snd-pdm";
+               #sound-dai-cells = <0>;
+               to_ddr = <2>;
+               clocks = <&clkaudio CLKID_AUDIO_PDM
+                                       &clkc CLKID_MPLL3
+                                       &clkaudio CLKID_AUDIO_PDMIN0
+                                       &clkaudio CLKID_AUDIO_PDMIN1>;
+               clock-names = "gate", "pll_clk", "pdm_dclk", "pdm_sysclk";
+               interrupts = <GIC_SPI 86 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "pdmin_irq";
+               pinctrl-names = "pdm_pins";
+               pinctrl-0 = <&pdmin>;
+               filter_mode = <1>; /* mode 0~4, defalut:1 */
+               status = "okay";
+       };
+}; /* end of audiobus */
+
+&pinctrl_periphs {
+       tdmout_a: tdmout_a {
+               mux {
+                       pins = "GPIOX_12", "GPIOX_13", "GPIOX_15";
+                       //pins = "GPIOX_15";//slave
+                       function = "tdma_out";
+               };
+       };
+
+       tdmin_a: tdmin_a {
+               mux {
+                       pins = "GPIOX_14";
+                       //pins = "GPIOX_12", "GPIOX_13", "GPIOX_14";//slave
+                       function = "tdma_in";
+               };
+       };
+
+       tdmb_mclk: tdmb_mclk {
+               mux {
+                       pins = "GPIOA_1";
+                       function = "mclk";
+               };
+       };
+
+       tdmout_b: tdmout_b {
+               mux {
+                       pins = "GPIOA_8", "GPIOA_9", "GPIOA_10",
+                               "GPIOA_11", "GPIOA_12", "GPIOA_13";
+                       function = "tdmb_out";
+               };
+       };
+       // tdmin and tdmout are the same pins. can't use at same time
+       /*
+        *tdmin_b:tdmin_b {
+        *      mux {
+        *              pins = "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13";
+        *              function = "tdmb_in";
+        *      };
+        *};
+        */
+
+       tdmc_mclk: tdmc_mclk {
+               mux {
+                       pins = "GPIOA_0";
+                       function = "mclk";
+               };
+       };
+
+       tdmout_c:tdmout_c {
+               mux {
+                       pins = "GPIOA_2", "GPIOA_3", "GPIOA_4",
+                               "GPIOA_5", "GPIOA_6", "GPIOA_7";
+                       function = "tdmc_out";
+               };
+       };
+
+
+       //tdmin_c:tdmin_c {
+       //      mux {
+       //              pins = "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7";
+       //              function = "tdmc_in";
+       //      };
+       //};
+
+       spdifout: spidfout {
+               mux {
+                       pins = "GPIOA_20";
+                       function = "spdif_out";
+               };
+       };
+
+       spdifin: spidfin {
+               mux {
+                       pins = "GPIOA_19";
+                       function = "spdif_in";
+               };
+       };
+
+       pdmin: pdmin {
+               mux {
+                       pins = "GPIOA_14", "GPIOA_15", "GPIOA_16",
+                               "GPIOA_17", "GPIOA_18";
+                       function = "pdm";
+               };
+       };
+}; /* end of pinctrl_periphs */
+/* Audio Related End */
 &spicc_a{
        status = "okay";
        num_chipselect = <1>;
index 589c03c..8ffd724 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&b_uart_pins>;
        };
+       /* Sound iomap */
+       aml_snd_iomap {
+               compatible = "amlogic, snd_iomap";
+               status = "okay";
+               #address-cells=<2>;
+               #size-cells=<2>;
+               ranges;
+               pdm_bus {
+                       reg = <0x0 0xFF632000 0x0 0x20>;
+               };
+               audiobus_base {
+                       reg = <0x0 0xFF642000 0x0 0x2000>;
+               };
+       };
+       pdm_codec:dummy{
+               #sound-dai-cells = <0>;
+               compatible = "amlogic, pdm_dummy_codec";
+               status = "okay";
+       };
+       dummy_codec:dummy{
+               #sound-dai-cells = <0>;
+               compatible = "amlogic, aml_dummy_codec";
+               status = "okay";
+       };
+
+       meson_sound {
+               compatible = "amlogic, sound-card";
+               aml-audio-card,name = "AML-AXGSOUND";
+               //aml-audio-card,mclk-fs = <256>;
+
+               aml-audio-card,dai-link@0 {
+                       format = "dsp_a";
+                       mclk-fs = <512>;
+                       continuous-clock;
+                       //bitclock-inversion;
+                       //frame-inversion;
+                       //bitclock-master = <&tdmacodec>;
+                       //frame-master = <&tdmacodec>;
+                       tdmacpu: cpu {
+                               sound-dai = <&aml_tdma>;
+                               dai-tdm-slot-tx-mask =
+                                                       <1 1 1 1 1 1 1 1>;
+                               dai-tdm-slot-rx-mask =
+                                                       <1 1 1 1 1 1 1 1>;
+                               dai-tdm-slot-num = <8>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <24576000>;
+                       };
+                       tdmacodec: codec {
+                               sound-dai = <&dummy_codec &dummy_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@1 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       bitclock-inversion;
+                       frame-inversion;
+                       //bitclock-master = <&aml_tdmb>;
+                       //frame-master = <&aml_tdmb>;
+                       cpu {
+                               sound-dai = <&aml_tdmb>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&dummy_codec &dummy_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@2 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       bitclock-inversion;
+                       frame-inversion;
+                       //bitclock-master = <&aml_tdmc>;
+                       //frame-master = <&aml_tdmc>;
+                       cpu {
+                               sound-dai = <&aml_tdmc>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&tas5707_36 &tas5707_3a>;
+                       };
+               };
+
+               aml-audio-card,dai-link@3 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       //bitclock-inversion;
+                       //frame-inversion;
+                       bitclock-master = <&aml_pdm>;
+                       frame-master = <&aml_pdm>;
+                       cpu {
+                               sound-dai = <&aml_pdm>;
+                       };
+                       codec {
+                               sound-dai = <&pdm_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@4 {
+                       //format = "i2s";
+                       mclk-fs = <128>;
+                       continuous-clock;
+                       cpu {
+                               sound-dai = <&aml_spdif>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&dummy_codec>;
+                       };
+               };
+       };
+
        wifi{
                compatible = "amlogic, aml_wifi";
                dev_name = "aml_wifi";
 
 }; /* end of / */
 
+/* Audio Related start */
+/* for spk board */
+&i2c_b {
+       status = "okay";
+       //pinctrl-names="default";
+       //pinctrl-0=<&b_i2c_master>;
+       tlv320adc3101_32: tlv320adc3101_32@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x32>;
+               status = "disabled";
+       };
+
+       tas5707_36: tas5707_36@36 {
+               compatible = "ti,tas5707";
+               #sound-dai-cells = <0>;
+               reg = <0x1b>;
+               status = "okay";
+               reset_pin = <&gpio_ao GPIOAO_4 0>;
+       };
+
+       tas5707_3a: tas5707_3a@3a {
+               compatible = "ti,tas5707";
+               #sound-dai-cells = <0>;
+               reg = <0x1d>;
+               status = "okay";
+       };
+};
+
+/* for mic board */
+&i2c_ao {
+       status = "okay";
+       pinctrl-names="default";
+       pinctrl-0=<&ao_i2c_master_pin2>;
+
+       tlv320adc3101_30: tlv320adc3101_30@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x30>;
+               status = "okay";
+       };
+       tlv320adc3101_34: tlv320adc3101_34@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x34>;
+               status = "okay";
+       };
+       tlv320adc3101_36: tlv320adc3101_36@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x36>;
+               status = "okay";
+       };
+};
+
+&audiobus {
+       aml_tdma: tdma {
+               compatible = "amlogic, snd-tdma";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1>;
+               dai-tdm-clk-sel = <0>;
+               tdm_from_ddr = <0>;
+               tdm_to_ddr = <0>;
+               clocks = <&clkc CLKID_MPLL0>;
+                                       //&clkaudio CLKID_AUDIO_TDMOUTA
+                                       //&clkaudio CLKID_AUDIO_MCLK_A>;
+               clock-names = "mpll0", "gate", "mclk";
+               interrupts =
+                       <GIC_SPI 84 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmout_a &tdmin_a>;
+       };
+
+       aml_tdmb: tdmb {
+               compatible = "amlogic, snd-tdmb";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-clk-sel = <1>;
+               tdm_from_ddr = <1>;
+               tdm_to_ddr = <1>;
+               clocks = <&clkc CLKID_MPLL1>;
+               clock-names = "mpll1";
+               interrupts =
+                       <GIC_SPI 85 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmb_mclk &tdmout_b>;
+       };
+
+       aml_tdmc: tdmc {
+               compatible = "amlogic, snd-tdmc";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask-in = <0 1 0 0>;
+               dai-tdm-lane-slot-mask-out = <1 0 1 1>;
+               dai-tdm-clk-sel = <2>;
+               tdm_from_ddr = <2>;
+               tdm_to_ddr = <2>;
+               clocks = <&clkc CLKID_MPLL2>;
+               clock-names = "mpll2";
+               interrupts =
+                       <GIC_SPI 86 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmc_mclk &tdmout_c>;// &tdmin_c>;
+       };
+
+       aml_spdif: spdif {
+               compatible = "amlogic, snd-spdif";
+               #sound-dai-cells = <0>;
+               spdif_from_ddr = <0>;
+               spdif_to_ddr = <0>;
+               clocks = <&clkc CLKID_MPLL0
+                               &clkc CLKID_FCLK_DIV4
+                               &clkaudio CLKID_AUDIO_SPDIFIN
+                               &clkaudio CLKID_AUDIO_SPDIFOUT
+                               &clkaudio CLKID_AUDIO_SPDIFIN_CTRL
+                               &clkaudio CLKID_AUDIO_SPDIFOUT_CTRL>;
+               clock-names = "sysclk", "fixed_clk", "gate_spdifin",
+                               "gate_spdifout", "clk_spdifin", "clk_spdifout";
+               interrupts =
+                               <GIC_SPI 87 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 84 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+
+               interrupt-names = "irq_spdifin", "irq_toddr", "irq_frddr";
+               pinctrl-names = "spdif_pins";
+               pinctrl-0 = <&spdifout &spdifin>;
+               status = "okay";
+       };
+       aml_pdm: pdm {
+               compatible = "amlogic, snd-pdm";
+               #sound-dai-cells = <0>;
+               to_ddr = <2>;
+               clocks = <&clkaudio CLKID_AUDIO_PDM
+                                       &clkc CLKID_MPLL3
+                                       &clkaudio CLKID_AUDIO_PDMIN0
+                                       &clkaudio CLKID_AUDIO_PDMIN1>;
+               clock-names = "gate", "pll_clk", "pdm_dclk", "pdm_sysclk";
+               interrupts = <GIC_SPI 86 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "pdmin_irq";
+               pinctrl-names = "pdm_pins";
+               pinctrl-0 = <&pdmin>;
+               filter_mode = <1>; /* mode 0~4, defalut:1 */
+               status = "okay";
+       };
+}; /* end of audiobus */
+
+&pinctrl_periphs {
+       tdmout_a: tdmout_a {
+               mux {
+                       pins = "GPIOX_12", "GPIOX_13", "GPIOX_15";
+                       //pins = "GPIOX_15";//slave
+                       function = "tdma_out";
+               };
+       };
+
+       tdmin_a: tdmin_a {
+               mux {
+                       pins = "GPIOX_14";
+                       //pins = "GPIOX_12", "GPIOX_13", "GPIOX_14";//slave
+                       function = "tdma_in";
+               };
+       };
+
+       tdmb_mclk: tdmb_mclk {
+               mux {
+                       pins = "GPIOA_1";
+                       function = "mclk";
+               };
+       };
+
+       tdmout_b: tdmout_b {
+               mux {
+                       pins = "GPIOA_8", "GPIOA_9", "GPIOA_10",
+                               "GPIOA_11", "GPIOA_12", "GPIOA_13";
+                       function = "tdmb_out";
+               };
+       };
+       // tdmin and tdmout are the same pins. can't use at same time
+       /*
+        *tdmin_b:tdmin_b {
+        *      mux {
+        *              pins = "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13";
+        *              function = "tdmb_in";
+        *      };
+        *};
+        */
+
+       tdmc_mclk: tdmc_mclk {
+               mux {
+                       pins = "GPIOA_0";
+                       function = "mclk";
+               };
+       };
+
+       tdmout_c:tdmout_c {
+               mux {
+                       pins = "GPIOA_2", "GPIOA_3", "GPIOA_4",
+                               "GPIOA_5", "GPIOA_6", "GPIOA_7";
+                       function = "tdmc_out";
+               };
+       };
+
+
+       //tdmin_c:tdmin_c {
+       //      mux {
+       //              pins = "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7";
+       //              function = "tdmc_in";
+       //      };
+       //};
+
+       spdifout: spidfout {
+               mux {
+                       pins = "GPIOA_20";
+                       function = "spdif_out";
+               };
+       };
+
+       spdifin: spidfin {
+               mux {
+                       pins = "GPIOA_19";
+                       function = "spdif_in";
+               };
+       };
+
+       pdmin: pdmin {
+               mux {
+                       pins = "GPIOA_14", "GPIOA_15", "GPIOA_16",
+                               "GPIOA_17", "GPIOA_18";
+                       function = "pdm";
+               };
+       };
+}; /* end of pinctrl_periphs */
+/* Audio Related End */
+
+
 &spicc_a{
        status = "disabled";
        num_chipselect = <1>;
index 4847493..7267b37 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&b_uart_pins>;
        };
+
+       /* Sound iomap */
+       aml_snd_iomap {
+               compatible = "amlogic, snd_iomap";
+               status = "okay";
+               #address-cells=<2>;
+               #size-cells=<2>;
+               ranges;
+               pdm_bus {
+                       reg = <0x0 0xFF632000 0x0 0x20>;
+               };
+               audiobus_base {
+                       reg = <0x0 0xFF642000 0x0 0x2000>;
+               };
+       };
+       pdm_codec:dummy{
+               #sound-dai-cells = <0>;
+               compatible = "amlogic, pdm_dummy_codec";
+               status = "okay";
+       };
+       dummy_codec:dummy{
+               #sound-dai-cells = <0>;
+               compatible = "amlogic, aml_dummy_codec";
+               status = "okay";
+       };
+
+       meson_sound {
+               compatible = "amlogic, sound-card";
+               aml-audio-card,name = "AML-AXGSOUND";
+               //aml-audio-card,mclk-fs = <256>;
+
+               aml-audio-card,dai-link@0 {
+                       format = "i2s";//"dsp_a";
+                       mclk-fs = <256>;//512
+                       continuous-clock;
+                       bitclock-inversion;
+                       //frame-inversion;
+                       bitclock-master = <&aml_tdma>;
+                       frame-master = <&aml_tdma>;
+                       cpu {
+                               sound-dai = <&aml_tdma>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               sound-dai = <&dummy_codec &dummy_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@1 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       bitclock-inversion;
+                       //frame-inversion;
+                       bitclock-master = <&aml_tdmb>;
+                       frame-master = <&aml_tdmb>;
+                       cpu {
+                               sound-dai = <&aml_tdmb>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               //sound-dai = <&dummy_codec &dummy_codec>;
+                               sound-dai = <&tas5707_36>;
+                       };
+               };
+
+               aml-audio-card,dai-link@2 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       bitclock-inversion;
+                       //frame-inversion;
+                       bitclock-master = <&aml_tdmc>;
+                       frame-master = <&aml_tdmc>;
+                       cpu {
+                               sound-dai = <&aml_tdmc>;
+                               dai-tdm-slot-tx-mask = <1 1>;
+                               dai-tdm-slot-rx-mask = <1 1>;
+                               dai-tdm-slot-num = <2>;
+                               dai-tdm-slot-width = <32>;
+                               system-clock-frequency = <12288000>;
+                       };
+                       codec {
+                               //sound-dai = <&tas5707_36 &tas5707_3a>;
+                               sound-dai = <&dummy_codec &dummy_codec>;
+                       };
+               };
+
+               aml-audio-card,dai-link@3 {
+                       format = "i2s";
+                       mclk-fs = <256>;
+                       continuous-clock;
+                       //bitclock-inversion;
+                       //frame-inversion;
+                       bitclock-master = <&aml_pdm>;
+                       frame-master = <&aml_pdm>;
+                       cpu {
+                               sound-dai = <&aml_pdm>;
+                       };
+                       codec {
+                               sound-dai = <&pdm_codec>;
+                       };
+               };
+
+               /*aml-audio-card,dai-link@4 {
+                *      //format = "i2s";
+                *      mclk-fs = <128>;
+                *      continuous-clock;
+                *      cpu {
+                *              sound-dai = <&aml_spdif>;
+                *              system-clock-frequency = <12288000>;
+                *      };
+                *      codec {
+                *              sound-dai = <&dummy_codec>;
+                *      };
+                *};
+                */
+       };
        wifi{
                compatible = "amlogic, aml_wifi";
                dev_name = "aml_wifi";
        };
 }; /* end of / */
 
+/* for spk board */
+&i2c_b {
+       status = "okay";
+       //pinctrl-names="default";
+       //pinctrl-0=<&b_i2c_master>;
+       tlv320adc3101_32: tlv320adc3101_32@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x19>;
+               status = "disabled";
+       };
+
+       tas5707_36: tas5707_36@36 {
+               compatible = "ti,tas5707";
+               #sound-dai-cells = <0>;
+               reg = <0x1b>;
+               status = "okay";
+               reset_pin = <&gpio_ao GPIOAO_4 0>;
+       };
+
+       tas5707_3a: tas5707_3a@3a {
+               compatible = "ti,tas5707";
+               #sound-dai-cells = <0>;
+               reg = <0x1d>;
+               status = "disable";
+       };
+};
+
+/* for mic board */
+&i2c_ao {
+       status = "okay";
+       pinctrl-names="default";
+       pinctrl-0=<&ao_i2c_master_pin2>;
+
+       tlv320adc3101_30: tlv320adc3101_30@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x18>;
+               status = "okay";
+       };
+       tlv320adc3101_34: tlv320adc3101_34@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x1a>;
+               status = "okay";
+       };
+       tlv320adc3101_36: tlv320adc3101_36@30 {
+               compatible = "ti,tlv320adc3101";
+               #sound-dai-cells = <0>;
+               reg = <0x1b>;
+               status = "okay";
+       };
+};
+
+&audiobus {
+       aml_tdma: tdma {
+               compatible = "amlogic, snd-tdma";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               /* select tdm lr/bclk src, see aml_axg_tdm.c */
+               dai-tdm-clk-sel = <0>;
+               tdm_from_ddr = <0>;
+               tdm_to_ddr = <0>;
+               clocks = <&clkc CLKID_MPLL2>;
+                                       //&clkaudio CLKID_AUDIO_TDMOUTA
+                                       //&clkaudio CLKID_AUDIO_MCLK_A>;
+               clock-names = "mpll0", "gate", "mclk";
+               interrupts =
+                       <GIC_SPI 84 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmin_a &tdmout_a>;
+       };
+
+       aml_tdmb: tdmb {
+               compatible = "amlogic, snd-tdmb";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-clk-sel = <2>;
+               tdm_from_ddr = <1>;
+               tdm_to_ddr = <1>;
+               clocks = <&clkc CLKID_MPLL1>;
+               clock-names = "mpll1";
+               interrupts =
+                       <GIC_SPI 85 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmb_mclk &tdmout_b>;
+       };
+
+       aml_tdmc: tdmc {
+               compatible = "amlogic, snd-tdmc";
+               #sound-dai-cells = <0>;
+               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-clk-sel = <2>;
+               tdm_from_ddr = <2>;
+               tdm_to_ddr = <2>;
+               clocks = <&clkc CLKID_MPLL2>;
+               clock-names = "mpll2";
+               interrupts =
+                       <GIC_SPI 86 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "tdmin", "tdmout";
+               pinctrl-names = "tdm_pins";
+               pinctrl-0 = <&tdmc_mclk &tdmout_c>;
+       };
+
+       aml_spdif: spdif {
+               compatible = "amlogic, snd-spdif";
+               #sound-dai-cells = <0>;
+               spdif_from_ddr = <0>;
+               spdif_to_ddr = <0>;
+               clocks = <&clkc CLKID_MPLL0
+                               &clkc CLKID_FCLK_DIV4
+                               &clkaudio CLKID_AUDIO_SPDIFIN
+                               &clkaudio CLKID_AUDIO_SPDIFOUT
+                               &clkaudio CLKID_AUDIO_SPDIFIN_CTRL
+                               &clkaudio CLKID_AUDIO_SPDIFOUT_CTRL>;
+               clock-names = "sysclk", "fixed_clk", "gate_spdifin",
+                               "gate_spdifout", "clk_spdifin", "clk_spdifout";
+               interrupts =
+                               <GIC_SPI 87 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 84 IRQ_TYPE_EDGE_RISING
+                               GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+
+               interrupt-names = "irq_spdifin", "irq_toddr", "irq_frddr";
+               pinctrl-names = "spdif_pins";
+               pinctrl-0 = <&spdifout &spdifin>;
+               status = "disabled";
+       };
+
+       aml_pdm: pdm {
+               compatible = "amlogic, snd-pdm";
+               #sound-dai-cells = <0>;
+               to_ddr = <2>;
+               clocks = <&clkaudio CLKID_AUDIO_PDM
+                                       &clkc CLKID_MPLL3
+                                       &clkaudio CLKID_AUDIO_PDMIN0
+                                       &clkaudio CLKID_AUDIO_PDMIN1>;
+               clock-names = "gate", "pll_clk", "pdm_dclk", "pdm_sysclk";
+               interrupts = <GIC_SPI 86 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "pdmin_irq";
+               pinctrl-names = "pdm_pins";
+               pinctrl-0 = <&pdmin>;
+               filter_mode = <1>; /* mode 0~4, defalut:1 */
+               status = "okay";
+       };
+}; /* end of audiobus */
+
+&pinctrl_periphs {
+       tdmout_a: tdmout_a {
+               mux {
+                       pins = "GPIOX_12", "GPIOX_13", "GPIOX_15";
+                               //pins = "GPIOX_15";//slave
+                               function = "tdma_out";
+               };
+       };
+
+       tdmin_a: tdmin_a {
+               mux {
+                       pins = "GPIOX_14";
+                       //pins = "GPIOX_12", "GPIOX_13", "GPIOX_14";//slave
+                               function = "tdma_in";
+                       };
+       };
+       tdmb_mclk: tdmb_mclk {
+               mux {
+                       pins = "GPIOA_1";
+                       function = "mclk";
+               };
+       };
+
+       tdmout_b: tdmout_b {
+               mux {
+                       pins = "GPIOA_8", "GPIOA_9", "GPIOA_10",
+                               "GPIOA_11";
+                       function = "tdmb_out";
+               };
+       };
+       // tdmin and tdmout are the same pins. can't use at same time
+       /*
+        *tdmin_b:tdmin_b {
+        *      mux {
+        *              pins = "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13";
+        *              function = "tdmb_in";
+        *      };
+        *};
+        */
+
+       tdmc_mclk: tdmc_mclk {
+               mux {
+                       pins = "GPIOA_0";
+                       function = "mclk";
+               };
+       };
+
+       tdmout_c:tdmout_c {
+               mux {
+                       pins = "GPIOA_2", "GPIOA_3", "GPIOA_4",
+                               "GPIOA_5";
+                       function = "tdmc_out";
+               };
+       };
+
+       /*
+        *tdmin_c:tdmin_c {
+        *      mux {
+        *              pins = "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7";
+        *              function = "tdmc_in";
+        *      };
+        *};
+        */
+
+       spdifout: spidfout {
+               mux {
+                       pins = "GPIOA_20";
+                       function = "spdif_out";
+               };
+       };
+
+       spdifin: spidfin {
+               mux {
+                       pins = "GPIOA_19";
+                       function = "spdif_in";
+               };
+       };
+
+       pdmin: pdmin {
+               mux {
+                       pins = "GPIOA_14", "GPIOA_15", "GPIOA_16",
+                               "GPIOA_17", "GPIOA_18";
+                       function = "pdm";
+               };
+       };
+}; /* end of pinctrl_periphs */
+
 &spicc_a{
        status = "disabled";
        num_chipselect = <1>;
index d37e5aa..5c15369 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/amlogic,axg-clkc.h>
+#include <dt-bindings/clock/amlogic,axg-audio-clk.h>
 #include <dt-bindings/gpio/mesonaxg-gpio.h>
 #include <dt-bindings/pwm/pwm.h>
 #include <dt-bindings/pwm/meson.h>
                                reg = <0x0 0x0 0x0 0x320>;
                        };
                };/* end of hiubus*/
+
+               audiobus: audiobus@0xff642000 {
+                       compatible = "amlogic, audio-controller", "simple-bus";
+                       reg = <0x0 0xff642000 0x0 0x2000>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges = <0x0 0x0 0x0 0xff642000 0x0 0x2000>;
+                       clkaudio: audio_clocks {
+                               compatible = "amlogic, audio_clocks";
+                               #clock-cells = <1>;
+                               reg = <0x0 0x0 0x0 0xb0>;
+                       };
+               };/* end of audiobus*/
        }; /* end of soc*/
 
        pwm:meson-pwm {
index 2846bd5..758f651 100644 (file)
@@ -372,9 +372,13 @@ CONFIG_SND_SOC=y
 CONFIG_AMLOGIC_SND_SOC_CODECS=y
 CONFIG_AMLOGIC_SND_CODEC_DUMMY_CODEC=y
 CONFIG_AMLOGIC_SND_CODEC_PCM2BT=y
+CONFIG_AMLOGIC_SND_CODEC_PDM_DUMMY_CODEC=y
 CONFIG_AMLOGIC_SND_CODEC_AMLT9015=y
 CONFIG_AMLOGIC_SND_SOC_TAS5707=y
+CONFIG_AMLOGIC_SND_SOC_TLV320ADC3101=y
 CONFIG_AMLOGIC_SND_SOC=y
+CONFIG_AMLOGIC_SND_SOC_MESON=y
+CONFIG_AMLOGIC_SND_SOC_AUGE=y
 CONFIG_AMLOGIC_SND_SPLIT_MODE=y
 CONFIG_UHID=y
 CONFIG_USB_HIDDEV=y
index 0cbb5b3..88db2bb 100644 (file)
@@ -128,12 +128,12 @@ static const struct meson_desc_pin mesonaxg_periphs_pins[] = {
                MESON_FUNCTION(0x3, "norflash")),       /*NOR_CS */
        MESON_PINCTRL_PIN(MESON_PIN(GPIOA_0, EE_OFF), 0xb, 0,
                MESON_FUNCTION(0x0, "gpio"),
-               MESON_FUNCTION(0x1, "mclk_a"),          /*MCLK_A*/
+               MESON_FUNCTION(0x1, "mclk"),            /*MCLK_A*/
                MESON_FUNCTION(0x2, "pwm_vs"),          /*PWM_VS*/
                MESON_FUNCTION(0x5, "wifi")),           /*WIFI_BEACON*/
        MESON_PINCTRL_PIN(MESON_PIN(GPIOA_1, EE_OFF), 0xb, 4,
                MESON_FUNCTION(0x0, "gpio"),
-               MESON_FUNCTION(0x1, "mclk_a"),          /*MCLK_A*/
+               MESON_FUNCTION(0x1, "mclk"),            /*MCLK_B*/
                MESON_FUNCTION(0x3, "spdif_in"),        /*SPDIF_IN*/
                MESON_FUNCTION(0x4, "spdif_out"),       /*SPDIF_OUT*/
                MESON_FUNCTION(0x5, "wifi")),           /*WIFI_BEACON*/
@@ -286,15 +286,24 @@ static const struct meson_desc_pin mesonaxg_periphs_pins[] = {
                MESON_FUNCTION(0x3, "pwm_d")),          /*PWM_D*/
        MESON_PINCTRL_PIN(MESON_PIN(GPIOX_12, EE_OFF), 0x5, 16,
                MESON_FUNCTION(0x0, "gpio"),
+               MESON_FUNCTION(0x1, "tdma_out"),        /*TDMA_OUT*/
+               MESON_FUNCTION(0x2, "tdma_in"),         /*TDMA_IN*/
                MESON_FUNCTION(0x4, "eth")),            /*ETH_RGMII_RX_CLK*/
        MESON_PINCTRL_PIN(MESON_PIN(GPIOX_13, EE_OFF), 0x5, 20,
                MESON_FUNCTION(0x0, "gpio"),
+               MESON_FUNCTION(0x1, "tdma_out"),        /*TDMA_OUT*/
+               MESON_FUNCTION(0x2, "tdma_in"),         /*TDMA_IN*/
                MESON_FUNCTION(0x4, "eth")),            /*ETH_RXD0*/
        MESON_PINCTRL_PIN(MESON_PIN(GPIOX_14, EE_OFF), 0x5, 24,
                MESON_FUNCTION(0x0, "gpio"),
+               MESON_FUNCTION(0x1, "tdma_in"),         /*TDMA_IN*/
+               MESON_FUNCTION(0x2, "tdma_out"),        /*TDMA_OUT*/
                MESON_FUNCTION(0x4, "eth")),            /*ETH_RXD1*/
        MESON_PINCTRL_PIN(MESON_PIN(GPIOX_15, EE_OFF), 0x5, 28,
                MESON_FUNCTION(0x0, "gpio"),
+               MESON_FUNCTION(0x1, "tdma_out"),        /*TDMA_OUT*/
+               MESON_FUNCTION(0x2, "tdma_out1"),       /*TDMA_OUT1*/
+               MESON_FUNCTION(0x3, "tdma_in"),         /*TDMA_IN*/
                MESON_FUNCTION(0x4, "eth")),            /*ETH_RX_DV*/
        MESON_PINCTRL_PIN(MESON_PIN(GPIOX_16, EE_OFF), 0x6, 0,
                MESON_FUNCTION(0x0, "gpio"),
diff --git a/include/dt-bindings/clock/amlogic,axg-audio-clk.h b/include/dt-bindings/clock/amlogic,axg-audio-clk.h
new file mode 100644 (file)
index 0000000..5c2ad55
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * include/dt-bindings/clock/amlogic,axg-audio-clk.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AGX_AUDIO_CLK_H
+#define __AGX_AUDIO_CLK_H
+
+/*
+ * CLKID audio index values
+ */
+
+#define CLKID_AUDIO_DDR_ARB                                    0
+#define CLKID_AUDIO_PDM                                                1
+#define CLKID_AUDIO_TDMINA                                     2
+#define CLKID_AUDIO_TDMINB                                     3
+#define CLKID_AUDIO_TDMINC                                     4
+#define CLKID_AUDIO_TDMINLB                                    5
+#define CLKID_AUDIO_TDMOUTA                                    6
+#define CLKID_AUDIO_TDMOUTB                                    7
+#define CLKID_AUDIO_TDMOUTC                                    8
+#define CLKID_AUDIO_FRDDRA                                     9
+#define CLKID_AUDIO_FRDDRB                                     10
+#define CLKID_AUDIO_FRDDRC                                     11
+#define CLKID_AUDIO_TODDRA                                     12
+#define CLKID_AUDIO_TODDRB                                     13
+#define CLKID_AUDIO_TODDRC                                     14
+#define CLKID_AUDIO_LOOPBACK                           15
+#define CLKID_AUDIO_SPDIFIN                                    16
+#define CLKID_AUDIO_SPDIFOUT                           17
+#define CLKID_AUDIO_RESAMPLE                           18
+#define CLKID_AUDIO_POWER_DETECT                       19
+
+#define MCLK_BASE                                                      20
+#define CLKID_AUDIO_MCLK_A             (MCLK_BASE + 0)
+#define CLKID_AUDIO_MCLK_B             (MCLK_BASE + 1)
+#define CLKID_AUDIO_MCLK_C             (MCLK_BASE + 2)
+#define CLKID_AUDIO_MCLK_D             (MCLK_BASE + 3)
+#define CLKID_AUDIO_MCLK_E             (MCLK_BASE + 4)
+#define CLKID_AUDIO_MCLK_F             (MCLK_BASE + 5)
+
+#define CLKID_AUDIO_SPDIFIN_CTRL               (MCLK_BASE + 6)
+#define CLKID_AUDIO_SPDIFOUT_CTRL              (MCLK_BASE + 7)
+#define CLKID_AUDIO_PDMIN0             (MCLK_BASE + 8)
+#define CLKID_AUDIO_PDMIN1             (MCLK_BASE + 9)
+
+#define NUM_AUDIO_CLKS                 (MCLK_BASE + 10)
+#endif /* __AGX_AUDIO_CLK_H */
index 58d5799..41d8d56 100644 (file)
@@ -1,5 +1,9 @@
+#
+# Amlogic SoC audio configuration
+#
+
 menuconfig AMLOGIC_SND_SOC
-       bool "Amlogic Meson ASoC"
+       bool "Amlogic ASoC"
        default n
        help
          Say Y or M if you want to add support for codecs attached to
@@ -8,20 +12,26 @@ menuconfig AMLOGIC_SND_SOC
 
 if AMLOGIC_SND_SOC
 
-config AMLOGIC_SND_SPLIT_MODE
-       bool "AIU split mode, otherwise normal mode"
+config AMLOGIC_SND_SOC_MESON
+       bool "Amlogic Meson Asoc"
        depends on AMLOGIC_SND_SOC
        default n
        help
-               Say 'Y' to enable AIU split mode. If not, it's normal mode.
+         Say Y or M if you want to add support for meson arch to the
+         Amlogic Asoc Interface. it is for old audio arch, less than
+         kernel4.9.
 
-config AMLOGIC_SND_SPLIT_MODE_MMAP
-       bool "AIU split mode, mmap"
-       depends on AMLOGIC_SND_SPLIT_MODE
+config AMLOGIC_SND_SOC_AUGE
+       bool "Amlogic Auge Asoc"
        depends on AMLOGIC_SND_SOC
        default n
        help
-               Say 'Y' or 'N' to enable/disable AIU split mmap
+         Say Y or M if you want to add support for audio arch Auge
+         to the Amlogic Asoc Interface. it is a new audio arch to
+         distinguish Meson audio arch. it is base on kernel 4.9
 
-endif # AMLOGIC_SND_SOC
+# All the supported SoCs
+source "sound/soc/amlogic/meson/Kconfig"
+source "sound/soc/amlogic/auge/Kconfig"
 
+endif # AMLOGIC_SND_SOC
index a430b00..d1fa3c8 100644 (file)
@@ -1,31 +1,2 @@
-# AML Platform Support
-snd-soc-aml-pcm-objs := aml_pcm.o
-snd-soc-aml-i2s-objs := aml_i2s.o
-snd-soc-aml-i2s-dai-objs := aml_i2s_dai.o
-snd-soc-aml-pcm-dai-objs := aml_pcm_dai.o
-snd-soc-aml-spdif-dai-objs  := aml_spdif_dai.o
-snd-soc-aml-hw-objs  := aml_audio_hw.o
-snd-soc-aml-hw-pcm2bt-objs  := aml_audio_hw_pcm.o
-snd-soc-aml-dmic-objs  := aml_dmic.o
-
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-pcm.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-i2s.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-i2s-dai.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-pcm-dai.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-hw.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += aml_notify.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-hw-pcm2bt.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-spdif-dai.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-dmic.o
-
-# AML spdif codec support
-snd-soc-aml-spdif-codec-objs := aml_spdif_codec.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-spdif-codec.o
-
-#AML M8 Machine support
-snd-soc-aml-meson-objs := aml_meson.o
-obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-meson.o
-
-#AML G9TV Machine support
-snd-soc-aml-tv-objs := aml_tv.o
-#obj-$(CONFIG_AMLOGIC_SND_SOC) += snd-soc-aml-tv.o
+obj-$(CONFIG_AMLOGIC_SND_SOC)   += meson/
+obj-$(CONFIG_AMLOGIC_SND_SOC)   += auge/
diff --git a/sound/soc/amlogic/auge/Kconfig b/sound/soc/amlogic/auge/Kconfig
new file mode 100644 (file)
index 0000000..eafeb0d
--- /dev/null
@@ -0,0 +1,7 @@
+menuconfig AMLOGIC_SND_SOC_AUGE
+       bool "Amlogic Auge ASoC"
+       default n
+       help
+               Say Y or M if you want to add support for codecs attached to
+               the Amlogic Asoc interface. You will also need
+               to select the audio interfaces to support below.
diff --git a/sound/soc/amlogic/auge/Makefile b/sound/soc/amlogic/auge/Makefile
new file mode 100644 (file)
index 0000000..ec978fb
--- /dev/null
@@ -0,0 +1,14 @@
+obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE)     += audio_controller.o \
+                                               audio_io.o \
+                                               clocks.o \
+                                               card.o \
+                                               card_utils.o \
+                                               tdm.o \
+                                               tdm_hw.o \
+                                               spdif.o \
+                                               spdif_hw.o \
+                                               pdm.o \
+                                               pdm_hw.o \
+                                               pdm_hw_coeff.o \
+                                               iomap.o \
+                                               ddr_mngr.o
diff --git a/sound/soc/amlogic/auge/audio_controller.c b/sound/soc/amlogic/auge/audio_controller.c
new file mode 100644 (file)
index 0000000..eeb37d2
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * sound/soc/amlogic/auge/audio_controller.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/clk-provider.h>
+
+#include "audio_io.h"
+#include "regs.h"
+
+#define DRV_NAME "aml-audio-controller"
+
+static unsigned int aml_audio_mmio_read(struct aml_audio_controller *actrlr,
+                       unsigned int reg)
+{
+       struct regmap *regmap = actrlr->regmap;
+       unsigned int val;
+
+       regmap_read(regmap, (reg << 2), &val);
+
+       return val;
+}
+
+static int aml_audio_mmio_write(struct aml_audio_controller *actrlr,
+                       unsigned int reg, unsigned int value)
+{
+       struct regmap *regmap = actrlr->regmap;
+
+       return regmap_write(regmap, (reg << 2), value);
+}
+
+static int aml_audio_mmio_update_bits(struct aml_audio_controller *actrlr,
+                       unsigned int reg, unsigned int mask, unsigned int value)
+{
+       struct regmap *regmap = actrlr->regmap;
+
+       return regmap_update_bits(regmap, (reg << 2), mask, value);
+}
+
+struct aml_audio_ctrl_ops aml_actrl_mmio_ops = {
+       .read                   = aml_audio_mmio_read,
+       .write                  = aml_audio_mmio_write,
+       .update_bits    = aml_audio_mmio_update_bits,
+};
+
+static struct regmap_config aml_audio_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+};
+
+static const struct of_device_id amlogic_audio_controller_of_match[] = {
+       { .compatible = "amlogic, audio-controller" },
+       {},
+};
+
+static int register_audio_controller(struct platform_device *pdev,
+                       struct aml_audio_controller *actrl)
+{
+       struct resource *res_mem;
+       void __iomem *regs;
+       struct regmap *regmap;
+
+       /* get platform res from dtb */
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem)
+               return -ENOENT;
+
+       regs = devm_ioremap_resource(&pdev->dev, res_mem);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       aml_audio_regmap_config.max_register = 4 * resource_size(res_mem);
+
+       regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &aml_audio_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       /* init aml audio bus mmio controller */
+       aml_init_audio_controller(actrl, regmap, &aml_actrl_mmio_ops);
+       platform_set_drvdata(pdev, actrl);
+
+       /* gate on all clks on bringup stage, need gate separately */
+       aml_audiobus_write(actrl, EE_AUDIO_CLK_GATE_EN, 0xfffff);
+
+       return 0;
+}
+
+static int aml_audio_controller_probe(struct platform_device *pdev)
+{
+       struct aml_audio_controller *actrl;
+
+       pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+       actrl = devm_kzalloc(&pdev->dev, sizeof(*actrl), GFP_KERNEL);
+       if (!actrl)
+               return -ENOMEM;
+
+       return register_audio_controller(pdev, actrl);
+}
+
+static struct platform_driver aml_audio_controller_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = amlogic_audio_controller_of_match,
+       },
+       .probe = aml_audio_controller_probe,
+};
+module_platform_driver(aml_audio_controller_driver);
+
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("Amlogic audio controller ASoc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, amlogic_audio_controller_of_match);
diff --git a/sound/soc/amlogic/auge/audio_controller.h b/sound/soc/amlogic/auge/audio_controller.h
new file mode 100644 (file)
index 0000000..75480f8
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * sound/soc/amlogic/auge/audio_controller.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_AUDIO_CONTROLLER_H_
+#define __AML_AUDIO_CONTROLLER_H_
+
+struct aml_audio_controller;
+
+#endif
diff --git a/sound/soc/amlogic/auge/audio_io.c b/sound/soc/amlogic/auge/audio_io.c
new file mode 100644 (file)
index 0000000..feb75a1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * sound/soc/amlogic/auge/audio_io.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include "audio_io.h"
+
+int aml_init_audio_controller(struct aml_audio_controller *actrlr,
+                       struct regmap *regmap, struct aml_audio_ctrl_ops *ops)
+{
+       actrlr->regmap = regmap;
+       actrlr->ops = ops;
+
+       return 0;
+}
+
+int aml_audiobus_write(struct aml_audio_controller *actrlr,
+                       unsigned int reg, unsigned int value)
+{
+       if (actrlr->ops->write)
+               return actrlr->ops->write(actrlr, reg, value);
+
+       return -1;
+}
+
+unsigned int aml_audiobus_read(struct aml_audio_controller *actrlr,
+               unsigned int reg)
+{
+       if (actrlr->ops->read)
+               return actrlr->ops->read(actrlr, reg);
+
+       return 0;
+}
+
+int aml_audiobus_update_bits(struct aml_audio_controller *actrlr,
+       unsigned int reg, unsigned int mask, unsigned int value)
+{
+       if (actrlr->ops->update_bits)
+               return actrlr->ops->update_bits(actrlr, reg, mask, value);
+
+       return -1;
+}
+
+/* Module information */
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("ALSA Soc Aml Audio Utils");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amlogic/auge/audio_io.h b/sound/soc/amlogic/auge/audio_io.h
new file mode 100644 (file)
index 0000000..97b068a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * sound/soc/amlogic/auge/audio_io.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_AUDIO_IO_H_
+#define __AML_AUDIO_IO_H_
+
+struct aml_audio_controller;
+
+struct aml_audio_ctrl_ops {
+       unsigned int (*read)(struct aml_audio_controller *actrlr,
+                       unsigned int reg);
+       int (*write)(struct aml_audio_controller *actrlr,
+                       unsigned int reg, unsigned int value);
+       int (*update_bits)(struct aml_audio_controller *actrlr,
+               unsigned int reg, unsigned int mask, unsigned int value);
+};
+
+struct aml_audio_controller {
+       struct regmap *regmap;
+       const struct aml_audio_ctrl_ops *ops;
+};
+
+/* audio io controller */
+int aml_init_audio_controller(struct aml_audio_controller *actrlr,
+                       struct regmap *regmap, struct aml_audio_ctrl_ops *ops);
+int aml_audiobus_write(struct aml_audio_controller *actrlr,
+                       unsigned int reg, unsigned int value);
+unsigned int aml_audiobus_read(struct aml_audio_controller *actrlr,
+                       unsigned int reg);
+int aml_audiobus_update_bits(struct aml_audio_controller *actrlr,
+               unsigned int reg, unsigned int mask, unsigned int value);
+
+#endif
diff --git a/sound/soc/amlogic/auge/card.c b/sound/soc/amlogic/auge/card.c
new file mode 100644 (file)
index 0000000..97604e2
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * sound/soc/amlogic/auge/card.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include "card.h"
+
+struct aml_jack {
+       struct snd_soc_jack jack;
+       struct snd_soc_jack_pin pin;
+       struct snd_soc_jack_gpio gpio;
+};
+
+struct aml_card_data {
+       struct snd_soc_card snd_card;
+       struct aml_dai_props {
+               struct aml_dai cpu_dai;
+               struct aml_dai codec_dai;
+               unsigned int mclk_fs;
+       } *dai_props;
+       unsigned int mclk_fs;
+       struct aml_jack hp_jack;
+       struct aml_jack mic_jack;
+       struct snd_soc_dai_link *dai_link;
+};
+
+#define aml_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define aml_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define aml_priv_to_props(priv, i) ((priv)->dai_props + (i))
+
+#define DAI    "sound-dai"
+#define CELL   "#sound-dai-cells"
+#define PREFIX "aml-audio-card,"
+
+#define aml_card_init_hp(card, sjack, prefix)\
+       aml_card_init_jack(card, sjack, 1, prefix)
+#define aml_card_init_mic(card, sjack, prefix)\
+       aml_card_init_jack(card, sjack, 0, prefix)
+static int aml_card_init_jack(struct snd_soc_card *card,
+                                     struct aml_jack *sjack,
+                                     int is_hp, char *prefix)
+{
+       struct device *dev = card->dev;
+       enum of_gpio_flags flags;
+       char prop[128];
+       char *pin_name;
+       char *gpio_name;
+       int mask;
+       int det;
+
+       sjack->gpio.gpio = -ENOENT;
+
+       if (is_hp) {
+               snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
+               pin_name        = "Headphones";
+               gpio_name       = "Headphone detection";
+               mask            = SND_JACK_HEADPHONE;
+       } else {
+               snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
+               pin_name        = "Mic Jack";
+               gpio_name       = "Mic detection";
+               mask            = SND_JACK_MICROPHONE;
+       }
+
+       det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
+       if (det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       if (gpio_is_valid(det)) {
+               sjack->pin.pin          = pin_name;
+               sjack->pin.mask         = mask;
+
+               sjack->gpio.name        = gpio_name;
+               sjack->gpio.report      = mask;
+               sjack->gpio.gpio        = det;
+               sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
+               sjack->gpio.debounce_time = 150;
+
+               snd_soc_card_jack_new(card, pin_name, mask,
+                                     &sjack->jack,
+                                     &sjack->pin, 1);
+
+               snd_soc_jack_add_gpios(&sjack->jack, 1,
+                                      &sjack->gpio);
+       }
+
+       return 0;
+}
+
+static void aml_card_remove_jack(struct aml_jack *sjack)
+{
+       if (gpio_is_valid(sjack->gpio.gpio))
+               snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
+}
+
+static int aml_card_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct aml_card_data *priv =    snd_soc_card_get_drvdata(rtd->card);
+       struct aml_dai_props *dai_props =
+               aml_priv_to_props(priv, rtd->num);
+       int ret;
+
+       ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(dai_props->codec_dai.clk);
+       if (ret)
+               clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+       return ret;
+}
+
+static void aml_card_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct aml_card_data *priv =    snd_soc_card_get_drvdata(rtd->card);
+       struct aml_dai_props *dai_props =
+               aml_priv_to_props(priv, rtd->num);
+
+       clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+       clk_disable_unprepare(dai_props->codec_dai.clk);
+}
+
+static int aml_card_hw_params(struct snd_pcm_substream *substream,
+                                     struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct aml_dai_props *dai_props =
+               aml_priv_to_props(priv, rtd->num);
+       unsigned int mclk, mclk_fs = 0;
+       int ret = 0;
+
+       if (priv->mclk_fs)
+               mclk_fs = priv->mclk_fs;
+       else if (dai_props->mclk_fs)
+               mclk_fs = dai_props->mclk_fs;
+
+       if (mclk_fs) {
+               mclk = params_rate(params) * mclk_fs;
+               ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+                                            SND_SOC_CLOCK_IN);
+               if (ret && ret != -ENOTSUPP)
+                       goto err;
+
+               ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+                                            SND_SOC_CLOCK_OUT);
+               if (ret && ret != -ENOTSUPP)
+                       goto err;
+       }
+       return 0;
+err:
+       return ret;
+}
+
+static struct snd_soc_ops aml_card_ops = {
+       .startup = aml_card_startup,
+       .shutdown = aml_card_shutdown,
+       .hw_params = aml_card_hw_params,
+};
+
+static int aml_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct aml_card_data *priv =    snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *codec = rtd->codec_dai;
+       struct snd_soc_dai *cpu = rtd->cpu_dai;
+       struct aml_dai_props *dai_props =
+               aml_priv_to_props(priv, rtd->num);
+       int ret;
+
+       ret = aml_card_init_dai(codec, &dai_props->codec_dai);
+       if (ret < 0)
+               return ret;
+
+       ret = aml_card_init_dai(cpu, &dai_props->cpu_dai);
+       if (ret < 0)
+               return ret;
+
+       ret = aml_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
+       if (ret < 0)
+               return ret;
+
+       ret = aml_card_init_mic(rtd->card, &priv->hp_jack, PREFIX);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int aml_card_dai_link_of(struct device_node *node,
+                                       struct aml_card_data *priv,
+                                       int idx,
+                                       bool is_top_level_node)
+{
+       struct device *dev = aml_priv_to_dev(priv);
+       struct snd_soc_dai_link *dai_link = aml_priv_to_link(priv, idx);
+       struct aml_dai_props *dai_props = aml_priv_to_props(priv, idx);
+       struct aml_dai *cpu_dai = &dai_props->cpu_dai;
+       struct aml_dai *codec_dai = &dai_props->codec_dai;
+       struct device_node *cpu = NULL;
+       struct device_node *plat = NULL;
+       struct device_node *codec = NULL;
+       char prop[128];
+       char *prefix = "";
+       int ret, single_cpu;
+
+       /* For single DAI link & old style of DT node */
+       if (is_top_level_node)
+               prefix = PREFIX;
+
+       snprintf(prop, sizeof(prop), "%scpu", prefix);
+       cpu = of_get_child_by_name(node, prop);
+
+       snprintf(prop, sizeof(prop), "%splat", prefix);
+       plat = of_get_child_by_name(node, prop);
+
+       snprintf(prop, sizeof(prop), "%scodec", prefix);
+       codec = of_get_child_by_name(node, prop);
+
+       if (!cpu || !codec) {
+               ret = -EINVAL;
+               dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+               goto dai_link_of_err;
+       }
+
+       ret = aml_card_parse_daifmt(dev, node, codec,
+                                           prefix, &dai_link->dai_fmt);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
+
+       ret = aml_card_parse_cpu(cpu, dai_link,
+                                        DAI, CELL, &single_cpu);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+#if 0
+       ret = aml_card_parse_codec(codec, dai_link, DAI, CELL);
+#else
+       ret = snd_soc_of_get_dai_link_codecs(dev, codec, dai_link);
+#endif
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       ret = aml_card_parse_platform(plat, dai_link, DAI, CELL);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       ret = snd_soc_of_parse_tdm_slot(cpu,    &cpu_dai->tx_slot_mask,
+                                               &cpu_dai->rx_slot_mask,
+                                               &cpu_dai->slots,
+                                               &cpu_dai->slot_width);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       ret = snd_soc_of_parse_tdm_slot(codec,  &codec_dai->tx_slot_mask,
+                                               &codec_dai->rx_slot_mask,
+                                               &codec_dai->slots,
+                                               &codec_dai->slot_width);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       ret = aml_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+#if 0
+       ret = aml_card_parse_clk_codec(codec, dai_link, codec_dai);
+       if (ret < 0)
+               goto dai_link_of_err;
+#endif
+
+       ret = aml_card_canonicalize_dailink(dai_link);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       ret = aml_card_set_dailink_name(dev, dai_link,
+                                               "%s-%s",
+                                               dai_link->cpu_dai_name,
+                                               dai_link->codecs->dai_name);
+       if (ret < 0)
+               goto dai_link_of_err;
+
+       dai_link->ops = &aml_card_ops;
+       dai_link->init = aml_card_dai_init;
+
+       dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
+       dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
+       dev_dbg(dev, "\tcpu : %s / %d\n",
+               dai_link->cpu_dai_name,
+               dai_props->cpu_dai.sysclk);
+       dev_dbg(dev, "\tcodec : %s / %d\n",
+               dai_link->codecs->dai_name,
+               dai_props->codec_dai.sysclk);
+
+       aml_card_canonicalize_cpu(dai_link, single_cpu);
+
+dai_link_of_err:
+       of_node_put(cpu);
+       of_node_put(codec);
+
+       return ret;
+}
+
+static int aml_card_parse_aux_devs(struct device_node *node,
+                                          struct aml_card_data *priv)
+{
+       struct device *dev = aml_priv_to_dev(priv);
+       struct device_node *aux_node;
+       int i, n, len;
+
+       if (!of_find_property(node, PREFIX "aux-devs", &len))
+               return 0;               /* Ok to have no aux-devs */
+
+       n = len / sizeof(__be32);
+       if (n <= 0)
+               return -EINVAL;
+
+       priv->snd_card.aux_dev = devm_kzalloc(dev,
+                       n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL);
+       if (!priv->snd_card.aux_dev)
+               return -ENOMEM;
+
+       for (i = 0; i < n; i++) {
+               aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
+               if (!aux_node)
+                       return -EINVAL;
+               priv->snd_card.aux_dev[i].codec_of_node = aux_node;
+       }
+
+       priv->snd_card.num_aux_devs = n;
+       return 0;
+}
+
+static int aml_card_parse_of(struct device_node *node,
+                                    struct aml_card_data *priv)
+{
+       struct device *dev = aml_priv_to_dev(priv);
+       struct device_node *dai_link;
+       int ret;
+
+       if (!node)
+               return -EINVAL;
+
+       dai_link = of_get_child_by_name(node, PREFIX "dai-link");
+
+       /* The off-codec widgets */
+       if (of_property_read_bool(node, PREFIX "widgets")) {
+               ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
+                                       PREFIX "widgets");
+               if (ret)
+                       goto card_parse_end;
+       }
+
+       /* DAPM routes */
+       if (of_property_read_bool(node, PREFIX "routing")) {
+               ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
+                                       PREFIX "routing");
+               if (ret)
+                       goto card_parse_end;
+       }
+
+       /* Factor to mclk, used in hw_params() */
+       of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
+
+       /* Single/Muti DAI link(s) & New style of DT node */
+       if (dai_link) {
+               struct device_node *np = NULL;
+               int i = 0;
+
+               for_each_child_of_node(node, np) {
+                       dev_dbg(dev, "\tlink %d:\n", i);
+                       ret = aml_card_dai_link_of(np, priv,
+                                                          i, false);
+                       if (ret < 0) {
+                               of_node_put(np);
+                               goto card_parse_end;
+                       }
+                       i++;
+               }
+       } else {
+               /* For single DAI link & old style of DT node */
+               ret = aml_card_dai_link_of(node, priv, 0, true);
+               if (ret < 0)
+                       goto card_parse_end;
+       }
+
+       ret = aml_card_parse_card_name(&priv->snd_card, PREFIX);
+       if (ret < 0)
+               goto card_parse_end;
+
+       ret = aml_card_parse_aux_devs(node, priv);
+
+card_parse_end:
+       of_node_put(dai_link);
+
+       return ret;
+}
+
+static int aml_card_probe(struct platform_device *pdev)
+{
+       struct aml_card_data *priv;
+       struct snd_soc_dai_link *dai_link;
+       struct aml_dai_props *dai_props;
+       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       int num, ret;
+
+       /* Get the number of DAI links */
+       if (np && of_get_child_by_name(np, PREFIX "dai-link"))
+               num = of_get_child_count(np);
+       else
+               num = 1;
+
+       /* Allocate the private data and the DAI link array */
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
+       dai_link  = devm_kzalloc(dev, sizeof(*dai_link)  * num, GFP_KERNEL);
+       if (!dai_props || !dai_link)
+               return -ENOMEM;
+
+       priv->dai_props                 = dai_props;
+       priv->dai_link                  = dai_link;
+
+       /* Init snd_soc_card */
+       priv->snd_card.owner            = THIS_MODULE;
+       priv->snd_card.dev              = dev;
+       priv->snd_card.dai_link         = priv->dai_link;
+       priv->snd_card.num_links        = num;
+
+       if (np && of_device_is_available(np)) {
+
+               ret = aml_card_parse_of(np, priv);
+               if (ret < 0) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "%s, parse error %d\n",
+                                       __func__, ret);
+                       goto err;
+               }
+
+       } else {
+               struct aml_card_info *cinfo;
+
+               cinfo = dev->platform_data;
+               if (!cinfo) {
+                       dev_err(dev, "no info for asoc-aml-card\n");
+                       return -EINVAL;
+               }
+
+               if (!cinfo->name ||
+                   !cinfo->codec_dai.name ||
+                   !cinfo->codec ||
+                   !cinfo->platform ||
+                   !cinfo->cpu_dai.name) {
+                       dev_err(dev, "insufficient aml_card_info settings\n");
+                       return -EINVAL;
+               }
+
+               priv->snd_card.name     =
+                               (cinfo->card) ? cinfo->card : cinfo->name;
+               dai_link->name          = cinfo->name;
+               dai_link->stream_name   = cinfo->name;
+               dai_link->platform_name = cinfo->platform;
+               dai_link->codec_name    = cinfo->codec;
+               dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
+               dai_link->codec_dai_name = cinfo->codec_dai.name;
+               dai_link->dai_fmt       = cinfo->daifmt;
+               dai_link->init          = aml_card_dai_init;
+               memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
+                                       sizeof(priv->dai_props->cpu_dai));
+               memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
+                                       sizeof(priv->dai_props->codec_dai));
+       }
+
+       snd_soc_card_set_drvdata(&priv->snd_card, priv);
+
+       ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+       if (ret >= 0)
+               return ret;
+err:
+       aml_card_clean_reference(&priv->snd_card);
+
+       return ret;
+}
+
+static int aml_card_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct aml_card_data *priv = snd_soc_card_get_drvdata(card);
+
+       aml_card_remove_jack(&priv->hp_jack);
+       aml_card_remove_jack(&priv->mic_jack);
+
+       return aml_card_clean_reference(card);
+}
+
+static const struct of_device_id aml_of_match[] = {
+       { .compatible = "amlogic, sound-card", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, aml_of_match);
+
+static struct platform_driver aml_card = {
+       .driver = {
+               .name = "asoc-aml-card",
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = aml_of_match,
+       },
+       .probe = aml_card_probe,
+       .remove = aml_card_remove,
+};
+
+module_platform_driver(aml_card);
+
+MODULE_ALIAS("platform:asoc-aml-card");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC aml Sound Card");
+MODULE_AUTHOR("AMLogic, Inc.");
diff --git a/sound/soc/amlogic/auge/card.h b/sound/soc/amlogic/auge/card.h
new file mode 100644 (file)
index 0000000..1199d25
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * sound/soc/amlogic/auge/card.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_CARD_H_
+#define __AML_CARD_H_
+
+#include <sound/soc.h>
+#include "card_utils.h"
+
+struct aml_card_info {
+       const char *name;
+       const char *card;
+       const char *codec;
+       const char *platform;
+
+       unsigned int daifmt;
+       struct aml_dai cpu_dai;
+       struct aml_dai codec_dai;
+};
+
+#endif /* __AML_CARD_H_ */
diff --git a/sound/soc/amlogic/auge/card_utils.c b/sound/soc/amlogic/auge/card_utils.c
new file mode 100644 (file)
index 0000000..3b6b8e1
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * sound/soc/amlogic/auge/card_utils.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include "card_utils.h"
+
+int aml_card_parse_daifmt(struct device *dev,
+                                 struct device_node *node,
+                                 struct device_node *codec,
+                                 char *prefix,
+                                 unsigned int *retfmt)
+{
+       struct device_node *bitclkmaster = NULL;
+       struct device_node *framemaster = NULL;
+       int prefix_len = prefix ? strlen(prefix) : 0;
+       unsigned int daifmt;
+
+       daifmt = snd_soc_of_parse_daifmt(node, prefix,
+                                        &bitclkmaster, &framemaster);
+       daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+       if (prefix_len && !bitclkmaster && !framemaster) {
+               /*
+                * No dai-link level and master setting was not found from
+                * sound node level, revert back to legacy DT parsing and
+                * take the settings from codec node.
+                */
+               dev_dbg(dev, "Revert to legacy daifmt parsing\n");
+
+               daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
+                       (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
+       } else {
+               if (codec == bitclkmaster)
+                       daifmt |= (codec == framemaster) ?
+                               SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
+               else
+                       daifmt |= (codec == framemaster) ?
+                               SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
+       }
+
+       of_node_put(bitclkmaster);
+       of_node_put(framemaster);
+
+       *retfmt = daifmt;
+
+       return 0;
+}
+
+int aml_card_set_dailink_name(struct device *dev,
+                                     struct snd_soc_dai_link *dai_link,
+                                     const char *fmt, ...)
+{
+       va_list ap;
+       char *name = NULL;
+       int ret = -ENOMEM;
+
+       va_start(ap, fmt);
+       name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
+       va_end(ap);
+
+       if (name) {
+               ret = 0;
+
+               dai_link->name          = name;
+               dai_link->stream_name   = name;
+       }
+
+       return ret;
+}
+
+int aml_card_parse_card_name(struct snd_soc_card *card,
+                                    char *prefix)
+{
+       char prop[128];
+       int ret;
+
+       snprintf(prop, sizeof(prop), "%sname", prefix);
+
+       /* Parse the card name from DT */
+       ret = snd_soc_of_parse_card_name(card, prop);
+       if (ret < 0)
+               return ret;
+
+       if (!card->name && card->dai_link)
+               card->name = card->dai_link->name;
+
+       return 0;
+}
+
+int aml_card_parse_clk(struct device_node *node,
+                              struct device_node *dai_of_node,
+                              struct aml_dai *aml_dai)
+{
+       struct clk *clk;
+       u32 val;
+
+       /*
+        * Parse dai->sysclk come from "clocks = <&xxx>"
+        * (if system has common clock)
+        *  or "system-clock-frequency = <xxx>"
+        *  or device's module clock.
+        */
+       clk = of_clk_get(node, 0);
+       if (!IS_ERR(clk)) {
+               aml_dai->sysclk = clk_get_rate(clk);
+               aml_dai->clk = clk;
+       } else if (!of_property_read_u32(node,
+                       "system-clock-frequency", &val)) {
+               aml_dai->sysclk = val;
+       } else {
+               clk = of_clk_get(dai_of_node, 0);
+               if (!IS_ERR(clk))
+                       aml_dai->sysclk = clk_get_rate(clk);
+       }
+
+       return 0;
+}
+
+int aml_card_parse_dai(struct device_node *node,
+                                   struct device_node **dai_of_node,
+                                   const char **dai_name,
+                                   const char *list_name,
+                                   const char *cells_name,
+                                   int *is_single_link)
+{
+       struct of_phandle_args args;
+       int ret;
+
+       if (!node)
+               return 0;
+
+       /*
+        * Get node via "sound-dai = <&phandle port>"
+        * it will be used as xxx_of_node on soc_bind_dai_link()
+        */
+       ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args);
+       if (ret)
+               return ret;
+
+       /* Get dai->name */
+       if (dai_name) {
+               ret = snd_soc_of_get_dai_name(node, dai_name);
+               if (ret < 0)
+                       return ret;
+       }
+
+       *dai_of_node = args.np;
+
+       if (is_single_link)
+               *is_single_link = !args.args_count;
+
+       return 0;
+}
+
+int aml_card_init_dai(struct snd_soc_dai *dai,
+                             struct aml_dai *aml_dai)
+{
+       int ret;
+
+       if (aml_dai->sysclk) {
+               ret = snd_soc_dai_set_sysclk(dai, 0, aml_dai->sysclk, 0);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dai->dev, "aml-card: set_sysclk error\n");
+                       return ret;
+               }
+       }
+
+       if (aml_dai->slots) {
+               ret = snd_soc_dai_set_tdm_slot(dai,
+                                              aml_dai->tx_slot_mask,
+                                              aml_dai->rx_slot_mask,
+                                              aml_dai->slots,
+                                              aml_dai->slot_width);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dai->dev, "aml-card: set_tdm_slot error\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+int aml_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
+{
+       if (!dai_link->cpu_dai_name ||
+                       (!dai_link->codec_dai_name && !dai_link->codecs))
+               return -EINVAL;
+
+       /* Assumes platform == cpu */
+       if (!dai_link->platform_of_node)
+               dai_link->platform_of_node = dai_link->cpu_of_node;
+
+       return 0;
+}
+
+void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
+                                      int is_single_links)
+{
+       /*
+        * In soc_bind_dai_link() will check cpu name after
+        * of_node matching if dai_link has cpu_dai_name.
+        * but, it will never match if name was created by
+        * fmt_single_name() remove cpu_dai_name if cpu_args
+        * was 0. See:
+        *      fmt_single_name()
+        *      fmt_multiple_name()
+        */
+       if (is_single_links)
+               dai_link->cpu_dai_name = NULL;
+}
+
+int aml_card_clean_reference(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *dai_link;
+       int num_links;
+
+       for (num_links = 0, dai_link = card->dai_link;
+            num_links < card->num_links;
+            num_links++, dai_link++) {
+               of_node_put(dai_link->cpu_of_node);
+               of_node_put(dai_link->codec_of_node);
+       }
+       return 0;
+}
diff --git a/sound/soc/amlogic/auge/card_utils.h b/sound/soc/amlogic/auge/card_utils.h
new file mode 100644 (file)
index 0000000..c88dcf8
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * sound/soc/amlogic/auge/card_utils.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_CARD_CORE_H
+#define __AML_CARD_CORE_H
+
+#include <sound/soc.h>
+
+struct aml_dai {
+       const char *name;
+       unsigned int sysclk;
+       int slots;
+       int slot_width;
+       unsigned int tx_slot_mask;
+       unsigned int rx_slot_mask;
+       struct clk *clk;
+};
+
+int aml_card_parse_daifmt(struct device *dev,
+                                 struct device_node *node,
+                                 struct device_node *codec,
+                                 char *prefix,
+                                 unsigned int *retfmt);
+__printf(3, 4)
+int aml_card_set_dailink_name(struct device *dev,
+                                     struct snd_soc_dai_link *dai_link,
+                                     const char *fmt, ...);
+int aml_card_parse_card_name(struct snd_soc_card *card,
+                                    char *prefix);
+
+#define aml_card_parse_clk_cpu(node, dai_link, aml_dai)                \
+       aml_card_parse_clk(node, dai_link->cpu_of_node, aml_dai)
+#define aml_card_parse_clk_codec(node, dai_link, aml_dai)              \
+       aml_card_parse_clk(node, dai_link->codec_of_node, aml_dai)
+int aml_card_parse_clk(struct device_node *node,
+                              struct device_node *dai_of_node,
+                              struct aml_dai *aml_dai);
+
+#define aml_card_parse_cpu(node, dai_link,                             \
+                       list_name, cells_name, is_single_link)  \
+       aml_card_parse_dai(node, &dai_link->cpu_of_node,                \
+               &dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
+#define aml_card_parse_codec(node, dai_link, list_name, cells_name)    \
+       aml_card_parse_dai(node, &dai_link->codec_of_node,              \
+               &dai_link->codec_dai_name, list_name, cells_name, NULL)
+#define aml_card_parse_platform(node, dai_link, list_name, cells_name) \
+       aml_card_parse_dai(node, &dai_link->platform_of_node,           \
+               NULL, list_name, cells_name, NULL)
+int aml_card_parse_dai(struct device_node *node,
+                                 struct device_node **endpoint_np,
+                                 const char **dai_name,
+                                 const char *list_name,
+                                 const char *cells_name,
+                                 int *is_single_links);
+
+int aml_card_init_dai(struct snd_soc_dai *dai,
+                             struct aml_dai *aml_dai);
+
+int aml_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link);
+void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
+                                     int is_single_links);
+
+int aml_card_clean_reference(struct snd_soc_card *card);
+
+#endif /* __AML_CARD_CORE_H */
diff --git a/sound/soc/amlogic/auge/clocks.c b/sound/soc/amlogic/auge/clocks.c
new file mode 100644 (file)
index 0000000..ab6f8f9
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * sound/soc/amlogic/auge/audio_clocks.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/amlogic,axg-audio-clk.h>
+
+#include <linux/clk-provider.h>
+#include "regs.h"
+
+#define DRV_NAME "aml-audio-clocks"
+
+spinlock_t aclk_lock;
+
+#define CLOCK_GATE(_name, _reg, _bit) \
+struct clk_gate _name = { \
+       .reg = (void __iomem *)(_reg), \
+       .bit_idx = (_bit), \
+       .lock = &aclk_lock,     \
+       .hw.init = &(struct clk_init_data) { \
+               .name = #_name, \
+               .ops = &clk_gate_ops, \
+               .parent_names = (const char *[]){ "clk81" }, \
+               .num_parents = 1, \
+               .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
+       }, \
+}
+
+static CLOCK_GATE(audio_ddr_arb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 0);
+static CLOCK_GATE(audio_pdm, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 1);
+static CLOCK_GATE(audio_tdmina, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 2);
+static CLOCK_GATE(audio_tdminb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 3);
+static CLOCK_GATE(audio_tdminc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 4);
+static CLOCK_GATE(audio_tdminlb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 5);
+static CLOCK_GATE(audio_tdmouta, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 6);
+static CLOCK_GATE(audio_tdmoutb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 7);
+static CLOCK_GATE(audio_tdmoutc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 8);
+static CLOCK_GATE(audio_frddra, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 9);
+static CLOCK_GATE(audio_frddrb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 10);
+static CLOCK_GATE(audio_frddrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 11);
+static CLOCK_GATE(audio_toddra, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 12);
+static CLOCK_GATE(audio_toddrb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 13);
+static CLOCK_GATE(audio_toddrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 14);
+static CLOCK_GATE(audio_loopback, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 15);
+static CLOCK_GATE(audio_spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 16);
+static CLOCK_GATE(audio_spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 17);
+static CLOCK_GATE(audio_resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 18);
+static CLOCK_GATE(audio_power_detect,
+               AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN), 19);
+
+static struct clk_gate *audio_clk_gates[] = {
+       &audio_ddr_arb,
+       &audio_pdm,
+       &audio_tdmina,
+       &audio_tdminb,
+       &audio_tdminc,
+       &audio_tdminlb,
+       &audio_tdmouta,
+       &audio_tdmoutb,
+       &audio_tdmoutc,
+       &audio_frddra,
+       &audio_frddrb,
+       &audio_frddrc,
+       &audio_toddra,
+       &audio_toddrb,
+       &audio_toddrc,
+       &audio_loopback,
+       &audio_spdifin,
+       &audio_spdifout,
+       &audio_resample,
+       &audio_power_detect,
+};
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw *audio_clk_hws[] = {
+       [CLKID_AUDIO_DDR_ARB] = &audio_ddr_arb.hw,
+       [CLKID_AUDIO_PDM] = &audio_pdm.hw,
+       [CLKID_AUDIO_TDMINA] = &audio_tdmina.hw,
+       [CLKID_AUDIO_TDMINB] = &audio_tdminb.hw,
+       [CLKID_AUDIO_TDMINC] = &audio_tdminc.hw,
+       [CLKID_AUDIO_TDMINLB] = &audio_tdminlb.hw,
+       [CLKID_AUDIO_TDMOUTA] = &audio_tdmouta.hw,
+       [CLKID_AUDIO_TDMOUTB] = &audio_tdmoutb.hw,
+       [CLKID_AUDIO_TDMOUTC] = &audio_tdmoutc.hw,
+       [CLKID_AUDIO_FRDDRA] = &audio_frddra.hw,
+       [CLKID_AUDIO_FRDDRB] = &audio_frddrb.hw,
+       [CLKID_AUDIO_FRDDRC] = &audio_frddrc.hw,
+       [CLKID_AUDIO_TODDRA] = &audio_toddra.hw,
+       [CLKID_AUDIO_TODDRB] = &audio_toddrb.hw,
+       [CLKID_AUDIO_TODDRC] = &audio_toddrc.hw,
+       [CLKID_AUDIO_LOOPBACK] = &audio_loopback.hw,
+       [CLKID_AUDIO_SPDIFIN] = &audio_spdifin.hw,
+       [CLKID_AUDIO_SPDIFOUT] = &audio_spdifout.hw,
+       [CLKID_AUDIO_RESAMPLE] = &audio_resample.hw,
+       [CLKID_AUDIO_POWER_DETECT] = &audio_power_detect.hw,
+};
+
+const char *mclk_parent_names[] = {"mpll0", "mpll1", "mpll2", "mpll3",
+       "hifi_pll", "fclk_div3", "fclk_div4", "gp0_pll"};
+
+#define CLOCK_COM_MUX(_name, _reg, _mask, _shift) \
+struct clk_mux _name##_mux = { \
+       .reg = (void __iomem *)(_reg), \
+       .mask = (_mask), \
+       .shift = (_shift), \
+       .lock = &aclk_lock,     \
+}
+#define CLOCK_COM_DIV(_name, _reg, _shift, _width) \
+struct clk_divider _name##_div = { \
+       .reg = (void __iomem *)(_reg), \
+       .shift = (_shift), \
+       .width = (_width), \
+       .lock = &aclk_lock,     \
+}
+#define CLOCK_COM_GATE(_name, _reg, _bit) \
+struct clk_gate _name##_gate = { \
+       .reg = (void __iomem *)(_reg), \
+       .bit_idx = (_bit), \
+       .lock = &aclk_lock,     \
+}
+
+/* mclk_a */
+CLOCK_COM_MUX(mclk_a, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_A_CTRL), 0x7, 24);
+CLOCK_COM_DIV(mclk_a, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_A_CTRL), 0, 16);
+CLOCK_COM_GATE(mclk_a, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_A_CTRL), 31);
+/* mclk_b */
+CLOCK_COM_MUX(mclk_b, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_B_CTRL), 0x7, 24);
+CLOCK_COM_DIV(mclk_b, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_B_CTRL), 0, 16);
+CLOCK_COM_GATE(mclk_b, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_B_CTRL), 31);
+/* mclk_c */
+CLOCK_COM_MUX(mclk_c, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_C_CTRL), 0x7, 24);
+CLOCK_COM_DIV(mclk_c, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_C_CTRL), 0, 16);
+CLOCK_COM_GATE(mclk_c, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_C_CTRL), 31);
+/* mclk_d */
+CLOCK_COM_MUX(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL), 0x7, 24);
+CLOCK_COM_DIV(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL), 0, 16);
+CLOCK_COM_GATE(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL), 31);
+/* mclk_e */
+CLOCK_COM_MUX(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL), 0x7, 24);
+CLOCK_COM_DIV(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL), 0, 16);
+CLOCK_COM_GATE(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL), 31);
+/* mclk_f */
+CLOCK_COM_MUX(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL), 0x7, 24);
+CLOCK_COM_DIV(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL), 0, 16);
+CLOCK_COM_GATE(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL), 31);
+/* spdifin */
+CLOCK_COM_MUX(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 0x7, 24);
+CLOCK_COM_DIV(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 0, 8);
+CLOCK_COM_GATE(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 31);
+/* spdifout */
+CLOCK_COM_MUX(spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_CTRL), 0x7, 24);
+CLOCK_COM_DIV(spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_CTRL), 0, 10);
+CLOCK_COM_GATE(spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_CTRL), 31);
+/* pdmin0 */
+CLOCK_COM_MUX(pdmin0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL0), 0x7, 24);
+CLOCK_COM_DIV(pdmin0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL0), 0, 16);
+CLOCK_COM_GATE(pdmin0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL0), 31);
+/* pdmin1 */
+CLOCK_COM_MUX(pdmin1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL1), 0x7, 24);
+CLOCK_COM_DIV(pdmin1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL1), 0, 16);
+CLOCK_COM_GATE(pdmin1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL1), 31);
+
+#define IOMAP_COM_CLK(_name, _iobase) \
+do { \
+       _name##_mux.reg += (unsigned long)(iobase); \
+       _name##_div.reg += (unsigned long)(iobase); \
+       _name##_gate.reg += (unsigned long)(iobase); \
+} while (0)
+
+#define REGISTER_CLK_COM(_name) \
+       clk_register_composite(NULL, #_name, \
+                       mclk_parent_names, ARRAY_SIZE(mclk_parent_names), \
+                       &_name##_mux.hw, &clk_mux_ops, \
+                       &_name##_div.hw, &clk_divider_ops, \
+                       &_name##_gate.hw, &clk_gate_ops, \
+                       CLK_SET_RATE_NO_REPARENT)
+
+static int register_audio_clk(struct clk **clks, void __iomem *iobase)
+{
+       IOMAP_COM_CLK(mclk_a, iobase);
+       clks[CLKID_AUDIO_MCLK_A] = REGISTER_CLK_COM(mclk_a);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_MCLK_A]));
+
+       IOMAP_COM_CLK(mclk_b, iobase);
+       clks[CLKID_AUDIO_MCLK_B] = REGISTER_CLK_COM(mclk_b);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_MCLK_B]));
+
+       IOMAP_COM_CLK(mclk_c, iobase);
+       clks[CLKID_AUDIO_MCLK_C] = REGISTER_CLK_COM(mclk_c);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_MCLK_C]));
+
+       IOMAP_COM_CLK(mclk_d, iobase);
+       clks[CLKID_AUDIO_MCLK_D] = REGISTER_CLK_COM(mclk_d);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_MCLK_D]));
+
+       IOMAP_COM_CLK(mclk_e, iobase);
+       clks[CLKID_AUDIO_MCLK_E] = REGISTER_CLK_COM(mclk_e);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_MCLK_E]));
+
+       IOMAP_COM_CLK(mclk_f, iobase);
+       clks[CLKID_AUDIO_MCLK_F] = REGISTER_CLK_COM(mclk_f);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_MCLK_F]));
+
+       IOMAP_COM_CLK(spdifin, iobase);
+       clks[CLKID_AUDIO_SPDIFIN_CTRL] = REGISTER_CLK_COM(spdifin);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_SPDIFIN_CTRL]));
+
+       IOMAP_COM_CLK(spdifout, iobase);
+       clks[CLKID_AUDIO_SPDIFOUT_CTRL] = REGISTER_CLK_COM(spdifout);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_SPDIFOUT_CTRL]));
+
+       IOMAP_COM_CLK(pdmin0, iobase);
+       clks[CLKID_AUDIO_PDMIN0] = REGISTER_CLK_COM(pdmin0);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_PDMIN0]));
+
+       IOMAP_COM_CLK(pdmin1, iobase);
+       clks[CLKID_AUDIO_PDMIN1] = REGISTER_CLK_COM(pdmin1);
+       WARN_ON(IS_ERR(clks[CLKID_AUDIO_PDMIN1]));
+
+       return 0;
+}
+
+static int aml_audio_clocks_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct clk **clks;
+       struct clk_onecell_data *clk_data;
+       void __iomem *clk_base;
+       int clkid, ret;
+
+       clk_base = of_iomap(np, 0);
+       if (!clk_base) {
+               dev_err(dev, "%s: Unable to map clk base\n", __func__);
+               return -ENXIO;
+       }
+
+       clk_data = devm_kmalloc(dev, sizeof(*clk_data), GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clks = devm_kmalloc(dev, NUM_AUDIO_CLKS * sizeof(*clks), GFP_KERNEL);
+       if (!clks)
+               return -ENOMEM;
+
+       /* register all audio clks */
+       if (ARRAY_SIZE(audio_clk_gates) == MCLK_BASE
+                       && ARRAY_SIZE(audio_clk_gates) == MCLK_BASE) {
+               dev_info(dev, "%s register audio gate clks\n", __func__);
+               for (clkid = 0; clkid < MCLK_BASE; clkid++) {
+                       audio_clk_gates[clkid]->reg += (unsigned long)clk_base;
+                       clks[clkid] = clk_register(NULL, audio_clk_hws[clkid]);
+                       WARN_ON(IS_ERR(clks[clkid]));
+               }
+       } else {
+               return -EINVAL;
+       }
+
+       /* register composite audio clks */
+       register_audio_clk(clks, clk_base);
+
+       clk_data->clks = clks;
+       clk_data->clk_num = NUM_AUDIO_CLKS;
+
+       ret = of_clk_add_provider(np, of_clk_src_onecell_get,
+                       clk_data);
+       if (ret < 0)
+               dev_err(dev, "%s fail ret: %d\n", __func__, ret);
+
+       return 0;
+}
+
+static const struct of_device_id amlogic_audio_clocks_of_match[] = {
+       { .compatible = "amlogic, audio_clocks" },
+       {},
+};
+
+static struct platform_driver aml_audio_clocks_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = amlogic_audio_clocks_of_match,
+       },
+       .probe = aml_audio_clocks_probe,
+};
+module_platform_driver(aml_audio_clocks_driver);
+
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("Amlogic audio clocks ASoc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, amlogic_audio_clocks_of_match);
diff --git a/sound/soc/amlogic/auge/ddr_mngr.c b/sound/soc/amlogic/auge/ddr_mngr.c
new file mode 100644 (file)
index 0000000..3f4ff75
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * sound/soc/amlogic/auge/ddr_mngr.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "regs.h"
+#include "ddr_mngr.h"
+
+static DEFINE_MUTEX(ddr_mutex);
+
+struct ddr_desc {
+       /* start address of DDR */
+       unsigned int start;
+       /* finish address of DDR */
+       unsigned int finish;
+       /* interrupt address or counts of DDR blocks */
+       unsigned int intrpt;
+       /* fifo total counts */
+       unsigned int fifo_depth;
+       /* fifo start threshold */
+       unsigned int fifo_thr;
+       enum ddr_types data_type;
+       unsigned int edian;
+       unsigned int pp_mode;
+       //unsigned int reg_base;
+       struct clk *ddr;
+       struct clk *ddr_arb;
+};
+
+struct toddr {
+       struct ddr_desc dscrpt;
+       struct device *dev;
+       unsigned int resample: 1;
+       unsigned int ext_signed: 1;
+       unsigned int msb_bit;
+       unsigned int lsb_bit;
+       unsigned int reg_base;
+       enum toddr_src src;
+       struct aml_audio_controller *actrl;
+};
+
+struct frddr {
+       struct ddr_desc dscrpt;
+       struct device *dev;
+       enum frddr_dest dest;
+       struct aml_audio_controller *actrl;
+       unsigned int reg_base;
+};
+
+#define DDRMAX 3
+static struct frddr *frddrs[DDRMAX];
+static struct toddr *toddrs[DDRMAX];
+
+/* to DDRS */
+static struct toddr *register_toddr_l(struct device *dev,
+       struct aml_audio_controller *actrl, enum ddr_num id)
+{
+       struct toddr *to;
+       unsigned int mask_bit;
+
+       if (toddrs[id] != NULL)
+               return NULL;
+
+       to = kzalloc(sizeof(struct toddr), GFP_KERNEL);
+       if (!to)
+               return NULL;
+
+       switch (id) {
+       case DDR_A:
+               to->reg_base = EE_AUDIO_TODDR_A_CTRL0;
+               break;
+       case DDR_B:
+               to->reg_base = EE_AUDIO_TODDR_B_CTRL0;
+               break;
+       case DDR_C:
+               to->reg_base = EE_AUDIO_TODDR_C_CTRL0;
+               break;
+       default:
+               return NULL;
+       }
+
+       /* enable audio ddr arb */
+       mask_bit = id;
+       aml_audiobus_update_bits(actrl, EE_AUDIO_ARB_CTRL,
+                       1<<31|1<<mask_bit, 1<<31|1<<mask_bit);
+       to->dev = dev;
+       to->actrl = actrl;
+       toddrs[id] = to;
+       pr_info("toddrs[%d] occupied by device %s\n", id, dev_name(dev));
+       return to;
+}
+
+static int unregister_toddr_l(struct device *dev, enum ddr_num id)
+{
+       struct toddr *to;
+       struct aml_audio_controller *actrl;
+       unsigned int mask_bit;
+       unsigned int value;
+
+       if (dev == NULL)
+               return -EINVAL;
+
+       to = toddrs[id];
+       if (to->dev != dev)
+               return -EINVAL;
+
+       /* disable audio ddr arb */
+       mask_bit = id;
+       actrl = to->actrl;
+       aml_audiobus_update_bits(actrl, EE_AUDIO_ARB_CTRL,
+                       1<<mask_bit, 0<<mask_bit);
+       /* no ddr active, disable arb switch */
+       value = aml_audiobus_read(actrl, EE_AUDIO_ARB_CTRL) & 0x77;
+       if (value == 0)
+               aml_audiobus_update_bits(actrl, EE_AUDIO_ARB_CTRL,
+                               1<<31, 0<<31);
+
+       kfree(to);
+       toddrs[id] = NULL;
+       pr_info("toddrs[%d] released by device %s\n", id, dev_name(dev));
+
+       return 0;
+}
+
+struct toddr *aml_audio_register_toddr(struct device *dev,
+       struct aml_audio_controller *actrl, enum ddr_num id)
+{
+       struct toddr *to = NULL;
+
+       mutex_lock(&ddr_mutex);
+       to = register_toddr_l(dev, actrl, id);
+       mutex_unlock(&ddr_mutex);
+       return to;
+}
+
+int aml_audio_unregister_toddr(struct device *dev, enum ddr_num id)
+{
+       int ret;
+
+       mutex_lock(&ddr_mutex);
+       ret = unregister_toddr_l(dev, id);
+       mutex_unlock(&ddr_mutex);
+       return ret;
+}
+
+static inline unsigned int
+       calc_toddr_address(unsigned int reg, unsigned int base)
+{
+       return base + reg - EE_AUDIO_TODDR_A_CTRL0;
+}
+
+int aml_toddr_set_buf(struct toddr *to, unsigned int start,
+                       unsigned int end)
+{
+       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_START_ADDR, reg_base);
+       aml_audiobus_write(actrl, reg, start);
+       reg = calc_toddr_address(EE_AUDIO_TODDR_A_FINISH_ADDR, reg_base);
+       aml_audiobus_write(actrl, reg, end);
+
+       return 0;
+}
+
+int aml_toddr_set_intrpt(struct toddr *to, unsigned int intrpt)
+{
+       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_INT_ADDR, reg_base);
+       aml_audiobus_write(actrl, reg, intrpt);
+       reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
+       aml_audiobus_update_bits(actrl, reg, 0xff<<16, 4<<16);
+
+       return 0;
+}
+
+unsigned int aml_toddr_get_position(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_STATUS2, reg_base);
+       return aml_audiobus_read(actrl, reg);
+}
+
+void aml_toddr_enable(struct toddr *to, bool enable)
+{
+       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_update_bits(actrl, reg, 1<<31, enable<<31);
+}
+
+void aml_toddr_select_src(struct toddr *to, enum toddr_src src)
+{
+       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_update_bits(actrl, reg, 0x7, src & 0x7);
+}
+
+void aml_toddr_set_fifos(struct toddr *to, unsigned int thresh)
+{
+       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_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)
+{
+       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_update_bits(actrl, reg, 0x1fff<<3,
+                               type<<13|msb<<8|lsb<<3);
+}
+
+/* from DDRS */
+static struct frddr *register_frddr_l(struct device *dev,
+       struct aml_audio_controller *actrl, enum ddr_num id)
+{
+       struct frddr *from;
+       unsigned int mask_bit;
+
+       if (frddrs[id] != NULL)
+               return NULL;
+
+       from = kzalloc(sizeof(struct frddr), GFP_KERNEL);
+       if (!from)
+               return NULL;
+
+       switch (id) {
+       case DDR_A:
+               from->reg_base = EE_AUDIO_FRDDR_A_CTRL0;
+               break;
+       case DDR_B:
+               from->reg_base = EE_AUDIO_FRDDR_B_CTRL0;
+               break;
+       case DDR_C:
+               from->reg_base = EE_AUDIO_FRDDR_C_CTRL0;
+               break;
+       default:
+               return NULL;
+       }
+
+       /* enable audio ddr arb */
+       mask_bit = id + 4;
+       aml_audiobus_update_bits(actrl, EE_AUDIO_ARB_CTRL,
+                       1<<31|1<<mask_bit, 1<<31|1<<mask_bit);
+       from->dev = dev;
+       from->actrl = actrl;
+       frddrs[id] = from;
+       pr_info("frddrs[%d] claimed by device %s\n", id, dev_name(dev));
+       return from;
+}
+
+static int unregister_frddr_l(struct device *dev, enum ddr_num id)
+{
+       struct frddr *from;
+       struct aml_audio_controller *actrl;
+       unsigned int mask_bit;
+       unsigned int value;
+
+       if (dev == NULL)
+               return -EINVAL;
+
+       from = frddrs[id];
+       if (from->dev != dev)
+               return -EINVAL;
+
+       /* disable audio ddr arb */
+       mask_bit = id + 4;
+       actrl = from->actrl;
+       aml_audiobus_update_bits(actrl, EE_AUDIO_ARB_CTRL,
+                       1<<mask_bit, 0<<mask_bit);
+       /* no ddr active, disable arb switch */
+       value = aml_audiobus_read(actrl, EE_AUDIO_ARB_CTRL) & 0x77;
+       if (value == 0)
+               aml_audiobus_update_bits(actrl, EE_AUDIO_ARB_CTRL,
+                               1<<31, 0<<31);
+
+       kfree(from);
+       frddrs[id] = NULL;
+       pr_info("frddrs[%d] released by device %s\n", id, dev_name(dev));
+       return 0;
+}
+
+struct frddr *aml_audio_register_frddr(struct device *dev,
+       struct aml_audio_controller *actrl, enum ddr_num id)
+{
+       struct frddr *fr = NULL;
+
+       mutex_lock(&ddr_mutex);
+       fr = register_frddr_l(dev, actrl, id);
+       mutex_unlock(&ddr_mutex);
+       return fr;
+}
+
+int aml_audio_unregister_frddr(struct device *dev, enum ddr_num id)
+{
+       int ret;
+
+       mutex_lock(&ddr_mutex);
+       ret = unregister_frddr_l(dev, id);
+       mutex_unlock(&ddr_mutex);
+       return ret;
+}
+
+static inline unsigned int
+       calc_frddr_address(unsigned int reg, unsigned int base)
+{
+       return base + reg - EE_AUDIO_FRDDR_A_CTRL0;
+}
+
+int aml_frddr_set_buf(struct frddr *fr, unsigned int start,
+                       unsigned int end)
+{
+       struct aml_audio_controller *actrl = fr->actrl;
+       unsigned int reg_base = fr->reg_base;
+       unsigned int reg;
+
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_START_ADDR, reg_base);
+       aml_audiobus_write(actrl, reg, start);
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_FINISH_ADDR, reg_base);
+       aml_audiobus_write(actrl, reg, end);
+
+       return 0;
+}
+
+int aml_frddr_set_intrpt(struct frddr *fr, unsigned int intrpt)
+{
+       struct aml_audio_controller *actrl = fr->actrl;
+       unsigned int reg_base = fr->reg_base;
+       unsigned int reg;
+
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_INT_ADDR, reg_base);
+       aml_audiobus_write(actrl, reg, intrpt);
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_CTRL0, reg_base);
+       aml_audiobus_update_bits(actrl, reg, 0xff<<16, 4<<16);
+
+       return 0;
+}
+
+unsigned int aml_frddr_get_position(struct frddr *fr)
+{
+       struct aml_audio_controller *actrl = fr->actrl;
+       unsigned int reg_base = fr->reg_base;
+       unsigned int reg;
+
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_STATUS2, reg_base);
+       return aml_audiobus_read(actrl, reg);
+}
+
+void aml_frddr_enable(struct frddr *fr, bool enable)
+{
+       struct aml_audio_controller *actrl = fr->actrl;
+       unsigned int reg_base = fr->reg_base;
+       unsigned int reg;
+
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_CTRL0, reg_base);
+       aml_audiobus_update_bits(actrl, reg, 1<<31, enable<<31);
+}
+
+void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest dst)
+{
+       struct aml_audio_controller *actrl = fr->actrl;
+       unsigned int reg_base = fr->reg_base;
+       unsigned int reg;
+
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_CTRL0, reg_base);
+       aml_audiobus_update_bits(actrl, reg, 0x7, dst & 0x7);
+}
+
+void aml_frddr_set_fifos(struct frddr *fr,
+               unsigned int depth, unsigned int thresh)
+{
+       struct aml_audio_controller *actrl = fr->actrl;
+       unsigned int reg_base = fr->reg_base;
+       unsigned int reg;
+
+       reg = calc_frddr_address(EE_AUDIO_FRDDR_A_CTRL1, reg_base);
+       aml_audiobus_update_bits(actrl, reg,
+                       0xffff<<16 | 0xf<<8,
+                       (depth - 1)<<24 | (thresh - 1)<<16 | 2<<8);
+}
+
+/* Module information */
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("ALSA Soc Aml Audio DDR Manager");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/amlogic/auge/ddr_mngr.h b/sound/soc/amlogic/auge/ddr_mngr.h
new file mode 100644 (file)
index 0000000..7927744
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * sound/soc/amlogic/auge/ddr_mngr.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_AUDIO_DDR_MANAGER_H_
+#define __AML_AUDIO_DDR_MANAGER_H_
+
+#include <linux/device.h>
+#include "audio_io.h"
+
+enum ddr_num {
+       DDR_A,
+       DDR_B,
+       DDR_C,
+};
+
+enum ddr_types {
+       LJ_8BITS,
+       LJ_16BITS,
+       RJ_16BITS,
+       LJ_32BITS,
+       RJ_32BITS,
+};
+
+enum toddr_src {
+       TDMIN_A,
+       TDMIN_B,
+       TDMIN_C,
+       SPDIFIN,
+       PDMIN,
+       NONE,
+       TDMIN_LB,
+       LOOPBACK,
+};
+
+enum frddr_dest {
+       TDMOUT_A,
+       TDMOUT_B,
+       TDMOUT_C,
+       SPDIFOUT,
+};
+
+/* to ddrs */
+struct toddr *aml_audio_register_toddr(struct device *dev,
+               struct aml_audio_controller *actrl, enum ddr_num);
+int aml_audio_unregister_toddr(struct device *dev, enum ddr_num);
+int aml_toddr_set_buf(struct toddr *to, unsigned int start,
+                       unsigned int end);
+int aml_toddr_set_intrpt(struct toddr *to, unsigned int intrpt);
+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);
+
+/* from ddrs */
+struct frddr *aml_audio_register_frddr(struct device *dev,
+               struct aml_audio_controller *actrl, enum ddr_num);
+int aml_audio_unregister_frddr(struct device *dev, enum ddr_num);
+int aml_frddr_set_buf(struct frddr *fr, unsigned int start,
+                       unsigned int end);
+int aml_frddr_set_intrpt(struct frddr *fr, unsigned int intrpt);
+unsigned int aml_frddr_get_position(struct frddr *fr);
+void aml_frddr_enable(struct frddr *fr, bool enable);
+void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest);
+void aml_frddr_set_fifos(struct frddr *fr,
+               unsigned int depth, unsigned int thresh);
+
+#endif
+
diff --git a/sound/soc/amlogic/auge/iomap.c b/sound/soc/amlogic/auge/iomap.c
new file mode 100644 (file)
index 0000000..a457ba4
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * sound/soc/amlogic/auge/iomap.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include "iomap.h"
+
+static void __iomem *aml_snd_reg_map[IO_MAX];
+
+
+static int aml_snd_read(u32 base_type, unsigned int reg, unsigned int *val)
+{
+       if ((base_type >= IO_PDM_BUS) && (base_type < IO_MAX)) {
+               *val = readl((aml_snd_reg_map[base_type] + (reg << 2)));
+
+               return 0;
+       }
+
+       return -1;
+}
+
+static void aml_snd_write(u32 base_type, unsigned int reg, unsigned int val)
+{
+
+       if ((base_type >= IO_PDM_BUS) && (base_type < IO_MAX)) {
+               writel(val, (aml_snd_reg_map[base_type] + (reg << 2)));
+
+               return;
+       }
+
+       pr_err("write snd reg %x error\n", reg);
+}
+
+static void aml_snd_update_bits(u32 base_type,
+                       unsigned int reg, unsigned int mask,
+                       unsigned int val)
+{
+       if ((base_type >= IO_PDM_BUS) && (base_type < IO_MAX)) {
+               unsigned int tmp, orig;
+
+               aml_snd_read(base_type, reg, &orig);
+               tmp = orig & ~mask;
+               tmp |= val & mask;
+               aml_snd_write(base_type, reg, tmp);
+
+               return;
+       }
+       pr_err("write snd reg %x error\n", reg);
+
+}
+
+int aml_pdm_read(unsigned int reg)
+{
+       int ret, val = 0;
+
+       ret = aml_snd_read(IO_PDM_BUS, reg, &val);
+
+       if (ret) {
+               pr_err("read pdm reg %x error %d\n", reg, ret);
+               return -1;
+       }
+       return val;
+}
+EXPORT_SYMBOL(aml_pdm_read);
+
+void aml_pdm_write(unsigned int reg, unsigned int val)
+{
+       aml_snd_write(IO_PDM_BUS, reg, val);
+}
+EXPORT_SYMBOL(aml_pdm_write);
+
+void aml_pdm_update_bits(unsigned int reg,
+               unsigned int mask, unsigned int val)
+{
+       aml_snd_update_bits(IO_PDM_BUS, reg, mask, val);
+}
+EXPORT_SYMBOL(aml_pdm_update_bits);
+
+static int snd_iomap_probe(struct platform_device *pdev)
+{
+       struct resource res;
+       struct device_node *np, *child;
+       int i = 0;
+       int ret = 0;
+
+       np = pdev->dev.of_node;
+       for_each_child_of_node(np, child) {
+               if (of_address_to_resource(child, 0, &res)) {
+                       ret = -1;
+                       pr_err("%s could not get resource",
+                               __func__);
+                       break;
+               }
+               aml_snd_reg_map[i] =
+                       ioremap_nocache(res.start, resource_size(&res));
+               pr_info("aml_snd_reg_map[%d], reg:%x, size:%x\n",
+                       i, (u32)res.start, (u32)resource_size(&res));
+
+               i++;
+       }
+       pr_info("aml snd iomap probe done\n");
+
+       return ret;
+}
+
+static const struct of_device_id snd_iomap_dt_match[] = {
+       { .compatible = "amlogic, snd_iomap" },
+       {},
+};
+
+static  struct platform_driver snd_iomap_platform_driver = {
+       .probe          = snd_iomap_probe,
+       .driver         = {
+               .owner          = THIS_MODULE,
+               .name           = "snd_iomap",
+               .of_match_table = snd_iomap_dt_match,
+       },
+};
+
+int __init meson_snd_iomap_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&snd_iomap_platform_driver);
+
+       return ret;
+}
+core_initcall(meson_snd_iomap_init);
diff --git a/sound/soc/amlogic/auge/iomap.h b/sound/soc/amlogic/auge/iomap.h
new file mode 100644 (file)
index 0000000..4d5bdd7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * sound/soc/amlogic/auge/iomap.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_SND_IOMAP_H__
+#define __AML_SND_IOMAP_H__
+
+enum{
+       IO_PDM_BUS = 0,
+       IO_AUDIO_BUS,
+
+       IO_MAX,
+};
+
+extern int aml_pdm_read(unsigned int reg);
+
+extern void aml_pdm_write(unsigned int reg, unsigned int val);
+
+extern void aml_pdm_update_bits(unsigned int reg,
+       unsigned int mask, unsigned int val);
+
+#endif
diff --git a/sound/soc/amlogic/auge/pdm.c b/sound/soc/amlogic/auge/pdm.c
new file mode 100644 (file)
index 0000000..6a6d863
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * sound/soc/amlogic/auge/pdm.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pdm.h"
+#include "pdm_hw.h"
+#include "audio_io.h"
+#include "iomap.h"
+#include "regs.h"
+#include "ddr_mngr.h"
+
+static struct snd_pcm_hardware aml_pdm_hardware = {
+       .info                   =
+                                       SNDRV_PCM_INFO_MMAP |
+                                       SNDRV_PCM_INFO_MMAP_VALID |
+                                       SNDRV_PCM_INFO_INTERLEAVED |
+                                       SNDRV_PCM_INFO_PAUSE |
+                                       SNDRV_PCM_INFO_RESUME,
+
+       .formats                =       SNDRV_PCM_FMTBIT_S16 |
+                                       SNDRV_PCM_FMTBIT_S24 |
+                                       SNDRV_PCM_FMTBIT_S32,
+
+       .rate_min               =       8000,
+       .rate_max               =       48000,
+
+       .channels_min           =       1,
+       .channels_max           =       8,
+
+       .buffer_bytes_max       =       32 * 1024,
+       .period_bytes_max       =       16 * 1024,
+       .period_bytes_min       =       32,
+       .periods_min            =       2,
+       .periods_max            =       1024,
+       .fifo_size              =       0,
+};
+
+static unsigned int period_sizes[] = {
+       64, 128, 256, 512, 1024, 2048, 4096,
+       8192, 16384, 32768, 65536, 65536 * 2, 65536 * 4
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = {
+       .count = ARRAY_SIZE(period_sizes),
+       .list = period_sizes,
+       .mask = 0
+};
+
+static int s_pdm_filter_mode;
+
+static const char *const pdm_filter_mode_texts[] = {
+       "Filter Mode 0",
+       "Filter Mode 1",
+       "Filter Mode 2",
+       "Filter Mode 3",
+       "Filter Mode 4"
+};
+
+static const struct soc_enum pdm_filter_mode_enum =
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(pdm_filter_mode_texts),
+                       pdm_filter_mode_texts);
+
+static int aml_pdm_filter_mode_get_enum(
+       struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = s_pdm_filter_mode;
+
+       return 0;
+}
+
+static int aml_pdm_filter_mode_set_enum(
+       struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       s_pdm_filter_mode = ucontrol->value.enumerated.item[0];
+
+       return 0;
+}
+
+static int aml_pdm_cntrl_get_reg(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol) {
+       struct soc_mixer_control *mixcntrl =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int reg = mixcntrl->reg;
+       unsigned int shift = mixcntrl->shift;
+       unsigned int max = mixcntrl->max;
+       unsigned int invert = mixcntrl->invert;
+       unsigned int value = (((unsigned int)
+               aml_pdm_read(reg))
+               >> shift) & max;
+
+       if (invert)
+               value = (~value) & max;
+       ucontrol->value.integer.value[0] = value;
+
+       return 0;
+}
+
+static int aml_pdm_cntrl_set_reg(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol) {
+       struct soc_mixer_control *mixcntrl =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int reg = mixcntrl->reg;
+       unsigned int shift = mixcntrl->shift;
+       unsigned int max = mixcntrl->max;
+       unsigned int invert = mixcntrl->invert;
+       unsigned int value = ucontrol->value.integer.value[0];
+       unsigned int reg_value = (unsigned int)
+               aml_pdm_read(reg);
+
+       if (invert)
+               value = (~value) & mixcntrl->max;
+       max = ~(max << shift);
+       reg_value &= max;
+       reg_value |= (value << shift);
+       aml_pdm_write(reg, reg_value);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new snd_pdm_controls[] = {
+       /* which set */
+       SOC_ENUM_EXT("PDM Filter Mode",
+                    pdm_filter_mode_enum,
+                    aml_pdm_filter_mode_get_enum,
+                    aml_pdm_filter_mode_set_enum),
+
+       /* hcis gain controls */
+       SOC_SINGLE_EXT("HCIC shift gain",
+                        PDM_HCIC_CTRL1, 24, 0x3F, 0,
+                        aml_pdm_cntrl_get_reg,
+                        aml_pdm_cntrl_set_reg
+                        ),
+};
+
+static irqreturn_t aml_pdm_isr_handler(int irq, void *data)
+{
+       struct snd_pcm_substream *substream =
+               (struct snd_pcm_substream *)data;
+
+       pr_debug("%s\n", __func__);
+
+       snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+static int aml_pdm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct aml_pdm *p_pdm = (struct aml_pdm *)
+                                                       dev_get_drvdata(dev);
+       int ret;
+
+       pr_info("%s, stream:%d, irq :%d\n",
+               __func__, substream->stream, p_pdm->irq_pdmin);
+
+       snd_soc_set_runtime_hwparams(substream, &aml_pdm_hardware);
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       /* Ensure that period size is a multiple of 32bytes */
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                          &hw_constraints_period_sizes);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev,
+                       "%s() setting constraints failed: %d\n",
+                       __func__, ret);
+               return -EINVAL;
+       }
+
+       /* Ensure that buffer size is a multiple of period size */
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev,
+                       "%s() setting constraints failed: %d\n",
+                       __func__, ret);
+               return -EINVAL;
+       }
+
+       runtime->private_data = p_pdm;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+
+               p_pdm->tddr = aml_audio_register_toddr
+                                       (dev, p_pdm->actrl, p_pdm->to_ddr_num);
+               if (p_pdm->tddr == NULL) {
+                       dev_err(dev, "failed to claim to ddr %u\n",
+                                       p_pdm->to_ddr_num);
+                       return -ENXIO;
+               }
+
+               ret = request_irq(p_pdm->irq_pdmin,
+                               aml_pdm_isr_handler,
+                               IRQF_SHARED,
+                               "pdmin_irq",
+                               substream);
+
+               if (ret) {
+                       aml_audio_unregister_toddr(p_pdm->dev,
+                               p_pdm->to_ddr_num);
+                       dev_err(p_pdm->dev,
+                               "failed to claim irq %u\n",
+                               p_pdm->irq_pdmin);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int aml_pdm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct aml_pdm *p_pdm = (struct aml_pdm *)dev_get_drvdata(dev);
+
+       pr_info("enter %s type: %d, irq:%d\n",
+               __func__, substream->stream, p_pdm->irq_pdmin);
+
+       aml_audio_unregister_toddr(p_pdm->dev, p_pdm->to_ddr_num);
+       free_irq(p_pdm->irq_pdmin, substream);
+
+       return 0;
+}
+
+
+static int aml_pdm_hw_params(
+       struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret = 0;
+
+       pr_info("enter %s\n", __func__);
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       runtime->dma_bytes = params_buffer_bytes(params);
+       memset(runtime->dma_area, 0, runtime->dma_bytes);
+
+       return ret;
+}
+
+static int aml_pdm_hw_free(struct snd_pcm_substream *substream)
+{
+       pr_info("%s\n", __func__);
+       snd_pcm_lib_free_pages(substream);
+
+       return 0;
+}
+
+static int aml_pdm_prepare(
+       struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_pdm *p_pdm = runtime->private_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               struct toddr *to = p_pdm->tddr;
+               unsigned int start_addr, end_addr, int_addr;
+
+               start_addr = runtime->dma_addr;
+               end_addr = start_addr + runtime->dma_bytes - 8;
+               int_addr = frames_to_bytes(runtime, runtime->period_size) / 8;
+
+               aml_toddr_set_buf(to, start_addr, end_addr);
+               aml_toddr_set_intrpt(to, int_addr);
+       }
+
+       return 0;
+}
+
+static int aml_pdm_trigger(
+       struct snd_pcm_substream *substream, int cmd)
+{
+       return 0;
+}
+
+static snd_pcm_uframes_t aml_pdm_pointer(
+       struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_pdm *p_pdm = runtime->private_data;
+       unsigned int addr = 0, start_addr = 0;
+
+       start_addr = runtime->dma_addr;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               addr = aml_toddr_get_position(p_pdm->tddr);
+
+       return bytes_to_frames(runtime, addr - start_addr);
+}
+
+static int aml_pdm_mmap(
+       struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       return dma_mmap_coherent(substream->pcm->card->dev, vma,
+                       runtime->dma_area, runtime->dma_addr,
+                       runtime->dma_bytes);
+}
+
+static int aml_pdm_silence(
+       struct snd_pcm_substream *substream,
+       int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned char *ppos = NULL;
+       ssize_t n;
+
+       pr_info("%s\n", __func__);
+
+       n = frames_to_bytes(runtime, count);
+       ppos = runtime->dma_area + frames_to_bytes(runtime, pos);
+       memset(ppos, 0, n);
+
+       return 0;
+}
+
+static int aml_pdm_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
+{
+       struct snd_pcm *pcm = soc_runtime->pcm;
+       struct snd_pcm_substream *substream;
+       struct snd_soc_dai *dai = soc_runtime->cpu_dai;
+       int size = aml_pdm_hardware.buffer_bytes_max;
+       int ret = -EINVAL;
+
+       pr_info("%s dai->name: %s dai->id: %d\n",
+               __func__, dai->name, dai->id);
+
+       /* only capture for PDM */
+       substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+       if (substream) {
+               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                       soc_runtime->platform->dev,
+                                       size, &substream->dma_buffer);
+               if (ret) {
+                       dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void aml_pdm_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+
+       pr_info("%s\n", __func__);
+
+       substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+       if (substream) {
+               snd_dma_free_pages(&substream->dma_buffer);
+               substream->dma_buffer.area = NULL;
+               substream->dma_buffer.addr = 0;
+       }
+}
+
+static struct snd_pcm_ops aml_pdm_ops = {
+       .open = aml_pdm_open,
+       .close = aml_pdm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = aml_pdm_hw_params,
+       .hw_free = aml_pdm_hw_free,
+       .prepare = aml_pdm_prepare,
+       .trigger = aml_pdm_trigger,
+       .pointer = aml_pdm_pointer,
+       .mmap = aml_pdm_mmap,
+       .silence = aml_pdm_silence,
+};
+
+static int aml_pdm_probe(struct snd_soc_platform *platform)
+{
+       pr_info("%s\n", __func__);
+
+       return 0;
+}
+
+struct snd_soc_platform_driver aml_soc_platform_pdm = {
+       .pcm_new = aml_pdm_pcm_new,
+       .pcm_free = aml_pdm_pcm_free,
+       .ops = &aml_pdm_ops,
+       .probe = aml_pdm_probe,
+};
+EXPORT_SYMBOL_GPL(aml_soc_platform_pdm);
+
+static int aml_pdm_dai_hw_params(
+       struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       return 0;
+}
+
+static int aml_pdm_dai_set_fmt(
+       struct snd_soc_dai *dai, unsigned int fmt)
+{
+       return 0;
+}
+
+
+static int aml_pdm_dai_prepare(
+       struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(dai);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int bitwidth;
+       unsigned int toddr_type, lsb;
+
+       /* set bclk */
+       bitwidth = snd_pcm_format_width(runtime->format);
+       lsb = 32 - bitwidth;
+
+       switch (bitwidth) {
+       case 16:
+               toddr_type = 2;
+               break;
+       case 24:
+               toddr_type = 3;
+               break;
+       case 32:
+               toddr_type = 4;
+               break;
+       default:
+               pr_err("invalid bit_depth: %d\n",
+                               bitwidth);
+               return -1;
+       }
+
+       pr_info("%s rate:%d, bits:%d, channels:%d\n",
+               __func__,
+               runtime->rate,
+               bitwidth,
+               runtime->channels);
+
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               struct toddr *to = p_pdm->tddr;
+               unsigned int osr = 192;
+
+               /* to ddr pdmin */
+               aml_toddr_select_src(to, PDMIN);
+               aml_toddr_set_format(to, toddr_type, 31, lsb);
+               aml_toddr_set_fifos(to, 0x40);
+
+               aml_pdm_ctrl(p_pdm->actrl,
+                       bitwidth, runtime->channels);
+
+               /* filter for pdm */
+               if (runtime->rate == 48000)
+                       osr = 64;
+               else if (runtime->rate == 32000)
+                       osr = 96;
+               else if (runtime->rate == 16000)
+                       osr = 192;
+               else if (runtime->rate == 8000)
+                       osr = 384;
+               else
+                       pr_err("Not support rate:%d\n", runtime->rate);
+
+               p_pdm->filter_mode = s_pdm_filter_mode;
+               aml_pdm_filter_ctrl(osr, p_pdm->filter_mode);
+       }
+
+       pr_info("%s\n", __func__);
+
+       return 0;
+}
+
+static int aml_pdm_dai_trigger(
+       struct snd_pcm_substream *substream, int cmd,
+               struct snd_soc_dai *dai)
+{
+       struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(dai);
+       struct aml_audio_controller *actrl = p_pdm->actrl;
+
+       pr_info("%s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               /* TODO */
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       aml_pdm_set_clk(actrl, 1);
+                       aml_pdm_enable(actrl, true);
+               }
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       dev_info(substream->pcm->card->dev, "pdm capture enable\n");
+                       aml_toddr_enable(p_pdm->tddr, 1);
+               }
+
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       /* do not disable pdm clk */
+                       /*aml_pdm_set_clk(actrl, 0);*/
+
+                       aml_pdm_enable(actrl, false);
+               }
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       dev_info(substream->pcm->card->dev, "pdm capture enable\n");
+                       aml_toddr_enable(p_pdm->tddr, 0);
+               }
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+return 0;
+}
+
+
+static int aml_pdm_dai_set_sysclk(struct snd_soc_dai *cpu_dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned int pll_freq = 0;
+
+       pll_freq = freq * 50;
+       if (pll_freq > 196608000)
+               pll_freq = 196608000;
+
+       pr_info("%s irq:%d freq:%d, pll_freq:%d\n",
+               __func__, p_pdm->irq_pdmin, freq, pll_freq);
+
+       clk_set_rate(p_pdm->clk_pll, pll_freq);
+       clk_set_rate(p_pdm->clk_pdm_sysclk, pll_freq);
+       clk_set_rate(p_pdm->clk_pdm_dclk, pll_freq / 64);
+
+       return 0;
+}
+
+static int aml_pdm_dai_set_bclk_ratio(struct snd_soc_dai *cpu_dai,
+                                               unsigned int ratio)
+{
+       /* struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai);
+        *
+        * pr_info("%s ratio:%d\n", __func__, ratio);
+        * aml_pdm_set_bclk_ratio(p_pdm->actrl, ratio);
+        */
+
+       return 0;
+}
+
+static int aml_pdm_dai_probe(struct snd_soc_dai *dai)
+{
+       int ret = 0;
+
+       ret = snd_soc_add_dai_controls(dai, snd_pdm_controls,
+                               ARRAY_SIZE(snd_pdm_controls));
+       if (ret < 0) {
+               pr_err("%s, failed add snd pdm controls\n", __func__);
+               return ret;
+       }
+
+       pr_info("%s\n", __func__);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops aml_pdm_dai_ops = {
+       .set_fmt        = aml_pdm_dai_set_fmt,
+       .hw_params      = aml_pdm_dai_hw_params,
+       .prepare        = aml_pdm_dai_prepare,
+       .trigger        = aml_pdm_dai_trigger,
+       .set_sysclk     = aml_pdm_dai_set_sysclk,
+       .set_bclk_ratio = aml_pdm_dai_set_bclk_ratio,
+};
+
+struct snd_soc_dai_driver aml_pdm_dai[] = {
+       {
+               .name = "PDM",
+               .capture = {
+                       .channels_min = PDM_CHANNELS_MIN,
+                       .channels_max = PDM_CHANNELS_MAX,
+                       .rates        = PDM_RATES,
+                       .formats      = PDM_FORMATS,
+               },
+               .probe            = aml_pdm_dai_probe,
+               .ops     = &aml_pdm_dai_ops,
+       },
+};
+EXPORT_SYMBOL_GPL(aml_pdm_dai);
+
+static const struct snd_soc_component_driver aml_pdm_component = {
+       .name = DRV_NAME,
+};
+
+static int aml_pdm_platform_probe(struct platform_device *pdev)
+{
+       struct aml_pdm *p_pdm;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *node_prt = NULL;
+       struct platform_device *pdev_parent;
+       struct aml_audio_controller *actrl = NULL;
+       struct device *dev = &pdev->dev;
+
+       int ret;
+
+       p_pdm = devm_kzalloc(&pdev->dev,
+                       sizeof(struct aml_pdm),
+                       GFP_KERNEL);
+       if (!p_pdm) {
+               /*dev_err(&pdev->dev, "Can't allocate pcm_p\n");*/
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* get audio controller */
+       node_prt = of_get_parent(node);
+       if (node_prt == NULL)
+               return -ENXIO;
+
+       pdev_parent = of_find_device_by_node(node_prt);
+       of_node_put(node_prt);
+       actrl = (struct aml_audio_controller *)
+                               platform_get_drvdata(pdev_parent);
+       p_pdm->actrl = actrl;
+
+       /* parse DTS configured ddr */
+       ret = of_property_read_u32(node, "to_ddr",
+                       &p_pdm->to_ddr_num);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't retrieve tdm_to_ddr\n");
+               return -ENXIO;
+       }
+
+       /* clock gate */
+       p_pdm->clk_gate = devm_clk_get(&pdev->dev, "gate");
+       if (IS_ERR(p_pdm->clk_gate)) {
+               dev_err(&pdev->dev,
+                       "Can't get pdm gate\n");
+               return PTR_ERR(p_pdm->clk_gate);
+       }
+       clk_prepare_enable(p_pdm->clk_gate);
+
+       /* pinmux */
+       p_pdm->pdm_pins = devm_pinctrl_get_select(&pdev->dev, "pdm_pins");
+       if (IS_ERR(p_pdm->pdm_pins)) {
+               p_pdm->pdm_pins = NULL;
+               dev_err(&pdev->dev,
+                       "Can't get pdm pinmux\n");
+               return PTR_ERR(p_pdm->pdm_pins);
+       }
+
+       /* irq */
+       p_pdm->irq_pdmin = platform_get_irq_byname(pdev, "pdmin_irq");
+       if (p_pdm->irq_pdmin < 0) {
+               dev_err(&pdev->dev,
+                       "Can't get pdmin irq number\n");
+               return -EINVAL;
+       }
+
+       p_pdm->clk_pll = devm_clk_get(&pdev->dev, "pll_clk");
+       if (IS_ERR(p_pdm->clk_pll)) {
+               dev_err(&pdev->dev,
+                       "Can't retrieve pll clock\n");
+               ret = PTR_ERR(p_pdm->clk_pll);
+               goto err;
+       }
+
+       p_pdm->clk_pdm_sysclk = devm_clk_get(&pdev->dev, "pdm_sysclk");
+       if (IS_ERR(p_pdm->clk_pdm_sysclk)) {
+               dev_err(&pdev->dev,
+                       "Can't retrieve clk_pdm_sysclk clock\n");
+               ret = PTR_ERR(p_pdm->clk_pdm_sysclk);
+               goto err;
+       }
+
+       p_pdm->clk_pdm_dclk = devm_clk_get(&pdev->dev, "pdm_dclk");
+       if (IS_ERR(p_pdm->clk_pdm_dclk)) {
+               dev_err(&pdev->dev,
+                       "Can't retrieve clk_pdm_dclk clock\n");
+               ret = PTR_ERR(p_pdm->clk_pdm_dclk);
+               goto err;
+       }
+
+       ret = clk_set_parent(p_pdm->clk_pdm_sysclk, p_pdm->clk_pll);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't set clk_pdm_sysclk parent clock\n");
+               ret = PTR_ERR(p_pdm->clk_pdm_sysclk);
+               goto err;
+       }
+
+       ret = clk_set_parent(p_pdm->clk_pdm_dclk, p_pdm->clk_pll);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't set clk_pdm_dclk parent clock\n");
+               ret = PTR_ERR(p_pdm->clk_pdm_dclk);
+               goto err;
+       }
+
+       /* enable clock */
+       ret = clk_prepare_enable(p_pdm->clk_pll);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't enable pcm clk_pll clock: %d\n", ret);
+               goto err;
+       }
+
+       ret = clk_prepare_enable(p_pdm->clk_pdm_sysclk);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't enable pcm clk_pdm_sysclk clock: %d\n", ret);
+               goto err;
+       }
+
+       ret = clk_prepare_enable(p_pdm->clk_pdm_dclk);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't enable pcm clk_pdm_dclk clock: %d\n", ret);
+               goto err;
+       }
+
+       ret = of_property_read_u32(node, "filter_mode",
+                       &p_pdm->filter_mode);
+       if (ret < 0) {
+               /* defulat set 1 */
+               p_pdm->filter_mode = 1;
+       }
+       s_pdm_filter_mode = p_pdm->filter_mode;
+       pr_info("%s pdm filter mode from dts:%d\n",
+               __func__, p_pdm->filter_mode);
+
+       p_pdm->dev = dev;
+       dev_set_drvdata(&pdev->dev, p_pdm);
+
+       /*config ddr arb */
+       aml_pdm_arb_config(p_pdm->actrl);
+
+       ret = snd_soc_register_component(&pdev->dev,
+                               &aml_pdm_component,
+                               aml_pdm_dai,
+                               ARRAY_SIZE(aml_pdm_dai));
+
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_component failed\n");
+               goto err;
+       }
+
+       pr_info("%s, register soc platform\n", __func__);
+
+       return snd_soc_register_platform(&pdev->dev, &aml_soc_platform_pdm);
+
+err:
+       return ret;
+
+}
+
+static int aml_pdm_platform_remove(struct platform_device *pdev)
+{
+       struct aml_pdm *pdm_priv = dev_get_drvdata(&pdev->dev);
+
+       clk_disable_unprepare(pdm_priv->clk_pll);
+       clk_disable_unprepare(pdm_priv->clk_pdm_dclk);
+
+       snd_soc_unregister_component(&pdev->dev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id aml_pdm_device_id[] = {
+       { .compatible = "amlogic, snd-pdm" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, aml_pdm_device_id);
+
+struct platform_driver aml_pdm_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(aml_pdm_device_id),
+       },
+       .probe = aml_pdm_platform_probe,
+       .remove = aml_pdm_platform_remove,
+};
+module_platform_driver(aml_pdm_driver);
+
+
+MODULE_AUTHOR("AMLogic, Inc.");
+MODULE_DESCRIPTION("Amlogic PDM ASoc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amlogic/auge/pdm.h b/sound/soc/amlogic/auge/pdm.h
new file mode 100644 (file)
index 0000000..fc59635
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * sound/soc/amlogic/auge/pdm.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_PDM_H__
+#define __AML_PDM_H__
+
+#include <linux/clk.h>
+#include <linux/pinctrl/consumer.h>
+
+
+#define DRV_NAME "snd_pdm"
+
+#define DEFAULT_FS_RATIO               256
+
+#define PDM_CHANNELS_MIN               1
+#define PDM_CHANNELS_MAX               8
+
+#define PDM_RATES                      SNDRV_PCM_RATE_8000_48000
+#define PDM_FORMATS                    (SNDRV_PCM_FMTBIT_S16_LE |\
+                                               SNDRV_PCM_FMTBIT_S24_LE |\
+                                               SNDRV_PCM_FMTBIT_S32_LE)
+
+#if 1
+struct aml_pdm {
+       struct device *dev;
+       struct aml_audio_controller *actrl;
+       struct pinctrl *pdm_pins;
+       struct clk *clk_gate;
+       struct clk *clk_pll;
+       struct clk *clk_pdm_sysclk;
+       struct clk *clk_pdm_dclk;
+       int irq_pdmin;
+       unsigned int to_ddr_num;
+       struct toddr *tddr;
+       /*
+        * filter mode:0~4,
+        * from mode 0 to 4, the performance is from high to low,
+        * the group delay (latency) is from high to low.
+        */
+       int filter_mode;
+};
+#endif
+
+#endif /*__AML_PDM_H__*/
diff --git a/sound/soc/amlogic/auge/pdm_hw.c b/sound/soc/amlogic/auge/pdm_hw.c
new file mode 100644 (file)
index 0000000..9bf4ab8
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * sound/soc/amlogic/auge/pdm_hw.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include "pdm_hw.h"
+#include "regs.h"
+#include "iomap.h"
+#include "pdm_hw_coeff.c"
+
+void aml_pdm_enable(
+       struct aml_audio_controller *actrl,
+       bool is_enalbe)
+{
+       aml_pdm_update_bits(PDM_CTRL, 1 << 31, is_enalbe << 31);
+}
+
+void aml_pdm_ctrl(
+       struct aml_audio_controller *actrl,
+       int bitdepth, int channels)
+{
+       int mode, i, ch_mask = 0, sample_count = 28;
+
+       if (bitdepth == 32)
+               mode = 0;
+       else
+               mode = 1;
+
+       for (i = 0; i < channels; i++)
+               ch_mask |= (1 << i);
+
+       pr_info("%s, channels mask:%x\n", __func__, ch_mask);
+
+       aml_pdm_write(PDM_CTRL, 0);
+
+       aml_pdm_write(PDM_CTRL,
+                               (0 << 31) |
+                               /* invert the PDM_DCLK or not */
+                               (0 << 30) |
+                               /* output mode:  1: 24bits. 0: 32 bits */
+                               (mode << 29) |
+                               /* bypass mode.
+                                * 1: bypass all filter. 0: normal mode.
+                                */
+                               (0 << 28) |
+                               /* PDM Asynchronous FIFO soft reset.
+                                * write 1 to soft reset AFIFO
+                                */
+                               (1 << 16) |
+                               /* PDM channel reset. */
+                               (ch_mask << 8) |
+                               /* PDM channel enable */
+                               (ch_mask << 0)
+                               );
+
+       aml_pdm_write(PDM_CHAN_CTRL, ((sample_count << 24) |
+                                       (sample_count << 16) |
+                                       (sample_count << 8) |
+                                       (sample_count << 0)
+               ));
+       aml_pdm_write(PDM_CHAN_CTRL1, ((sample_count << 24) |
+                                       (sample_count << 16) |
+                                       (sample_count << 8) |
+                                       (sample_count << 0)
+               ));
+}
+
+void aml_pdm_arb_config(struct aml_audio_controller *actrl)
+{
+       /* config ddr arb */
+       aml_audiobus_write(actrl, EE_AUDIO_ARB_CTRL, 1<<31|0xff<<0);
+}
+
+void aml_pdm_set_clk(
+       struct aml_audio_controller *actrl,
+       int is_enable)
+{
+       return;
+       aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_CLK_PDMIN_CTRL0, 1 << 31, is_enable << 31);
+       aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_CLK_PDMIN_CTRL1, 1 << 31, is_enable << 31);
+}
+
+void aml_pdm_set_bclk_ratio(
+       struct aml_audio_controller *actrl,
+       int ratio)
+{
+       unsigned int clk_id;
+       unsigned int mul;
+       unsigned int sample_count = ratio / 2;
+
+       pr_info("%s, ratio:%d, count:%d\n", __func__, ratio, sample_count);
+
+       clk_id = 2; /* according to dts, mpll2 */
+
+       /* sysclk */
+       mul = 1;
+       aml_audiobus_write(actrl, EE_AUDIO_CLK_PDMIN_CTRL1,
+                                       1 << 31 | /* clk enable */
+                                       clk_id << 24 | /* clk src */
+                                       (mul - 1)/* clk_div */
+                                       );
+       /* dclk */
+       mul = ratio;
+       aml_audiobus_write(actrl, EE_AUDIO_CLK_PDMIN_CTRL0,
+                                       1 << 31 | /* clk enable */
+                                       clk_id << 24 | /* clk src */
+                                       (mul - 1)); /* clk_div */
+
+
+}
+
+
+/* config for hcic, lpf1,2,3, hpf */
+static void aml_pdm_filters_config(int osr,
+       int lpf1_len, int lpf2_len, int lpf3_len)
+{
+       int32_t hcic_dn_rate;
+       int32_t hcic_tap_num;
+       int32_t hcic_gain;
+       int32_t hcic_shift;
+       int32_t f1_tap_num;
+       int32_t f2_tap_num;
+       int32_t f3_tap_num;
+       int32_t f1_rnd_mode;
+       int32_t f2_rnd_mode;
+       int32_t f3_rnd_mode;
+       int32_t f1_ds_rate;
+       int32_t f2_ds_rate;
+       int32_t f3_ds_rate;
+       int32_t hpf_en;
+       int32_t hpf_shift_step;
+       int32_t hpf_out_factor;
+       int32_t pdm_out_mode;
+
+       /* current Dclk: 3072000*/
+       switch (osr) {
+       case 64:
+               hcic_dn_rate = 0x0008;
+               hcic_gain        = 0x80;
+               hcic_shift       = 0x15;
+               break;
+       case 96:
+               hcic_dn_rate = 0x000c;
+               hcic_gain        = 0x78;
+               hcic_shift       = 0x19;
+               break;
+       case 128:
+               hcic_dn_rate = 0x0010;
+               hcic_gain        = 0x80;
+               hcic_shift       = 0x1c;
+               break;
+       case 192:
+               hcic_dn_rate = 0x0018;
+               hcic_gain        = 0x78;
+               hcic_shift       = 0x20;
+               break;
+       case 384:
+               hcic_dn_rate = 0x0030;
+               hcic_gain        = 0x78;
+               hcic_shift       = 0x27;
+               break;
+       default:
+               pr_info("Not support osr:%d, translate to :192\n", osr);
+               hcic_dn_rate = 0x0018;
+               hcic_gain        = 0x78;
+               hcic_shift       = 0x20;
+               break;
+       }
+
+       /* TODO: fixed hcic_shift 'cause of Dmic */
+#if 0
+       hcic_shift -= 0x4;
+#endif
+
+       hcic_tap_num = 0x0007;
+       f1_tap_num       = lpf1_len;
+       f2_tap_num       = lpf2_len;
+       f3_tap_num       = lpf3_len;
+       hpf_shift_step = 0xd;
+       hpf_en           = 1;
+       pdm_out_mode     = 0;
+       hpf_out_factor = 0x8000;
+       f1_rnd_mode  = 1;
+       f2_rnd_mode  = 0;
+       f3_rnd_mode  = 1;
+       f1_ds_rate       = 2;
+       f2_ds_rate       = 2;
+       f3_ds_rate       = 2;
+
+       /* hcic */
+       aml_pdm_write(PDM_HCIC_CTRL1,
+               (0x80000000 |
+               hcic_tap_num |
+               (hcic_dn_rate << 4) |
+               (hcic_gain << 16) |
+               (hcic_shift << 24))
+               );
+
+       /* lpf */
+       aml_pdm_write(PDM_F1_CTRL,
+               (0x80000000 |
+               f1_tap_num |
+               (2 << 12) |
+               (f1_rnd_mode << 16))
+               );
+       aml_pdm_write(PDM_F2_CTRL,
+               (0x80000000 |
+               f2_tap_num |
+               (2 << 12) |
+               (f2_rnd_mode << 16))
+               );
+       aml_pdm_write(PDM_F3_CTRL,
+               (0x80000000 |
+               f3_tap_num |
+               (2 << 12) |
+               (f3_rnd_mode << 16))
+               );
+
+       /* hpf */
+       aml_pdm_write(PDM_HPF_CTRL,
+               (hpf_out_factor |
+               (hpf_shift_step << 16) |
+               (hpf_en << 31))
+               );
+
+}
+
+/* coefficent for LPF1,2,3 */
+static void aml_pdm_LPF_coeff(
+       int lpf1_len, const int *lpf1_coeff,
+       int lpf2_len, const int *lpf2_coeff,
+       int lpf3_len, const int *lpf3_coeff)
+{
+       int i;
+       int32_t data;
+       int32_t data_tmp;
+
+       aml_pdm_write(PDM_COEFF_ADDR, 0);
+       for (i = 0;
+               i < lpf1_len;
+               i++)
+               aml_pdm_write(PDM_COEFF_DATA, lpf1_coeff[i]);
+       for (i = 0;
+               i < lpf2_len;
+               i++)
+               aml_pdm_write(PDM_COEFF_DATA, lpf2_coeff[i]);
+       for (i = 0;
+               i < lpf3_len;
+               i++)
+               aml_pdm_write(PDM_COEFF_DATA, lpf3_coeff[i]);
+
+       aml_pdm_write(PDM_COEFF_ADDR, 0);
+       for (i = 0; i < lpf1_len; i++) {
+               data = aml_pdm_read(PDM_COEFF_DATA);
+               data_tmp = lpf1_coeff[i];
+               if (data != data_tmp) {
+                       pr_info("FAILED coeff data verified wrong!\n");
+                       pr_info("Coeff = %x\n", data);
+                       pr_info("DDR COEFF = %x\n", data_tmp);
+               }
+       }
+       for (i = 0; i < lpf2_len; i++) {
+               data = aml_pdm_read(PDM_COEFF_DATA);
+               data_tmp = lpf2_coeff[i];
+               if (data != data_tmp) {
+                       pr_info("FAILED coeff data verified wrong!\n");
+                       pr_info("Coeff = %x\n", data);
+                       pr_info("DDR COEFF = %x\n", data_tmp);
+               }
+       }
+       for (i = 0; i < lpf3_len; i++) {
+               data = aml_pdm_read(PDM_COEFF_DATA);
+               data_tmp = lpf3_coeff[i];
+               if (data != data_tmp) {
+                       pr_info("FAILED coeff data verified wrong!\n");
+                       pr_info("Coeff = %x\n", data);
+                       pr_info("DDR COEFF = %x\n", data_tmp);
+               }
+       }
+
+}
+
+void aml_pdm_filter_ctrl(int osr, int mode)
+{
+       int lpf1_len, lpf2_len, lpf3_len;
+       const int *lpf1_coeff, *lpf2_coeff, *lpf3_coeff;
+
+       pr_info("%s, osr:%d, mode:%d\n",
+               __func__, osr, mode);
+
+       /* select LPF coefficent
+        * For filter 1 and filter 3,
+        * it's only relative with coefficent mode
+        * For filter 2,
+        * it's only relative with osr and hcic stage number
+        */
+
+       /* mode and its latency
+        *      mode    |       latency
+        *      0               |       47.7
+        *      1               |       38.7
+        *      2               |       26
+        *      3               |       20.4
+        *      4               |       15
+        */
+
+       switch (osr) {
+       case 64:
+               lpf2_coeff = lpf2_osr64;
+               break;
+       case 96:
+               lpf2_coeff = lpf2_osr96;
+               break;
+       case 128:
+               lpf2_coeff = lpf2_osr128;
+               break;
+       case 192:
+               lpf2_coeff = lpf2_osr192;
+               break;
+       case 256:
+               lpf2_coeff = lpf2_osr256;
+               break;
+       case 384:
+               lpf2_coeff = lpf2_osr384;
+               break;
+       default:
+               pr_info("default mode 1, osr 64, 48k\n");
+               lpf2_coeff = lpf2_osr64;
+               break;
+       }
+
+       switch (mode) {
+       case 0:
+               lpf1_len = 110;
+               lpf2_len = 33;
+               lpf3_len = 147;
+               lpf1_coeff = lpf1_mode0;
+               lpf3_coeff = lpf3_mode0;
+               break;
+       case 1:
+               lpf1_len = 87;
+               lpf2_len = 33;
+               lpf3_len = 117;
+               lpf1_coeff = lpf1_mode1;
+               lpf3_coeff = lpf3_mode1;
+               break;
+       case 2:
+               lpf1_len = 87;
+               lpf2_len = 33;
+               lpf3_len = 66;
+               lpf1_coeff = lpf1_mode2;
+               lpf3_coeff = lpf3_mode2;
+               break;
+       case 3:
+               lpf1_len = 65;
+               lpf2_len = 33;
+               lpf3_len = 49;
+               lpf1_coeff = lpf1_mode3;
+               lpf3_coeff = lpf3_mode3;
+               break;
+       case 4:
+               lpf1_len = 43;
+               lpf2_len = 33;
+               lpf3_len = 32;
+               lpf1_coeff = lpf1_mode4;
+               lpf3_coeff = lpf3_mode4;
+               break;
+       default:
+               pr_info("default mode 1, osr 64\n");
+               lpf1_len = 87;
+               lpf2_len = 33;
+               lpf3_len = 117;
+               lpf1_coeff = lpf1_mode1;
+               lpf3_coeff = lpf3_mode1;
+               break;
+       }
+
+       /* config filter */
+       aml_pdm_filters_config(osr,
+               lpf1_len,
+               lpf2_len,
+               lpf3_len);
+
+       aml_pdm_LPF_coeff(
+               lpf1_len, lpf1_coeff,
+               lpf2_len, lpf2_coeff,
+               lpf3_len, lpf3_coeff
+               );
+
+       aml_pdm_update_bits(PDM_CTRL, 1 << 31, 1 << 31);
+}
diff --git a/sound/soc/amlogic/auge/pdm_hw.h b/sound/soc/amlogic/auge/pdm_hw.h
new file mode 100644 (file)
index 0000000..373354e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * sound/soc/amlogic/auge/pdm_hw.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_PDM_HW_H__
+#define __AML_PDM_HW_H__
+#include "audio_io.h"
+
+extern void aml_pdm_enable(
+       struct aml_audio_controller *actrl,
+       bool is_enalbe);
+
+extern void aml_pdm_ctrl(
+       struct aml_audio_controller *actrl,
+       int bitdepth, int channels);
+
+extern void aml_pdm_arb_config(struct aml_audio_controller *actrl);
+
+extern void aml_pdm_set_clk(
+       struct aml_audio_controller *actrl,
+       int is_enable);
+
+extern void aml_pdm_set_bclk_ratio(
+       struct aml_audio_controller *actrl,
+       int ratio);
+
+extern int aml_pmd_set_HPF_filter_parameters(void *array);
+
+extern void aml_pdm_filter_ctrl(int osr, int set);
+
+#endif /*__AML_PDM_HW_H__*/
diff --git a/sound/soc/amlogic/auge/pdm_hw_coeff.c b/sound/soc/amlogic/auge/pdm_hw_coeff.c
new file mode 100644 (file)
index 0000000..b44ba53
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * sound/soc/amlogic/auge/pdm_hw_coeff.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+/* LPF coefficent
+ * For filter 1 and filter 3, it's only relative with coefficent mode
+ * For filter 2, it's only relative with osr and hcic stage number
+ */
+
+static const int lpf2_osr64[]  = {
+       0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818,
+       0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41,
+       0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0,
+       0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000,
+       0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93,
+       0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12,
+       0x0002c1, 0xfff004, 0x00050a,
+};
+
+static const int lpf2_osr96[]  = {
+       0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818,
+       0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41,
+       0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0,
+       0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000,
+       0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93,
+       0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12,
+       0x0002c1, 0xfff004, 0x00050a
+};
+
+static const int lpf2_osr128[]  = {
+       0x00050b, 0xfff002, 0x0002c6, 0x003c15, 0xffa7fc,
+       0xffc899, 0x010b29, 0xff518f, 0xfebd98, 0x02909c,
+       0xff5ab8, 0xfc6254, 0x0563b2, 0x000000, 0xf46f16,
+       0x11c6a2, 0x2eb45a, 0x11c6a2, 0xf46f16, 0x000000,
+       0x0563b2, 0xfc6254, 0xff5ab8, 0x02909c, 0xfebd98,
+       0xff518f, 0x010b29, 0xffc899, 0xffa7fc, 0x003c15,
+       0x0002c6, 0xfff002, 0x00050b
+};
+
+static const int lpf2_osr192[] = {
+       0x00050b, 0xfff002, 0x0002c7, 0x003c16, 0xffa7f7,
+       0xffc89f, 0x010b35, 0xff516f, 0xfebd9a, 0x0290e8,
+       0xff5a6d, 0xfc61f8, 0x05649b, 0x000000, 0xf46d02,
+       0x11c6cc, 0x2eb731, 0x11c6cc, 0xf46d02, 0x000000,
+       0x05649b, 0xfc61f8, 0xff5a6d, 0x0290e8, 0xfebd9a,
+       0xff516f, 0x010b35, 0xffc89f, 0xffa7f7, 0x003c16,
+       0x0002c7, 0xfff002, 0x00050b
+};
+
+static const int lpf2_osr256[] = {
+       0x00050b, 0xfff002, 0x0002c7, 0x003c16, 0xffa7f6,
+       0xffc8a0, 0x010b37, 0xff516a, 0xfebd9a, 0x0290f4,
+       0xff5a62, 0xfc61ea, 0x0564bf, 0x000000, 0xf46cb0,
+       0x11c6d2, 0x2eb7a1, 0x11c6d2, 0xf46cb0, 0x000000,
+       0x0564bf, 0xfc61ea, 0xff5a62, 0x0290f4, 0xfebd9a,
+       0xff516a, 0x010b37, 0xffc8a0, 0xffa7f6, 0x003c16,
+       0x0002c7, 0xfff002, 0x00050b
+};
+
+static const int lpf2_osr384[] = {
+       0x00050b, 0xfff002, 0x0002c7, 0x003c16, 0xffa7f6,
+       0xffc8a0, 0x010b37, 0xff516a, 0xfebd9a, 0x0290f4,
+       0xff5a62, 0xfc61ea, 0x0564bf, 0x000000, 0xf46cb0,
+       0x11c6d2, 0x2eb7a1, 0x11c6d2, 0xf46cb0, 0x000000,
+       0x0564bf, 0xfc61ea, 0xff5a62, 0x0290f4, 0xfebd9a,
+       0xff516a, 0x010b37, 0xffc8a0, 0xffa7f6, 0x003c16,
+       0x0002c7, 0xfff002, 0x00050b
+};
+
+static const int lpf1_mode0[] = {
+       0x000006, 0x000002, 0xffffeb, 0xffffbe, 0xffff8a,
+       0xffff76, 0xffffb4, 0x00006b, 0x000187, 0x0002a7,
+       0x00031d, 0x00022c, 0xffff6b, 0xfffb35, 0xfff6e7,
+       0xfff4aa, 0xfff6b8, 0xfffe3f, 0x000a43, 0x00172a,
+       0x001f54, 0x001cfd, 0x000ce4, 0xfff0d0, 0xffd098,
+       0xffb8cd, 0xffb6b8, 0xffd2b1, 0x000adb, 0x0050ad,
+       0x008b46, 0x009ee9, 0x0077e0, 0x001506, 0xff8d7a,
+       0xff0dc4, 0xfecb6c, 0xfef1b8, 0xff8da0, 0x0080db,
+       0x0182b7, 0x0231a8, 0x023283, 0x0154bd, 0xffaf64,
+       0xfdab1a, 0xfbf20a, 0xfb46e9, 0xfc4cb4, 0xff4f72,
+       0x041fa5, 0x0a0e12, 0x100c37, 0x14eab3, 0x17a4fe,
+       0x17a4fe, 0x14eab3, 0x100c37, 0x0a0e12, 0x041fa5,
+       0xff4f72, 0xfc4cb4, 0xfb46e9, 0xfbf20a, 0xfdab1a,
+       0xffaf64, 0x0154bd, 0x023283, 0x0231a8, 0x0182b7,
+       0x0080db, 0xff8da0, 0xfef1b8, 0xfecb6c, 0xff0dc4,
+       0xff8d7a, 0x001506, 0x0077e0, 0x009ee9, 0x008b46,
+       0x0050ad, 0x000adb, 0xffd2b1, 0xffb6b8, 0xffb8cd,
+       0xffd098, 0xfff0d0, 0x000ce4, 0x001cfd, 0x001f54,
+       0x00172a, 0x000a43, 0xfffe3f, 0xfff6b8, 0xfff4aa,
+       0xfff6e7, 0xfffb35, 0xffff6b, 0x00022c, 0x00031d,
+       0x0002a7, 0x000187, 0x00006b, 0xffffb4, 0xffff76,
+       0xffff8a, 0xffffbe, 0xffffeb, 0x000002, 0x000006,
+};
+
+static const int lpf3_mode0[] = {
+       0x000007, 0x000000, 0xffffe8, 0x000000, 0x000038,
+       0x000000, 0xffff94, 0x000000, 0x0000c0, 0x000000,
+       0xfffec1, 0x000000, 0x0001f7, 0x000000, 0xfffd05,
+       0x000000, 0x000460, 0x000000, 0xfff9c1, 0x000000,
+       0x0008b7, 0x000000, 0xfff416, 0x000000, 0x000fff,
+       0x000000, 0xffeadc, 0x000000, 0x001b8a, 0x000000,
+       0xffdc97, 0x000000, 0x002d01, 0x000000, 0xffc767,
+       0x000000, 0x00467f, 0x000000, 0xffa8f1, 0x000000,
+       0x006ab0, 0x000000, 0xff7e26, 0x000000, 0x009d20,
+       0x000000, 0xff42ce, 0x000000, 0x00e2f1, 0x000000,
+       0xfef07e, 0x000000, 0x014470, 0x000000, 0xfe7c1b,
+       0x000000, 0x01d10f, 0x000000, 0xfdcf39, 0x000000,
+       0x02aaeb, 0x000000, 0xfcb2e7, 0x000000, 0x04311d,
+       0x000000, 0xfa719c, 0x000000, 0x07f53f, 0x000000,
+       0xf288b5, 0x000000, 0x28b482, 0x3fffff, 0x28b482,
+       0x000000, 0xf288b5, 0x000000, 0x07f53f, 0x000000,
+       0xfa719c, 0x000000, 0x04311d, 0x000000, 0xfcb2e7,
+       0x000000, 0x02aaeb, 0x000000, 0xfdcf39, 0x000000,
+       0x01d10f, 0x000000, 0xfe7c1b, 0x000000, 0x014470,
+       0x000000, 0xfef07e, 0x000000, 0x00e2f1, 0x000000,
+       0xff42ce, 0x000000, 0x009d20, 0x000000, 0xff7e26,
+       0x000000, 0x006ab0, 0x000000, 0xffa8f1, 0x000000,
+       0x00467f, 0x000000, 0xffc767, 0x000000, 0x002d01,
+       0x000000, 0xffdc97, 0x000000, 0x001b8a, 0x000000,
+       0xffeadc, 0x000000, 0x000fff, 0x000000, 0xfff416,
+       0x000000, 0x0008b7, 0x000000, 0xfff9c1, 0x000000,
+       0x000460, 0x000000, 0xfffd05, 0x000000, 0x0001f7,
+       0x000000, 0xfffec1, 0x000000, 0x0000c0, 0x000000,
+       0xffff94, 0x000000, 0x000038, 0x000000, 0xffffe8,
+       0x000000, 0x000007
+};
+
+static const int lpf1_mode1[] = {
+       0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45,
+       0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21,
+       0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212,
+       0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa,
+       0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef,
+       0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077,
+       0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690,
+       0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3,
+       0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686,
+       0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812,
+       0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60,
+       0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000,
+       0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e,
+       0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c,
+       0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece,
+       0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645,
+       0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9,
+       0xffffb2, 0x000014,
+};
+
+static const int lpf3_mode1[] = {
+       0x000000, 0x000081, 0x000000, 0xfffedb, 0x000000,
+       0x00022d, 0x000000, 0xfffc46, 0x000000, 0x0005f7,
+       0x000000, 0xfff6eb, 0x000000, 0x000d4e, 0x000000,
+       0xffed1e, 0x000000, 0x001a1c, 0x000000, 0xffdcb0,
+       0x000000, 0x002ede, 0x000000, 0xffc2d1, 0x000000,
+       0x004ebe, 0x000000, 0xff9beb, 0x000000, 0x007dd7,
+       0x000000, 0xff633a, 0x000000, 0x00c1d2, 0x000000,
+       0xff11d5, 0x000000, 0x012368, 0x000000, 0xfe9c45,
+       0x000000, 0x01b252, 0x000000, 0xfdebf6, 0x000000,
+       0x0290b8, 0x000000, 0xfcca0d, 0x000000, 0x041d7c,
+       0x000000, 0xfa8152, 0x000000, 0x07e9c6, 0x000000,
+       0xf28fb5, 0x000000, 0x28b216, 0x3fffde, 0x28b216,
+       0x000000, 0xf28fb5, 0x000000, 0x07e9c6, 0x000000,
+       0xfa8152, 0x000000, 0x041d7c, 0x000000, 0xfcca0d,
+       0x000000, 0x0290b8, 0x000000, 0xfdebf6, 0x000000,
+       0x01b252, 0x000000, 0xfe9c45, 0x000000, 0x012368,
+       0x000000, 0xff11d5, 0x000000, 0x00c1d2, 0x000000,
+       0xff633a, 0x000000, 0x007dd7, 0x000000, 0xff9beb,
+       0x000000, 0x004ebe, 0x000000, 0xffc2d1, 0x000000,
+       0x002ede, 0x000000, 0xffdcb0, 0x000000, 0x001a1c,
+       0x000000, 0xffed1e, 0x000000, 0x000d4e, 0x000000,
+       0xfff6eb, 0x000000, 0x0005f7, 0x000000, 0xfffc46,
+       0x000000, 0x00022d, 0x000000, 0xfffedb, 0x000000,
+       0x000081, 0x000000,
+};
+
+static const int lpf1_mode2[] = {
+       0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45,
+       0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21,
+       0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212,
+       0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa,
+       0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef,
+       0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077,
+       0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690,
+       0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3,
+       0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686,
+       0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812,
+       0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60,
+       0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000,
+       0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e,
+       0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c,
+       0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece,
+       0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645,
+       0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9,
+       0xffffb2, 0x000014
+};
+
+static const int lpf3_mode2[] = {
+       0x00005e, 0xffff19, 0xfffe3e, 0x00030a, 0x0004de,
+       0xfff899, 0xfff531, 0x000f4a, 0x001510, 0xffe39e,
+       0xffda78, 0x0030d1, 0x003e97, 0xffb0c5, 0xff9cd2,
+       0x007aec, 0x009706, 0xff47dd, 0xff20f2, 0x010cbd,
+       0x01426b, 0xfe7e4e, 0xfe3340, 0x0226a1, 0x0293d1,
+       0xfce4d3, 0xfc382d, 0x04ad05, 0x05ef42, 0xf82315,
+       0xf4bde1, 0x130bdd, 0x399128, 0x399128, 0x130bdd,
+       0xf4bde1, 0xf82315, 0x05ef42, 0x04ad05, 0xfc382d,
+       0xfce4d3, 0x0293d1, 0x0226a1, 0xfe3340, 0xfe7e4e,
+       0x01426b, 0x010cbd, 0xff20f2, 0xff47dd, 0x009706,
+       0x007aec, 0xff9cd2, 0xffb0c5, 0x003e97, 0x0030d1,
+       0xffda78, 0xffe39e, 0x001510, 0x000f4a, 0xfff531,
+       0xfff899, 0x0004de, 0x00030a, 0xfffe3e, 0xffff19,
+       0x00005e
+};
+
+static const int lpf1_mode3[] = {
+       0x000000, 0xfffc12, 0xfff5cb, 0xfff022, 0xffeffa,
+       0xfffa03, 0x000f84, 0x002b96, 0x00429d, 0x00455c,
+       0x00277a, 0xffe762, 0xff93e1, 0xff4bc4, 0xff3567,
+       0xff6f81, 0x000000, 0x00c850, 0x018619, 0x01e3e3,
+       0x01972b, 0x008323, 0xfed332, 0xfd00e8, 0xfbbe66,
+       0xfbc791, 0xfda631, 0x017bb2, 0x06e40b, 0x0cfe8e,
+       0x129dfd, 0x1693d6, 0x18011b, 0x1693d6, 0x129dfd,
+       0x0cfe8e, 0x06e40b, 0x017bb2, 0xfda631, 0xfbc791,
+       0xfbbe66, 0xfd00e8, 0xfed332, 0x008323, 0x01972b,
+       0x01e3e3, 0x018619, 0x00c850, 0x000000, 0xff6f81,
+       0xff3567, 0xff4bc4, 0xff93e1, 0xffe762, 0x00277a,
+       0x00455c, 0x00429d, 0x002b96, 0x000f84, 0xfffa03,
+       0xffeffa, 0xfff022, 0xfff5cb, 0xfffc12, 0x000000,
+};
+
+static const int lpf3_mode3[] = {
+       0x000000, 0xfff4f6, 0x000000, 0x001e36, 0x000000,
+       0xffbfb6, 0x000000, 0x007789, 0x000000, 0xff3423,
+       0x000000, 0x0147cc, 0x000000, 0xfe0523, 0x000000,
+       0x02ffbb, 0x000000, 0xfb728b, 0x000000, 0x0732af,
+       0x000000, 0xf301d5, 0x000000, 0x288c99, 0x40023d,
+       0x288c99, 0x000000, 0xf301d5, 0x000000, 0x0732af,
+       0x000000, 0xfb728b, 0x000000, 0x02ffbb, 0x000000,
+       0xfe0523, 0x000000, 0x0147cc, 0x000000, 0xff3423,
+       0x000000, 0x007789, 0x000000, 0xffbfb6, 0x000000,
+       0x001e36, 0x000000, 0xfff4f6, 0x000000
+};
+
+static const int lpf1_mode4[] = {
+       0xfff71d, 0xffd0ad, 0xffa4b6, 0xff8cdb, 0xffa5d4,
+       0x000000, 0x009021, 0x012899, 0x0181ac, 0x0151f3,
+       0x0070b6, 0xfef591, 0xfd46bc, 0xfc0b63, 0xfc00d4,
+       0xfdbd02, 0x017215, 0x06c95c, 0x0ce665, 0x1295f9,
+       0x169d63, 0x181214, 0x169d63, 0x1295f9, 0x0ce665,
+       0x06c95c, 0x017215, 0xfdbd02, 0xfc00d4, 0xfc0b63,
+       0xfd46bc, 0xfef591, 0x0070b6, 0x0151f3, 0x0181ac,
+       0x012899, 0x009021, 0x000000, 0xffa5d4, 0xff8cdb,
+       0xffa4b6, 0xffd0ad, 0xfff71d
+};
+
+static const int lpf3_mode4[] = {
+       0xffd46b, 0xffb7a1, 0x006ded, 0x009ddb, 0xff25e9,
+       0xfedaef, 0x018208, 0x01f591, 0xfd7972, 0xfcbff4,
+       0x043527, 0x058a27, 0xf872cb, 0xf4f5a2, 0x12ef7c,
+       0x399f1f, 0x399f1f, 0x12ef7c, 0xf4f5a2, 0xf872cb,
+       0x058a27, 0x043527, 0xfcbff4, 0xfd7972, 0x01f591,
+       0x018208, 0xfedaef, 0xff25e9, 0x009ddb, 0x006ded,
+       0xffb7a1, 0xffd46b
+};
diff --git a/sound/soc/amlogic/auge/regs.h b/sound/soc/amlogic/auge/regs.h
new file mode 100644 (file)
index 0000000..1be9d4a
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * sound/soc/amlogic/auge/regs.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_REGS_H_
+#define __AML_REGS_H_
+
+/*
+ *  PDM - Registers
+ *  PDM
+ *
+ *  BASE_ADR                         32'hFF632000
+ */
+
+#define     PDM_CTRL                                           0x00
+#define     PDM_HCIC_CTRL1                                     0x01
+#define     PDM_HCIC_CTRL2                                     0x02
+#define     PDM_F1_CTRL                                        0x03
+#define     PDM_F2_CTRL                                        0x04
+#define     PDM_F3_CTRL                                        0x05
+#define     PDM_HPF_CTRL                                       0x06
+#define     PDM_CHAN_CTRL                                      0x07
+#define     PDM_CHAN_CTRL1                                     0x08
+#define     PDM_COEFF_ADDR                                     0x09
+#define     PDM_COEFF_DATA                                     0x0A
+#define     PDM_CLKG_CTRL                                      0x0B
+#define     PDM_STS                                            0x0C
+
+
+/**
+ *  AUDIO - Registers
+ *  AUDIO CLOCK, TODDR, FRDDR, TDM, SPDIF, LOOPBACK, RESAMPLE,
+ *  POWER DETECT, SECURITY
+ *
+ *  BASE_ADR                         32'hFF642000
+ */
+
+#define     EE_AUDIO_CLK_GATE_EN                               0x000
+#define     EE_AUDIO_MCLK_A_CTRL                               0x001
+#define     EE_AUDIO_MCLK_B_CTRL                               0x002
+#define     EE_AUDIO_MCLK_C_CTRL                               0x003
+#define     EE_AUDIO_MCLK_D_CTRL                               0x004
+#define     EE_AUDIO_MCLK_E_CTRL                               0x005
+#define     EE_AUDIO_MCLK_F_CTRL                               0x006
+#define     EE_AUDIO_MST_A_SCLK_CTRL0                          0x010
+#define     EE_AUDIO_MST_A_SCLK_CTRL1                          0x011
+#define     EE_AUDIO_MST_B_SCLK_CTRL0                          0x012
+#define     EE_AUDIO_MST_B_SCLK_CTRL1                          0x013
+#define     EE_AUDIO_MST_C_SCLK_CTRL0                          0x014
+#define     EE_AUDIO_MST_C_SCLK_CTRL1                          0x015
+#define     EE_AUDIO_MST_D_SCLK_CTRL0                          0x016
+#define     EE_AUDIO_MST_D_SCLK_CTRL1                          0x017
+#define     EE_AUDIO_MST_E_SCLK_CTRL0                          0x018
+#define     EE_AUDIO_MST_E_SCLK_CTRL1                          0x019
+#define     EE_AUDIO_MST_F_SCLK_CTRL0                          0x01a
+#define     EE_AUDIO_MST_F_SCLK_CTRL1                          0x01b
+#define     EE_AUDIO_CLK_TDMIN_A_CTRL                          0x020
+#define     EE_AUDIO_CLK_TDMIN_B_CTRL                          0x021
+#define     EE_AUDIO_CLK_TDMIN_C_CTRL                          0x022
+#define     EE_AUDIO_CLK_TDMIN_LB_CTRL                         0x023
+#define     EE_AUDIO_CLK_TDMOUT_A_CTRL                         0x024
+#define     EE_AUDIO_CLK_TDMOUT_B_CTRL                         0x025
+#define     EE_AUDIO_CLK_TDMOUT_C_CTRL                         0x026
+#define     EE_AUDIO_CLK_SPDIFIN_CTRL                          0x027
+#define     EE_AUDIO_CLK_SPDIFOUT_CTRL                         0x028
+#define     EE_AUDIO_CLK_RESAMPLE_CTRL                         0x029
+#define     EE_AUDIO_CLK_LOCKER_CTRL                           0x02a
+#define     EE_AUDIO_CLK_PDMIN_CTRL0                           0x02b
+#define     EE_AUDIO_CLK_PDMIN_CTRL1                           0x02c
+#define     EE_AUDIO_TODDR_A_CTRL0                             0x040
+#define     EE_AUDIO_TODDR_A_CTRL1                             0x041
+#define     EE_AUDIO_TODDR_A_START_ADDR                        0x042
+#define     EE_AUDIO_TODDR_A_FINISH_ADDR                       0x043
+#define     EE_AUDIO_TODDR_A_INT_ADDR                          0x044
+#define     EE_AUDIO_TODDR_A_STATUS1                           0x045
+#define     EE_AUDIO_TODDR_A_STATUS2                           0x046
+#define     EE_AUDIO_TODDR_A_START_ADDRB                       0x047
+#define     EE_AUDIO_TODDR_A_FINISH_ADDRB                      0x048
+#define     EE_AUDIO_TODDR_B_CTRL0                             0x050
+#define     EE_AUDIO_TODDR_B_CTRL1                             0x051
+#define     EE_AUDIO_TODDR_B_START_ADDR                        0x052
+#define     EE_AUDIO_TODDR_B_FINISH_ADDR                       0x053
+#define     EE_AUDIO_TODDR_B_INT_ADDR                          0x054
+#define     EE_AUDIO_TODDR_B_STATUS1                           0x055
+#define     EE_AUDIO_TODDR_B_STATUS2                           0x056
+#define     EE_AUDIO_TODDR_B_START_ADDRB                       0x057
+#define     EE_AUDIO_TODDR_B_FINISH_ADDRB                      0x058
+#define     EE_AUDIO_TODDR_C_CTRL0                             0x060
+#define     EE_AUDIO_TODDR_C_CTRL1                             0x061
+#define     EE_AUDIO_TODDR_C_START_ADDR                        0x062
+#define     EE_AUDIO_TODDR_C_FINISH_ADDR                       0x063
+#define     EE_AUDIO_TODDR_C_INT_ADDR                          0x064
+#define     EE_AUDIO_TODDR_C_STATUS1                           0x065
+#define     EE_AUDIO_TODDR_C_STATUS2                           0x066
+#define     EE_AUDIO_TODDR_C_START_ADDRB                       0x067
+#define     EE_AUDIO_TODDR_C_FINISH_ADDRB                      0x068
+#define     EE_AUDIO_FRDDR_A_CTRL0                             0x070
+#define     EE_AUDIO_FRDDR_A_CTRL1                             0x071
+#define     EE_AUDIO_FRDDR_A_START_ADDR                        0x072
+#define     EE_AUDIO_FRDDR_A_FINISH_ADDR                       0x073
+#define     EE_AUDIO_FRDDR_A_INT_ADDR                          0x074
+#define     EE_AUDIO_FRDDR_A_STATUS1                           0x075
+#define     EE_AUDIO_FRDDR_A_STATUS2                           0x076
+#define     EE_AUDIO_FRDDR_A_START_ADDRB                       0x077
+#define     EE_AUDIO_FRDDR_A_FINISH_ADDRB                      0x078
+#define     EE_AUDIO_FRDDR_B_CTRL0                             0x080
+#define     EE_AUDIO_FRDDR_B_CTRL1                             0x081
+#define     EE_AUDIO_FRDDR_B_START_ADDR                        0x082
+#define     EE_AUDIO_FRDDR_B_FINISH_ADDR                       0x083
+#define     EE_AUDIO_FRDDR_B_INT_ADDR                          0x084
+#define     EE_AUDIO_FRDDR_B_STATUS1                           0x085
+#define     EE_AUDIO_FRDDR_B_STATUS2                           0x086
+#define     EE_AUDIO_FRDDR_B_START_ADDRB                       0x087
+#define     EE_AUDIO_FRDDR_B_FINISH_ADDRB                      0x088
+#define     EE_AUDIO_FRDDR_C_CTRL0                             0x090
+#define     EE_AUDIO_FRDDR_C_CTRL1                             0x091
+#define     EE_AUDIO_FRDDR_C_START_ADDR                        0x092
+#define     EE_AUDIO_FRDDR_C_FINISH_ADDR                       0x093
+#define     EE_AUDIO_FRDDR_C_INT_ADDR                          0x094
+#define     EE_AUDIO_FRDDR_C_STATUS1                           0x095
+#define     EE_AUDIO_FRDDR_C_STATUS2                           0x096
+#define     EE_AUDIO_FRDDR_C_START_ADDRB                       0x097
+#define     EE_AUDIO_FRDDR_C_FINISH_ADDRB                      0x098
+#define     EE_AUDIO_ARB_CTRL                                  0x0a0
+#define     EE_AUDIO_LB_CTRL0                                  0x0b0
+#define     EE_AUDIO_LB_CTRL1                                  0x0b1
+#define     EE_AUDIO_TDMIN_A_CTRL                              0x0c0
+#define     EE_AUDIO_TDMIN_A_SWAP                              0x0c1
+#define     EE_AUDIO_TDMIN_A_MASK0                             0x0c2
+#define     EE_AUDIO_TDMIN_A_MASK1                             0x0c3
+#define     EE_AUDIO_TDMIN_A_MASK2                             0x0c4
+#define     EE_AUDIO_TDMIN_A_MASK3                             0x0c5
+#define     EE_AUDIO_TDMIN_A_STAT                              0x0c6
+#define     EE_AUDIO_TDMIN_A_MUTE_VAL                          0x0c7
+#define     EE_AUDIO_TDMIN_A_MUTE0                             0x0c8
+#define     EE_AUDIO_TDMIN_A_MUTE1                             0x0c9
+#define     EE_AUDIO_TDMIN_A_MUTE2                             0x0ca
+#define     EE_AUDIO_TDMIN_A_MUTE3                             0x0cb
+#define     EE_AUDIO_TDMIN_B_CTRL                              0x0d0
+#define     EE_AUDIO_TDMIN_B_SWAP                              0x0d1
+#define     EE_AUDIO_TDMIN_B_MASK0                             0x0d2
+#define     EE_AUDIO_TDMIN_B_MASK1                             0x0d3
+#define     EE_AUDIO_TDMIN_B_MASK2                             0x0d4
+#define     EE_AUDIO_TDMIN_B_MASK3                             0x0d5
+#define     EE_AUDIO_TDMIN_B_STAT                              0x0d6
+#define     EE_AUDIO_TDMIN_B_MUTE_VAL                          0x0d7
+#define     EE_AUDIO_TDMIN_B_MUTE0                             0x0d8
+#define     EE_AUDIO_TDMIN_B_MUTE1                             0x0d9
+#define     EE_AUDIO_TDMIN_B_MUTE2                             0x0da
+#define     EE_AUDIO_TDMIN_B_MUTE3                             0x0db
+#define     EE_AUDIO_TDMIN_C_CTRL                              0x0e0
+#define     EE_AUDIO_TDMIN_C_SWAP                              0x0e1
+#define     EE_AUDIO_TDMIN_C_MASK0                             0x0e2
+#define     EE_AUDIO_TDMIN_C_MASK1                             0x0e3
+#define     EE_AUDIO_TDMIN_C_MASK2                             0x0e4
+#define     EE_AUDIO_TDMIN_C_MASK3                             0x0e5
+#define     EE_AUDIO_TDMIN_C_STAT                              0x0e6
+#define     EE_AUDIO_TDMIN_C_MUTE_VAL                          0x0e7
+#define     EE_AUDIO_TDMIN_C_MUTE0                             0x0e8
+#define     EE_AUDIO_TDMIN_C_MUTE1                             0x0e9
+#define     EE_AUDIO_TDMIN_C_MUTE2                             0x0ea
+#define     EE_AUDIO_TDMIN_C_MUTE3                             0x0eb
+#define     EE_AUDIO_TDMIN_LB_CTRL                             0x0f0
+#define     EE_AUDIO_TDMIN_LB_SWAP                             0x0f1
+#define     EE_AUDIO_TDMIN_LB_MASK0                            0x0f2
+#define     EE_AUDIO_TDMIN_LB_MASK1                            0x0f3
+#define     EE_AUDIO_TDMIN_LB_MASK2                            0x0f4
+#define     EE_AUDIO_TDMIN_LB_MASK3                            0x0f5
+#define     EE_AUDIO_TDMIN_LB_STAT                             0x0f6
+#define     EE_AUDIO_TDMIN_LB_MUTE_VAL                         0x0f7
+#define     EE_AUDIO_TDMIN_LB_MUTE0                            0x0f8
+#define     EE_AUDIO_TDMIN_LB_MUTE1                            0x0f9
+#define     EE_AUDIO_TDMIN_LB_MUTE2                            0x0fa
+#define     EE_AUDIO_TDMIN_LB_MUTE3                            0x0fb
+#define     EE_AUDIO_SPDIFIN_CTRL0                             0x100
+#define     EE_AUDIO_SPDIFIN_CTRL1                             0x101
+#define     EE_AUDIO_SPDIFIN_CTRL2                             0x102
+#define     EE_AUDIO_SPDIFIN_CTRL3                             0x103
+#define     EE_AUDIO_SPDIFIN_CTRL4                             0x104
+#define     EE_AUDIO_SPDIFIN_CTRL5                             0x105
+#define     EE_AUDIO_SPDIFIN_CTRL6                             0x106
+#define     EE_AUDIO_SPDIFIN_STAT0                             0x107
+#define     EE_AUDIO_SPDIFIN_STAT1                             0x108
+#define     EE_AUDIO_SPDIFIN_STAT2                             0x109
+#define     EE_AUDIO_SPDIFIN_MUTE_VAL                          0x10a
+#define     EE_AUDIO_RESAMPLE_CTRL0                            0x110
+#define     EE_AUDIO_RESAMPLE_CTRL1                            0x111
+#define     EE_AUDIO_RESAMPLE_CTRL2                            0x112
+#define     EE_AUDIO_RESAMPLE_CTRL3                            0x113
+#define     EE_AUDIO_RESAMPLE_COEF0                            0x114
+#define     EE_AUDIO_RESAMPLE_COEF1                            0x115
+#define     EE_AUDIO_RESAMPLE_COEF2                            0x116
+#define     EE_AUDIO_RESAMPLE_COEF3                            0x117
+#define     EE_AUDIO_RESAMPLE_COEF4                            0x118
+#define     EE_AUDIO_RESAMPLE_STATUS1                          0x119
+#define     EE_AUDIO_SPDIFOUT_STAT                             0x120
+#define     EE_AUDIO_SPDIFOUT_GAIN0                            0x121
+#define     EE_AUDIO_SPDIFOUT_GAIN1                            0x122
+#define     EE_AUDIO_SPDIFOUT_CTRL0                            0x123
+#define     EE_AUDIO_SPDIFOUT_CTRL1                            0x124
+#define     EE_AUDIO_SPDIFOUT_PREAMB                           0x125
+#define     EE_AUDIO_SPDIFOUT_SWAP                             0x126
+#define     EE_AUDIO_SPDIFOUT_CHSTS0                           0x127
+#define     EE_AUDIO_SPDIFOUT_CHSTS1                           0x128
+#define     EE_AUDIO_SPDIFOUT_CHSTS2                           0x129
+#define     EE_AUDIO_SPDIFOUT_CHSTS3                           0x12a
+#define     EE_AUDIO_SPDIFOUT_CHSTS4                           0x12b
+#define     EE_AUDIO_SPDIFOUT_CHSTS5                           0x12c
+#define     EE_AUDIO_SPDIFOUT_CHSTS6                           0x12d
+#define     EE_AUDIO_SPDIFOUT_CHSTS7                           0x12e
+#define     EE_AUDIO_SPDIFOUT_CHSTS8                           0x12f
+#define     EE_AUDIO_SPDIFOUT_CHSTS9                           0x130
+#define     EE_AUDIO_SPDIFOUT_CHSTSA                           0x131
+#define     EE_AUDIO_SPDIFOUT_CHSTSB                           0x132
+#define     EE_AUDIO_SPDIFOUT_MUTE_VAL                         0x133
+#define     EE_AUDIO_TDMOUT_A_CTRL0                            0x140
+#define     EE_AUDIO_TDMOUT_A_CTRL1                            0x141
+#define     EE_AUDIO_TDMOUT_A_SWAP                             0x142
+#define     EE_AUDIO_TDMOUT_A_MASK0                            0x143
+#define     EE_AUDIO_TDMOUT_A_MASK1                            0x144
+#define     EE_AUDIO_TDMOUT_A_MASK2                            0x145
+#define     EE_AUDIO_TDMOUT_A_MASK3                            0x146
+#define     EE_AUDIO_TDMOUT_A_STAT                             0x147
+#define     EE_AUDIO_TDMOUT_A_GAIN0                            0x148
+#define     EE_AUDIO_TDMOUT_A_GAIN1                            0x149
+#define     EE_AUDIO_TDMOUT_A_MUTE_VAL                         0x14a
+#define     EE_AUDIO_TDMOUT_A_MUTE0                            0x14b
+#define     EE_AUDIO_TDMOUT_A_MUTE1                            0x14c
+#define     EE_AUDIO_TDMOUT_A_MUTE2                            0x14d
+#define     EE_AUDIO_TDMOUT_A_MUTE3                            0x14e
+#define     EE_AUDIO_TDMOUT_A_MASK_VAL                         0x14f
+#define     EE_AUDIO_TDMOUT_B_CTRL0                            0x150
+#define     EE_AUDIO_TDMOUT_B_CTRL1                            0x151
+#define     EE_AUDIO_TDMOUT_B_SWAP                             0x152
+#define     EE_AUDIO_TDMOUT_B_MASK0                            0x153
+#define     EE_AUDIO_TDMOUT_B_MASK1                            0x154
+#define     EE_AUDIO_TDMOUT_B_MASK2                            0x155
+#define     EE_AUDIO_TDMOUT_B_MASK3                            0x156
+#define     EE_AUDIO_TDMOUT_B_STAT                             0x157
+#define     EE_AUDIO_TDMOUT_B_GAIN0                            0x158
+#define     EE_AUDIO_TDMOUT_B_GAIN1                            0x159
+#define     EE_AUDIO_TDMOUT_B_MUTE_VAL                         0x15a
+#define     EE_AUDIO_TDMOUT_B_MUTE0                            0x15b
+#define     EE_AUDIO_TDMOUT_B_MUTE1                            0x15c
+#define     EE_AUDIO_TDMOUT_B_MUTE2                            0x15d
+#define     EE_AUDIO_TDMOUT_B_MUTE3                            0x15e
+#define     EE_AUDIO_TDMOUT_B_MASK_VAL                         0x15f
+#define     EE_AUDIO_TDMOUT_C_CTRL0                            0x160
+#define     EE_AUDIO_TDMOUT_C_CTRL1                            0x161
+#define     EE_AUDIO_TDMOUT_C_SWAP                             0x162
+#define     EE_AUDIO_TDMOUT_C_MASK0                            0x163
+#define     EE_AUDIO_TDMOUT_C_MASK1                            0x164
+#define     EE_AUDIO_TDMOUT_C_MASK2                            0x165
+#define     EE_AUDIO_TDMOUT_C_MASK3                            0x166
+#define     EE_AUDIO_TDMOUT_C_STAT                             0x167
+#define     EE_AUDIO_TDMOUT_C_GAIN0                            0x168
+#define     EE_AUDIO_TDMOUT_C_GAIN1                            0x169
+#define     EE_AUDIO_TDMOUT_C_MUTE_VAL                         0x16a
+#define     EE_AUDIO_TDMOUT_C_MUTE0                            0x16b
+#define     EE_AUDIO_TDMOUT_C_MUTE1                            0x16c
+#define     EE_AUDIO_TDMOUT_C_MUTE2                            0x16d
+#define     EE_AUDIO_TDMOUT_C_MUTE3                            0x16e
+#define     EE_AUDIO_TDMOUT_C_MASK_VAL                         0x16f
+#define     EE_AUDIO_POW_DET_CTRL0                             0x180
+#define     EE_AUDIO_POW_DET_TH_HI                             0x181
+#define     EE_AUDIO_POW_DET_TH_LO                             0x182
+#define     EE_AUDIO_POW_DET_VALUE                             0x183
+#define     EE_AUDIO_SECURITY_CTRL                             0x193
+
+#define     AUD_ADDR_OFFSET(addr)                              ((addr) << 2)
+
+enum clk_sel {
+       MASTER_A,
+       MASTER_B,
+       MASTER_C,
+       MASTER_D,
+       MASTER_E,
+       MASTER_F,
+       SLAVE_A,
+       SLAVE_B,
+       SLAVE_C,
+       SLAVE_D,
+       SLAVE_E,
+       SLAVE_F,
+       SLAVE_G,
+       SLAVE_H,
+       SLAVE_I,
+       SLAVE_J
+};
+
+#endif
diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c
new file mode 100644 (file)
index 0000000..4d6f4b3
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * sound/soc/amlogic/auge/spdif.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+
+#include "ddr_mngr.h"
+#include "spdif_hw.h"
+
+
+#define DRV_NAME "aml_spdif"
+
+struct aml_spdif {
+       struct pinctrl *pin_ctl;
+       struct aml_audio_controller *actrl;
+       struct device *dev;
+       struct clk *gate_spdifin;
+       struct clk *gate_spdifout;
+       struct clk *sysclk;
+       struct clk *fixed_clk;
+       struct clk *clk_spdifin;
+       struct clk *clk_spdifout;
+       unsigned int sysclk_freq;
+       /* bclk src selection */
+       int irq_toddr;
+       int irq_frddr;
+       int irq_spdifin;
+       unsigned int from_ddr_num;
+       unsigned int to_ddr_num;
+       struct toddr *tddr;
+       struct frddr *fddr;
+};
+
+static const struct snd_pcm_hardware aml_spdif_hardware = {
+       .info =
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_INTERLEAVED |
+           SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE,
+       .formats =
+           SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+           SNDRV_PCM_FMTBIT_S32_LE,
+
+       .period_bytes_min = 64,
+       .period_bytes_max = 128 * 1024,
+       .periods_min = 2,
+       .periods_max = 1024,
+       .buffer_bytes_max = 256 * 1024,
+
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 32,
+};
+
+static irqreturn_t aml_spdifout_isr(int irq, void *devid)
+{
+       struct snd_pcm_substream *substream =
+               (struct snd_pcm_substream *)devid;
+
+       snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t aml_spdifin_isr(int irq, void *devid)
+{
+       struct snd_pcm_substream *substream =
+               (struct snd_pcm_substream *)devid;
+
+       snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+/* detect PCM/RAW and sample changes by the source */
+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);
+
+       return IRQ_HANDLED;
+}
+
+static int aml_spdif_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct aml_spdif *p_spdif;
+       int ret = 0;
+
+       pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+       p_spdif = (struct aml_spdif *)dev_get_drvdata(dev);
+
+       snd_soc_set_runtime_hwparams(substream, &aml_spdif_hardware);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               p_spdif->fddr = aml_audio_register_frddr(dev,
+                       p_spdif->actrl,
+                       p_spdif->from_ddr_num);
+               if (p_spdif->fddr == NULL) {
+                       dev_err(dev, "failed to claim from ddr %u\n",
+                                       p_spdif->from_ddr_num);
+                       return -ENXIO;
+               }
+
+               ret = request_irq(p_spdif->irq_frddr,
+                       aml_spdifout_isr, 0, "spdifout", substream);
+               if (ret) {
+                       aml_audio_unregister_frddr(dev, p_spdif->from_ddr_num);
+                       dev_err(p_spdif->dev, "failed to claim irq %u\n",
+                                       p_spdif->irq_frddr);
+                       return ret;
+               }
+       } else {
+               p_spdif->tddr = aml_audio_register_toddr(dev,
+                       p_spdif->actrl,
+                       p_spdif->to_ddr_num);
+               if (p_spdif->tddr == NULL) {
+                       dev_err(dev, "failed to claim to ddr %u\n",
+                                       p_spdif->to_ddr_num);
+                       return -ENXIO;
+               }
+
+               ret = request_irq(p_spdif->irq_toddr,
+                               aml_spdifin_isr, 0, "spdifin", substream);
+               if (ret) {
+                       aml_audio_unregister_toddr(dev, p_spdif->to_ddr_num);
+                       dev_err(p_spdif->dev, "failed to claim irq %u\n",
+                                               p_spdif->irq_toddr);
+                       return ret;
+               }
+       }
+
+       runtime->private_data = p_spdif;
+
+       return 0;
+}
+
+
+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__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               aml_audio_unregister_frddr(p_spdif->dev, p_spdif->from_ddr_num);
+               free_irq(p_spdif->irq_frddr, substream);
+       } else {
+               aml_audio_unregister_toddr(p_spdif->dev, p_spdif->to_ddr_num);
+               free_irq(p_spdif->irq_toddr, substream);
+       }
+
+       runtime->private_data = NULL;
+
+       return 0;
+}
+
+
+static int aml_spdif_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int aml_spdif_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+
+       return 0;
+}
+
+static int aml_spdif_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       return 0;
+}
+
+static int aml_spdif_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_spdif *p_spdif = runtime->private_data;
+       unsigned int start_addr, end_addr, int_addr;
+
+       start_addr = runtime->dma_addr;
+       end_addr = start_addr + runtime->dma_bytes - 8;
+       int_addr = frames_to_bytes(runtime, runtime->period_size) / 8;
+
+       pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               struct frddr *fr = p_spdif->fddr;
+
+               aml_frddr_set_buf(fr, start_addr, end_addr);
+               aml_frddr_set_intrpt(fr, int_addr);
+       } else {
+               struct toddr *to = p_spdif->tddr;
+
+               aml_toddr_set_buf(to, start_addr, end_addr);
+               aml_toddr_set_intrpt(to, int_addr);
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t aml_spdif_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_spdif *p_spdif = runtime->private_data;
+       unsigned int addr, start_addr;
+
+       start_addr = runtime->dma_addr;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               addr = aml_frddr_get_position(p_spdif->fddr);
+       else
+               addr = aml_toddr_get_position(p_spdif->tddr);
+
+       return bytes_to_frames(runtime, addr - start_addr);
+}
+
+int aml_spdif_silence(struct snd_pcm_substream *substream, int channel,
+                   snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       char *ppos;
+       int n;
+
+       n = frames_to_bytes(runtime, count);
+       ppos = runtime->dma_area + frames_to_bytes(runtime, pos);
+       memset(ppos, 0, n);
+
+       return 0;
+}
+
+static int aml_spdif_mmap(struct snd_pcm_substream *substream,
+                       struct vm_area_struct *vma)
+{
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops aml_spdif_ops = {
+       .open      = aml_spdif_open,
+       .close     = aml_spdif_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = aml_spdif_hw_params,
+       .hw_free   = aml_spdif_hw_free,
+       .prepare   = aml_spdif_prepare,
+       .trigger   = aml_spdif_trigger,
+       .pointer   = aml_spdif_pointer,
+       .silence   = aml_spdif_silence,
+       .mmap      = aml_spdif_mmap,
+};
+
+#define PREALLOC_BUFFER                (32 * 1024)
+#define PREALLOC_BUFFER_MAX    (256 * 1024)
+static int aml_spdif_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(
+                       rtd->pcm, SNDRV_DMA_TYPE_DEV,
+                       rtd->card->snd_card->dev,
+                       PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+}
+
+struct snd_soc_platform_driver aml_spdif_platform = {
+       .ops = &aml_spdif_ops,
+       .pcm_new = aml_spdif_new,
+};
+
+static int aml_dai_spdif_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       struct device *dev = p_spdif->dev;
+       int ret;
+
+       /* gate on */
+       clk_prepare_enable(p_spdif->gate_spdifin);
+       clk_prepare_enable(p_spdif->gate_spdifout);
+
+       ret = clk_set_parent(p_spdif->clk_spdifin, p_spdif->fixed_clk);
+       if (ret) {
+               dev_err(dev,
+                       "Can't set clk_spdifin parent clock\n");
+               ret = PTR_ERR(p_spdif->clk_spdifin);
+               return ret;
+       }
+
+       clk_set_rate(p_spdif->clk_spdifin, 250000000);
+       ret = clk_prepare_enable(p_spdif->clk_spdifin);
+       if (ret) {
+               dev_err(dev,
+                       "Can't enable pcm clk_spdifin clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_parent(p_spdif->clk_spdifout, p_spdif->sysclk);
+       if (ret) {
+               dev_err(dev,
+                       "Can't set clk_spdifout parent clock\n");
+               ret = PTR_ERR(p_spdif->clk_spdifout);
+               return ret;
+       }
+
+       /* enable clock */
+       ret = clk_prepare_enable(p_spdif->clk_spdifout);
+       if (ret) {
+               dev_err(dev,
+                       "Can't enable pcm clk_spdifout clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = request_irq(p_spdif->irq_spdifin,
+                       aml_spdifin_status_isr, 0, "irq_spdifin", p_spdif);
+       if (ret) {
+               dev_err(p_spdif->dev, "failed to claim irq_spdifin %u\n",
+                                       p_spdif->irq_spdifin);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int aml_dai_spdif_remove(struct snd_soc_dai *cpu_dai)
+{
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+       free_irq(p_spdif->irq_spdifin, p_spdif);
+       free_irq(p_spdif->irq_frddr, p_spdif);
+       free_irq(p_spdif->irq_toddr, p_spdif);
+
+       clk_disable_unprepare(p_spdif->clk_spdifin);
+       clk_disable_unprepare(p_spdif->clk_spdifout);
+       clk_disable_unprepare(p_spdif->sysclk);
+       clk_disable_unprepare(p_spdif->fixed_clk);
+       clk_disable_unprepare(p_spdif->gate_spdifin);
+       clk_disable_unprepare(p_spdif->gate_spdifout);
+
+       return 0;
+}
+
+static int aml_dai_spdif_startup(
+       struct snd_pcm_substream *substream,
+       struct snd_soc_dai *cpu_dai)
+{
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+       aml_spdif_fifo_reset(p_spdif->actrl, substream->stream);
+
+       return 0;
+}
+
+static void aml_dai_spdif_shutdown(
+       struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+}
+
+static int aml_dai_spdif_prepare(
+       struct snd_pcm_substream *substream,
+       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned int bit_depth = 0;
+
+       pr_info("%s stream:%d\n", __func__, substream->stream);
+
+       bit_depth = snd_pcm_format_width(runtime->format);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               struct frddr *fr = p_spdif->fddr;
+
+               aml_frddr_select_dst(fr, SPDIFOUT);
+               aml_frddr_set_fifos(fr, 0x40, 0x20);
+       } else {
+               struct toddr *to = p_spdif->tddr;
+               unsigned int lsb, toddr_type;
+
+               switch (bit_depth) {
+               case 8:
+                       toddr_type = 0;
+                       break;
+               case 16:
+                       toddr_type = 1;
+                       break;
+               case 24:
+                       toddr_type = 4;
+                       break;
+               case 32:
+                       toddr_type = 3;
+                       break;
+               default:
+                       dev_err(p_spdif->dev,
+                               "runtime format invalid bit_depth: %d\n",
+                               bit_depth);
+                       return -EINVAL;
+               }
+
+               if (bit_depth <= 24)
+                       lsb = 28 - bit_depth;
+               else
+                       lsb = 4;
+
+               // to ddr spdifin
+               aml_toddr_select_src(to, SPDIFIN);
+               aml_toddr_set_format(to, toddr_type, 27, lsb);
+               aml_toddr_set_fifos(to, 0x40);
+       }
+
+       aml_spdif_fifo_ctrl(p_spdif->actrl, bit_depth, substream->stream);
+
+       return 0;
+}
+
+static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *cpu_dai)
+{
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dev_info(substream->pcm->card->dev, "spdif playback enable\n");
+                       aml_frddr_enable(p_spdif->fddr, 1);
+               } else {
+                       dev_info(substream->pcm->card->dev, "spdif capture enable\n");
+                       aml_toddr_enable(p_spdif->tddr, 1);
+               }
+               aml_spdif_enable(p_spdif->actrl,
+                       substream->stream, true);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dev_info(substream->pcm->card->dev, "spdif playback disable\n");
+                       aml_frddr_enable(p_spdif->fddr, 0);
+               } else {
+                       dev_info(substream->pcm->card->dev, "spdif capture disable\n");
+                       aml_toddr_enable(p_spdif->tddr, 0);
+               }
+               aml_spdif_enable(p_spdif->actrl,
+                       substream->stream, false);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       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)
+{
+       unsigned int rate = params_rate(params);
+       int ret = 0;
+
+       pr_info("%s\n", __func__);
+       rate *= 128;
+       snd_soc_dai_set_sysclk(cpu_dai,
+                       0, rate, SND_SOC_CLOCK_OUT);
+
+       return ret;
+}
+
+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);
+
+       return 0;
+}
+
+static void aml_set_spdifclk(struct aml_spdif *p_spdif)
+{
+       unsigned int mpll_freq = 0;
+
+       pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+       if (p_spdif->sysclk_freq) {
+               unsigned int mul = 4;
+
+               mpll_freq = p_spdif->sysclk_freq * mul;
+               clk_set_rate(p_spdif->sysclk, mpll_freq);
+               clk_set_rate(p_spdif->clk_spdifout,
+                       p_spdif->sysclk_freq);
+       }
+}
+
+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);
+
+       p_spdif->sysclk_freq = freq;
+       pr_info("aml_dai_set_spdif_sysclk, %d, %d, %d\n",
+                       clk_id, freq, dir);
+       aml_set_spdifclk(p_spdif);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops aml_dai_spdif_ops = {
+       .startup = aml_dai_spdif_startup,
+       .shutdown = aml_dai_spdif_shutdown,
+       .prepare = aml_dai_spdif_prepare,
+       .trigger = aml_dai_spdif_trigger,
+       .hw_params = aml_dai_spdif_hw_params,
+       .set_fmt = aml_dai_set_spdif_fmt,
+       .set_sysclk = aml_dai_set_spdif_sysclk,
+};
+
+#define AML_DAI_SPDIF_RATES            (SNDRV_PCM_RATE_8000_192000)
+#define AML_DAI_SPDIF_FORMATS          (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver aml_spdif_dai = {
+       .name = "SPDIF",
+       .id = 0,
+       .probe = aml_dai_spdif_probe,
+       .remove = aml_dai_spdif_remove,
+       .playback = {
+             .channels_min = 1,
+             .channels_max = 2,
+             .rates = AML_DAI_SPDIF_RATES,
+             .formats = AML_DAI_SPDIF_FORMATS,
+       },
+       .capture = {
+            .channels_min = 1,
+            .channels_max = 2,
+            .rates = AML_DAI_SPDIF_RATES,
+            .formats = AML_DAI_SPDIF_FORMATS,
+       },
+       .ops = &aml_dai_spdif_ops,
+};
+
+static const struct snd_soc_component_driver aml_spdif_component = {
+       .name           = DRV_NAME,
+};
+
+static int aml_spdif_clks_parse_of(struct aml_spdif *p_spdif)
+{
+       struct device *dev = p_spdif->dev;
+
+       /* clock gate */
+       p_spdif->gate_spdifin = devm_clk_get(dev, "gate_spdifin");
+       if (IS_ERR(p_spdif->gate_spdifin)) {
+               dev_err(dev, "Can't get spdifin gate\n");
+               return PTR_ERR(p_spdif->gate_spdifin);
+       }
+
+       p_spdif->gate_spdifout = devm_clk_get(dev, "gate_spdifout");
+       if (IS_ERR(p_spdif->gate_spdifout)) {
+               dev_err(dev, "Can't get spdifout gate\n");
+               return PTR_ERR(p_spdif->gate_spdifout);
+       }
+
+       p_spdif->sysclk = devm_clk_get(dev, "sysclk");
+       if (IS_ERR(p_spdif->sysclk)) {
+               dev_err(dev, "Can't retrieve sysclk clock\n");
+               return PTR_ERR(p_spdif->sysclk);
+       }
+
+       p_spdif->fixed_clk = devm_clk_get(dev, "fixed_clk");
+       if (IS_ERR(p_spdif->fixed_clk)) {
+               dev_err(dev, "Can't retrieve fixed_clk\n");
+               return PTR_ERR(p_spdif->fixed_clk);
+       }
+
+       p_spdif->clk_spdifin = devm_clk_get(dev, "clk_spdifin");
+       if (IS_ERR(p_spdif->clk_spdifin)) {
+               dev_err(dev, "Can't retrieve spdifin clock\n");
+               return PTR_ERR(p_spdif->clk_spdifin);
+       }
+
+       p_spdif->clk_spdifout = devm_clk_get(dev, "clk_spdifout");
+       if (IS_ERR(p_spdif->clk_spdifout)) {
+               dev_err(dev, "Can't retrieve spdifout clock\n");
+               return PTR_ERR(p_spdif->clk_spdifout);
+       }
+
+       return 0;
+}
+
+static int aml_spdif_platform_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *node_prt = NULL;
+       struct platform_device *pdev_parent;
+       struct device *dev = &pdev->dev;
+       struct aml_audio_controller *actrl = NULL;
+       struct aml_spdif *aml_spdif = NULL;
+       int ret = 0;
+
+       aml_spdif = devm_kzalloc(dev, sizeof(struct aml_spdif), GFP_KERNEL);
+       if (!aml_spdif)
+               return -ENOMEM;
+
+       aml_spdif->dev = dev;
+       dev_set_drvdata(dev, aml_spdif);
+
+       /* get audio controller */
+       node_prt = of_get_parent(node);
+       if (node_prt == NULL)
+               return -ENXIO;
+
+       pdev_parent = of_find_device_by_node(node_prt);
+       of_node_put(node_prt);
+       actrl = (struct aml_audio_controller *)
+                               platform_get_drvdata(pdev_parent);
+       aml_spdif->actrl = actrl;
+
+       /* parse DTS configured ddr */
+       ret = of_property_read_u32(node, "spdif_from_ddr",
+                       &aml_spdif->from_ddr_num);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't retrieve spdif_from_ddr\n");
+               return -ENXIO;
+       }
+
+       ret = of_property_read_u32(node, "spdif_to_ddr",
+                       &aml_spdif->to_ddr_num);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't retrieve spdif_to_ddr\n");
+               return -ENXIO;
+       }
+
+       ret = aml_spdif_clks_parse_of(aml_spdif);
+       if (ret)
+               return -EINVAL;
+
+       /* irqs */
+       aml_spdif->irq_spdifin = platform_get_irq_byname(pdev, "irq_spdifin");
+       if (aml_spdif->irq_spdifin < 0)
+               dev_err(dev, "platform_get_irq_byname failed\n");
+
+       aml_spdif->irq_toddr = platform_get_irq_byname(pdev, "irq_toddr");
+       if (aml_spdif->irq_toddr < 0)
+               dev_err(dev, "platform_get_irq_byname failed\n");
+
+       aml_spdif->irq_frddr = platform_get_irq_byname(pdev, "irq_frddr");
+       if (aml_spdif->irq_frddr < 0)
+               dev_err(dev, "platform_get_irq_byname failed\n");
+
+       /* spdif pinmux */
+       aml_spdif->pin_ctl = devm_pinctrl_get_select(dev, "spdif_pins");
+       if (IS_ERR(aml_spdif->pin_ctl)) {
+               dev_info(dev, "aml_spdif_get_pins error!\n");
+               return PTR_ERR(aml_spdif->pin_ctl);
+       }
+
+       ret = devm_snd_soc_register_component(dev, &aml_spdif_component,
+                                        &aml_spdif_dai, 1);
+       if (ret) {
+               dev_err(dev, "devm_snd_soc_register_component failed\n");
+               return ret;
+       }
+
+       pr_info("%s, register soc platform\n", __func__);
+
+       return devm_snd_soc_register_platform(dev, &aml_spdif_platform);
+}
+
+static const struct of_device_id aml_spdif_device_id[] = {
+       { .compatible = "amlogic, snd-spdif" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, aml_spdif_device_id);
+
+struct platform_driver aml_spdif_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = aml_spdif_device_id,
+       },
+       .probe = aml_spdif_platform_probe,
+};
+module_platform_driver(aml_spdif_driver);
+
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("Amlogic SPDIF ASoc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, aml_spdif_device_id);
diff --git a/sound/soc/amlogic/auge/spdif_hw.c b/sound/soc/amlogic/auge/spdif_hw.c
new file mode 100644 (file)
index 0000000..cb8719b
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * sound/soc/amlogic/auge/spdif_hw.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <sound/soc.h>
+
+#include "spdif_hw.h"
+
+void aml_spdif_enable(
+       struct aml_audio_controller *actrl,
+       int stream,
+       bool is_enable)
+{
+       pr_info("spdif stream :%d is_enable:%d\n", stream, is_enable);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_SPDIFOUT_CTRL0, 1<<31, is_enable<<31);
+       } else {
+               aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_SPDIFIN_CTRL0, 1<<31, is_enable<<31);
+       }
+}
+
+void aml_spdif_arb_config(struct aml_audio_controller *actrl)
+{
+       /* config ddr arb */
+       aml_audiobus_write(actrl, EE_AUDIO_ARB_CTRL, 1<<31|0xff<<0);
+}
+
+void aml_spdifin_status_check(struct aml_audio_controller *actrl)
+{
+       unsigned int val;
+
+       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);
+}
+
+void aml_spdif_fifo_reset(
+       struct aml_audio_controller *actrl,
+       int stream)
+{
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* reset afifo */
+               aml_audiobus_update_bits(actrl,
+                               EE_AUDIO_SPDIFOUT_CTRL0, 3<<28, 0);
+               aml_audiobus_update_bits(actrl,
+                               EE_AUDIO_SPDIFOUT_CTRL0, 1<<29, 1<<29);
+               aml_audiobus_update_bits(actrl,
+                               EE_AUDIO_SPDIFOUT_CTRL0, 1<<28, 1<<28);
+       } else {
+               /* reset afifo */
+               aml_audiobus_update_bits(actrl,
+                               EE_AUDIO_SPDIFIN_CTRL0, 3<<28, 0);
+               aml_audiobus_update_bits(actrl,
+                               EE_AUDIO_SPDIFIN_CTRL0, 1<<29, 1<<29);
+               aml_audiobus_update_bits(actrl,
+                               EE_AUDIO_SPDIFIN_CTRL0, 1<<28, 1<<28);
+       }
+}
+
+void aml_spdif_fifo_ctrl(
+       struct aml_audio_controller *actrl,
+       int bitwidth,
+       int stream)
+{
+       unsigned int frddr_type, toddr_type;
+
+       switch (bitwidth) {
+       case 8:
+               frddr_type = 0;
+               toddr_type = 0;
+               break;
+       case 16:
+               frddr_type = 1;
+               toddr_type = 1;
+               break;
+       case 24:
+               frddr_type = 4;
+               toddr_type = 4;
+               break;
+       case 32:
+               frddr_type = 3;
+               toddr_type = 3;
+               break;
+       default:
+               pr_err("runtime format invalid bitwidth: %d\n",
+                       bitwidth);
+               return;
+       }
+
+       pr_info("%s, bit depth:%d, frddr type:%d, toddr:type:%d\n",
+       __func__, bitwidth, frddr_type, toddr_type);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               // mask lane 0 L/R channels
+               aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_SPDIFOUT_CTRL0,
+                       0x1<<29|0x1<<28|0x1<<20|0x1<<19|0xff<<4,
+                       1<<29|1<<28|0<<20|0<<19|0x3<<4);
+
+               aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_SPDIFOUT_CTRL1,
+                       0x3 << 24 | 0x1f << 8 | 0x7 << 4,
+                       0 << 24 | (bitwidth - 1) << 8 | frddr_type<<4);
+
+               aml_audiobus_write(actrl,
+                       EE_AUDIO_SPDIFOUT_SWAP,
+                       1<<4);
+       } else {
+               unsigned int lsb;
+
+               if (bitwidth <= 24)
+                       lsb = 28 - bitwidth;
+               else
+                       lsb = 4;
+
+               // 250M
+               aml_audiobus_write(actrl,
+                       EE_AUDIO_SPDIFIN_CTRL1,
+                       0xff << 20 | 25000 << 0);
+
+               aml_audiobus_write(actrl,
+                       EE_AUDIO_SPDIFIN_CTRL2,
+                       140 << 20 | 100 << 10 | 86 << 0);
+
+               aml_audiobus_write(actrl,
+                       EE_AUDIO_SPDIFIN_CTRL3,
+                       83 << 20 | 60 << 10 | 30 << 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)
+                       );
+
+               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]; */
+                       );
+
+               aml_audiobus_update_bits(actrl,
+                       EE_AUDIO_SPDIFIN_CTRL0,
+                       0x3<<24|1<<12,
+                       3<<24|1<<12);
+       }
+
+}
diff --git a/sound/soc/amlogic/auge/spdif_hw.h b/sound/soc/amlogic/auge/spdif_hw.h
new file mode 100644 (file)
index 0000000..696483f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * sound/soc/amlogic/auge/spdif_hw.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_SPDIF_HW_H__
+#define __AML_SPDIF_HW_H__
+#include "audio_io.h"
+#include "regs.h"
+
+extern void aml_spdif_enable(
+       struct aml_audio_controller *actrl,
+       int stream,
+       bool is_enable);
+
+extern void aml_spdif_arb_config(struct aml_audio_controller *actrl);
+
+extern void aml_spdifin_status_check(
+       struct aml_audio_controller *actrl);
+
+extern void aml_spdif_fifo_reset(
+       struct aml_audio_controller *actrl,
+       int stream);
+
+extern void aml_spdif_fifo_ctrl(
+       struct aml_audio_controller *actrl,
+       int bitwidth,
+       int stream);
+#endif
diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c
new file mode 100644 (file)
index 0000000..a4df898
--- /dev/null
@@ -0,0 +1,954 @@
+/*
+ * sound/soc/amlogic/auge/tdm.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "ddr_mngr.h"
+#include "tdm_hw.h"
+
+#define DRV_NAME "aml_tdm"
+
+#define TDM_A  0
+#define TDM_B  1
+#define TDM_C  2
+#define LANE_MAX 4
+
+static void dump_pcm_setting(struct pcm_setting *setting)
+{
+       if (setting == NULL)
+               return;
+
+       pr_info("dump_pcm_setting(%p)\n", setting);
+       pr_info("\tpcm_mode(%d)\n", setting->pcm_mode);
+       pr_info("\tsysclk(%d)\n", setting->sysclk);
+       pr_info("\tsysclk_bclk_ratio(%d)\n", setting->sysclk_bclk_ratio);
+       pr_info("\tbclk(%d)\n", setting->bclk);
+       pr_info("\tbclk_lrclk_ratio(%d)\n", setting->bclk_lrclk_ratio);
+       pr_info("\tlrclk(%d)\n", setting->lrclk);
+       pr_info("\ttx_mask(%#x)\n", setting->tx_mask);
+       pr_info("\trx_mask(%#x)\n", setting->rx_mask);
+       pr_info("\tslots(%d)\n", setting->slots);
+       pr_info("\tslot_width(%d)\n", setting->slot_width);
+       pr_info("\tlane_mask_in(%#x)\n", setting->lane_mask_in);
+       pr_info("\tlane_mask_out(%#x)\n", setting->lane_mask_out);
+}
+
+struct aml_tdm {
+       struct pcm_setting setting;
+       struct pinctrl *pin_ctl;
+       struct aml_audio_controller *actrl;
+       struct device *dev;
+       struct clk *clk;
+       struct clk *clk_gate;
+       struct clk *mclk;
+       unsigned int id;
+       /* bclk src selection */
+       unsigned int clk_sel;
+       int irq_tdmout;
+       int irq_tdmin;
+       unsigned int from_ddr_num;
+       unsigned int to_ddr_num;
+       struct toddr *tddr;
+       struct frddr *fddr;
+};
+
+static const struct snd_pcm_hardware aml_tdm_hardware = {
+       .info =
+       SNDRV_PCM_INFO_MMAP |
+       SNDRV_PCM_INFO_MMAP_VALID |
+       SNDRV_PCM_INFO_INTERLEAVED |
+           SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE,
+       .formats =
+           SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+           SNDRV_PCM_FMTBIT_S32_LE,
+
+       .period_bytes_min = 64,
+       .period_bytes_max = 128 * 1024,
+       .periods_min = 2,
+       .periods_max = 1024,
+       .buffer_bytes_max = 256 * 1024,
+
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 32,
+};
+
+static irqreturn_t aml_tdmout_isr(int irq, void *devid)
+{
+       struct snd_pcm_substream *substream = (struct snd_pcm_substream *)devid;
+
+       snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t aml_tdmin_isr(int irq, void *devid)
+{
+       struct snd_pcm_substream *substream = (struct snd_pcm_substream *)devid;
+
+       snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+/* get counts of '1's in val */
+static unsigned int pop_count(unsigned int val)
+{
+       unsigned int count = 0;
+
+       while (val) {
+               count++;
+               val = val & (val - 1);
+       }
+
+       return count;
+}
+
+static int snd_soc_of_get_slot_mask(struct device_node *np,
+                                   const char *prop_name,
+                                   unsigned int *mask)
+{
+       u32 val;
+       const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
+       int i;
+
+       if (!of_slot_mask)
+               return 0;
+
+       val /= sizeof(u32);
+       for (i = 0; i < val; i++)
+               if (be32_to_cpup(&of_slot_mask[i]))
+                       *mask |= (1 << i);
+
+       return val;
+}
+
+static int of_parse_tdm_lane_slot_in(struct device_node *np,
+                             unsigned int *lane_mask)
+{
+       if (lane_mask)
+               return snd_soc_of_get_slot_mask(np,
+                       "dai-tdm-lane-slot-mask-in", lane_mask);
+
+       return -EINVAL;
+}
+
+static int of_parse_tdm_lane_slot_out(struct device_node *np,
+                             unsigned int *lane_mask)
+{
+       if (lane_mask)
+               return snd_soc_of_get_slot_mask(np,
+                       "dai-tdm-lane-slot-mask-out", lane_mask);
+
+       return -EINVAL;
+}
+
+static int aml_tdm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct aml_tdm *p_tdm;
+       int ret = 0;
+
+       p_tdm = (struct aml_tdm *)dev_get_drvdata(dev);
+
+       snd_soc_set_runtime_hwparams(substream, &aml_tdm_hardware);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               p_tdm->fddr = aml_audio_register_frddr(dev,
+                       p_tdm->actrl, p_tdm->from_ddr_num);
+               if (p_tdm->fddr == NULL) {
+                       dev_err(dev, "failed to claim from ddr %u\n",
+                                       p_tdm->from_ddr_num);
+                       return -ENXIO;
+               }
+
+               ret = request_irq(p_tdm->irq_tdmout,
+                       aml_tdmout_isr, 0, "tdmout", substream);
+               if (ret) {
+                       aml_audio_unregister_frddr(dev,
+                               p_tdm->from_ddr_num);
+                       dev_err(p_tdm->dev, "failed to claim irq %u\n",
+                                       p_tdm->irq_tdmout);
+                       return ret;
+               }
+       } else {
+               p_tdm->tddr = aml_audio_register_toddr(dev,
+                       p_tdm->actrl, p_tdm->to_ddr_num);
+               if (p_tdm->tddr == NULL) {
+                       dev_err(dev, "failed to claim to ddr %u\n",
+                                       p_tdm->to_ddr_num);
+                       return -ENXIO;
+               }
+
+               ret = request_irq(p_tdm->irq_tdmin,
+                               aml_tdmin_isr, 0, "tdmin", substream);
+               if (ret) {
+                       aml_audio_unregister_toddr(dev, p_tdm->to_ddr_num);
+                       dev_err(p_tdm->dev, "failed to claim irq %u\n",
+                                               p_tdm->irq_tdmin);
+                       return ret;
+               }
+       }
+
+       runtime->private_data = p_tdm;
+       return 0;
+}
+
+static int aml_tdm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_tdm *p_tdm = runtime->private_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               aml_audio_unregister_frddr(p_tdm->dev,
+                               p_tdm->from_ddr_num);
+               free_irq(p_tdm->irq_tdmout, substream);
+       } else {
+               aml_audio_unregister_toddr(p_tdm->dev,
+                               p_tdm->to_ddr_num);
+
+               free_irq(p_tdm->irq_tdmin, substream);
+       }
+
+       return 0;
+}
+
+static int aml_tdm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int aml_tdm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int aml_tdm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_tdm *p_tdm = runtime->private_data;
+       unsigned int start_addr, end_addr, int_addr;
+
+       start_addr = runtime->dma_addr;
+       end_addr = start_addr + runtime->dma_bytes - 8;
+       int_addr = frames_to_bytes(runtime, runtime->period_size)/8;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               struct frddr *fr = p_tdm->fddr;
+
+               aml_frddr_set_buf(fr, start_addr, end_addr);
+               aml_frddr_set_intrpt(fr, int_addr);
+       } else {
+               struct toddr *to = p_tdm->tddr;
+
+               aml_toddr_set_buf(to, start_addr, end_addr);
+               aml_toddr_set_intrpt(to, int_addr);
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t aml_tdm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_tdm *p_tdm = runtime->private_data;
+       unsigned int addr, start_addr;
+
+       start_addr = runtime->dma_addr;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               addr = aml_frddr_get_position(p_tdm->fddr);
+       else
+               addr = aml_toddr_get_position(p_tdm->tddr);
+
+       return bytes_to_frames(runtime, addr - start_addr);
+}
+
+static int aml_tdm_mmap(struct snd_pcm_substream *substream,
+                       struct vm_area_struct *vma)
+{
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops aml_tdm_ops = {
+       .open = aml_tdm_open,
+       .close = aml_tdm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = aml_tdm_hw_params,
+       .hw_free = aml_tdm_hw_free,
+       .prepare = aml_tdm_prepare,
+       .pointer = aml_tdm_pointer,
+       .mmap = aml_tdm_mmap,
+};
+
+#define PREALLOC_BUFFER                (32 * 1024)
+#define PREALLOC_BUFFER_MAX    (256 * 1024)
+static int aml_tdm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(
+               rtd->pcm, SNDRV_DMA_TYPE_DEV,
+               rtd->card->snd_card->dev, PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+}
+
+struct snd_soc_platform_driver aml_tdm_platform = {
+       .ops = &aml_tdm_ops,
+       .pcm_new = aml_tdm_new,
+};
+
+static int aml_dai_tdm_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *cpu_dai)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       aml_tdm_fifo_reset(p_tdm->actrl, substream->stream, p_tdm->id);
+
+       return 0;
+}
+
+static void aml_dai_tdm_shutdown(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+}
+
+static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *cpu_dai)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+       int bit_depth;
+
+       bit_depth = snd_pcm_format_width(runtime->format);
+
+       aml_tdm_fifo_ctrl(p_tdm->actrl,
+               bit_depth,
+               substream->stream,
+               p_tdm->id);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               struct frddr *fr = p_tdm->fddr;
+               enum frddr_dest dst;
+
+               switch (p_tdm->id) {
+               case 0:
+                       dst = TDMOUT_A;
+                       break;
+               case 1:
+                       dst = TDMOUT_B;
+                       break;
+               case 2:
+                       dst = TDMOUT_C;
+                       break;
+               default:
+                       dev_err(p_tdm->dev,     "invalid id: %d\n",
+                                       p_tdm->id);
+                       return -EINVAL;
+               }
+               aml_frddr_select_dst(fr, dst);
+               aml_frddr_set_fifos(fr, 0x40, 0x20);
+       } else {
+               struct toddr *to = p_tdm->tddr;
+               enum toddr_src src;
+               unsigned int lsb = 32 - bit_depth;
+               unsigned int toddr_type;
+
+               switch (bit_depth) {
+               case 8:
+                       toddr_type = 0;
+                       break;
+               case 16:
+                       toddr_type = 2;
+                       break;
+               case 24:
+               case 32:
+                       toddr_type = 4;
+                       break;
+               default:
+                       dev_err(p_tdm->dev, "invalid bit_depth: %d\n",
+                                       bit_depth);
+                       return -EINVAL;
+               }
+
+               dev_info(substream->pcm->card->dev, "tdm prepare----capture\n");
+               switch (p_tdm->id) {
+               case 0:
+                       src = TDMIN_A;
+               break;
+               case 1:
+                       src = TDMIN_B;
+               break;
+               case 2:
+                       src = TDMIN_C;
+               break;
+               default:
+                       dev_err(p_tdm->dev, "invalid id: %d\n",
+                                       p_tdm->id);
+                       return -EINVAL;
+               }
+
+               aml_toddr_select_src(to, src);
+               aml_toddr_set_format(to, toddr_type, 31, lsb);
+               aml_toddr_set_fifos(to, 0x40);
+       }
+
+       return 0;
+}
+
+static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *cpu_dai)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               aml_tdm_enable(p_tdm->actrl,
+                       substream->stream, p_tdm->id, true);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dev_info(substream->pcm->card->dev, "tdm playback enable\n");
+                       aml_frddr_enable(p_tdm->fddr, 1);
+               } else {
+                       dev_info(substream->pcm->card->dev, "tdm capture enable\n");
+                       aml_toddr_enable(p_tdm->tddr, 1);
+               }
+
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               aml_tdm_enable(p_tdm->actrl,
+                       substream->stream, p_tdm->id, false);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       dev_info(substream->pcm->card->dev, "tdm playback enable\n");
+                       aml_frddr_enable(p_tdm->fddr, 0);
+               } else {
+                       dev_info(substream->pcm->card->dev, "tdm capture enable\n");
+                       aml_toddr_enable(p_tdm->tddr, 0);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pcm_setting_init(struct pcm_setting *setting, unsigned int rate,
+                       unsigned int channels)
+{
+
+       setting->lrclk = rate;
+       setting->bclk_lrclk_ratio = setting->slots * setting->slot_width;
+       setting->bclk = setting->lrclk * setting->bclk_lrclk_ratio;
+
+       /* calculate mclk */
+       setting->sysclk_bclk_ratio = 4;
+       setting->sysclk = 4 * setting->bclk;
+
+       return 0;
+}
+static int aml_tdm_set_lanes(struct aml_tdm *p_tdm,
+                               unsigned int channels, int stream)
+{
+       struct pcm_setting *setting = &p_tdm->setting;
+       unsigned int lanes, swap_val;
+       unsigned int i;
+
+       pr_info("asoc debug: %d-%d\n", channels, setting->slots);
+
+       swap_val = 0;
+       // assume mask channels one lane
+       lanes = (channels - 1) / setting->slots + 1;
+
+       pr_info("asoc debug: lanes_ddr = %d\n", lanes);
+
+       // set channels swap
+       for (i = 0; i < channels; i++)
+               swap_val |= i << (i * 4);
+       aml_tdm_set_lane_channel_swap(p_tdm->actrl,
+               stream, p_tdm->id, swap_val);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               aml_tdm_set_channel_mask(p_tdm->actrl,
+                       stream, p_tdm->id, lanes, setting->tx_mask);
+
+               if (pop_count(setting->tx_mask) > 2)
+                       swap_val = 1 << 4;
+
+               aml_tdm_set_lane_channel_swap(p_tdm->actrl,
+                       stream, p_tdm->id, swap_val);
+       } else {
+               aml_tdm_set_channel_mask(p_tdm->actrl,
+                       stream, p_tdm->id, lanes, setting->rx_mask);
+
+               aml_tdm_set_lane_channel_swap(p_tdm->actrl,
+                       stream, p_tdm->id, swap_val);
+       }
+
+       return 0;
+}
+
+static int aml_dai_tdm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *cpu_dai)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+       struct pcm_setting *setting = &p_tdm->setting;
+       unsigned int rate = params_rate(params);
+       unsigned int channels = params_channels(params);
+       int ret;
+
+
+       ret = pcm_setting_init(setting, rate, channels);
+       if (ret)
+               return ret;
+
+       dump_pcm_setting(setting);
+
+       /* set pcm dai hw params */
+       // TODO: add clk_id
+       snd_soc_dai_set_sysclk(cpu_dai,
+               0, setting->sysclk, SND_SOC_CLOCK_OUT);
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, 0, setting->sysclk_bclk_ratio);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_bclk_ratio(cpu_dai, setting->bclk_lrclk_ratio);
+       if (ret)
+               return ret;
+
+       ret = aml_tdm_set_lanes(p_tdm, channels, substream->stream);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int aml_dai_tdm_hw_free(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *cpu_dai)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       aml_tdm_set_channel_mask(p_tdm->actrl,
+               substream->stream, p_tdm->id, 4, 0);
+
+       return 0;
+}
+
+static int aml_dai_set_tdm_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       pr_info("asoc aml_dai_set_tdm_fmt, %#x, %p, id(%d), clksel(%d)\n",
+               fmt, p_tdm, p_tdm->id, p_tdm->clk_sel);
+
+       aml_tdm_set_format(p_tdm->actrl,
+               &(p_tdm->setting), p_tdm->clk_sel, p_tdm->id, fmt);
+
+       return 0;
+}
+
+static void aml_tdm_set_mclk(struct aml_tdm *p_tdm)
+{
+       struct aml_audio_controller *actrl = p_tdm->actrl;
+       unsigned int clk_id, offset;
+       unsigned int mpll_freq = 0;
+
+       offset = p_tdm->clk_sel;
+
+       /* slave mode */
+       if (offset > MASTER_F)
+               return;
+
+       clk_id = p_tdm->id;
+
+       if (p_tdm->setting.sysclk) {
+               unsigned int mul = 4;
+
+               mpll_freq = p_tdm->setting.sysclk * mul;
+               clk_set_rate(p_tdm->clk, mpll_freq);
+               aml_audiobus_write(actrl, EE_AUDIO_MCLK_A_CTRL + offset,
+                                               1 << 31 | //clk enable
+                                               clk_id << 24 | // clk src
+                                               (mul - 1)); //clk_div mclk
+
+               if (offset == 2) {
+                       //enable another mclka also;
+                       offset = 0;
+                       aml_audiobus_write(actrl, EE_AUDIO_MCLK_A_CTRL + offset,
+                                       1 << 31 | //clk enable
+                                       clk_id << 24 | // clk src
+                                       (mul - 1)); //clk_div mclk
+               }
+       }
+}
+
+static int aml_dai_set_tdm_sysclk(struct snd_soc_dai *cpu_dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       p_tdm->setting.sysclk = freq;
+       pr_info("aml_dai_set_tdm_sysclk, %d, %d, %d\n",
+                       clk_id, freq, dir);
+       aml_tdm_set_mclk(p_tdm);
+
+       return 0;
+}
+
+static int aml_dai_set_bclk_ratio(struct snd_soc_dai *cpu_dai,
+                                               unsigned int ratio)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned int bclk_ratio, lrclk_hi;
+
+       p_tdm->setting.bclk_lrclk_ratio = ratio;
+       bclk_ratio = ratio - 1;
+       lrclk_hi = 0;
+
+       if (p_tdm->setting.pcm_mode == SND_SOC_DAIFMT_I2S ||
+               p_tdm->setting.pcm_mode == SND_SOC_DAIFMT_LEFT_J) {
+               pr_info("aml_dai_set_bclk_ratio, select I2S mode\n");
+               lrclk_hi = bclk_ratio / 2;
+       } else {
+               pr_info("aml_dai_set_bclk_ratio, select TDM mode\n");
+       }
+       aml_tdm_set_bclk_ratio(p_tdm->actrl,
+               p_tdm->clk_sel, lrclk_hi, bclk_ratio);
+
+       return 0;
+}
+
+static int aml_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                                               int div_id, int div)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned int mclk_ratio;
+
+       pr_info("aml_dai_set_clkdiv, div %d, clksel(%d)\n",
+                       div, p_tdm->clk_sel);
+
+       p_tdm->setting.sysclk_bclk_ratio = div;
+       mclk_ratio = div - 1;
+       aml_tdm_set_lrclkdiv(p_tdm->actrl, p_tdm->clk_sel, mclk_ratio);
+
+       return 0;
+}
+
+static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai,
+                               unsigned int tx_mask, unsigned int rx_mask,
+                               int slots, int slot_width)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       pr_info("aml_dai_set_tdm_slot, %x, %x, %d, %d\n",
+                       tx_mask, rx_mask, slots, slot_width);
+       p_tdm->setting.tx_mask = tx_mask;
+       p_tdm->setting.rx_mask = rx_mask;
+       p_tdm->setting.slots = slots;
+       p_tdm->setting.slot_width = slot_width;
+
+       aml_tdm_set_slot(p_tdm->actrl, slots, slot_width, p_tdm->id);
+
+       return 0;
+}
+
+static int aml_dai_tdm_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+       struct device *dev = p_tdm->dev;
+       int ret;
+
+       /* config ddr arb */
+       aml_tdm_arb_config(p_tdm->actrl);
+
+       ret = clk_prepare_enable(p_tdm->clk);
+       if (ret) {
+               dev_err(dev, "Can't enable mpll clock: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int aml_dai_tdm_remove(struct snd_soc_dai *cpu_dai)
+{
+       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       clk_disable_unprepare(p_tdm->clk);
+       return 0;
+}
+
+static struct snd_soc_dai_ops aml_dai_tdm_ops = {
+       .startup = aml_dai_tdm_startup,
+       .shutdown = aml_dai_tdm_shutdown,
+       .prepare = aml_dai_tdm_prepare,
+       .trigger = aml_dai_tdm_trigger,
+       .hw_params = aml_dai_tdm_hw_params,
+       .hw_free = aml_dai_tdm_hw_free,
+       .set_fmt = aml_dai_set_tdm_fmt,
+       .set_sysclk = aml_dai_set_tdm_sysclk,
+       .set_bclk_ratio = aml_dai_set_bclk_ratio,
+       .set_clkdiv = aml_dai_set_clkdiv,
+       .set_tdm_slot = aml_dai_set_tdm_slot,
+};
+
+#define AML_DAI_TDM_RATES              (SNDRV_PCM_RATE_8000_192000)
+#define AML_DAI_TDM_FORMATS            (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver aml_tdm_dai[] = {
+       {
+       .name = "TDM-A",
+       .id = 1,
+       .probe = aml_dai_tdm_probe,
+       .remove = aml_dai_tdm_remove,
+       .playback = {
+             .channels_min = 1,
+             .channels_max = 32,
+             .rates = AML_DAI_TDM_RATES,
+             .formats = AML_DAI_TDM_FORMATS,
+       },
+       .capture = {
+            .channels_min = 1,
+            .channels_max = 32,
+            .rates = AML_DAI_TDM_RATES,
+            .formats = AML_DAI_TDM_FORMATS,
+       },
+       .ops = &aml_dai_tdm_ops,
+       .symmetric_rates = 1,
+       },
+       {
+       .name = "TDM-B",
+       .id = 2,
+       .probe = aml_dai_tdm_probe,
+       .remove = aml_dai_tdm_remove,
+       .playback = {
+             .channels_min = 1,
+             .channels_max = 8,
+             .rates = AML_DAI_TDM_RATES,
+             .formats = AML_DAI_TDM_FORMATS,
+       },
+       .capture = {
+            .channels_min = 1,
+            .channels_max = 8,
+            .rates = AML_DAI_TDM_RATES,
+            .formats = AML_DAI_TDM_FORMATS,
+       },
+       .ops = &aml_dai_tdm_ops,
+       .symmetric_rates = 1,
+       },
+       {
+       .name = "TDM-C",
+       .id = 3,
+       .probe = aml_dai_tdm_probe,
+       .remove = aml_dai_tdm_remove,
+       .playback = {
+             .channels_min = 1,
+             .channels_max = 8,
+             .rates = AML_DAI_TDM_RATES,
+             .formats = AML_DAI_TDM_FORMATS,
+       },
+       .capture = {
+            .channels_min = 1,
+            .channels_max = 8,
+            .rates = AML_DAI_TDM_RATES,
+            .formats = AML_DAI_TDM_FORMATS,
+       },
+       .ops = &aml_dai_tdm_ops,
+       .symmetric_rates = 1,
+       },
+};
+
+static const struct snd_soc_component_driver aml_tdm_component = {
+       .name           = DRV_NAME,
+};
+
+static const struct of_device_id aml_tdm_device_id[] = {
+       { .compatible = "amlogic, snd-tdma", .data = (void *)TDM_A},
+       { .compatible = "amlogic, snd-tdmb", .data = (void *)TDM_B},
+       { .compatible = "amlogic, snd-tdmc", .data = (void *)TDM_C},
+       {},
+};
+MODULE_DEVICE_TABLE(of, aml_tdm_device_id);
+
+static int aml_tdm_platform_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *node_prt = NULL;
+       struct platform_device *pdev_parent;
+       struct device *dev = &pdev->dev;
+       struct aml_audio_controller *actrl = NULL;
+       struct aml_tdm *p_tdm = NULL;
+       const struct of_device_id *id;
+       unsigned long iddata = 0;
+       int ret = 0;
+
+       p_tdm = devm_kzalloc(dev, sizeof(struct aml_tdm), GFP_KERNEL);
+       if (!p_tdm)
+               return -ENOMEM;
+
+
+       /* get tdm device id */
+       id = of_match_device(of_match_ptr(aml_tdm_device_id), dev);
+       pr_info("id = %lu\n", (unsigned long)id->data);
+       iddata = (unsigned long)id->data;
+       p_tdm->id = (unsigned int)iddata;
+
+       /* get audio controller */
+       node_prt = of_get_parent(node);
+       if (node_prt == NULL)
+               return -ENXIO;
+
+       pdev_parent = of_find_device_by_node(node_prt);
+       of_node_put(node_prt);
+       actrl = (struct aml_audio_controller *)
+                               platform_get_drvdata(pdev_parent);
+       p_tdm->actrl = actrl;
+
+       /* get tdm mclk sel configs */
+       ret = of_property_read_u32(node, "dai-tdm-clk-sel",
+                       &p_tdm->clk_sel);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't retrieve dai-tdm-clk-sel\n");
+               return -ENXIO;
+       }
+
+       /* get tdm lanes info. if not, set to default 1 */
+       ret = of_parse_tdm_lane_slot_in(node,
+                       &p_tdm->setting.lane_mask_in);
+       if (ret < 0)
+               p_tdm->setting.lane_mask_in = 0x1;
+
+       ret = of_parse_tdm_lane_slot_out(node,
+                       &p_tdm->setting.lane_mask_out);
+       if (ret < 0)
+               p_tdm->setting.lane_mask_out = 0x1;
+
+       /* get sysclk source */
+       if (iddata == TDM_A) {
+               p_tdm->clk = devm_clk_get(&pdev->dev, "mpll0");
+               if (IS_ERR(p_tdm->clk)) {
+                       dev_err(&pdev->dev, "Can't retrieve mpll0 clock\n");
+                       return PTR_ERR(p_tdm->clk);
+               }
+#if 0
+               p_tdm->clk_gate = devm_clk_get(&pdev->dev, "gate");
+               if (IS_ERR(p_tdm->clk_gate)) {
+                       dev_err(&pdev->dev, "Can't retrieve clockgate\n");
+                       return PTR_ERR(p_tdm->clk_gate);
+               }
+
+               p_tdm->mclk = devm_clk_get(&pdev->dev, "mclk");
+               if (IS_ERR(p_tdm->mclk)) {
+                       dev_err(&pdev->dev, "Can't retrieve mclk\n");
+                       return PTR_ERR(p_tdm->mclk);
+               }
+#endif
+       } else if (iddata == TDM_B) {
+               p_tdm->clk = devm_clk_get(&pdev->dev, "mpll1");
+               if (IS_ERR(p_tdm->clk)) {
+                       dev_err(&pdev->dev, "Can't retrieve mpll1 clock\n");
+                       return PTR_ERR(p_tdm->clk);
+               }
+       } else if (iddata == TDM_C) {
+               p_tdm->clk = devm_clk_get(&pdev->dev, "mpll2");
+               if (IS_ERR(p_tdm->clk)) {
+                       dev_err(&pdev->dev, "Can't retrieve mpll2 clock\n");
+                       return PTR_ERR(p_tdm->clk);
+               }
+       } else {
+               return -EINVAL;
+       }
+
+       /* parse DTS configured ddr */
+       ret = of_property_read_u32(node, "tdm_from_ddr",
+                       &p_tdm->from_ddr_num);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't retrieve tdm_from_ddr\n");
+               return -ENXIO;
+       }
+
+       ret = of_property_read_u32(node, "tdm_to_ddr",
+                       &p_tdm->to_ddr_num);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't retrieve tdm_to_ddr\n");
+               return -ENXIO;
+       }
+
+       /* irqs */
+       p_tdm->irq_tdmout = platform_get_irq_byname(pdev, "tdmout");
+       if (p_tdm->irq_tdmout < 0)
+               dev_err(dev, "platform_get_irq_byname failed\n");
+
+       p_tdm->irq_tdmin = platform_get_irq_byname(pdev, "tdmin");
+       if (p_tdm->irq_tdmin < 0)
+               dev_err(dev, "platform_get_irq_byname failed\n");
+
+       p_tdm->pin_ctl = devm_pinctrl_get_select(dev, "tdm_pins");
+       if (IS_ERR(p_tdm->pin_ctl)) {
+               dev_info(dev, "aml_tdm_get_pins error!\n");
+               /*return PTR_ERR(p_tdm->pin_ctl);*/
+       }
+
+       p_tdm->dev = dev;
+       dev_set_drvdata(dev, p_tdm);
+
+       ret = devm_snd_soc_register_component(dev, &aml_tdm_component,
+                                        &aml_tdm_dai[iddata], 1);
+       if (ret) {
+               dev_err(dev, "devm_snd_soc_register_component failed\n");
+               return ret;
+       }
+
+       pr_info("%s, try register soc platform\n", __func__);
+
+       return devm_snd_soc_register_platform(dev, &aml_tdm_platform);
+}
+
+struct platform_driver aml_tdm_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = aml_tdm_device_id,
+       },
+       .probe = aml_tdm_platform_probe,
+};
+module_platform_driver(aml_tdm_driver);
+
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("Amlogic TDM ASoc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, aml_tdm_device_id);
diff --git a/sound/soc/amlogic/auge/tdm_hw.c b/sound/soc/amlogic/auge/tdm_hw.c
new file mode 100644 (file)
index 0000000..1372dff
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * sound/soc/amlogic/auge/tdm_hw.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <sound/soc.h>
+
+#include "tdm_hw.h"
+
+void aml_tdm_enable(
+       struct aml_audio_controller *actrl,
+       int stream, int index,
+       bool is_enable)
+{
+       unsigned int offset, reg;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               pr_info("tdm playback enable\n");
+
+               offset = EE_AUDIO_TDMOUT_B_CTRL0
+                               - EE_AUDIO_TDMOUT_A_CTRL0;
+               reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
+               aml_audiobus_update_bits(actrl, reg, 1<<31, is_enable<<31);
+       } else {
+               pr_info("tdm capture enable\n");
+
+               offset = EE_AUDIO_TDMIN_B_CTRL
+                               - EE_AUDIO_TDMIN_A_CTRL;
+               reg = EE_AUDIO_TDMIN_A_CTRL + offset * index;
+               aml_audiobus_update_bits(actrl, reg, 1<<31, is_enable<<31);
+       }
+
+}
+
+void aml_tdm_arb_config(struct aml_audio_controller *actrl)
+{
+       /* config ddr arb */
+       aml_audiobus_write(actrl, EE_AUDIO_ARB_CTRL, 1<<31|0xff<<0);
+}
+
+void aml_tdm_fifo_reset(
+       struct aml_audio_controller *actrl,
+       int stream, int index)
+{
+       unsigned int reg, offset;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               offset = EE_AUDIO_TDMOUT_B_CTRL0
+                               - EE_AUDIO_TDMOUT_A_CTRL0;
+               reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
+               /* reset afifo */
+               aml_audiobus_update_bits(actrl, reg, 3<<28, 0);
+               aml_audiobus_update_bits(actrl, reg, 1<<29, 1<<29);
+               aml_audiobus_update_bits(actrl, reg, 1<<28, 1<<28);
+       } else {
+               offset = EE_AUDIO_TDMIN_B_CTRL
+                               - EE_AUDIO_TDMIN_A_CTRL;
+               reg = EE_AUDIO_TDMIN_A_CTRL + offset * index;
+               /* reset afifo */
+               aml_audiobus_update_bits(actrl, reg, 3<<28, 0);
+               aml_audiobus_update_bits(actrl, reg, 1<<29, 1<<29);
+               aml_audiobus_update_bits(actrl, reg, 1<<28, 1<<28);
+       }
+
+}
+
+void aml_tdm_fifo_ctrl(
+       struct aml_audio_controller *actrl,
+       int bitwidth, int stream,
+       int index)
+{
+       unsigned int frddr_type, toddr_type;
+       unsigned int reg, offset;
+
+       switch (bitwidth) {
+       case 8:
+               frddr_type = 0;
+               toddr_type = 0;
+               break;
+       case 16:
+               frddr_type = 2;
+               toddr_type = 2;
+               break;
+       case 24:
+       case 32:
+               frddr_type = 4;
+               toddr_type = 4;
+               break;
+       default:
+               pr_err("invalid bit_depth: %d\n",
+                       bitwidth);
+               return;
+       }
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               pr_info("tdm prepare----playback\n");
+               // from ddr, 63bit split into 2 samples
+               offset = EE_AUDIO_TDMOUT_B_CTRL1
+                               - EE_AUDIO_TDMOUT_A_CTRL1;
+               reg = EE_AUDIO_TDMOUT_A_CTRL1 + offset * index;
+               aml_audiobus_update_bits(actrl, reg,
+                               0x3<<24|0x1f<<8|0x7<<4,
+                               index<<24|(bitwidth-1)<<8|frddr_type<<4);
+       } else {
+               pr_info("tdm prepare----capture\n");
+       }
+
+}
+
+void aml_tdm_set_format(
+       struct aml_audio_controller *actrl,
+       struct pcm_setting *p_config,
+       unsigned int clk_sel,
+       unsigned int index,
+       unsigned int fmt)
+{
+       unsigned int binv, finv, id;
+       unsigned int valb, valf;
+       unsigned int reg_in, reg_out, off_set;
+       int bclkin_skew, bclkout_skew;
+       int master_mode;
+
+       id = index;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               valb = SLAVE_A + id;
+               valf = SLAVE_A;
+               master_mode = 0;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               valb = MASTER_A + clk_sel;
+               valf = MASTER_A + clk_sel;
+               master_mode = 1;
+               break;
+       default:
+               return;
+       }
+
+       //TODO: clk tree
+       reg_out = EE_AUDIO_CLK_TDMOUT_A_CTRL + id;
+       reg_in = EE_AUDIO_CLK_TDMIN_A_CTRL + id;
+       aml_audiobus_update_bits(actrl,
+               reg_out,
+               0xff<<20,
+               valb<<24|valf<<20);
+       aml_audiobus_update_bits(actrl,
+               reg_in,
+               0xff<<20,
+               valb<<24|valf<<20);
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               if (master_mode) {
+                       bclkout_skew = 1;
+                       bclkin_skew = 5;
+               } else {
+                       bclkout_skew = 2;
+                       bclkin_skew = 3;
+               }
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               if (master_mode) {
+                       bclkout_skew = 1;
+                       bclkin_skew = 4;
+               } else {
+                       bclkout_skew = 2;
+                       bclkin_skew = 3;
+               }
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_DSP_B:
+               //TODO: need test
+               bclkout_skew = 2;
+               bclkin_skew = 2;
+               break;
+       default:
+               return;
+       }
+
+       p_config->pcm_mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+       /* set lrclk/bclk invertion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_IF:
+               /* Invert both clocks */
+               binv = 1;
+               finv = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               /* Invert bit clock */
+               binv = 1;
+               finv = 0;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               /* Invert frame clock */
+               binv = 0;
+               finv = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+               /* normal cases */
+               binv = 0;
+               finv = 0;
+               break;
+       default:
+               return;
+       }
+
+       pr_info("master_mode(%d), binv(%d), finv(%d) out_skew(%d), in_skew(%d)\n",
+                       master_mode, binv, finv, bclkout_skew, bclkin_skew);
+
+       /* TDM out */
+       reg_out = EE_AUDIO_CLK_TDMOUT_A_CTRL + id;
+       aml_audiobus_update_bits(actrl, reg_out,
+               0x3<<30|0x1<<29, 0x3<<30/*|binv<<29*/);
+       // sclk_ph0 (pad) invert
+       off_set = EE_AUDIO_MST_B_SCLK_CTRL1 - EE_AUDIO_MST_A_SCLK_CTRL1;
+       reg_out = EE_AUDIO_MST_A_SCLK_CTRL1 + off_set * id;
+       aml_audiobus_update_bits(actrl, reg_out, 0x3f, binv);
+
+       off_set = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
+       reg_out = EE_AUDIO_TDMOUT_A_CTRL0 + off_set * id;
+       aml_audiobus_update_bits(actrl, reg_out, 0x1f<<15, bclkout_skew<<15);
+
+       off_set = EE_AUDIO_TDMOUT_B_CTRL1 - EE_AUDIO_TDMOUT_A_CTRL1;
+       reg_out = EE_AUDIO_TDMOUT_A_CTRL1 + off_set * id;
+       aml_audiobus_update_bits(actrl, reg_out, 0x1<<28, finv<<28);
+
+       /* TDM in */
+       reg_in = EE_AUDIO_CLK_TDMIN_A_CTRL + id;
+       aml_audiobus_update_bits(actrl, reg_in,
+                               0x3<<30|0x1<<29, 0x3<<30|binv<<29);
+
+       off_set = EE_AUDIO_TDMIN_B_CTRL - EE_AUDIO_TDMIN_A_CTRL;
+       reg_in = EE_AUDIO_TDMIN_A_CTRL + off_set * id;
+       if (p_config->pcm_mode == SND_SOC_DAIFMT_I2S)
+               aml_audiobus_update_bits(actrl, reg_in,
+                       1<<30|3<<26|0x1<<25|0x7<<16,
+                       1<<30|3<<26|1<<25|bclkin_skew<<16);
+       else
+               aml_audiobus_update_bits(actrl, reg_in,
+                       3<<26|0x7<<16, 3<<26|bclkin_skew<<16);
+
+}
+
+void aml_tdm_set_slot(
+       struct aml_audio_controller *actrl,
+       int slots, int slot_width, int index)
+{
+       unsigned int reg, offset;
+
+       offset = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
+       reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
+       aml_audiobus_update_bits(actrl, reg,
+                               0x3ff, ((slots - 1) << 5) | (slot_width - 1));
+
+       offset = EE_AUDIO_TDMIN_B_CTRL - EE_AUDIO_TDMIN_A_CTRL;
+       reg = EE_AUDIO_TDMIN_A_CTRL + offset * index;
+       aml_audiobus_update_bits(actrl, reg,
+               0xf<<20|0x7<<16|0x1f, index<<20|(slot_width-1));
+}
+
+void aml_tdm_set_channel_mask(
+       struct aml_audio_controller *actrl,
+       int stream, int index, int lanes, int mask)
+{
+       unsigned int offset, reg;
+       int i;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               offset = EE_AUDIO_TDMOUT_B_MASK0 - EE_AUDIO_TDMOUT_A_MASK0;
+               reg = EE_AUDIO_TDMOUT_A_MASK0 + offset * index;
+       } else {
+               offset = EE_AUDIO_TDMIN_B_MASK0 - EE_AUDIO_TDMIN_A_MASK0;
+               reg = EE_AUDIO_TDMIN_A_MASK0 + offset * index;
+       }
+
+       /* mask 0~3 */
+       for (i = 0; i < lanes; i++)
+               aml_audiobus_write(actrl, reg + i, mask);
+
+}
+
+void aml_tdm_set_lane_channel_swap(
+       struct aml_audio_controller *actrl,
+       int stream, int index, int swap)
+{
+       unsigned int offset, reg;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               // set lanes mask acordingly
+               offset = EE_AUDIO_TDMOUT_B_MASK0 - EE_AUDIO_TDMOUT_A_MASK0;
+               reg = EE_AUDIO_TDMOUT_A_MASK0 + offset * index;
+
+               pr_info("\ttdmout swap val = %#x\n", swap);
+               offset = EE_AUDIO_TDMOUT_B_SWAP - EE_AUDIO_TDMOUT_A_SWAP;
+               reg = EE_AUDIO_TDMOUT_A_SWAP + offset * index;
+               aml_audiobus_write(actrl, reg, swap);
+       } else {
+               offset = EE_AUDIO_TDMIN_B_MASK0 - EE_AUDIO_TDMIN_A_MASK0;
+               reg = EE_AUDIO_TDMIN_A_MASK0 + offset * index;
+
+               pr_info("\ttdmin swap val = %#x\n", swap);
+               offset = EE_AUDIO_TDMIN_B_SWAP - EE_AUDIO_TDMIN_A_SWAP;
+               reg = EE_AUDIO_TDMIN_A_SWAP + offset * index;
+               aml_audiobus_write(actrl, reg, swap);
+       }
+}
+
+void aml_tdm_set_bclk_ratio(
+       struct aml_audio_controller *actrl,
+       int clk_sel, int lrclk_hi, int bclk_ratio)
+{
+       unsigned int reg, reg_step = 2;
+
+       reg = EE_AUDIO_MST_A_SCLK_CTRL0 + reg_step * clk_sel;
+
+       aml_audiobus_update_bits(actrl, reg,
+                               (3 << 30)|0x3ff<<10|0x3ff,
+                               (3 << 30)|lrclk_hi<<10|bclk_ratio);
+}
+
+void aml_tdm_set_lrclkdiv(
+       struct aml_audio_controller *actrl,
+       int clk_sel, int ratio)
+{
+       unsigned int reg, reg_step = 2;
+
+       pr_info("aml_dai_set_clkdiv, clksel(%d), ratio(%d)\n",
+                       clk_sel, ratio);
+
+       reg = EE_AUDIO_MST_A_SCLK_CTRL0 + reg_step * clk_sel;
+
+       aml_audiobus_update_bits(actrl, reg,
+               (3 << 30)|(0x3ff << 20),
+               (3 << 30)|(ratio << 20));
+}
diff --git a/sound/soc/amlogic/auge/tdm_hw.h b/sound/soc/amlogic/auge/tdm_hw.h
new file mode 100644 (file)
index 0000000..b093b6d
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * sound/soc/amlogic/auge/tdm_hw.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __AML_TDM_HW_H__
+#define __AML_TDM_HW_H__
+
+#include "audio_io.h"
+#include "regs.h"
+
+struct pcm_setting {
+       unsigned int pcm_mode;
+       unsigned int sysclk;
+       unsigned int sysclk_bclk_ratio;
+       unsigned int bclk;
+       unsigned int bclk_lrclk_ratio;
+       unsigned int lrclk;
+       unsigned int tx_mask;
+       unsigned int rx_mask;
+       unsigned int slots;
+       unsigned int slot_width;
+       unsigned int pcm_width;
+       unsigned int lane_mask_out;
+       unsigned int lane_mask_in;
+};
+
+extern void aml_tdm_enable(
+       struct aml_audio_controller *actrl,
+       int stream, int index,
+       bool is_enable);
+
+extern void aml_tdm_arb_config(
+       struct aml_audio_controller *actrl);
+
+extern void aml_tdm_fifo_reset(
+       struct aml_audio_controller *actrl,
+       int stream, int index);
+
+extern void aml_tdm_fifo_ctrl(
+       struct aml_audio_controller *actrl,
+       int bitwidth, int stream,
+       int index);
+
+extern void aml_tdm_set_format(
+       struct aml_audio_controller *actrl,
+       struct pcm_setting *p_config,
+       unsigned int clk_sel,
+       unsigned int index,
+       unsigned int fmt);
+
+extern void aml_tdm_set_slot(
+       struct aml_audio_controller *actrl,
+       int slots, int slot_width, int index);
+
+extern void aml_tdm_set_channel_mask(
+       struct aml_audio_controller *actrl,
+       int stream, int index, int lanes, int mask);
+
+extern void aml_tdm_set_lane_channel_swap(
+       struct aml_audio_controller *actrl,
+       int stream, int index, int swap);
+
+extern void aml_tdm_set_bclk_ratio(
+       struct aml_audio_controller *actrl,
+       int clk_sel, int lrclk_hi, int bclk_ratio);
+
+extern void aml_tdm_set_lrclkdiv(
+       struct aml_audio_controller *actrl,
+       int clk_sel, int ratio);
+
+#endif
diff --git a/sound/soc/amlogic/meson/Kconfig b/sound/soc/amlogic/meson/Kconfig
new file mode 100644 (file)
index 0000000..2a028e2
--- /dev/null
@@ -0,0 +1,30 @@
+menuconfig AMLOGIC_SND_SOC_MESON
+       bool "Amlogic Meson ASoC"
+       default n
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the Amlogic Asoc interface. You will also need
+         to select the audio interfaces to support below.
+
+if AMLOGIC_SND_SOC_MESON
+
+config AMLOGIC_SND_SPLIT_MODE
+       bool "AIU split/interleave mode"
+       depends on AMLOGIC_SND_SOC_MESON
+       default n
+       help
+         Say Y to enable AIU split mode. If not, it is normal mode.
+         Say Y to enable AIU split mode. If not, it is normal mode.
+         Say Y to enable AIU split mode. If not, it is normal mode.
+         Say Y to enable AIU split mode. If not, it is normal mode.
+
+config AMLOGIC_SND_SPLIT_MODE_MMAP
+       bool "AIU split mode, mmap"
+       depends on AMLOGIC_SND_SPLIT_MODE
+       depends on AMLOGIC_SND_SOC_MESON
+       default n
+       help
+               Say Y or N to enable/disable AIU split mmap
+
+endif # AMLOGIC_SND_SOC_MESON
+
diff --git a/sound/soc/amlogic/meson/Makefile b/sound/soc/amlogic/meson/Makefile
new file mode 100644 (file)
index 0000000..467ebef
--- /dev/null
@@ -0,0 +1,31 @@
+# AML Platform Support
+snd-soc-pcm-objs        := pcm.o
+snd-soc-i2s-objs        := i2s.o
+snd-soc-i2s-dai-objs    := i2s_dai.o
+snd-soc-pcm-dai-objs    := pcm_dai.o
+snd-soc-spdif-dai-objs  := spdif_dai.o
+snd-soc-hw-objs         := audio_hw.o
+snd-soc-hw-pcm2bt-objs  := audio_hw_pcm.o
+snd-soc-dmic-objs          := dmic.o
+
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-pcm.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-i2s.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-i2s-dai.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-pcm-dai.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-hw.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += notify.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-hw-pcm2bt.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-spdif-dai.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-dmic.o
+
+# AML spdif codec support
+snd-soc-spdif-codec-objs := spdif_codec.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-spdif-codec.o
+
+#AML M8 Machine support
+snd-soc-meson-objs := meson.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-meson.o
+
+#AML G9TV Machine support
+snd-soc-tv-objs := tv.o
+#obj-$(CONFIG_AMLOGIC_SND_SOC_MESON) += snd-soc-tv.o
similarity index 99%
rename from sound/soc/amlogic/aml_audio_hw.c
rename to sound/soc/amlogic/meson/audio_hw.c
index 17e289e..0309558 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_audio_hw.c
+ * sound/soc/amlogic/meson/audio_hw.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -28,7 +28,7 @@
 #include <linux/amlogic/media/sound/aiu_regs.h>
 #include <linux/amlogic/media/sound/audin_regs.h>
 #include <linux/amlogic/cpu_version.h>
-#include "aml_audio_hw.h"
+#include "audio_hw.h"
 
 /* i2s mode 0: master 1: slave */
 /* source: 0: linein; 1: ATV; 2: HDMI-in */
similarity index 99%
rename from sound/soc/amlogic/aml_audio_hw.h
rename to sound/soc/amlogic/meson/audio_hw.h
index c8ddea4..dc0397c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_audio_hw.h
+ * sound/soc/amlogic/meson/audio_hw.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_audio_hw_pcm.c
rename to sound/soc/amlogic/meson/audio_hw_pcm.c
index e3bba87..c7eae7d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_audio_hw_pcm.c
+ * sound/soc/amlogic/meson/audio_hw_pcm.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -26,7 +26,7 @@
 
 #include <linux/amlogic/iomap.h>
 #include <linux/amlogic/media/sound/audin_regs.h>
-#include "aml_audio_hw_pcm.h"
+#include "audio_hw_pcm.h"
 
 #include <linux/amlogic/media/sound/aiu_regs.h>
 
similarity index 95%
rename from sound/soc/amlogic/aml_audio_hw_pcm.h
rename to sound/soc/amlogic/meson/audio_hw_pcm.h
index 304eaf3..58a3a49 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_audio_hw_pcm.h
+ * sound/soc/amlogic/meson/audio_hw_pcm.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -21,7 +21,7 @@
 #include "sound/asound.h"
 #include <sound/pcm.h>
 
-#include "aml_audio_hw.h"
+#include "audio_hw.h"
 
 void aml_set_pcm_format(int pcm_mode);
 void pcm_in_enable(struct snd_pcm_substream *substream, int flag);
similarity index 99%
rename from sound/soc/amlogic/aml_dmic.c
rename to sound/soc/amlogic/meson/dmic.c
index dfb2f63..3a7b7dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_dmic.c
+ * sound/soc/amlogic/meson/dmic.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_i2s.c
rename to sound/soc/amlogic/meson/i2s.c
index a0cdf2b..a4f8e56 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_i2s.c
+ * sound/soc/amlogic/meson/i2s.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -39,9 +39,9 @@
 
 /* Amlogic headers */
 #include <linux/amlogic/iomap.h>
-#include "aml_i2s.h"
-#include "aml_spdif_dai.h"
-#include "aml_audio_hw.h"
+#include "i2s.h"
+#include "spdif_dai.h"
+#include "audio_hw.h"
 #include <linux/amlogic/media/sound/aiu_regs.h>
 #include <linux/amlogic/media/sound/audin_regs.h>
 
similarity index 98%
rename from sound/soc/amlogic/aml_i2s.h
rename to sound/soc/amlogic/meson/i2s.h
index 32e2ded..b032cb3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_i2s.h
+ * sound/soc/amlogic/meson/i2s.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 98%
rename from sound/soc/amlogic/aml_i2s_dai.c
rename to sound/soc/amlogic/meson/i2s_dai.c
index 97feeeb..306f72a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_i2s_dai.c
+ * sound/soc/amlogic/meson/i2s_dai.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
 #include <sound/control.h>
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
-#include "aml_i2s_dai.h"
-#include "aml_pcm.h"
-#include "aml_i2s.h"
-#include "aml_audio_hw.h"
+#include "i2s_dai.h"
+#include "pcm.h"
+#include "i2s.h"
+#include "audio_hw.h"
 #include <linux/amlogic/media/sound/aout_notify.h>
-#include "aml_spdif_dai.h"
+#include "spdif_dai.h"
 
 struct aml_dai_info dai_info[3] = { {0} };
 
similarity index 95%
rename from sound/soc/amlogic/aml_i2s_dai.h
rename to sound/soc/amlogic/meson/i2s_dai.h
index 0e2c94d..2c1d2e5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_i2s_dai.h
+ * sound/soc/amlogic/meson/i2s_dai.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_meson.c
rename to sound/soc/amlogic/meson/meson.c
index cf71284..11d46ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_meson.c
+ * sound/soc/amlogic/meson/meson.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -41,9 +41,9 @@
 /* #include <linux/amlogic/saradc.h> */
 #include <linux/amlogic/iomap.h>
 
-#include "aml_i2s.h"
-#include "aml_meson.h"
-#include "aml_audio_hw.h"
+#include "i2s.h"
+#include "meson.h"
+#include "audio_hw.h"
 #include <linux/amlogic/media/sound/audin_regs.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
similarity index 98%
rename from sound/soc/amlogic/aml_meson.h
rename to sound/soc/amlogic/meson/meson.h
index 11beaee..3d15328 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_meson.h
+ * sound/soc/amlogic/meson/meson.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 97%
rename from sound/soc/amlogic/aml_notify.c
rename to sound/soc/amlogic/meson/notify.c
index 4a87930..8dd9ab8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_notify.c
+ * sound/soc/amlogic/meson/notify.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_pcm.c
rename to sound/soc/amlogic/meson/pcm.c
index 1a546c4..7b61cbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_pcm.c
+ * sound/soc/amlogic/meson/pcm.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -38,8 +38,8 @@
 #include <sound/pcm_params.h>
 
 #include <linux/amlogic/media/sound/audin_regs.h>
-#include "aml_pcm.h"
-#include "aml_audio_hw_pcm.h"
+#include "pcm.h"
+#include "audio_hw_pcm.h"
 
 /*--------------------------------------------------------------------------
  * Hardware definition
similarity index 96%
rename from sound/soc/amlogic/aml_pcm.h
rename to sound/soc/amlogic/meson/pcm.h
index 8eb9dab..365dd26 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_pcm.h
+ * sound/soc/amlogic/meson/pcm.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 98%
rename from sound/soc/amlogic/aml_pcm_dai.c
rename to sound/soc/amlogic/meson/pcm_dai.c
index b58c8ce..8d07aa1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_pcm_dai.c
+ * sound/soc/amlogic/meson/pcm_dai.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include "aml_pcm_dai.h"
-#include "aml_pcm.h"
-#include "aml_i2s.h"
-#include "aml_audio_hw_pcm.h"
+#include "pcm_dai.h"
+#include "pcm.h"
+#include "i2s.h"
+#include "audio_hw_pcm.h"
 
 #include <linux/of.h>
 
similarity index 95%
rename from sound/soc/amlogic/aml_pcm_dai.h
rename to sound/soc/amlogic/meson/pcm_dai.h
index 4f6b047..e86655d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_pcm_dai.h
+ * sound/soc/amlogic/meson/pcm_dai.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_spdif_codec.c
rename to sound/soc/amlogic/meson/spdif_codec.c
index 15f06c2..8bb69c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_spdif_codec.c
+ * sound/soc/amlogic/meson/spdif_codec.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_spdif_dai.c
rename to sound/soc/amlogic/meson/spdif_dai.c
index 22b6a88..080eea3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_spdif_dai.c
+ * sound/soc/amlogic/meson/spdif_dai.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -41,9 +41,9 @@
 #include <sound/pcm_params.h>
 
 #include <linux/amlogic/iomap.h>
-#include "aml_audio_hw.h"
-#include "aml_spdif_dai.h"
-#include "aml_i2s.h"
+#include "audio_hw.h"
+#include "spdif_dai.h"
+#include "i2s.h"
 #include <linux/amlogic/media/sound/aout_notify.h>
 #include <linux/amlogic/media/sound/aiu_regs.h>
 #include <linux/amlogic/media/sound/audin_regs.h>
similarity index 98%
rename from sound/soc/amlogic/aml_spdif_dai.h
rename to sound/soc/amlogic/meson/spdif_dai.h
index 98b5b06..d6e7fda 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_spdif_dai.h
+ * sound/soc/amlogic/meson/spdif_dai.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
similarity index 99%
rename from sound/soc/amlogic/aml_tv.c
rename to sound/soc/amlogic/meson/tv.c
index d5ec348..6e72fc7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_tv.c
+ * sound/soc/amlogic/meson/tv.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
@@ -47,9 +47,9 @@
 #include <sound/tas57xx.h>
 #endif
 
-#include "aml_i2s.h"
-#include "aml_audio_hw.h"
-#include "aml_tv.h"
+#include "i2s.h"
+#include "audio_hw.h"
+#include "tv.h"
 
 #define DRV_NAME "aml_snd_card_tv"
 
similarity index 97%
rename from sound/soc/amlogic/aml_tv.h
rename to sound/soc/amlogic/meson/tv.h
index 260c766..2dad633 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/soc/amlogic/aml_tv.h
+ * sound/soc/amlogic/aml_meson/tv.h
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
index d94ce2f..7273c7f 100644 (file)
@@ -11,7 +11,7 @@ menuconfig AMLOGIC_SND_SOC_CODECS
 config AMLOGIC_SND_CODEC_DUMMY_CODEC
        bool "Amlogic Audio dummy codec"
        depends on AMLOGIC_SND_SOC_CODECS
-    default n
+       default n
        help
                Amlogic Audio codec,
                dummy codec,
@@ -21,17 +21,27 @@ config AMLOGIC_SND_CODEC_DUMMY_CODEC
 config AMLOGIC_SND_CODEC_PCM2BT
        bool "Amlogic Audio pcm2bt codec"
        depends on AMLOGIC_SND_SOC_CODECS
-    default n
+       default n
        help
                Amlogic Audio codec,
                pcm2bt codec,
                pcm2bt codec,
                this codec is internal
 
+config AMLOGIC_SND_CODEC_PDM_DUMMY_CODEC
+        bool "Amlogic Audio pdm dummy codec"
+        depends on AMLOGIC_SND_SOC_CODECS
+       default n
+        help
+                Amlogic Audio pdm codec,
+                pdm dummy codec,
+                pdm dummy codec,
+                this codec is internal
+
 config AMLOGIC_SND_CODEC_AMLT9015
        bool "Amlogic Audio AMLT9015 codec"
        depends on AMLOGIC_SND_SOC_CODECS
-    default n
+       default n
        help
                Amlogic Audio codec,
                AMLT9015 codec,
@@ -39,16 +49,16 @@ config AMLOGIC_SND_CODEC_AMLT9015
                this codec is internal
 
 config AMLOGIC_SND_CODEC_PMU3
-       bool "Amlogic Audio AML PMU3 codec"
-       depends on AMLOGIC_SND_SOC_CODECS
+        bool "Amlogic Audio AML PMU3 codec"
+        depends on AMLOGIC_SND_SOC_CODECS
        default n
-       help
-               Amlogic Audio codec,
-               AML PMU3 codec,
-               AML PMU3 codec,
-               this codec is internal
-
-# Amlogic add Third part codec
+        help
+                Amlogic Audio codec,
+                AML PMU3 codec,
+                AML PMU3 codec,
+                this codec is internal
+#Third part codecs
+# Amlogic add codecs
 config AMLOGIC_SND_SOC_TAS5707
        bool "Texas Instruments TAS5707 amplifier"
        depends on AMLOGIC_SND_SOC_CODECS
@@ -60,4 +70,13 @@ config AMLOGIC_SND_SOC_TAS5707
                 Enable support for Texas Instruments TAS5707 CODEC.
                 Select this if your TAS5707 is connected via an I2C bus.
 
+config AMLOGIC_SND_SOC_TLV320ADC3101
+       bool "Texas Instruments TLV320ADC3101"
+       depends on AMLOGIC_SND_SOC_CODECS
+       depends on I2C
+       default n
+       help
+               Enable Support for Texas INstruments TLV320ADC3101 CODEC.
+               Select this if your TLV320ADC3101 is connected via an I2C bus.
+
 #endif #AMLOGIC_SND_SOC_CODECS
index e27915d..d38d347 100644 (file)
@@ -1,17 +1,21 @@
 #Amlogic
 snd-soc-dummy_codec-objs := dummy_codec.o
+snd-soc-pdm-dummy-objs := pdm_dummy.o
 snd-soc-pcm2bt-objs  := pcm2bt.o
 snd-soc-aml_t9015-objs := aml_codec_t9015.o
 snd-soc-pmu3-objs := aml_pmu3.o
 
 #Third part codecs
 snd-soc-tas5707-objs := tas5707.o
+snd-soc-tlv320adc3101-objs := tlv320adc3101.o
 
 # Amlogic
-obj-$(CONFIG_AMLOGIC_SND_CODEC_DUMMY_CODEC)    += snd-soc-dummy_codec.o
-obj-$(CONFIG_AMLOGIC_SND_CODEC_PCM2BT) += snd-soc-pcm2bt.o
-obj-$(CONFIG_AMLOGIC_SND_CODEC_AMLT9015)       += snd-soc-aml_t9015.o
+obj-$(CONFIG_AMLOGIC_SND_CODEC_DUMMY_CODEC) += snd-soc-dummy_codec.o
+obj-$(CONFIG_AMLOGIC_SND_CODEC_PDM_DUMMY_CODEC) += snd-soc-pdm-dummy.o
+obj-$(CONFIG_AMLOGIC_SND_CODEC_PCM2BT) += snd-soc-pcm2bt.o
+obj-$(CONFIG_AMLOGIC_SND_CODEC_AMLT9015) += snd-soc-aml_t9015.o
 obj-$(CONFIG_AMLOGIC_SND_CODEC_PMU3) += snd-soc-pmu3.o
 
 #Third part codecs
-obj-$(CONFIG_AMLOGIC_SND_SOC_TAS5707) += snd-soc-tas5707.o
\ No newline at end of file
+obj-$(CONFIG_AMLOGIC_SND_SOC_TAS5707) += snd-soc-tas5707.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_TLV320ADC3101) += snd-soc-tlv320adc3101.o
\ No newline at end of file
diff --git a/sound/soc/codecs/amlogic/pdm_dummy.c b/sound/soc/codecs/amlogic/pdm_dummy.c
new file mode 100644 (file)
index 0000000..e47ac80
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * sound/soc/codecs/amlogic/pdm_dummy.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <sound/soc.h>
+
+#define DUMMY_RATES                    SNDRV_PCM_RATE_8000_48000
+#define DUMMY_FORMATS          (SNDRV_PCM_FMTBIT_S16_LE |\
+                                               SNDRV_PCM_FMTBIT_S24_LE |\
+                                               SNDRV_PCM_FMTBIT_S32_LE)
+
+static int pdm_dummy_set_fmt(
+       struct snd_soc_dai *codec_dai,
+       unsigned int fmt)
+{
+       return 0;
+}
+
+static int pdm_dummy_hw_params(
+       struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       return 0;
+}
+
+static int pdm_dummy_prepare(
+       struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       return 0;
+}
+
+
+static struct snd_soc_dai_ops pdm_dummy_ops = {
+       .set_fmt = pdm_dummy_set_fmt,
+       .hw_params = pdm_dummy_hw_params,
+       .prepare = pdm_dummy_prepare,
+};
+
+struct snd_soc_dai_driver pdm_dummy_dai = {
+       .name = "pdm",
+       .capture = {
+               .stream_name = "PDM Capture",
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = DUMMY_RATES,
+               .formats = DUMMY_FORMATS,
+       },
+       .ops = &pdm_dummy_ops,
+};
+
+static int pdm_dummy_probe(struct snd_soc_codec *codec)
+{
+       return 0;
+}
+
+static int pdm_dummy_remove(struct snd_soc_codec *codec)
+{
+       return 0;
+};
+
+struct snd_soc_codec_driver soc_codec_dev_pdm_dummy = {
+       .probe = pdm_dummy_probe,
+       .remove = pdm_dummy_remove,
+};
+
+
+static const struct of_device_id pdm_dummy_codec_device_id[] = {
+       { .compatible = "amlogic, pdm_dummy_codec", },
+       {},
+};
+
+static int pdm_dummy_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+               &soc_codec_dev_pdm_dummy,
+               &pdm_dummy_dai, 1);
+}
+
+static int pdm_dummy_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver pdm_dummy_platform_driver = {
+       .driver = {
+               .name = "pdm",
+               .owner = THIS_MODULE,
+               .of_match_table = pdm_dummy_codec_device_id,
+       },
+       .probe = pdm_dummy_platform_probe,
+       .remove = pdm_dummy_platform_remove,
+};
+
+static int __init pdm_dummy_init(void)
+{
+       return platform_driver_register(&pdm_dummy_platform_driver);
+}
+
+static void __exit pdm_dummy_exit(void)
+{
+       platform_driver_unregister(&pdm_dummy_platform_driver);
+}
+
+module_init(pdm_dummy_init);
+module_exit(pdm_dummy_exit);
+
+MODULE_AUTHOR("AMLogic, Inc.");
+MODULE_DESCRIPTION("ASoC pdm_dummy codec driver");
+MODULE_LICENSE("GPL");
index 37adcee..0c42513 100644 (file)
@@ -200,7 +200,7 @@ static int tas5707_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
        default:
-               return -EINVAL;
+               return 0;//-EINVAL;
        }
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -209,7 +209,7 @@ static int tas5707_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        case SND_SOC_DAIFMT_LEFT_J:
                break;
        default:
-               return -EINVAL;
+               return 0;//-EINVAL;
        }
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -218,7 +218,7 @@ static int tas5707_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        case SND_SOC_DAIFMT_NB_IF:
                break;
        default:
-               return -EINVAL;
+               return 0;//-EINVAL;
        }
 
        return 0;
diff --git a/sound/soc/codecs/amlogic/tlv320adc3101.c b/sound/soc/codecs/amlogic/tlv320adc3101.c
new file mode 100644 (file)
index 0000000..67830f2
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ * linux/sound/soc/codecs/tlv320adc3101.c
+ *
+ * Copyright 2011 Amlogic
+ *
+ * Author: Alex Deng <alex.deng@amlogic.com>
+ *
+ * Based on sound/soc/codecs/tlv320aic320x and TI driver for kernel 2.6.27.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "tlv320adc3101.h"
+
+struct adc3101_rate_divs {
+       u32 mclk;
+       u32 rate;
+       u8 p_val;
+       u8 pll_j;
+       u16 pll_d;
+       u16 dosr;
+       u8 ndac;
+       u8 mdac;
+       u8 aosr;
+       u8 nadc;
+       u8 madc;
+       u8 blck_N;
+};
+
+struct adc3101_priv {
+       struct regmap *regmap;
+       u32 sysclk;
+       u32 power_cfg;
+       u32 micpga_routing;
+       bool swapdacs;
+       int rstn_gpio;
+       struct snd_soc_codec *codec;
+       /* for more control */
+       int codec_cnt;
+       int codec_mask;
+       struct i2c_client *client[4];
+       u8 page_no;
+};
+
+enum{
+       MASK_1 = 1 << 0,
+       MASK_2 = 1 << 1,
+       MASK_3 = 1 << 2,
+       MASK_4 = 1 << 3
+};
+
+struct adc3101_priv *g_adc3101_priv;
+static int     lr_gain = 0x20;
+module_param(lr_gain, int, 0664);
+MODULE_PARM_DESC(lr_gain, "PGA Level Volume");
+
+/* 0dB min, 1dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
+/* 0dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
+
+static const struct snd_kcontrol_new adc3101_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("PCM Playback Volume", ADC3101_LDACVOL,
+                       ADC3101_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
+       SOC_DOUBLE_R_TLV("HP Driver Gain Volume", ADC3101_HPLGAIN,
+                       ADC3101_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
+       SOC_DOUBLE_R_TLV("LO Driver Gain Volume", ADC3101_LOLGAIN,
+                       ADC3101_LORGAIN, 0, 0x1D, 0, tlv_step_1),
+       SOC_DOUBLE_R("HP DAC Playback Switch", ADC3101_HPLGAIN,
+                       ADC3101_HPRGAIN, 6, 0x01, 1),
+       SOC_DOUBLE_R("LO DAC Playback Switch", ADC3101_LOLGAIN,
+                       ADC3101_LORGAIN, 6, 0x01, 1),
+       SOC_DOUBLE_R("Mic PGA Switch", ADC3101_LMICPGAVOL,
+                       ADC3101_RMICPGAVOL, 7, 0x01, 1),
+
+       SOC_SINGLE("ADCFGA Left Mute Switch", ADC3101_ADCFGA, 7, 1, 0),
+       SOC_SINGLE("ADCFGA Right Mute Switch", ADC3101_ADCFGA, 3, 1, 0),
+
+       SOC_DOUBLE_R_TLV("ADC Level Volume", ADC3101_LADCVOL,
+                       ADC3101_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
+       SOC_DOUBLE_R_TLV("PGA Level Volume", ADC3101_LMICPGAVOL,
+                       ADC3101_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
+
+       SOC_SINGLE("Auto-mute Switch", ADC3101_DACMUTE, 4, 7, 0),
+
+       SOC_SINGLE("AGC Left Switch", ADC3101_LAGC1, 7, 1, 0),
+       SOC_SINGLE("AGC Right Switch", ADC3101_RAGC1, 7, 1, 0),
+       SOC_DOUBLE_R("AGC Target Level", ADC3101_LAGC1, ADC3101_RAGC1,
+                       4, 0x07, 0),
+       SOC_DOUBLE_R("AGC Gain Hysteresis", ADC3101_LAGC1, ADC3101_RAGC1,
+                       0, 0x03, 0),
+       SOC_DOUBLE_R("AGC Hysteresis", ADC3101_LAGC2, ADC3101_RAGC2,
+                       6, 0x03, 0),
+       SOC_DOUBLE_R("AGC Noise Threshold", ADC3101_LAGC2, ADC3101_RAGC2,
+                       1, 0x1F, 0),
+       SOC_DOUBLE_R("AGC Max PGA", ADC3101_LAGC3, ADC3101_RAGC3,
+                       0, 0x7F, 0),
+       SOC_DOUBLE_R("AGC Attack Time", ADC3101_LAGC4, ADC3101_RAGC4,
+                       3, 0x1F, 0),
+       SOC_DOUBLE_R("AGC Decay Time", ADC3101_LAGC5, ADC3101_RAGC5,
+                       3, 0x1F, 0),
+       SOC_DOUBLE_R("AGC Noise Debounce", ADC3101_LAGC6, ADC3101_RAGC6,
+                       0, 0x1F, 0),
+       SOC_DOUBLE_R("AGC Signal Debounce", ADC3101_LAGC7, ADC3101_RAGC7,
+                       0, 0x0F, 0),
+};
+
+static const struct adc3101_rate_divs adc3101_divs[] = {
+       /* mclk rate p  j  d    dosr ndac mdac  aosr nadc  madc blk_N */
+
+       /* 8k rate */
+       {ADC3101_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
+       {ADC3101_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
+       {ADC3101_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
+       /* 11.025k rate */
+       {ADC3101_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
+       {ADC3101_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
+       /* 16k rate */
+       {ADC3101_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
+       {ADC3101_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
+       {ADC3101_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
+       /* 22.05k rate */
+       {ADC3101_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
+       {ADC3101_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
+       {ADC3101_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
+       /* 32k rate */
+       {ADC3101_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
+       {ADC3101_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
+       /* 44.1k rate */
+       {ADC3101_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
+       {ADC3101_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
+       {ADC3101_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
+       /* 48k rate */
+       {ADC3101_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
+       {ADC3101_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
+       {ADC3101_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
+
+       {ADC3101_FREQ_2048000, 8000, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
+       {ADC3101_FREQ_4096000, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
+       {ADC3101_FREQ_8192000, 32000, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
+       {ADC3101_FREQ_11289600, 44100, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
+       {ADC3101_FREQ_12288000, 48000, 1, 4, 0, 128, 2, 1, 128, 2, 1, 1},
+};
+
+static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("L_DAC Switch", ADC3101_HPLROUTE, 3, 1, 0),
+       SOC_DAPM_SINGLE("IN1_L Switch", ADC3101_HPLROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("R_DAC Switch", ADC3101_HPRROUTE, 3, 1, 0),
+       SOC_DAPM_SINGLE("IN1_R Switch", ADC3101_HPRROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("L_DAC Switch", ADC3101_LOLROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("R_DAC Switch", ADC3101_LORROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer_controls[] = {
+       SOC_DAPM_SINGLE("IN1_L P Switch", ADC3101_LMICPGAPIN, 6, 1, 0),
+       SOC_DAPM_SINGLE("IN2_L P Switch", ADC3101_LMICPGAPIN, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN3_L P Switch", ADC3101_LMICPGAPIN, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer_controls[] = {
+       SOC_DAPM_SINGLE("IN1_R P Switch", ADC3101_RMICPGAPIN, 6, 1, 0),
+       SOC_DAPM_SINGLE("IN2_R P Switch", ADC3101_RMICPGAPIN, 4, 1, 0),
+       SOC_DAPM_SINGLE("IN3_R P Switch", ADC3101_RMICPGAPIN, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adc3101_dapm_widgets[] = {
+       SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0,
+                          &left_input_mixer_controls[0],
+                          ARRAY_SIZE(left_input_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0,
+                          &right_input_mixer_controls[0],
+                          ARRAY_SIZE(right_input_mixer_controls)),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ADC3101_ADCSETUP, 7, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ADC3101_ADCSETUP, 6, 0),
+       SND_SOC_DAPM_MICBIAS("Mic Bias", ADC3101_MICBIAS, 6, 0),
+
+       SND_SOC_DAPM_INPUT("IN1_L"),
+       SND_SOC_DAPM_INPUT("IN1_R"),
+       SND_SOC_DAPM_INPUT("IN2_L"),
+       SND_SOC_DAPM_INPUT("IN2_R"),
+       SND_SOC_DAPM_INPUT("IN3_L"),
+       SND_SOC_DAPM_INPUT("IN3_R"),
+};
+
+static const struct snd_soc_dapm_route adc3101_dapm_routes[] = {
+       /* Left input */
+       {"Left Input Mixer", "IN1_L P Switch", "IN1_L"},
+       {"Left Input Mixer", "IN2_L P Switch", "IN2_L"},
+       {"Left Input Mixer", "IN3_L P Switch", "IN3_L"},
+
+       {"Left ADC", NULL, "Left Input Mixer"},
+
+       /* Right Input */
+       {"Right Input Mixer", "IN1_R P Switch", "IN1_R"},
+       {"Right Input Mixer", "IN2_R P Switch", "IN2_R"},
+       {"Right Input Mixer", "IN3_R P Switch", "IN3_R"},
+
+       {"Right ADC", NULL, "Right Input Mixer"},
+};
+
+static const struct regmap_range_cfg adc3101_regmap_pages[] = {
+       {
+               .range_min = 0,
+               .range_max = ADC3101_RMICPGAVOL,
+               .selector_reg = ADC3101_PSEL,
+               .selector_mask = 0xff,
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = 128,
+       },
+};
+
+static const struct regmap_config adc3101_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .ranges = adc3101_regmap_pages,
+       .num_ranges = ARRAY_SIZE(adc3101_regmap_pages),
+       .max_register = ADC3101_RMICPGAVOL,
+};
+
+static inline int adc3101_get_divs(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adc3101_divs); i++) {
+               if ((adc3101_divs[i].rate == rate)
+                   && (adc3101_divs[i].mclk == mclk)) {
+                       return i;
+               }
+       }
+
+       pr_err("adc3101: master clock and sample rate is not supported\n");
+       return -EINVAL;
+}
+
+static int adc3101_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct adc3101_priv *adc3101 = snd_soc_codec_get_drvdata(codec);
+
+       pr_info("%s freq:%d\n", __func__, freq);
+       switch (freq) {
+       case ADC3101_FREQ_12000000:
+       case ADC3101_FREQ_24000000:
+       case ADC3101_FREQ_25000000:
+       case ADC3101_FREQ_11289600:
+       case ADC3101_FREQ_12288000:
+       case ADC3101_FREQ_2048000:
+       case ADC3101_FREQ_4096000:
+       case ADC3101_FREQ_8192000:
+               adc3101->sysclk = freq;
+               return 0;
+       }
+
+       pr_err("adc3101: invalid frequency to set DAI system clock\n");
+       return -1;
+}
+
+static int adc3101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 iface_reg_1;
+       u8 dsp_a_val;
+       u8 iface_reg_2;
+
+       pr_info("%s ...\n", __func__);
+
+       iface_reg_1 = snd_soc_read(codec, ADC3101_IFACE1);
+       iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2);
+       dsp_a_val = snd_soc_read(codec, ADC3101_DATASLOTOFFSETCTL);
+       dsp_a_val = 0;
+       iface_reg_2 = snd_soc_read(codec, ADC3101_IFACE3);
+       iface_reg_2 = iface_reg_2 & ~(1 << 3);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface_reg_1 |= ADC3101_BCLKMASTER | ADC3101_WCLKMASTER;
+               pr_info("%s DAIFMT_CBM_CFM\n", __func__);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               pr_err("adc3101: invalid DAI master/slave interface\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface_reg_1 |= (ADC3101_DSP_MODE << ADC3101_PLLJ_SHIFT);
+               iface_reg_2 |= (1 << 3); /* invert bit clock */
+               dsp_a_val = 0x01; /* add offset 1 */
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface_reg_1 |= (ADC3101_DSP_MODE << ADC3101_PLLJ_SHIFT);
+               iface_reg_2 |= (1 << 3); /* invert bit clock */
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_reg_1 |=
+                       (ADC3101_RIGHT_JUSTIFIED_MODE << ADC3101_PLLJ_SHIFT);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg_1 |=
+                       (ADC3101_LEFT_JUSTIFIED_MODE << ADC3101_PLLJ_SHIFT);
+               break;
+       default:
+               pr_err("adc3101: invalid DAI interface format\n");
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, ADC3101_IFACE1, iface_reg_1);
+       snd_soc_write(codec, ADC3101_DATASLOTOFFSETCTL, dsp_a_val);
+       snd_soc_write(codec, ADC3101_IFACE3, iface_reg_2);
+
+       return 0;
+}
+
+static int __maybe_unused adc3101_hw_high_pass_filter(
+       struct snd_soc_codec *codec)
+{
+       /*page 4*/
+       char datas[4][31] = {
+               /* data 1*/
+               {
+                       0x0E,
+                       0x7F, 0xBE, 0x80, 0x42,
+                       0x7F, 0xBE, 0x7F, 0xBE,
+                       0x80, 0x84, 0x7F, 0xFF,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x7F, 0xFF, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00
+               },
+               /* data 2 */
+               {
+                       0x2c,
+                       0x7F, 0xFF, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x7F, 0xFF,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+               },
+               /* data 3 */
+               {
+                       0x4E,
+                       0x7F, 0xBE, 0x80,
+                       0x42, 0x7F, 0xBE, 0x7F,
+                       0xBE, 0x80, 0x84, 0x7F,
+                       0xFF, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x7F, 0xFF, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00
+               },
+               /* data 4 */
+               {
+                       0x6C,
+                       0x7F, 0xFF, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x7F, 0xFF,
+                       0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+               }
+       };
+       int i = 0, j = 0, c = 0;
+       int ret = 0;
+       int nums[] = {31, 21, 31, 21};
+       struct adc3101_priv *adc3101 = snd_soc_codec_get_drvdata(codec);
+
+       pr_info("%s ...\n", __func__);
+
+       snd_soc_write(codec, 0x3D, 2);
+       snd_soc_write(codec, 0x51, 0);
+       /* page 4 */
+       snd_soc_write(codec, ADC3101_PSEL, 0x4);
+
+       for (i = 0; i < adc3101->codec_cnt; i++) {
+               for (c = 0; c < 4; c++) {
+                       for (j = 0; j < nums[c]; j++) {
+                               ret = i2c_smbus_write_byte(
+                                               adc3101->client[i],
+                                               datas[c][j]);
+                               if (ret < 0)
+                                       pr_err("%x write error\n",
+                                               adc3101->client[i]->addr);
+                       }
+               }
+       }
+
+       snd_soc_write(codec, 0x51, 0xC0);
+       snd_soc_write(codec, 0x52, 0x00);
+       pr_info("%s done\n", __func__);
+
+       return 0;
+}
+
+
+static int adc3101_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct adc3101_priv *adc3101 = snd_soc_codec_get_drvdata(codec);
+       u8 data;
+       int i;
+
+       pr_info("%s ...\n", __func__);
+
+       i = adc3101_get_divs(adc3101->sysclk, params_rate(params));
+       if (i < 0) {
+               pr_err("adc3101: sampling rate not supported\n");
+               return i;
+       }
+
+       /* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */
+       snd_soc_write(codec, ADC3101_CLKMUX, 0);
+
+       /* We will fix R value to 1 and will make P & J=K.D as varialble */
+       data = snd_soc_read(codec, ADC3101_PLLPR);
+       data &= ~(7 << 4);
+
+       snd_soc_write(codec, ADC3101_PLLPR,
+                     (data | (adc3101_divs[i].p_val << 4) | 0x01));
+
+       snd_soc_write(codec, ADC3101_PLLJ, adc3101_divs[i].pll_j);
+
+       snd_soc_write(codec, ADC3101_PLLDMSB, (adc3101_divs[i].pll_d >> 8));
+       snd_soc_write(codec, ADC3101_PLLDLSB,
+                     (adc3101_divs[i].pll_d & 0xff));
+       /* NADC divider value */
+       data = snd_soc_read(codec, ADC3101_NADC);
+       data &= ~(0x7f);
+       data |= 0x80;
+       snd_soc_write(codec, ADC3101_NADC, data | adc3101_divs[i].nadc);
+
+       pr_info("%s NADC = 0x%02x\n",
+               __func__,
+               snd_soc_read(codec, ADC3101_NADC));
+
+       /* MADC divider value */
+       data = snd_soc_read(codec, ADC3101_MADC);
+       data &= ~(0x7f);
+       data |= 0x80;
+       snd_soc_write(codec, ADC3101_MADC, data | adc3101_divs[i].madc);
+       pr_info("%s MADC = 0x%02x\n",
+               __func__,
+               snd_soc_read(codec, ADC3101_MADC));
+
+       /* AOSR value */
+       snd_soc_write(codec, ADC3101_AOSR, adc3101_divs[i].aosr);
+       pr_info("%s AOSR=%02x\n",
+               __func__,
+               snd_soc_read(codec, ADC3101_AOSR));
+
+       data = snd_soc_read(codec, ADC3101_IFACE1);
+       data = data & ~(3 << 4);
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               data |= (ADC3101_WORD_LEN_20BITS << ADC3101_DOSRMSB_SHIFT);
+               break;
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               data |= (ADC3101_WORD_LEN_24BITS << ADC3101_DOSRMSB_SHIFT);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               data |= (ADC3101_WORD_LEN_32BITS << ADC3101_DOSRMSB_SHIFT);
+               break;
+       }
+       snd_soc_write(codec, ADC3101_IFACE1, data);
+       pr_info("%s iface1 = %02x\n", __func__, data);
+
+       snd_soc_write(codec, ADC3101_MICBIAS, 0x50);
+       /* 0x3f: differential, 0xFC:single input */
+       snd_soc_write(codec, ADC3101_LMICPGANIN, 0x3F);
+       /* 0x3f: differential input */
+       snd_soc_write(codec, ADC3101_RMICPGANIN, 0x3F);
+       /* 0x3f: differential, 0xFC:single input */
+       snd_soc_write(codec, ADC3101_LMICPGAPIN, 0x3F);
+       /* 0x3f: differential input */
+       snd_soc_write(codec, ADC3101_RMICPGAPIN, 0x3F);
+       snd_soc_write(codec, ADC3101_LMICPGAVOL, lr_gain);
+       snd_soc_write(codec, ADC3101_RMICPGAVOL, lr_gain);
+       snd_soc_write(codec, ADC3101_ADCSETUP, 0xc2);
+       snd_soc_write(codec, ADC3101_ADCFGA, 0);
+
+       pr_info("%s ADCSETUP = %02x\n", __func__,
+                       snd_soc_read(codec, ADC3101_ADCSETUP));
+       pr_info("%s DOUTCTL=%02x\n", __func__,
+                       snd_soc_read(codec, ADC3101_DOUTCTL));
+       pr_info("%s MICBIAS=%02x\n", __func__,
+                       snd_soc_read(codec, ADC3101_MICBIAS));
+
+       return 0;
+}
+
+static int adc3101_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u8 dac_reg;
+
+       dac_reg = snd_soc_read(codec, ADC3101_DACMUTE) & ~ADC3101_MUTEON;
+       if (mute)
+               snd_soc_write(codec, ADC3101_DACMUTE, dac_reg | ADC3101_MUTEON);
+       else
+               snd_soc_write(codec, ADC3101_DACMUTE, dac_reg);
+
+       return 0;
+}
+
+static int adc3101_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       pr_info("%s ..\n", __func__);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* Switch on PLL */
+               snd_soc_update_bits(codec, ADC3101_PLLPR,
+                                   ADC3101_PLLEN, ADC3101_PLLEN);
+
+               /* Switch on NDAC Divider */
+               snd_soc_update_bits(codec, ADC3101_NDAC,
+                                   ADC3101_NDACEN, ADC3101_NDACEN);
+
+               /* Switch on MDAC Divider */
+               snd_soc_update_bits(codec, ADC3101_MDAC,
+                                   ADC3101_MDACEN, ADC3101_MDACEN);
+
+               /* Switch on NADC Divider */
+               snd_soc_update_bits(codec, ADC3101_NADC,
+                                   ADC3101_NADCEN, ADC3101_NADCEN);
+
+               /* Switch on MADC Divider */
+               snd_soc_update_bits(codec, ADC3101_MADC,
+                                   ADC3101_MADCEN, ADC3101_MADCEN);
+
+               /* Switch on BCLK_N Divider */
+               snd_soc_update_bits(codec, ADC3101_BCLKN,
+                                   ADC3101_BCLKEN, ADC3101_BCLKEN);
+
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* Switch off PLL */
+               snd_soc_update_bits(codec, ADC3101_PLLPR,
+                                   ADC3101_PLLEN, 0);
+
+               /* Switch off NDAC Divider */
+               snd_soc_update_bits(codec, ADC3101_NDAC,
+                                   ADC3101_NDACEN, 0);
+
+               /* Switch off MDAC Divider */
+               snd_soc_update_bits(codec, ADC3101_MDAC,
+                                   ADC3101_MDACEN, 0);
+
+               /* Switch off NADC Divider */
+               snd_soc_update_bits(codec, ADC3101_NADC,
+                                   ADC3101_NADCEN, 0);
+
+               /* Switch off MADC Divider */
+               snd_soc_update_bits(codec, ADC3101_MADC,
+                                   ADC3101_MADCEN, 0);
+
+               /* Switch off BCLK_N Divider */
+               snd_soc_update_bits(codec, ADC3101_BCLKN,
+                                   ADC3101_BCLKEN, 0);
+               break;
+       case SND_SOC_BIAS_OFF:
+               break;
+       }
+       codec->component.dapm.bias_level = level;
+       snd_soc_codec_init_bias_level(codec, level);
+
+       return 0;
+}
+
+#define ADC3101_RATES  SNDRV_PCM_RATE_8000_96000
+#define ADC3101_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+                        | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops adc3101_ops = {
+       .hw_params = adc3101_hw_params,
+       .digital_mute = adc3101_mute,
+       .set_fmt = adc3101_set_dai_fmt,
+       .set_sysclk = adc3101_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver adc3101_dai[] = {
+       {
+               .name = "tlv320adc3101-hifi",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,//2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+               .ops = &adc3101_ops,
+               .symmetric_rates = 1,
+       },
+       {
+               .name = "tlv320adc3101-hifi@19",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,//2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+               .ops = &adc3101_ops,
+               .symmetric_rates = 1,
+       },
+       {
+               .name = "tlv320adc3101-hifi@1a",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,//2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+               .ops = &adc3101_ops,
+               .symmetric_rates = 1,
+       },
+       {
+               .name = "tlv320adc3101-hifi@1b",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = ADC3101_RATES,
+                       .formats = ADC3101_FORMATS,},
+               .ops = &adc3101_ops,
+               .symmetric_rates = 1,
+       },
+};
+
+static int adc3101_suspend(struct snd_soc_codec *codec)
+{
+       adc3101_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int adc3101_resume(struct snd_soc_codec *codec)
+{
+       adc3101_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+static int adc3101_codec_probe(struct snd_soc_codec *codec)
+{
+       u32 tmp_reg;
+
+       pr_info("%s ...\n", __func__);
+
+       snd_soc_write(codec, ADC3101_RESET, 0x01);
+
+       /*
+        * Workaround: for an unknown reason, the ADC needs to be powered up
+        * and down for the first capture to work properly. It seems related to
+        * a HW BUG or some kind of behavior not documented in the datasheet.
+        */
+       tmp_reg = snd_soc_read(codec, ADC3101_ADCSETUP);
+       snd_soc_write(codec, ADC3101_ADCSETUP, tmp_reg |
+                               ADC3101_LADC_EN | ADC3101_RADC_EN);
+       snd_soc_write(codec, ADC3101_ADCSETUP, tmp_reg);
+
+       pr_info("%s done...\n", __func__);
+
+       return 0;
+}
+
+static int adc3101_remove(struct snd_soc_codec *codec)
+{
+       adc3101_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver __maybe_unused soc_codec_dev_adc3101_2 = {
+       .probe = adc3101_codec_probe,
+       .remove = adc3101_remove,
+       .suspend = adc3101_suspend,
+       .resume = adc3101_resume,
+       .set_bias_level = adc3101_set_bias_level,
+
+};
+static struct snd_soc_codec_driver soc_codec_dev_adc3101 = {
+       .probe = adc3101_codec_probe,
+       .remove = adc3101_remove,
+       .suspend = adc3101_suspend,
+       .resume = adc3101_resume,
+       .set_bias_level = adc3101_set_bias_level,
+
+       .component_driver = {
+               .controls = adc3101_snd_controls,
+               .num_controls = ARRAY_SIZE(adc3101_snd_controls),
+               .dapm_widgets = adc3101_dapm_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(adc3101_dapm_widgets),
+               .dapm_routes = adc3101_dapm_routes,
+               .num_dapm_routes = ARRAY_SIZE(adc3101_dapm_routes),
+       }
+};
+
+static int adc3101_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct adc3101_priv *adc3101 = NULL;
+       int ret = 0;
+
+       pr_err("tlv320 %s ...\n", __func__);
+
+       adc3101 = devm_kzalloc(&i2c->dev, sizeof(struct adc3101_priv),
+                       GFP_KERNEL);
+       if (adc3101 == NULL)
+               return -ENOMEM;
+       adc3101->codec_cnt = 0;
+
+       adc3101->regmap = devm_regmap_init_i2c(i2c, &adc3101_i2c_regmap);
+       if (IS_ERR(adc3101->regmap)) {
+               pr_info("%s failed devm_regmap_init_i2c\n", __func__);
+               return PTR_ERR(adc3101->regmap);
+       }
+       i2c_set_clientdata(i2c, adc3101);
+
+       adc3101->power_cfg = 0;
+       adc3101->swapdacs = false;
+       adc3101->micpga_routing = 0;
+       adc3101->rstn_gpio = -1;
+
+       ret = of_get_named_gpio(i2c->dev.of_node, "gpio-reset", 0);
+       if (ret > 0)
+               adc3101->rstn_gpio = ret;
+
+       if (adc3101->rstn_gpio > 0) {
+               ret = devm_gpio_request_one(&i2c->dev,
+                                           adc3101->rstn_gpio,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "adc3101-reset-pin");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "not able to acquire gpio\n");
+                       return ret;
+               }
+       }
+       pr_info("%s i2c:%p\n", __func__, i2c);
+       if (g_adc3101_priv == NULL) {
+               g_adc3101_priv = adc3101;
+               ret = snd_soc_register_codec(&i2c->dev,
+                               &soc_codec_dev_adc3101, adc3101_dai, 1);
+       } else {
+               ret = snd_soc_register_codec(&i2c->dev,
+                               &soc_codec_dev_adc3101_2,
+                               adc3101_dai + g_adc3101_priv->codec_cnt,
+                               1);
+       }
+
+       pr_info("%s %x done\n", __func__, i2c->addr);
+
+       return ret;
+}
+
+static int adc3101_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+
+       return 0;
+}
+
+static const struct of_device_id tlv320adc3101_of_match[] = {
+       {.compatible = "ti,tlv320adc3101"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
+
+static const struct i2c_device_id adc3101_i2c_id[] = {
+       { "tlv320adc3101", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adc3101_i2c_id);
+
+static struct i2c_driver adc3101_i2c_driver = {
+       .driver = {
+               .name = "tlv320adc3101",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(tlv320adc3101_of_match),
+       },
+       .probe =    adc3101_i2c_probe,
+       .remove =   adc3101_i2c_remove,
+       .id_table = adc3101_i2c_id,
+};
+
+module_i2c_driver(adc3101_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC tlv320adc3101 codec driver");
+MODULE_AUTHOR("alex.deng <alex.deng@amlogic.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/amlogic/tlv320adc3101.h b/sound/soc/codecs/amlogic/tlv320adc3101.h
new file mode 100644 (file)
index 0000000..8b7b942
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * tlv320aic32x4.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef _TLV320ADC3101_H
+#define _TLV320ADC3101_H
+
+/* tlv320aic32x4 register space (in decimal to match datasheet) */
+
+#define ADC3101_REG(page, reg) ((page * 128) + reg)
+
+#define ADC3101_PAGE1          128
+
+#define        ADC3101_PSEL            ADC3101_REG(0, 0)
+#define        ADC3101_RESET           ADC3101_REG(0, 1)
+#define        ADC3101_CLKMUX          ADC3101_REG(0, 4)
+#define        ADC3101_PLLPR           ADC3101_REG(0, 5)
+#define        ADC3101_PLLJ            ADC3101_REG(0, 6)
+#define        ADC3101_PLLDMSB         ADC3101_REG(0, 7)
+#define        ADC3101_PLLDLSB         ADC3101_REG(0, 8)
+#define        ADC3101_NDAC            ADC3101_REG(0, 11)
+#define        ADC3101_MDAC            ADC3101_REG(0, 12)
+#define ADC3101_DOSRMSB                ADC3101_REG(0, 13)
+#define ADC3101_DOSRLSB                ADC3101_REG(0, 14)
+#define        ADC3101_NADC            ADC3101_REG(0, 18)
+#define        ADC3101_MADC            ADC3101_REG(0, 19)
+#define ADC3101_AOSR           ADC3101_REG(0, 20)
+#define ADC3101_CLKMUX2                ADC3101_REG(0, 25)
+#define ADC3101_CLKOUTM                ADC3101_REG(0, 26)
+#define ADC3101_IFACE1         ADC3101_REG(0, 27)
+#define ADC3101_DATASLOTOFFSETCTL ADC3101_REG(0, 28)
+#define ADC3101_IFACE3      ADC3101_REG(0, 29)
+#define ADC3101_BCLKN       ADC3101_REG(0, 30)
+#define ADC3101_IFACE4      ADC3101_REG(0, 31)
+#define ADC3101_IFACE5      ADC3101_REG(0, 32)
+#define ADC3101_IFACE6      ADC3101_REG(0, 33)
+#define ADC3101_I2SSYNC     ADC3101_REG(0, 34)
+
+#define ADC3101_ADCFLAG     ADC3101_REG(0, 36)
+#define ADC3101_DATASLOTOFFSETCTL2 ADC3101_REG(0, 37)
+#define ADC3101_TDMCTL      ADC3101_REG(0, 38)
+
+#define ADC3101_INTRADCFLAG  ADC3101_REG(0, 42)
+#define ADC3101_INTRADCFLAG2 ADC3101_REG(0, 43)
+
+#define ADC3101_DMCLKCTL    ADC3101_REG(0, 51)
+#define ADC3101_DMDINCTL    ADC3101_REG(0, 52)
+
+#define ADC3101_DOUTCTL                ADC3101_REG(0, 53)
+#define ADC3101_DINCTL         ADC3101_REG(0, 54)
+
+#define ADC3101_DACSPB         ADC3101_REG(0, 60)
+#define ADC3101_ADCSPB     ADC3101_REG(0, 61)
+#define ADC3101_DACSETUP    ADC3101_REG(0, 63)
+#define ADC3101_DACMUTE            ADC3101_REG(0, 64)
+#define ADC3101_LDACVOL            ADC3101_REG(0, 65)
+#define ADC3101_RDACVOL            ADC3101_REG(0, 66)
+#define ADC3101_ADCSETUP    ADC3101_REG(0, 81)
+#define        ADC3101_ADCFGA      ADC3101_REG(0, 82)
+#define ADC3101_LADCVOL            ADC3101_REG(0, 83)
+#define ADC3101_RADCVOL            ADC3101_REG(0, 84)
+#define ADC3101_LAGC1      ADC3101_REG(0, 86)
+#define ADC3101_LAGC2      ADC3101_REG(0, 87)
+#define ADC3101_LAGC3      ADC3101_REG(0, 88)
+#define ADC3101_LAGC4      ADC3101_REG(0, 89)
+#define ADC3101_LAGC5      ADC3101_REG(0, 90)
+#define ADC3101_LAGC6      ADC3101_REG(0, 91)
+#define ADC3101_LAGC7      ADC3101_REG(0, 92)
+#define ADC3101_RAGC1      ADC3101_REG(0, 94)
+#define ADC3101_RAGC2      ADC3101_REG(0, 95)
+#define ADC3101_RAGC3      ADC3101_REG(0, 96)
+#define ADC3101_RAGC4      ADC3101_REG(0, 97)
+#define ADC3101_RAGC5      ADC3101_REG(0, 98)
+#define ADC3101_RAGC6      ADC3101_REG(0, 99)
+#define ADC3101_RAGC7      ADC3101_REG(0, 100)
+#define ADC3101_PWRCFG         ADC3101_REG(1, 1)
+#define ADC3101_LDOCTL         ADC3101_REG(1, 2)
+#define ADC3101_OUTPWRCTL      ADC3101_REG(1, 9)
+#define ADC3101_CMMODE         ADC3101_REG(1, 10)
+#define ADC3101_HPLROUTE       ADC3101_REG(1, 12)
+#define ADC3101_HPRROUTE       ADC3101_REG(1, 13)
+#define ADC3101_LOLROUTE       ADC3101_REG(1, 14)
+#define ADC3101_LORROUTE       ADC3101_REG(1, 15)
+#define        ADC3101_HPLGAIN         ADC3101_REG(1, 16)
+#define        ADC3101_HPRGAIN         ADC3101_REG(1, 17)
+#define        ADC3101_LOLGAIN         ADC3101_REG(1, 18)
+#define        ADC3101_LORGAIN         ADC3101_REG(1, 19)
+#define ADC3101_HEADSTART      ADC3101_REG(1, 20)
+#define ADC3101_MICBIAS                ADC3101_REG(1, 51)
+#define ADC3101_LMICPGAPIN     ADC3101_REG(1, 52)
+#define ADC3101_LMICPGANIN     ADC3101_REG(1, 54)
+#define ADC3101_RMICPGAPIN     ADC3101_REG(1, 55)
+#define ADC3101_RMICPGANIN     ADC3101_REG(1, 57)
+#define ADC3101_FLOATINGINPUT  ADC3101_REG(1, 58)
+#define ADC3101_LMICPGAVOL     ADC3101_REG(1, 59)
+#define ADC3101_RMICPGAVOL     ADC3101_REG(1, 60)
+
+#define ADC3101_FREQ_2048000  2048000
+#define ADC3101_FREQ_4096000  4096000
+#define ADC3101_FREQ_8192000  8192000
+#define ADC3101_FREQ_11289600 11289600
+#define ADC3101_FREQ_12288000 12288000
+#define ADC3101_FREQ_12000000 12000000
+#define ADC3101_FREQ_24000000 24000000
+#define ADC3101_FREQ_44100000 44100000
+#define ADC3101_FREQ_48000000 48000000
+#define ADC3101_FREQ_96000000 96000000
+#define ADC3101_FREQ_25000000 25000000
+
+#define ADC3101_WORD_LEN_16BITS                0x00
+#define ADC3101_WORD_LEN_20BITS                0x01
+#define ADC3101_WORD_LEN_24BITS                0x02
+#define ADC3101_WORD_LEN_32BITS                0x03
+
+#define ADC3101_LADC_EN                        (1 << 7)
+#define ADC3101_RADC_EN                        (1 << 6)
+
+#define ADC3101_I2S_MODE               0x00
+#define ADC3101_DSP_MODE               0x01
+#define ADC3101_RIGHT_JUSTIFIED_MODE   0x02
+#define ADC3101_LEFT_JUSTIFIED_MODE    0x03
+
+#define ADC3101_AVDDWEAKDISABLE                0x08
+#define ADC3101_LDOCTLEN               0x01
+
+#define ADC3101_LDOIN_18_36            0x01
+#define ADC3101_LDOIN2HP               0x02
+
+#define ADC3101_DACSPBLOCK_MASK                0x1f
+#define ADC3101_ADCSPBLOCK_MASK                0x1f
+
+#define ADC3101_PLLJ_SHIFT             6
+#define ADC3101_DOSRMSB_SHIFT          4
+
+#define ADC3101_PLLCLKIN               0x03
+#define ADC3101_BCLKIN         0x05
+#define ADC3101_BCLKIN_PLLCLKIN                0x07
+
+#define ADC3101_MICBIAS_LDOIN          0x08
+#define ADC3101_MICBIAS_2075V          0x60
+
+#define ADC3101_LMICPGANIN_IN2R_10K    0x10
+#define ADC3101_LMICPGANIN_CM1L_10K    0x40
+#define ADC3101_RMICPGANIN_IN1L_10K    0x10
+#define ADC3101_RMICPGANIN_CM1R_10K    0x40
+
+#define ADC3101_LMICPGAVOL_NOGAIN      0x80
+#define ADC3101_RMICPGAVOL_NOGAIN      0x80
+
+#define ADC3101_BCLKMASTER             0x08
+#define ADC3101_WCLKMASTER             0x04
+#define ADC3101_PLLEN                  (0x01 << 7)
+#define ADC3101_NDACEN                 (0x01 << 7)
+#define ADC3101_MDACEN                 (0x01 << 7)
+#define ADC3101_NADCEN                 (0x01 << 7)
+#define ADC3101_MADCEN                 (0x01 << 7)
+#define ADC3101_BCLKEN                 (0x01 << 7)
+#define ADC3101_DACEN                  (0x03 << 6)
+#define ADC3101_RDAC2LCHN              (0x02 << 2)
+#define ADC3101_LDAC2RCHN              (0x02 << 4)
+#define ADC3101_LDAC2LCHN              (0x01 << 4)
+#define ADC3101_RDAC2RCHN              (0x01 << 2)
+#define ADC3101_DAC_CHAN_MASK          0x3c
+
+#define ADC3101_SSTEP2WCLK             0x01
+#define ADC3101_MUTEON                 0x0C
+#define        ADC3101_DACMOD2BCLK             0x01
+
+#endif /* _TLV320ADC3101_H */