--- /dev/null
+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>;
+};
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
+
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>;
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>;
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>;
#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 {
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
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*/
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"),
--- /dev/null
+/*
+ * 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 */
+#
+# 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
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
-# 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/
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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.");
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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");
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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__*/
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__*/
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
+
--- /dev/null
+# 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
/*
- * sound/soc/amlogic/aml_audio_hw.c
+ * sound/soc/amlogic/meson/audio_hw.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
#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 */
/*
- * sound/soc/amlogic/aml_audio_hw.h
+ * sound/soc/amlogic/meson/audio_hw.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_audio_hw_pcm.c
+ * sound/soc/amlogic/meson/audio_hw_pcm.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
#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>
/*
- * sound/soc/amlogic/aml_audio_hw_pcm.h
+ * sound/soc/amlogic/meson/audio_hw_pcm.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
#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);
/*
- * sound/soc/amlogic/aml_dmic.c
+ * sound/soc/amlogic/meson/dmic.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_i2s.c
+ * sound/soc/amlogic/meson/i2s.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/* 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>
/*
- * sound/soc/amlogic/aml_i2s.h
+ * sound/soc/amlogic/meson/i2s.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * 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} };
/*
- * sound/soc/amlogic/aml_i2s_dai.h
+ * sound/soc/amlogic/meson/i2s_dai.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_meson.c
+ * sound/soc/amlogic/meson/meson.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/* #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>
/*
- * sound/soc/amlogic/aml_meson.h
+ * sound/soc/amlogic/meson/meson.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_notify.c
+ * sound/soc/amlogic/meson/notify.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_pcm.c
+ * sound/soc/amlogic/meson/pcm.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
#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
/*
- * sound/soc/amlogic/aml_pcm.h
+ * sound/soc/amlogic/meson/pcm.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * 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>
/*
- * sound/soc/amlogic/aml_pcm_dai.h
+ * sound/soc/amlogic/meson/pcm_dai.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_spdif_codec.c
+ * sound/soc/amlogic/meson/spdif_codec.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_spdif_dai.c
+ * sound/soc/amlogic/meson/spdif_dai.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
#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>
/*
- * sound/soc/amlogic/aml_spdif_dai.h
+ * sound/soc/amlogic/meson/spdif_dai.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
/*
- * sound/soc/amlogic/aml_tv.c
+ * sound/soc/amlogic/meson/tv.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
#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"
/*
- * sound/soc/amlogic/aml_tv.h
+ * sound/soc/amlogic/aml_meson/tv.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
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,
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,
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
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
#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
--- /dev/null
+/*
+ * 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");
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
- return -EINVAL;
+ return 0;//-EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_LEFT_J:
break;
default:
- return -EINVAL;
+ return 0;//-EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_IF:
break;
default:
- return -EINVAL;
+ return 0;//-EINVAL;
}
return 0;
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * 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 */