Merge tag 'asoc-v5.11' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Mon, 14 Dec 2020 14:57:14 +0000 (15:57 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 14 Dec 2020 14:57:14 +0000 (15:57 +0100)
ASoC: Updates for v5.11

There's a lot of changes here but mostly cleanups and driver specific
things, the most user visible change is the support for boot time
selection of Intel DSP firmware which will make it easier for people to
move over to the preferred modern implementations in distros and other
large scale deployments.

This also includes a merge of the new auxillary bus which was done in
anticipation of use by the Intel DSP drivers which didn't quite make it.

 - Lots more cleanups and simplifications from Morimoto-san.
 - Support for some basic DPCM systems in the audio graph card from
   Sameer Pujar.
 - Remove some old pre-DT Freescale drivers for platforms that are now
   DT only.
 - Move selection of which Intel DSP implementation to use to boot time
   rather than requiring it to be selected at build time.
 - Support for Allwinner H6 I2S, Analog Devices ADAU1372, Intel
   Alderlake-S, GMediatek MT8192, NXP i.MX HDMI and XCVR, Realtek RT715,
   Qualcomm SM8250 and simple GPIO based muxes.

338 files changed:
Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
Documentation/devicetree/bindings/sound/adi,adau1372.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/adi,adau1977.txt [deleted file]
Documentation/devicetree/bindings/sound/adi,adau1977.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml
Documentation/devicetree/bindings/sound/audio-graph-card.txt [deleted file]
Documentation/devicetree/bindings/sound/audio-graph-card.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/audio-graph-port.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/audio-graph.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,aud2htx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,spdif.yaml
Documentation/devicetree/bindings/sound/fsl,xcvr.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/imx-audio-hdmi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml
Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nau8315.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt [deleted file]
Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,sm8250.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/renesas,rsnd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5682.txt
Documentation/devicetree/bindings/sound/simple-audio-mux.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/simple-card.yaml
Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt [deleted file]
Documentation/devicetree/bindings/sound/st,stm32-sai.txt [deleted file]
Documentation/devicetree/bindings/sound/st,stm32-sai.yaml [new file with mode: 0644]
Documentation/driver-api/auxiliary_bus.rst [new file with mode: 0644]
Documentation/driver-api/index.rst
drivers/base/Kconfig
drivers/base/Makefile
drivers/base/auxiliary.c [new file with mode: 0644]
drivers/base/regmap/Kconfig
drivers/base/regmap/Makefile
drivers/base/regmap/regmap-sdw-mbq.c [new file with mode: 0644]
drivers/soundwire/bus.c
drivers/soundwire/sysfs_slave_dpn.c
include/dt-bindings/sound/adi,adau1977.h [new file with mode: 0644]
include/linux/auxiliary_bus.h [new file with mode: 0644]
include/linux/mod_devicetable.h
include/linux/platform_data/adau1977.h [deleted file]
include/linux/regmap.h
include/linux/soundwire/sdw.h
include/linux/soundwire/sdw_registers.h
include/sound/graph_card.h [new file with mode: 0644]
include/sound/intel-dsp-config.h
include/sound/rt5682.h
include/sound/simple_card_utils.h
include/sound/soc-acpi-intel-match.h
include/sound/soc-acpi.h
include/sound/soc-component.h
include/sound/soc-dai.h
include/sound/soc-jack.h [new file with mode: 0644]
include/sound/soc-link.h
include/sound/soc-topology.h
include/sound/soc.h
include/sound/sof.h
include/sound/sof/dai.h
include/sound/sof/debug.h [new file with mode: 0644]
include/sound/sof/ext_manifest.h
include/sound/sof/header.h
include/sound/sof/trace.h
include/trace/events/asoc.h
include/uapi/sound/asoc.h
include/uapi/sound/sof/abi.h
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
sound/hda/intel-dsp-config.c
sound/soc/adi/Kconfig
sound/soc/amd/acp-da7219-max98357a.c
sound/soc/amd/raven/pci-acp3x.c
sound/soc/amd/renoir/rn-pci-acp3x.c
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel-i2s.c
sound/soc/bcm/bcm2835-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau1372-i2c.c [new file with mode: 0644]
sound/soc/codecs/adau1372-spi.c [new file with mode: 0644]
sound/soc/codecs/adau1372.c [new file with mode: 0644]
sound/soc/codecs/adau1372.h [new file with mode: 0644]
sound/soc/codecs/adau1977.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4118.c
sound/soc/codecs/ak5558.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.c
sound/soc/codecs/bd28623.c
sound/soc/codecs/cros_ec_codec.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs47l92.c
sound/soc/codecs/cx2072x.c
sound/soc/codecs/da7218.c
sound/soc/codecs/da7219.c
sound/soc/codecs/da9055.c
sound/soc/codecs/es7134.c
sound/soc/codecs/es7241.c
sound/soc/codecs/es8316.c
sound/soc/codecs/gtm601.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/inno_rk3036.c
sound/soc/codecs/jz4725b.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/jz4770.c
sound/soc/codecs/lpass-va-macro.c [new file with mode: 0644]
sound/soc/codecs/lpass-wsa-macro.c [new file with mode: 0644]
sound/soc/codecs/lpass-wsa-macro.h [new file with mode: 0644]
sound/soc/codecs/madera.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max98371.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/max98390.c
sound/soc/codecs/max9867.c
sound/soc/codecs/max98925.c
sound/soc/codecs/max98926.c
sound/soc/codecs/mt6359.c
sound/soc/codecs/mt6359.h
sound/soc/codecs/nau8315.c [new file with mode: 0644]
sound/soc/codecs/pcm1789-i2c.c
sound/soc/codecs/pcm179x-i2c.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rk3328_codec.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/rt1015.h
sound/soc/codecs/rt1015p.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt5660.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt715-sdca-sdw.c [new file with mode: 0644]
sound/soc/codecs/rt715-sdca-sdw.h [new file with mode: 0644]
sound/soc/codecs/rt715-sdca.c [new file with mode: 0644]
sound/soc/codecs/rt715-sdca.h [new file with mode: 0644]
sound/soc/codecs/rt715.c
sound/soc/codecs/rt715.h
sound/soc/codecs/simple-mux.c [new file with mode: 0644]
sound/soc/codecs/tas2562.c
sound/soc/codecs/tas571x.c
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/tlv320aic23-i2c.c
sound/soc/codecs/ts3a227e.c
sound/soc/codecs/tscs42xx.c
sound/soc/codecs/tscs454.c
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm_adsp.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_aud2htx.c [new file with mode: 0644]
sound/soc/fsl/fsl_aud2htx.h [new file with mode: 0644]
sound/soc/fsl/fsl_audmix.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_spdif.h
sound/soc/fsl/fsl_xcvr.c [new file with mode: 0644]
sound/soc/fsl/fsl_xcvr.h [new file with mode: 0644]
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-hdmi.c [new file with mode: 0644]
sound/soc/fsl/imx-mc13783.c [deleted file]
sound/soc/fsl/imx-ssi.c [deleted file]
sound/soc/fsl/mx27vis-aic32x4.c [deleted file]
sound/soc/fsl/phycore-ac97.c [deleted file]
sound/soc/fsl/wm1133-ev1.c [deleted file]
sound/soc/generic/Kconfig
sound/soc/generic/audio-graph-card.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-atom-controls.h
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bdw-rt5650.c
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/bytcht_cx2072x.c
sound/soc/intel/boards/bytcht_da7213.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_nau8824.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/sof_maxim_common.c
sound/soc/intel/boards/sof_realtek_common.c [new file with mode: 0644]
sound/soc/intel/boards/sof_realtek_common.h [new file with mode: 0644]
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/catpt/core.h
sound/soc/intel/catpt/device.c
sound/soc/intel/catpt/dsp.c
sound/soc/intel/catpt/loader.c
sound/soc/intel/catpt/pcm.c
sound/soc/intel/common/Makefile
sound/soc/intel/common/soc-acpi-intel-adl-match.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-cml-match.c
sound/soc/intel/common/soc-acpi-intel-tgl-match.c
sound/soc/intel/keembay/kmb_platform.c
sound/soc/intel/keembay/kmb_platform.h
sound/soc/intel/skylake/skl-topology.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/armada-370-db.c
sound/soc/mediatek/Kconfig
sound/soc/mediatek/Makefile
sound/soc/mediatek/common/mtk-afe-fe-dai.c
sound/soc/mediatek/common/mtk-base-afe.h
sound/soc/mediatek/common/mtk-btcvsd.c
sound/soc/mediatek/mt8183/mt8183-afe-clk.c
sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
sound/soc/mediatek/mt8192/Makefile [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-clk.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-clk.h [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-common.h [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-control.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-gpio.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-gpio.h [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-afe-pcm.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-dai-adda.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-dai-i2s.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-dai-pcm.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-dai-tdm.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-interconnection.h [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c [new file with mode: 0644]
sound/soc/mediatek/mt8192/mt8192-reg.h [new file with mode: 0644]
sound/soc/meson/Kconfig
sound/soc/meson/t9015.c
sound/soc/pxa/Kconfig
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/pxa-ssp.c
sound/soc/qcom/Kconfig
sound/soc/qcom/Makefile
sound/soc/qcom/apq8016_sbc.c
sound/soc/qcom/common.c
sound/soc/qcom/lpass-apq8016.c
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/lpass-hdmi.c
sound/soc/qcom/lpass-ipq806x.c
sound/soc/qcom/lpass-sc7180.c
sound/soc/qcom/lpass.h
sound/soc/qcom/qdsp6/q6adm.c
sound/soc/qcom/qdsp6/q6afe-clocks.c
sound/soc/qcom/qdsp6/q6afe.c
sound/soc/qcom/qdsp6/q6asm.c
sound/soc/qcom/sc7180.c [new file with mode: 0644]
sound/soc/qcom/sm8250.c [new file with mode: 0644]
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_pdm.c
sound/soc/rockchip/rockchip_spdif.c
sound/soc/samsung/i2s.c
sound/soc/samsung/midas_wm1811.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/snow.c
sound/soc/sh/Kconfig
sound/soc/soc-component.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dai.c
sound/soc/soc-dapm.c
sound/soc/soc-link.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/Kconfig
sound/soc/sof/control.c
sound/soc/sof/debug.c
sound/soc/sof/imx/Kconfig
sound/soc/sof/imx/imx-common.c
sound/soc/sof/intel/Kconfig
sound/soc/sof/intel/Makefile
sound/soc/sof/intel/apl.c
sound/soc/sof/intel/byt.c
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/ext_manifest.h [new file with mode: 0644]
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-pcm.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/hda.h
sound/soc/sof/intel/icl.c [new file with mode: 0644]
sound/soc/sof/intel/intel-ipc.c
sound/soc/sof/intel/tgl.c
sound/soc/sof/ipc.c
sound/soc/sof/loader.c
sound/soc/sof/nocodec.c
sound/soc/sof/ops.c
sound/soc/sof/ops.h
sound/soc/sof/pcm.c
sound/soc/sof/sof-acpi-dev.c
sound/soc/sof/sof-audio.c
sound/soc/sof/sof-audio.h
sound/soc/sof/sof-pci-dev.c
sound/soc/sof/sof-priv.h
sound/soc/sof/topology.c
sound/soc/sof/trace.c
sound/soc/stm/Kconfig
sound/soc/sunxi/Kconfig
sound/soc/sunxi/sun4i-i2s.c
sound/soc/sunxi/sun8i-codec.c
sound/soc/tegra/Kconfig
sound/soc/tegra/tegra186_dspk.c
sound/soc/tegra/tegra210_dmic.c
sound/soc/tegra/tegra210_i2s.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_max98090.c
sound/soc/tegra/tegra_rt5640.c
sound/soc/tegra/tegra_rt5677.c
sound/soc/tegra/tegra_sgtl5000.c
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/tegra_wm9712.c
sound/soc/tegra/trimslice.c
sound/soc/ti/Kconfig
sound/soc/ti/davinci-evm.c
sound/soc/ti/davinci-i2s.c
sound/soc/ti/davinci-mcasp.c
sound/soc/uniphier/aio-ld11.c
sound/soc/uniphier/aio-pxs2.c
sound/soc/uniphier/evea.c

index d61bc01..6f2398c 100644 (file)
@@ -199,8 +199,6 @@ patternProperties:
               description:
                 From common IIO binding. Used to pipe external sigma delta
                 modulator or internal ADC output to DFSDM channel.
-                This is not required for "st,stm32-dfsdm-pdm" compatibility as
-                PDM microphone is binded in Audio DT node.
 
           required:
             - io-channels
@@ -235,6 +233,10 @@ patternProperties:
               description: child node
 
               properties:
+                compatible:
+                  enum:
+                    - st,stm32h7-dfsdm-dai
+
                 "#sound-dai-cells":
                   const: 0
 
@@ -244,6 +246,7 @@ patternProperties:
                     modulator or internal ADC output to DFSDM channel.
 
               required:
+                - compatible
                 - "#sound-dai-cells"
                 - io-channels
 
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1372.yaml b/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
new file mode 100644 (file)
index 0000000..7014493
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/adi,adau1372.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+
+title: Analog Devices ADAU1372 CODEC
+
+maintainers:
+  - Alexandre Belloni <alexandre.belloni@bootlin.om>
+
+description: |
+  Analog Devices ADAU1372 four inputs and two outputs codec.
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1372.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,adau1372
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 0
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: "mclk"
+
+  powerdown-gpios:
+    description: GPIO used for hardware power-down.
+    maxItems: 1
+
+required:
+  - "#sound-dai-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        audio-codec@3c {
+                compatible = "adi,adau1372";
+                reg = <0x3c>;
+                #sound-dai-cells = <0>;
+                clock-names = "mclk";
+                clocks = <&adau1372z_xtal>;
+        };
+    };
+
+    adau1372z_xtal: clock {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <12288000>;
+    };
+...
+
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.txt b/Documentation/devicetree/bindings/sound/adi,adau1977.txt
deleted file mode 100644 (file)
index 37f8aad..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-Analog Devices ADAU1977/ADAU1978/ADAU1979
-
-Datasheets:
-https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf
-https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf
-https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf
-
-This driver supports both the I2C and SPI bus.
-
-Required properties:
- - compatible: Should contain one of the following:
-               "adi,adau1977"
-               "adi,adau1978"
-               "adi,adau1979"
-
- - AVDD-supply: analog power supply for the device, please consult
-                Documentation/devicetree/bindings/regulator/regulator.txt
-
-Optional properties:
- - reset-gpios: the reset pin for the chip, for more details consult
-                Documentation/devicetree/bindings/gpio/gpio.txt
-
- - DVDD-supply: supply voltage for the digital core, please consult
-                Documentation/devicetree/bindings/regulator/regulator.txt
-
-- adi,micbias: configures the voltage setting for the MICBIAS pin.
-               Select 0/1/2/3/4/5/6/7/8 to specify MICBIAS voltage
-               5V/5.5V/6V/6.5V/7V/7.5V/8V/8.5V/9V
-               If not specified the default value will be "7" meaning 8.5 Volts.
-               This property is only valid for the ADAU1977
-
-For required properties on SPI, please consult
-Documentation/devicetree/bindings/spi/spi-bus.txt
-
-Required properties on I2C:
-
- - reg:         The i2c address. Value depends on the state of ADDR0
-                and ADDR1, as wired in hardware.
-
-Examples:
-
-       adau1977_spi: adau1977@0 {
-               compatible = "adi,adau1977";
-               spi-max-frequency = <600000>;
-
-               AVDD-supply = <&regulator>;
-               DVDD-supply = <&regulator_digital>;
-
-               adi,micbias = <3>;
-               reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
-       };
-
-       adau1977_i2c: adau1977@11 {
-               compatible = "adi,adau1977";
-               reg = <0x11>;
-
-               AVDD-supply = <&regulator>;
-               DVDD-supply = <&regulator_digital>;
-
-               reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
-       };
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.yaml b/Documentation/devicetree/bindings/sound/adi,adau1977.yaml
new file mode 100644 (file)
index 0000000..b80454a
--- /dev/null
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/adi,adau1977.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADAU1977/ADAU1978/ADAU1979 Quad ADC with Diagnostics
+
+maintainers:
+  - Lars-Peter Clausen <lars@metafoo.de>
+  - Bogdan Togorean <bogdan.togorean@analog.com>
+
+description: |
+  Analog Devices ADAU1977 and similar quad ADC with Diagnostics
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,adau1977
+      - adi,adau1978
+      - adi,adau1979
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 0
+
+  reset-gpios:
+    maxItems: 1
+
+  spi-max-frequency: true
+
+  AVDD-supply:
+    description: Analog power support for the device.
+
+  DVDD-supply:
+    description: Supply voltage for digital core.
+
+  adi,micbias:
+    description: |
+      Configures the voltage setting for the MICBIAS pin.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1, 2, 3, 4, 5, 6, 7, 8]
+    default: 7
+
+required:
+  - reg
+  - compatible
+  - AVDD-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        adau1977_spi: adau1977@0 {
+            compatible = "adi,adau1977";
+            reg = <0>;
+            spi-max-frequency = <600000>;
+
+            AVDD-supply = <&regulator>;
+            DVDD-supply = <&regulator_digital>;
+
+            reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
+
+            adi,micbias = <3>;
+        };
+    };
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        adau1977_i2c: adau1977@11 {
+            compatible = "adi,adau1977";
+            reg = <0x11>;
+
+            AVDD-supply = <&regulator>;
+            DVDD-supply = <&regulator_digital>;
+
+            reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
+        };
+    };
index 112ae00..a16e37b 100644 (file)
@@ -24,6 +24,7 @@ properties:
       - items:
           - const: allwinner,sun50i-a64-i2s
           - const: allwinner,sun8i-h3-i2s
+      - const: allwinner,sun50i-h6-i2s
 
   reg:
     maxItems: 1
@@ -59,6 +60,7 @@ allOf:
               - allwinner,sun8i-a83t-i2s
               - allwinner,sun8i-h3-i2s
               - allwinner,sun50i-a64-codec-i2s
+              - allwinner,sun50i-h6-i2s
 
     then:
       required:
@@ -68,7 +70,9 @@ allOf:
       properties:
         compatible:
           contains:
-            const: allwinner,sun8i-a83t-i2s
+            enum:
+              - allwinner,sun8i-a83t-i2s
+              - allwinner,sun8i-h3-i2s
 
     then:
       properties:
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-card.txt
deleted file mode 100644 (file)
index d5f6919..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-Audio Graph Card:
-
-Audio Graph Card specifies audio DAI connections of SoC <-> codec.
-It is based on common bindings for device graphs.
-see ${LINUX}/Documentation/devicetree/bindings/graph.txt
-
-Basically, Audio Graph Card property is same as Simple Card.
-see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.yaml
-
-Below are same as Simple-Card.
-
-- label
-- widgets
-- routing
-- dai-format
-- frame-master
-- bitclock-master
-- bitclock-inversion
-- frame-inversion
-- mclk-fs
-- hp-det-gpio
-- mic-det-gpio
-- dai-tdm-slot-num
-- dai-tdm-slot-width
-- clocks / system-clock-frequency
-
-Required properties:
-
-- compatible                           : "audio-graph-card";
-- dais                                 : list of CPU DAI port{s}
-
-Optional properties:
-- pa-gpios: GPIO used to control external amplifier.
-
------------------------
-Example: Single DAI case
------------------------
-
-       sound_card {
-               compatible = "audio-graph-card";
-
-               dais = <&cpu_port>;
-       };
-
-       dai-controller {
-               ...
-               cpu_port: port {
-                       cpu_endpoint: endpoint {
-                               remote-endpoint = <&codec_endpoint>;
-
-                               dai-format = "left_j";
-                               ...
-                       };
-               };
-       };
-
-       audio-codec {
-               ...
-               port {
-                       codec_endpoint: endpoint {
-                               remote-endpoint = <&cpu_endpoint>;
-                       };
-               };
-       };
-
------------------------
-Example: Multi DAI case
------------------------
-
-       sound-card {
-               compatible = "audio-graph-card";
-
-               label = "sound-card";
-
-               dais = <&cpu_port0
-                       &cpu_port1
-                       &cpu_port2>;
-       };
-
-       audio-codec@0 {
-               ...
-               port {
-                       codec0_endpoint: endpoint {
-                               remote-endpoint = <&cpu_endpoint0>;
-                       };
-               };
-       };
-
-       audio-codec@1 {
-               ...
-               port {
-                       codec1_endpoint: endpoint {
-                               remote-endpoint = <&cpu_endpoint1>;
-                       };
-               };
-       };
-
-       audio-codec@2 {
-               ...
-               port {
-                       codec2_endpoint: endpoint {
-                               remote-endpoint = <&cpu_endpoint2>;
-                       };
-               };
-       };
-
-       dai-controller {
-               ...
-               ports {
-                       cpu_port0: port@0 {
-                               cpu_endpoint0: endpoint {
-                                       remote-endpoint = <&codec0_endpoint>;
-
-                                       dai-format = "left_j";
-                                       ...
-                               };
-                       };
-                       cpu_port1: port@1 {
-                               cpu_endpoint1: endpoint {
-                                       remote-endpoint = <&codec1_endpoint>;
-
-                                       dai-format = "i2s";
-                                       ...
-                               };
-                       };
-                       cpu_port2: port@2 {
-                               cpu_endpoint2: endpoint {
-                                       remote-endpoint = <&codec2_endpoint>;
-
-                                       dai-format = "i2s";
-                                       ...
-                               };
-                       };
-               };
-       };
-
-
------------------------
-Example: Sampling Rate Conversion
------------------------
-
-       sound_card {
-               compatible = "audio-graph-card";
-
-               label = "sound-card";
-               prefix = "codec";
-               routing = "codec Playback", "DAI0 Playback",
-                         "DAI0 Capture",   "codec Capture";
-               convert-rate = <48000>;
-
-               dais = <&cpu_port>;
-       };
-
-       audio-codec {
-               ...
-               port {
-                       codec_endpoint: endpoint {
-                               remote-endpoint = <&cpu_endpoint>;
-                       };
-               };
-       };
-
-       dai-controller {
-               ...
-               cpu_port: port {
-                       cpu_endpoint: endpoint {
-                               remote-endpoint = <&codec_endpoint>;
-
-                               dai-format = "left_j";
-                               ...
-                       };
-               };
-       };
-
------------------------
-Example: 2 CPU 1 Codec (Mixing)
------------------------
-
-       sound_card {
-               compatible = "audio-graph-card";
-
-               label = "sound-card";
-               routing = "codec Playback", "DAI0 Playback",
-                         "codec Playback", "DAI1 Playback",
-                         "DAI0 Capture",   "codec Capture";
-
-               dais = <&cpu_port>;
-       };
-
-       audio-codec {
-               ...
-
-               audio-graph-card,prefix = "codec";
-               audio-graph-card,convert-rate = <48000>;
-               port {
-                       reg = <0>;
-                       codec_endpoint0: endpoint@0 {
-                               remote-endpoint = <&cpu_endpoint0>;
-                       };
-                       codec_endpoint1: endpoint@1 {
-                               remote-endpoint = <&cpu_endpoint1>;
-                       };
-               };
-       };
-
-       dai-controller {
-               ...
-               cpu_port: port {
-                       cpu_endpoint0: endpoint@0 {
-                               remote-endpoint = <&codec_endpoint0>;
-
-                               dai-format = "left_j";
-                               ...
-                       };
-                       cpu_endpoint1: endpoint@1 {
-                               remote-endpoint = <&codec_endpoint1>;
-
-                               dai-format = "left_j";
-                               ...
-                       };
-               };
-       };
-
------------------------
-Example: Multi DAI with DPCM
------------------------
-
-       CPU0 ------ ak4613
-       CPU1 ------ HDMI
-       CPU2 ------ PCM3168A-p  /* DPCM 1ch/2ch */
-       CPU3 --/                /* DPCM 3ch/4ch */
-       CPU4 --/                /* DPCM 5ch/6ch */
-       CPU5 --/                /* DPCM 7ch/8ch */
-       CPU6 ------ PCM3168A-c
-
-       sound_card: sound {
-               compatible = "audio-graph-card";
-
-               label = "sound-card";
-
-               routing =       "pcm3168a Playback", "DAI2 Playback",
-                               "pcm3168a Playback", "DAI3 Playback",
-                               "pcm3168a Playback", "DAI4 Playback",
-                               "pcm3168a Playback", "DAI5 Playback";
-
-               dais = <&snd_port0      /* ak4613 */
-                       &snd_port1      /* HDMI0  */
-                       &snd_port2      /* pcm3168a playback */
-                       &snd_port3      /* pcm3168a capture  */
-                       >;
-       };
-
-       ak4613: codec@10 {
-               ...
-               port {
-                       ak4613_endpoint: endpoint {
-                               remote-endpoint = <&rsnd_endpoint0>;
-                       };
-               };
-       };
-
-       pcm3168a: audio-codec@44 {
-               ...
-               audio-graph-card,prefix = "pcm3168a";
-               audio-graph-card,convert-channels = <8>; /* TDM Split */
-               ports {
-                       port@0 {
-                               reg = <0>;
-                               pcm3168a_endpoint_p1: endpoint@1 {
-                                       remote-endpoint = <&rsnd_endpoint2>;
-                                       ...
-                               };
-                               pcm3168a_endpoint_p2: endpoint@2 {
-                                       remote-endpoint = <&rsnd_endpoint3>;
-                                       ...
-                               };
-                               pcm3168a_endpoint_p3: endpoint@3 {
-                                       remote-endpoint = <&rsnd_endpoint4>;
-                                       ...
-                               };
-                               pcm3168a_endpoint_p4: endpoint@4 {
-                                       remote-endpoint = <&rsnd_endpoint5>;
-                                       ...
-                               };
-                       };
-                       port@1 {
-                               reg = <1>;
-                               pcm3168a_endpoint_c: endpoint {
-                                       remote-endpoint = <&rsnd_endpoint6>;
-                                       ...
-                               };
-                       };
-               };
-       };
-
-       &sound {
-               ports {
-                       snd_port0: port@0 {
-                               rsnd_endpoint0: endpoint {
-                                       remote-endpoint = <&ak4613_endpoint>;
-                                       ...
-                               };
-                       };
-                       snd_port1: port@1 {
-                               rsnd_endpoint1: endpoint {
-                                       remote-endpoint = <&dw_hdmi0_snd_in>;
-                                       ...
-                               };
-                       };
-                       snd_port2: port@2 {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               rsnd_endpoint2: endpoint@2 {
-                                       remote-endpoint = <&pcm3168a_endpoint_p1>;
-                                       ...
-                               };
-                               rsnd_endpoint3: endpoint@3 {
-                                       remote-endpoint = <&pcm3168a_endpoint_p2>;
-                                       ...
-                               };
-                               rsnd_endpoint4: endpoint@4 {
-                                       remote-endpoint = <&pcm3168a_endpoint_p3>;
-                                       ...
-                               };
-                               rsnd_endpoint5: endpoint@5 {
-                                       remote-endpoint = <&pcm3168a_endpoint_p4>;
-                                       ...
-                               };
-                       };
-                       snd_port3: port@6 {
-                               rsnd_endpoint6: endpoint {
-                                       remote-endpoint = <&pcm3168a_endpoint_c>;
-                                       ...
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/audio-graph-card.yaml
new file mode 100644 (file)
index 0000000..109e55f
--- /dev/null
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/audio-graph-card.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio Graph Card Device Tree Bindings
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+allOf:
+  - $ref: /schemas/sound/audio-graph.yaml#
+
+properties:
+  compatible:
+    enum:
+      - audio-graph-card
+      - audio-graph-scu-card
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    sound {
+        compatible = "audio-graph-card";
+
+        dais = <&cpu_port_a>;
+    };
+
+    cpu {
+        /*
+         * dai-controller own settings
+         */
+
+        port {
+            cpu_endpoint: endpoint {
+                remote-endpoint = <&codec_endpoint>;
+                dai-format = "left_j";
+            };
+        };
+    };
+
+    codec {
+        /*
+         * codec own settings
+         */
+
+        port {
+            codec_endpoint: endpoint {
+                remote-endpoint = <&cpu_endpoint>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
new file mode 100644 (file)
index 0000000..2005014
--- /dev/null
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/audio-graph-port.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio Graph Card 'port' Node Bindings
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+select: false
+
+properties:
+  port:
+    description: single OF-Graph subnode
+    type: object
+    properties:
+      reg:
+        maxItems: 1
+      prefix:
+        description: "device name prefix"
+        $ref: /schemas/types.yaml#/definitions/string
+      convert-rate:
+        description: CPU to Codec rate convert.
+        $ref: /schemas/types.yaml#/definitions/uint32
+      convert-channels:
+        description: CPU to Codec rate channels.
+        $ref: /schemas/types.yaml#/definitions/uint32
+    patternProperties:
+      "^endpoint(@[0-9a-f]+)?":
+        type: object
+        properties:
+          remote-endpoint:
+            maxItems: 1
+          mclk-fs:
+            description: |
+              Multiplication factor between stream rate and codec mclk.
+              When defined, mclk-fs property defined in dai-link sub nodes are
+              ignored.
+            $ref: /schemas/types.yaml#/definitions/uint32
+          frame-inversion:
+            description: dai-link uses frame clock inversion
+            $ref: /schemas/types.yaml#/definitions/flag
+          bitclock-inversion:
+            description: dai-link uses bit clock inversion
+            $ref: /schemas/types.yaml#/definitions/flag
+          frame-master:
+            description: Indicates dai-link frame master.
+            $ref: /schemas/types.yaml#/definitions/phandle
+          bitclock-master:
+            description: Indicates dai-link bit clock master
+            $ref: /schemas/types.yaml#/definitions/phandle
+          dai-format:
+            description: audio format.
+            items:
+              enum:
+                - i2s
+                - right_j
+                - left_j
+                - dsp_a
+                - dsp_b
+                - ac97
+                - pdm
+                - msb
+                - lsb
+          convert-rate:
+            description: CPU to Codec rate convert.
+            $ref: /schemas/types.yaml#/definitions/uint32
+          convert-channels:
+            description: CPU to Codec rate channels.
+            $ref: /schemas/types.yaml#/definitions/uint32
+
+        required:
+          - remote-endpoint
+
+  ports:
+    description: multi OF-Graph subnode
+    type: object
+    patternProperties:
+      "^port(@[0-9a-f]+)?":
+        $ref: "#/properties/port"
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml
new file mode 100644 (file)
index 0000000..4b46794
--- /dev/null
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/audio-graph.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio Graph Device Tree Bindings
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+properties:
+  dais:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+  label:
+    maxItems: 1
+  prefix:
+    description: "device name prefix"
+    $ref: /schemas/types.yaml#/definitions/string
+  routing:
+    description: |
+      A list of the connections between audio components.
+      Each entry is a pair of strings, the first being the
+      connection's sink, the second being the connection's source.
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+  widgets:
+    description: User specified audio sound widgets.
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+  convert-rate:
+    description: CPU to Codec rate convert.
+    $ref: /schemas/types.yaml#/definitions/uint32
+  convert-channels:
+    description: CPU to Codec rate channels.
+    $ref: /schemas/types.yaml#/definitions/uint32
+  pa-gpios:
+    maxItems: 1
+  hp-det-gpio:
+    maxItems: 1
+  mic-det-gpio:
+    maxItems: 1
+
+required:
+  - dais
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/sound/fsl,aud2htx.yaml b/Documentation/devicetree/bindings/sound/fsl,aud2htx.yaml
new file mode 100644 (file)
index 0000000..aa4be71
--- /dev/null
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,aud2htx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Audio Subsystem to HDMI RTX Subsystem Controller
+
+maintainers:
+  - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+properties:
+  compatible:
+    const: fsl,imx8mp-aud2htx
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Peripheral clock
+
+  clock-names:
+    items:
+      - const: bus
+
+  dmas:
+    items:
+      - description: DMA controller phandle and request line for TX
+
+  dma-names:
+    items:
+      - const: tx
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - dmas
+  - dma-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/imx8mp-clock.h>
+
+    aud2htx: aud2htx@30cb0000 {
+        compatible = "fsl,imx8mp-aud2htx";
+        reg = <0x30cb0000 0x10000>;
+        interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&audiomix_clk IMX8MP_CLK_AUDIOMIX_AUD2HTX_IPG>;
+        clock-names = "bus";
+        dmas = <&sdma2 26 2 0>;
+        dma-names = "tx";
+        power-domains = <&audiomix_pd>;
+    };
index 2ac671f..50449b6 100644 (file)
@@ -20,6 +20,7 @@ properties:
       - fsl,imx35-spdif
       - fsl,vf610-spdif
       - fsl,imx6sx-spdif
+      - fsl,imx8qm-spdif
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
new file mode 100644 (file)
index 0000000..223b8ea
--- /dev/null
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,xcvr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Audio Transceiver (XCVR) Controller
+
+maintainers:
+  - Viorel Suman <viorel.suman@nxp.com>
+
+description: |
+  NXP XCVR (Audio Transceiver) is a on-chip functional module
+  that allows CPU to receive and transmit digital audio via
+  HDMI2.1 eARC, HDMI1.4 ARC and SPDIF.
+
+properties:
+  $nodename:
+    pattern: "^xcvr@.*"
+
+  compatible:
+    enum:
+      - fsl,imx8mp-xcvr
+
+  reg:
+    items:
+      - description: 20K RAM for code and data
+      - description: registers space
+      - description: RX FIFO address
+      - description: TX FIFO address
+
+  reg-names:
+    items:
+      - const: ram
+      - const: regs
+      - const: rxfifo
+      - const: txfifo
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Peripheral clock
+      - description: PHY clock
+      - description: SPBA clock
+      - description: PLL clock
+
+  clock-names:
+    items:
+      - const: ipg
+      - const: phy
+      - const: spba
+      - const: pll_ipg
+
+  dmas:
+    items:
+      - description: DMA controller phandle and request line for RX
+      - description: DMA controller phandle and request line for TX
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - clocks
+  - clock-names
+  - dmas
+  - dma-names
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/imx8mp-clock.h>
+    #include <dt-bindings/reset/imx8mp-reset.h>
+
+    xcvr: xcvr@30cc0000 {
+           compatible = "fsl,imx8mp-xcvr";
+           reg = <0x30cc0000 0x800>,
+                 <0x30cc0800 0x400>,
+                 <0x30cc0c00 0x080>,
+                 <0x30cc0e00 0x080>;
+           reg-names = "ram", "regs", "rxfifo", "txfifo";
+           interrupts = <0x0 128 IRQ_TYPE_LEVEL_HIGH>;
+           clocks = <&audiomix_clk IMX8MP_CLK_AUDIOMIX_EARC_IPG>,
+                    <&audiomix_clk IMX8MP_CLK_AUDIOMIX_EARC_PHY>,
+                    <&audiomix_clk IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT>,
+                    <&audiomix_clk IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT>;
+           clock-names = "ipg", "phy", "spba", "pll_ipg";
+           dmas = <&sdma2 30 2 0>, <&sdma2 31 2 0>;
+           dma-names = "rx", "tx";
+           resets = <&audiomix_reset 0>;
+    };
index f339be6..90d9e9d 100644 (file)
@@ -40,6 +40,8 @@ The compatible list for this generic sound card currently:
 
  "fsl,imx-audio-tlv320aic32x4"
 
+ "fsl,imx-audio-si476x"
+
 Required properties:
 
   - compatible         : Contains one of entries in the compatible list.
diff --git a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml
new file mode 100644 (file)
index 0000000..5095b78
--- /dev/null
@@ -0,0 +1,138 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/google,sc7180-trogdor.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google SC7180-Trogdor ASoC sound card driver
+
+maintainers:
+  - Rohit kumar <rohitkr@codeaurora.org>
+  - Cheng-Yi Chiang <cychiang@chromium.org>
+
+description:
+  This binding describes the SC7180 sound card which uses LPASS for audio.
+
+properties:
+  compatible:
+    enum:
+      - google,sc7180-trogdor
+      - google,sc7180-coachz
+
+  audio-routing:
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    description:
+      A list of the connections between audio components. Each entry is a
+      pair of strings, the first being the connection's sink, the second
+      being the connection's source.
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: User specified audio sound card name
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  dmic-gpios:
+    maxItems: 1
+    description: GPIO for switching between DMICs
+
+patternProperties:
+  "^dai-link(@[0-9])?$":
+    description:
+      Each subnode represents a dai link. Subnodes of each dai links would be
+      cpu/codec dais.
+
+    type: object
+
+    properties:
+      link-name:
+        description: Indicates dai-link name and PCM stream name.
+        $ref: /schemas/types.yaml#/definitions/string
+        maxItems: 1
+
+      reg:
+        description: dai link address.
+
+      cpu:
+        description: Holds subnode which indicates cpu dai.
+        type: object
+        properties:
+          sound-dai: true
+
+      codec:
+        description: Holds subnode which indicates codec dai.
+        type: object
+        properties:
+          sound-dai: true
+
+    required:
+      - link-name
+      - cpu
+      - codec
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - model
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
+
+examples:
+
+  - |
+    sound {
+        compatible = "google,sc7180-trogdor";
+        model = "sc7180-rt5682-max98357a-2mic";
+
+        audio-routing =
+                    "Headphone Jack", "HPOL",
+                    "Headphone Jack", "HPOR";
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        dmic-gpios = <&tlmm 86 0>;
+
+        dai-link@0 {
+            link-name = "MultiMedia0";
+            reg = <0>;
+            cpu {
+                sound-dai = <&lpass_cpu 0>;
+            };
+
+            codec {
+                sound-dai = <&alc5682 0>;
+            };
+        };
+
+        dai-link@1 {
+            link-name = "MultiMedia1";
+            reg = <1>;
+            cpu {
+                sound-dai = <&lpass_cpu 1>;
+            };
+
+            codec {
+                sound-dai = <&max98357a>;
+            };
+        };
+
+        dai-link@2 {
+            link-name = "MultiMedia2";
+            reg = <2>;
+            cpu {
+                sound-dai = <&lpass_hdmi 0>;
+            };
+
+            codec {
+                sound-dai = <&msm_dp>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-hdmi.yaml b/Documentation/devicetree/bindings/sound/imx-audio-hdmi.yaml
new file mode 100644 (file)
index 0000000..d5474f8
--- /dev/null
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/imx-audio-hdmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX audio complex with HDMI
+
+maintainers:
+  - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx-audio-hdmi
+      - fsl,imx-audio-sii902x
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: User specified audio sound card name
+
+  audio-cpu:
+    description: The phandle of an CPU DAI controller
+
+  hdmi-out:
+    description: |
+      This is a boolean property. If present, the transmitting function
+      of HDMI will be enabled, indicating there's a physical HDMI out
+      connector or jack on the board or it's connecting to some other IP
+      block, such as an HDMI encoder or display-controller.
+
+  hdmi-in:
+    description: |
+      This is a boolean property. If present, the receiving function of
+      HDMI will be enabled, indicating there is a physical HDMI in
+      connector/jack on the board.
+
+required:
+  - compatible
+  - model
+  - audio-cpu
+
+additionalProperties: false
+
+examples:
+  - |
+    sound-hdmi {
+        compatible = "fsl,imx-audio-hdmi";
+        model = "audio-hdmi";
+        audio-cpu = <&aud2htx>;
+        hdmi-out;
+    };
index 6d20a24..234f64a 100644 (file)
@@ -9,6 +9,9 @@ title: Marvel SSPA Digital Audio Interface Bindings
 maintainers:
   - Lubomir Rintel <lkundrak@v3.sk>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^audio-controller(@.*)?$"
@@ -58,29 +61,9 @@ properties:
         type: object
 
         properties:
-          remote-endpoint: true
-
-          frame-master:
-            type: boolean
-            description: SoC generates the frame clock
-
-          bitclock-master:
-            type: boolean
-            description: SoC generates the bit clock
-
           dai-format:
-            $ref: /schemas/types.yaml#/definitions/string
-            description: The digital audio format
             const: i2s
 
-        required:
-          - remote-endpoint
-
-    required:
-      - endpoint
-
-    additionalProperties: false
-
 required:
   - "#sound-dai-cells"
   - compatible
@@ -112,8 +95,6 @@ examples:
       port {
         endpoint {
           remote-endpoint = <&rt5631_0>;
-          frame-master;
-          bitclock-master;
           dai-format = "i2s";
         };
       };
diff --git a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
new file mode 100644 (file)
index 0000000..bf8c8ba
--- /dev/null
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8192-mt6359-rt1015-rt5682.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT8192 with MT6359, RT1015 and RT5682 ASoC sound card driver
+
+maintainers:
+   - Jiaxin Yu <jiaxin.yu@mediatek.com>
+   - Shane Chien <shane.chien@mediatek.com>
+
+description:
+  This binding describes the MT8192 sound card.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8192_mt6359_rt1015_rt5682
+      - mediatek,mt8192_mt6359_rt1015p_rt5682
+
+  mediatek,platform:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of MT8192 ASoC platform.
+
+additionalProperties: false
+
+required:
+  - compatible
+  - mediatek,platform
+
+examples:
+  - |
+
+    sound: mt8192-sound {
+        compatible = "mediatek,mt8192_mt6359_rt1015_rt5682";
+        mediatek,platform = <&afe>;
+        pinctrl-names = "aud_clk_mosi_off",
+                        "aud_clk_mosi_on";
+        pinctrl-0 = <&aud_clk_mosi_off>;
+        pinctrl-1 = <&aud_clk_mosi_on>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nau8315.txt b/Documentation/devicetree/bindings/sound/nau8315.txt
new file mode 100644 (file)
index 0000000..6eaec46
--- /dev/null
@@ -0,0 +1,18 @@
+Nuvoton NAU8315 Mono Class-D Amplifier
+
+Required properties:
+- compatible   : "nuvoton,nau8315"
+
+Optional properties:
+- enable-gpios : GPIO specifier for the chip's device enable input(EN) pin.
+        If this option is not specified then driver does not manage
+        the pin state (e.g. chip is always on).
+
+Example:
+
+#include <dt-bindings/gpio/gpio.h>
+
+nau8315 {
+       compatible = "nuvoton,nau8315";
+       enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt
deleted file mode 100644 (file)
index 21cd310..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-NVIDIA Tegra30 HDA controller
-
-Required properties:
-- compatible : For Tegra30, must contain "nvidia,tegra30-hda".  Otherwise,
-  must contain '"nvidia,<chip>-hda", "nvidia,tegra30-hda"', where <chip> is
-  tegra114, tegra124, or tegra132.
-- reg : Should contain the HDA registers location and length.
-- interrupts : The interrupt from the HDA controller.
-- clocks : Must contain an entry for each required entry in clock-names.
-  See ../clocks/clock-bindings.txt for details.
-- clock-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x
-- resets : Must contain an entry for each entry in reset-names.
-  See ../reset/reset.txt for details.
-- reset-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x
-
-Optional properties:
-- nvidia,model : The user-visible name of this sound complex. Since the property
-  is optional, legacy boards can use default name provided in hda driver.
-
-Example:
-
-hda@70030000 {
-       compatible = "nvidia,tegra124-hda", "nvidia,tegra30-hda";
-       reg = <0x0 0x70030000 0x0 0x10000>;
-       interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
-       clocks = <&tegra_car TEGRA124_CLK_HDA>,
-                <&tegra_car TEGRA124_CLK_HDA2HDMI>,
-                <&tegra_car TEGRA124_CLK_HDA2CODEC_2X>;
-       clock-names = "hda", "hda2hdmi", "hda2codec_2x";
-       resets = <&tegra_car 125>, /* hda */
-                <&tegra_car 128>, /* hda2hdmi */
-                <&tegra_car 111>; /* hda2codec_2x */
-       reset-names = "hda", "hda2hdmi", "hda2codec_2x";
-       nvidia,model = "jetson-tk1-hda";
-};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.yaml
new file mode 100644 (file)
index 0000000..e543a61
--- /dev/null
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra30-hda.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra HDA controller
+
+description: |
+  The High Definition Audio (HDA) block provides a serial interface to
+  audio codec. It supports multiple input and output streams.
+
+maintainers:
+  - Thierry Reding <treding@nvidia.com>
+  - Jon Hunter <jonathanh@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^hda@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra30-hda
+      - items:
+          - enum:
+              - nvidia,tegra194-hda
+              - nvidia,tegra186-hda
+              - nvidia,tegra210-hda
+              - nvidia,tegra124-hda
+          - const: nvidia,tegra30-hda
+      - items:
+          - const: nvidia,tegra132-hda
+          - const: nvidia,tegra124-hda
+          - const: nvidia,tegra30-hda
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: The interrupt from the HDA controller
+    maxItems: 1
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    maxItems: 3
+    items:
+      - const: hda
+      - const: hda2hdmi
+      - const: hda2codec_2x
+
+  resets:
+    maxItems: 3
+
+  reset-names:
+    maxItems: 3
+    items:
+      - const: hda
+      - const: hda2hdmi
+      - const: hda2codec_2x
+
+  power-domains:
+    maxItems: 1
+
+  interconnects:
+    maxItems: 2
+
+  interconnect-names:
+    items:
+      - const: dma-mem
+      - const: write
+
+  iommus:
+    maxItems: 1
+
+  nvidia,model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: |
+      The user-visible name of this sound complex. If this property is
+      not specified then boards can use default name provided in hda driver.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra124-car-common.h>
+    #include<dt-bindings/interrupt-controller/arm-gic.h>
+
+    hda@70030000 {
+        compatible = "nvidia,tegra124-hda", "nvidia,tegra30-hda";
+        reg = <0x70030000 0x10000>;
+        interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&tegra_car TEGRA124_CLK_HDA>,
+                 <&tegra_car TEGRA124_CLK_HDA2HDMI>,
+                 <&tegra_car TEGRA124_CLK_HDA2CODEC_2X>;
+        clock-names = "hda", "hda2hdmi", "hda2codec_2x";
+        resets = <&tegra_car 125>, /* hda */
+                 <&tegra_car 128>, /* hda2hdmi */
+                 <&tegra_car 111>; /* hda2codec_2x */
+        reset-names = "hda", "hda2hdmi", "hda2codec_2x";
+        nvidia,model = "jetson-tk1-hda";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
new file mode 100644 (file)
index 0000000..679b49c
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,lpass-va-macro.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPASS(Low Power Audio Subsystem) VA Macro audio codec DT bindings
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-va-macro
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  '#clock-cells':
+    const: 0
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: mclk
+      - const: core
+      - const: dcodec
+
+  clock-output-names:
+    items:
+      - const: fsgen
+
+  qcom,dmic-sample-rate:
+    description: dmic sample rate
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  vdd-micb-supply:
+    description: phandle to voltage regulator of MIC Bias
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    codec@3370000 {
+      compatible = "qcom,sm8250-lpass-va-macro";
+      reg = <0x3370000 0x1000>;
+      #sound-dai-cells = <1>;
+      #clock-cells = <0>;
+      clocks = <&aoncc 0>,
+               <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+      clock-names = "mclk", "core", "dcodec";
+      clock-output-names = "fsgen";
+      qcom,dmic-sample-rate = <600000>;
+      vdd-micb-supply = <&vreg_s4a_1p8>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
new file mode 100644 (file)
index 0000000..435b019
--- /dev/null
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,lpass-wsa-macro.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPASS(Low Power Audio Subsystem) VA Macro audio codec DT bindings
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-wsa-macro
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  '#clock-cells':
+    const: 0
+
+  clocks:
+    maxItems: 5
+
+  clock-names:
+    items:
+      - const: mclk
+      - const: npl
+      - const: macro
+      - const: dcodec
+      - const: fsgen
+
+  clock-output-names:
+    items:
+      - const: mclk
+
+  qcom,dmic-sample-rate:
+    description: dmic sample rate
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  vdd-micb-supply:
+    description: phandle to voltage regulator of MIC Bias
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    codec@3240000 {
+      compatible = "qcom,sm8250-lpass-wsa-macro";
+      reg = <0x3240000 0x1000>;
+      #sound-dai-cells = <1>;
+      #clock-cells = <0>;
+      clocks = <&audiocc 1>,
+               <&audiocc 0>,
+               <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&vamacro>;
+      clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+      clock-output-names = "mclk";
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
new file mode 100644 (file)
index 0000000..72ad9ab
--- /dev/null
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,sm8250.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies Inc. SM8250 ASoC sound card driver
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+  This bindings describes SC8250 SoC based sound cards
+  which uses LPASS internal codec for audio.
+
+properties:
+  compatible:
+    oneOf:
+      - const: qcom,sm8250-sndcard
+      - const: qcom,qrb5165-rb5-sndcard
+
+  audio-routing:
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    description:
+      A list of the connections between audio components. Each entry is a
+      pair of strings, the first being the connection's sink, the second
+      being the connection's source. Valid names could be power supplies,
+      MicBias of codec and the jacks on the board.
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: User visible long sound card name
+
+patternProperties:
+  ".*-dai-link$":
+    description:
+      Each subnode represents a dai link. Subnodes of each dai links would be
+      cpu/codec dais.
+
+    type: object
+
+    properties:
+      link-name:
+        description: Indicates dai-link name and PCM stream name.
+        $ref: /schemas/types.yaml#/definitions/string
+        maxItems: 1
+
+      cpu:
+        description: Holds subnode which indicates cpu dai.
+        type: object
+        properties:
+          sound-dai: true
+
+      platform:
+        description: Holds subnode which indicates platform dai.
+        type: object
+        properties:
+          sound-dai: true
+
+      codec:
+        description: Holds subnode which indicates codec dai.
+        type: object
+        properties:
+          sound-dai: true
+
+    required:
+      - link-name
+      - cpu
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - model
+
+additionalProperties: false
+
+examples:
+
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    #include <dt-bindings/sound/qcom,q6asm.h>
+    sound {
+        compatible = "qcom,qrb5165-rb5-sndcard";
+        model = "Qualcomm-qrb5165-RB5-WSA8815-Speakers-DMIC0";
+        audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT",
+                    "SpkrRight IN", "WSA_SPK2 OUT",
+                    "VA DMIC0", "vdd-micb",
+                    "VA DMIC1", "vdd-micb",
+                    "MM_DL1",  "MultiMedia1 Playback",
+                    "MM_DL2",  "MultiMedia2 Playback",
+                    "MultiMedia3 Capture", "MM_UL3";
+
+        mm1-dai-link {
+            link-name = "MultiMedia0";
+            cpu {
+                sound-dai = <&q6asmdai  MSM_FRONTEND_DAI_MULTIMEDIA1>;
+            };
+        };
+
+        mm2-dai-link {
+            link-name = "MultiMedia2";
+            cpu {
+                sound-dai = <&q6asmdai  MSM_FRONTEND_DAI_MULTIMEDIA2>;
+            };
+        };
+
+        mm3-dai-link {
+            link-name = "MultiMedia3";
+            cpu {
+                sound-dai = <&q6asmdai  MSM_FRONTEND_DAI_MULTIMEDIA3>;
+            };
+        };
+
+        hdmi-dai-link {
+            link-name = "HDMI Playback";
+            cpu {
+                sound-dai = <&q6afedai TERTIARY_MI2S_RX>;
+            };
+
+            platform {
+                sound-dai = <&q6routing>;
+            };
+
+            codec {
+                sound-dai = <&lt9611_codec 0>;
+            };
+        };
+
+        wsa-dai-link {
+            link-name = "WSA Playback";
+            cpu {
+                sound-dai = <&q6afedai WSA_CODEC_DMA_RX_0>;
+            };
+
+            platform {
+                sound-dai = <&q6routing>;
+            };
+
+            codec {
+                sound-dai = <&left_spkr>, <&right_spkr>, <&swr0 0>, <&wsamacro>;
+            };
+        };
+
+        va-dai-link {
+            link-name = "VA Capture";
+            cpu {
+                sound-dai = <&q6afedai VA_CODEC_DMA_TX_0>;
+            };
+
+            platform {
+                sound-dai = <&q6routing>;
+            };
+
+            codec {
+                sound-dai = <&vamacro 0>;
+            };
+        };
+    };
index b39743d..b731f16 100644 (file)
@@ -253,523 +253,3 @@ This is example of TDM 6ch.
 Driver can automatically switches TDM <-> stereo mode in this case.
 
 see "Example: simple sound card for TDM"
-
-=============================================
-Required properties:
-=============================================
-
-- compatible                   : "renesas,rcar_sound-<soctype>", fallbacks
-                                 "renesas,rcar_sound-gen1" if generation1, and
-                                 "renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
-                                 "renesas,rcar_sound-gen3" if generation3 (or RZ/G2)
-                                 Examples with soctypes are:
-                                   - "renesas,rcar_sound-r8a7742" (RZ/G1H)
-                                   - "renesas,rcar_sound-r8a7743" (RZ/G1M)
-                                   - "renesas,rcar_sound-r8a7744" (RZ/G1N)
-                                   - "renesas,rcar_sound-r8a7745" (RZ/G1E)
-                                   - "renesas,rcar_sound-r8a77470" (RZ/G1C)
-                                   - "renesas,rcar_sound-r8a774a1" (RZ/G2M)
-                                   - "renesas,rcar_sound-r8a774b1" (RZ/G2N)
-                                   - "renesas,rcar_sound-r8a774c0" (RZ/G2E)
-                                   - "renesas,rcar_sound-r8a774e1" (RZ/G2H)
-                                   - "renesas,rcar_sound-r8a7778" (R-Car M1A)
-                                   - "renesas,rcar_sound-r8a7779" (R-Car H1)
-                                   - "renesas,rcar_sound-r8a7790" (R-Car H2)
-                                   - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
-                                   - "renesas,rcar_sound-r8a7793" (R-Car M2-N)
-                                   - "renesas,rcar_sound-r8a7794" (R-Car E2)
-                                   - "renesas,rcar_sound-r8a7795" (R-Car H3)
-                                   - "renesas,rcar_sound-r8a7796" (R-Car M3-W)
-                                   - "renesas,rcar_sound-r8a77965" (R-Car M3-N)
-                                   - "renesas,rcar_sound-r8a77990" (R-Car E3)
-                                   - "renesas,rcar_sound-r8a77995" (R-Car D3)
-- reg                          : Should contain the register physical address.
-                                 required register is
-                                  SRU/ADG/SSI      if generation1
-                                  SRU/ADG/SSIU/SSI/AUDIO-DMAC-periperi if generation2/generation3
-                                  Select extended AUDIO-DMAC-periperi address if SoC has it,
-                                  otherwise select normal AUDIO-DMAC-periperi address.
-- reg-names                    : Should contain the register names.
-                                  scu/adg/ssi  if generation1
-                                  scu/adg/ssiu/ssi/audmapp if generation2/generation3
-- rcar_sound,ssi               : Should contain SSI feature.
-                                 The number of SSI subnode should be same as HW.
-                                 see below for detail.
-- rcar_sound,ssiu              : Should contain SSIU feature.
-                                 The number of SSIU subnode should be same as HW.
-                                 see below for detail.
-- rcar_sound,src               : Should contain SRC feature.
-                                 The number of SRC subnode should be same as HW.
-                                 see below for detail.
-- rcar_sound,ctu               : Should contain CTU feature.
-                                 The number of CTU subnode should be same as HW.
-                                 see below for detail.
-- rcar_sound,mix               : Should contain MIX feature.
-                                 The number of MIX subnode should be same as HW.
-                                 see below for detail.
-- rcar_sound,dvc               : Should contain DVC feature.
-                                 The number of DVC subnode should be same as HW.
-                                 see below for detail.
-- rcar_sound,dai               : DAI contents.
-                                 The number of DAI subnode should be same as HW.
-                                 see below for detail.
-- #sound-dai-cells             : it must be 0 if your system is using single DAI
-                                 it must be 1 if your system is using multi  DAI
-- clocks                       : References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks.
-- clock-names                  : List of necessary clock names.
-                                 "ssi-all", "ssi.X", "src.X", "mix.X", "ctu.X",
-                                 "dvc.X", "clk_a", "clk_b", "clk_c", "clk_i"
-
-Optional properties:
-- #clock-cells                 : it must be 0 if your system has audio_clkout
-                                 it must be 1 if your system has audio_clkout0/1/2/3
-- clock-frequency              : for all audio_clkout0/1/2/3
-- clkout-lr-asynchronous       : boolean property. it indicates that audio_clkoutn
-                                 is asynchronizes with lr-clock.
-- resets                       : References to SSI resets.
-- reset-names                  : List of valid reset names.
-                                 "ssi-all", "ssi.X"
-
-SSI subnode properties:
-- interrupts                   : Should contain SSI interrupt for PIO transfer
-- shared-pin                   : if shared clock pin
-- pio-transfer                 : use PIO transfer mode
-- no-busif                     : BUSIF is not ussed when [mem -> SSI] via DMA case
-- dma                          : Should contain Audio DMAC entry
-- dma-names                    : SSI  case "rx"  (=playback), "tx"  (=capture)
-                                 Deprecated: see SSIU subnode properties
-                                 SSIU case "rxu" (=playback), "txu" (=capture)
-
-SSIU subnode properties:
-- dma                          : Should contain Audio DMAC entry
-- dma-names                    : "rx" (=playback), "tx" (=capture)
-
-SRC subnode properties:
-- dma                          : Should contain Audio DMAC entry
-- dma-names                    : "rx" (=playback), "tx" (=capture)
-
-DVC subnode properties:
-- dma                          : Should contain Audio DMAC entry
-- dma-names                    : "tx" (=playback/capture)
-
-DAI subnode properties:
-- playback                     : list of playback modules
-- capture                      : list of capture  modules
-
-
-=============================================
-Example:
-=============================================
-
-rcar_sound: sound@ec500000 {
-       #sound-dai-cells = <1>;
-       compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
-       reg =   <0 0xec500000 0 0x1000>, /* SCU */
-               <0 0xec5a0000 0 0x100>,  /* ADG */
-               <0 0xec540000 0 0x1000>, /* SSIU */
-               <0 0xec541000 0 0x1280>, /* SSI */
-               <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
-       reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
-
-       clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>,
-               <&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>,
-               <&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>,
-               <&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>,
-               <&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>,
-               <&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>,
-               <&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>,
-               <&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>,
-               <&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>,
-               <&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>,
-               <&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>,
-               <&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>,
-               <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>;
-       clock-names = "ssi-all",
-                       "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-                       "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
-                       "src.9", "src.8", "src.7", "src.6", "src.5",
-                       "src.4", "src.3", "src.2", "src.1", "src.0",
-                       "dvc.0", "dvc.1",
-                       "clk_a", "clk_b", "clk_c", "clk_i";
-
-       rcar_sound,dvc {
-               dvc0: dvc-0 {
-                       dmas = <&audma0 0xbc>;
-                       dma-names = "tx";
-               };
-               dvc1: dvc-1 {
-                       dmas = <&audma0 0xbe>;
-                       dma-names = "tx";
-               };
-       };
-
-       rcar_sound,mix {
-               mix0: mix-0 { };
-               mix1: mix-1 { };
-       };
-
-       rcar_sound,ctu {
-               ctu00: ctu-0 { };
-               ctu01: ctu-1 { };
-               ctu02: ctu-2 { };
-               ctu03: ctu-3 { };
-               ctu10: ctu-4 { };
-               ctu11: ctu-5 { };
-               ctu12: ctu-6 { };
-               ctu13: ctu-7 { };
-       };
-
-       rcar_sound,src {
-               src0: src-0 {
-                       interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x85>, <&audma1 0x9a>;
-                       dma-names = "rx", "tx";
-               };
-               src1: src-1 {
-                       interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x87>, <&audma1 0x9c>;
-                       dma-names = "rx", "tx";
-               };
-               src2: src-2 {
-                       interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x89>, <&audma1 0x9e>;
-                       dma-names = "rx", "tx";
-               };
-               src3: src-3 {
-                       interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x8b>, <&audma1 0xa0>;
-                       dma-names = "rx", "tx";
-               };
-               src4: src-4 {
-                       interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x8d>, <&audma1 0xb0>;
-                       dma-names = "rx", "tx";
-               };
-               src5: src-5 {
-                       interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x8f>, <&audma1 0xb2>;
-                       dma-names = "rx", "tx";
-               };
-               src6: src-6 {
-                       interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x91>, <&audma1 0xb4>;
-                       dma-names = "rx", "tx";
-               };
-               src7: src-7 {
-                       interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x93>, <&audma1 0xb6>;
-                       dma-names = "rx", "tx";
-               };
-               src8: src-8 {
-                       interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x95>, <&audma1 0xb8>;
-                       dma-names = "rx", "tx";
-               };
-               src9: src-9 {
-                       interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x97>, <&audma1 0xba>;
-                       dma-names = "rx", "tx";
-               };
-       };
-
-       rcar_sound,ssiu {
-               ssiu00: ssiu-0 {
-                       dmas = <&audma0 0x15>, <&audma1 0x16>;
-                       dma-names = "rx", "tx";
-               };
-               ssiu01: ssiu-1 {
-                       dmas = <&audma0 0x35>, <&audma1 0x36>;
-                       dma-names = "rx", "tx";
-               };
-
-               ...
-
-               ssiu95: ssiu-49 {
-                       dmas = <&audma0 0xA5>, <&audma1 0xA6>;
-                       dma-names = "rx", "tx";
-               };
-               ssiu96: ssiu-50 {
-                       dmas = <&audma0 0xA7>, <&audma1 0xA8>;
-                       dma-names = "rx", "tx";
-               };
-               ssiu97: ssiu-51 {
-                       dmas = <&audma0 0xA9>, <&audma1 0xAA>;
-                       dma-names = "rx", "tx";
-               };
-       };
-
-       rcar_sound,ssi {
-               ssi0: ssi-0 {
-                       interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x01>, <&audma1 0x02>;
-                       dma-names = "rx", "tx";
-               };
-               ssi1: ssi-1 {
-                       interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x03>, <&audma1 0x04>;
-                       dma-names = "rx", "tx";
-               };
-
-               ...
-
-               ssi8: ssi-8 {
-                       interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x11>, <&audma1 0x12>;
-                       dma-names = "rx", "tx";
-               };
-               ssi9: ssi-9 {
-                       interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x13>, <&audma1 0x14>;
-                       dma-names = "rx", "tx";
-               };
-       };
-
-       rcar_sound,dai {
-               dai0 {
-                       playback = <&ssi5 &src5>;
-                       capture  = <&ssi6>;
-               };
-               dai1 {
-                       playback = <&ssi3>;
-               };
-               dai2 {
-                       capture  = <&ssi4>;
-               };
-               dai3 {
-                       playback = <&ssi7>;
-               };
-               dai4 {
-                       capture  = <&ssi8>;
-               };
-       };
-};
-
-=============================================
-Example: simple sound card
-=============================================
-
-       rsnd_ak4643: sound {
-               compatible = "simple-audio-card";
-
-               simple-audio-card,format = "left_j";
-               simple-audio-card,bitclock-master = <&sndcodec>;
-               simple-audio-card,frame-master = <&sndcodec>;
-
-               sndcpu: simple-audio-card,cpu {
-                       sound-dai = <&rcar_sound>;
-               };
-
-               sndcodec: simple-audio-card,codec {
-                       sound-dai = <&ak4643>;
-                       clocks = <&audio_clock>;
-               };
-       };
-
-&rcar_sound {
-       pinctrl-0 = <&sound_pins &sound_clk_pins>;
-       pinctrl-names = "default";
-
-       /* Single DAI */
-       #sound-dai-cells = <0>;
-
-
-       rcar_sound,dai {
-               dai0 {
-                       playback = <&ssi0 &src2 &dvc0>;
-                       capture  = <&ssi1 &src3 &dvc1>;
-               };
-       };
-};
-
-&ssi1 {
-       shared-pin;
-};
-
-=============================================
-Example: simple sound card for Asynchronous mode
-=============================================
-
-sound {
-       compatible = "simple-scu-audio-card";
-       ...
-       /*
-        * SRC Asynchronous mode setting
-        * Playback:
-        * All input data will be converted to 48kHz
-        * Capture:
-        * Inputed 48kHz data will be converted to
-        * system specified Hz
-        */
-       simple-audio-card,convert-rate = <48000>;
-       ...
-       simple-audio-card,cpu {
-               sound-dai = <&rcar_sound>;
-       };
-       simple-audio-card,codec {
-               ...
-       };
-};
-
-=============================================
-Example: simple sound card for channel convert
-=============================================
-
-sound {
-       compatible = "simple-scu-audio-card";
-       ...
-       /*
-        * CTU setting
-        * All input data will be converted to 2ch
-        * as output data
-        */
-       simple-audio-card,convert-channels = <2>;
-       ...
-       simple-audio-card,cpu {
-               sound-dai = <&rcar_sound>;
-       };
-       simple-audio-card,codec {
-               ...
-       };
-};
-
-=============================================
-Example: simple sound card for MIXer
-=============================================
-
-sound {
-       compatible = "simple-scu-audio-card";
-       ...
-       simple-audio-card,cpu@0 {
-               sound-dai = <&rcar_sound 0>;
-       };
-       simple-audio-card,cpu@1 {
-               sound-dai = <&rcar_sound 1>;
-       };
-       simple-audio-card,codec {
-               ...
-       };
-};
-
-&rcar_sound {
-       ...
-       rcar_sound,dai {
-               dai0 {
-                       playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
-               };
-               dai1 {
-                       playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
-               };
-       };
-};
-
-=============================================
-Example: simple sound card for TDM
-=============================================
-
-rsnd_tdm: sound {
-       compatible = "simple-audio-card";
-
-       simple-audio-card,format = "left_j";
-       simple-audio-card,bitclock-master = <&sndcodec>;
-       simple-audio-card,frame-master = <&sndcodec>;
-
-       sndcpu: simple-audio-card,cpu {
-               sound-dai = <&rcar_sound>;
-               dai-tdm-slot-num = <6>;
-       };
-
-       sndcodec: simple-audio-card,codec {
-               sound-dai = <&xxx>;
-       };
-};
-
-=============================================
-Example: simple sound card for TDM Split
-=============================================
-
-sound_card: sound {
-       compatible = "audio-graph-scu-card";
-       prefix = "xxxx";
-       routing = "xxxx Playback", "DAI0 Playback",
-                 "xxxx Playback", "DAI1 Playback",
-                 "xxxx Playback", "DAI2 Playback",
-                 "xxxx Playback", "DAI3 Playback";
-       convert-channels = <8>; /* TDM Split */
-
-       dais = <&rsnd_port0     /* playback ch1/ch2 */
-               &rsnd_port1     /* playback ch3/ch4 */
-               &rsnd_port2     /* playback ch5/ch6 */
-               &rsnd_port3     /* playback ch7/ch8 */
-               >;
-};
-
-audio-codec {
-       ...
-       port {
-               codec_0: endpoint@1 {
-                       remote-endpoint = <&rsnd_ep0>;
-               };
-               codec_1: endpoint@2 {
-                       remote-endpoint = <&rsnd_ep1>;
-               };
-               codec_2: endpoint@3 {
-                       remote-endpoint = <&rsnd_ep2>;
-               };
-               codec_3: endpoint@4 {
-                       remote-endpoint = <&rsnd_ep3>;
-               };
-       };
-};
-
-&rcar_sound {
-       ...
-       ports {
-               rsnd_port0: port@0 {
-                       rsnd_ep0: endpoint {
-                               remote-endpoint = <&codec_0>;
-                               ...
-                               playback = <&ssiu30 &ssi3>;
-                       };
-               };
-               rsnd_port1: port@1 {
-                       rsnd_ep1: endpoint {
-                               remote-endpoint = <&codec_1>;
-                               ...
-                               playback = <&ssiu31 &ssi3>;
-                       };
-               };
-               rsnd_port2: port@2 {
-                       rsnd_ep2: endpoint {
-                               remote-endpoint = <&codec_2>;
-                               ...
-                               playback = <&ssiu32 &ssi3>;
-                       };
-               };
-               rsnd_port3: port@3 {
-                       rsnd_ep3: endpoint {
-                               remote-endpoint = <&codec_3>;
-                               ...
-                               playback = <&ssiu33 &ssi3>;
-                       };
-               };
-       };
-};
-
-=============================================
-Example: simple sound card for Multi channel
-=============================================
-
-&rcar_sound {
-       pinctrl-0 = <&sound_pins &sound_clk_pins>;
-       pinctrl-names = "default";
-
-       /* Single DAI */
-       #sound-dai-cells = <0>;
-
-
-       rcar_sound,dai {
-               dai0 {
-                       playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
new file mode 100644 (file)
index 0000000..0fd37aa
--- /dev/null
@@ -0,0 +1,447 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/renesas,rsnd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas R-Car Sound Driver Device Tree Bindings
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+properties:
+
+  compatible:
+    oneOf:
+      # for Gen1 SoC
+      - items:
+          - enum:
+              - renesas,rcar_sound-r8a7778   # R-Car M1A
+              - renesas,rcar_sound-r8a7779   # R-Car H1
+          - enum:
+              - renesas,rcar_sound-gen1
+      # for Gen2 SoC
+      - items:
+          - enum:
+              - renesas,rcar_sound-r8a7742   # RZ/G1H
+              - renesas,rcar_sound-r8a7743   # RZ/G1M
+              - renesas,rcar_sound-r8a7744   # RZ/G1N
+              - renesas,rcar_sound-r8a7745   # RZ/G1E
+              - renesas,rcar_sound-r8a77470  # RZ/G1C
+              - renesas,rcar_sound-r8a7790   # R-Car H2
+              - renesas,rcar_sound-r8a7791   # R-Car M2-W
+              - renesas,rcar_sound-r8a7793   # R-Car M2-N
+              - renesas,rcar_sound-r8a7794   # R-Car E2
+          - enum:
+              - renesas,rcar_sound-gen2
+      # for Gen3 SoC
+      - items:
+          - enum:
+              - renesas,rcar_sound-r8a774a1  # RZ/G2M
+              - renesas,rcar_sound-r8a774b1  # RZ/G2N
+              - renesas,rcar_sound-r8a774c0  # RZ/G2E
+              - renesas,rcar_sound-r8a774e1  # RZ/G2H
+              - renesas,rcar_sound-r8a7795   # R-Car H3
+              - renesas,rcar_sound-r8a7796   # R-Car M3-W
+              - renesas,rcar_sound-r8a77961  # R-Car M3-W+
+              - renesas,rcar_sound-r8a77965  # R-Car M3-N
+              - renesas,rcar_sound-r8a77990  # R-Car E3
+              - renesas,rcar_sound-r8a77995  # R-Car D3
+          - enum:
+              - renesas,rcar_sound-gen3
+      # for Generic
+      - items:
+          - enum:
+              - renesas,rcar_sound-gen1
+              - renesas,rcar_sound-gen2
+              - renesas,rcar_sound-gen3
+
+  reg:
+    minItems: 1
+    maxItems: 5
+
+  reg-names:
+    minItems: 1
+    maxItems: 5
+
+  "#sound-dai-cells":
+    description: |
+      it must be 0 if your system is using single DAI
+      it must be 1 if your system is using multi  DAIs
+    enum: [0, 1]
+
+  "#clock-cells":
+    description: |
+      it must be 0 if your system has audio_clkout
+      it must be 1 if your system has audio_clkout0/1/2/3
+    enum: [0, 1]
+
+  clock-frequency:
+    description: for audio_clkout0/1/2/3
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+
+  clkout-lr-asynchronous:
+    description: audio_clkoutn is asynchronizes with lr-clock.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  power-domains: true
+
+  resets:
+    maxItems: 11
+
+  reset-names:
+    maxItems: 11
+
+  clocks:
+    description: References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks.
+    minItems: 1
+    maxItems: 31
+
+  clock-names:
+    description: List of necessary clock names.
+    minItems: 1
+    maxItems: 31
+    items:
+      oneOf:
+        - const: ssi-all
+        - pattern: '^ssi\.[0-9]$'
+        - pattern: '^src\.[0-9]$'
+        - pattern: '^mix\.[0-1]$'
+        - pattern: '^ctu\.[0-1]$'
+        - pattern: '^dvc\.[0-1]$'
+        - pattern: '^clk_(a|b|c|i)$'
+
+  port: true
+
+# use patternProperties to avoid naming "xxx,yyy" issue
+patternProperties:
+  "^rcar_sound,dvc$":
+    description: DVC subnode.
+    type: object
+    patternProperties:
+      "^dvc-[0-1]$":
+        type: object
+        properties:
+          dmas:
+            maxItems: 1
+          dma-names:
+            const: "tx"
+        required:
+          - dmas
+          - dma-names
+    additionalProperties: false
+
+  "^rcar_sound,mix$":
+    description: MIX subnode.
+    type: object
+    patternProperties:
+      "^mix-[0-1]$":
+        type: object
+        # no properties
+    additionalProperties: false
+
+  "^rcar_sound,ctu$":
+    description: CTU subnode.
+    type: object
+    patternProperties:
+      "^ctu-[0-7]$":
+        type: object
+        # no properties
+    additionalProperties: false
+
+  "^rcar_sound,src$":
+    description: SRC subnode.
+    type: object
+    patternProperties:
+      "^src-[0-9]$":
+        type: object
+        properties:
+          interrupts:
+            maxItems: 1
+          dmas:
+            maxItems: 2
+          dma-names:
+            allOf:
+              - items:
+                  enum:
+                    - tx
+                    - rx
+        required:
+          - interrupts
+          - dmas
+          - dma-names
+    additionalProperties: false
+
+  "^rcar_sound,ssiu$":
+    description: SSIU subnode.
+    type: object
+    patternProperties:
+      "^ssiu-[0-9]+$":
+        type: object
+        properties:
+          dmas:
+            maxItems: 2
+          dma-names:
+            allOf:
+              - items:
+                  enum:
+                    - tx
+                    - rx
+        required:
+          - dmas
+          - dma-names
+    additionalProperties: false
+
+  "^rcar_sound,ssi$":
+    description: SSI subnode.
+    type: object
+    patternProperties:
+      "^ssi-[0-9]$":
+        type: object
+        properties:
+          interrupts:
+            maxItems: 1
+          dmas:
+            minItems: 2
+            maxItems: 4
+          dma-names:
+            allOf:
+              - items:
+                  enum:
+                    - tx
+                    - rx
+                    - txu # if no ssiu node
+                    - rxu # if no ssiu node
+
+          shared-pin:
+            description: shared clock pin
+            $ref: /schemas/types.yaml#/definitions/flag
+          pio-transfer:
+            description: PIO transfer mode
+            $ref: /schemas/types.yaml#/definitions/flag
+          no-busif:
+            description: BUSIF is not used when [mem -> SSI] via DMA case
+            $ref: /schemas/types.yaml#/definitions/flag
+        required:
+          - interrupts
+          - dmas
+          - dma-names
+    additionalProperties: false
+
+  # For DAI base
+  "^rcar_sound,dai$":
+    description: DAI subnode.
+    type: object
+    patternProperties:
+      "^dai([0-9]+)?$":
+        type: object
+        properties:
+          playback:
+            $ref: /schemas/types.yaml#/definitions/phandle-array
+          capture:
+            $ref: /schemas/types.yaml#/definitions/phandle-array
+        anyOf:
+          - required:
+              - playback
+          - required:
+              - capture
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - "#sound-dai-cells"
+
+allOf:
+  - $ref: audio-graph.yaml#
+  - $ref: audio-graph-port.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: renesas,rcar_sound-gen1
+    then:
+      properties:
+        reg:
+          maxItems: 3
+        reg-names:
+          maxItems: 3
+          items:
+            enum:
+              - scu
+              - ssi
+              - adg
+    else:
+      properties:
+        reg:
+          maxItems: 5
+        reg-names:
+          maxItems: 5
+          items:
+            enum:
+              - scu
+              - adg
+              - ssiu
+              - ssi
+              - audmapp
+
+additionalProperties: false
+
+examples:
+  - |
+    rcar_sound: sound@ec500000 {
+        #sound-dai-cells = <1>;
+        compatible = "renesas,rcar_sound-r8a7790", "renesas,rcar_sound-gen2";
+        reg = <0xec500000 0x1000>, /* SCU  */
+              <0xec5a0000 0x100>,  /* ADG  */
+              <0xec540000 0x1000>, /* SSIU */
+              <0xec541000 0x1280>, /* SSI  */
+              <0xec740000 0x200>;  /* Audio DMAC peri peri*/
+        reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+        clocks = <&mstp10_clks 1005>,                      /* SSI-ALL    */
+                 <&mstp10_clks 1006>, <&mstp10_clks 1007>, /* SSI9, SSI8 */
+                 <&mstp10_clks 1008>, <&mstp10_clks 1009>, /* SSI7, SSI6 */
+                 <&mstp10_clks 1010>, <&mstp10_clks 1011>, /* SSI5, SSI4 */
+                 <&mstp10_clks 1012>, <&mstp10_clks 1013>, /* SSI3, SSI2 */
+                 <&mstp10_clks 1014>, <&mstp10_clks 1015>, /* SSI1, SSI0 */
+                 <&mstp10_clks 1022>, <&mstp10_clks 1023>, /* SRC9, SRC8 */
+                 <&mstp10_clks 1024>, <&mstp10_clks 1025>, /* SRC7, SRC6 */
+                 <&mstp10_clks 1026>, <&mstp10_clks 1027>, /* SRC5, SRC4 */
+                 <&mstp10_clks 1028>, <&mstp10_clks 1029>, /* SRC3, SRC2 */
+                 <&mstp10_clks 1030>, <&mstp10_clks 1031>, /* SRC1, SRC0 */
+                 <&mstp10_clks 1020>, <&mstp10_clks 1021>, /* MIX1, MIX0 */
+                 <&mstp10_clks 1020>, <&mstp10_clks 1021>, /* CTU1, CTU0 */
+                 <&mstp10_clks 1019>, <&mstp10_clks 1018>, /* DVC0, DVC1 */
+                 <&audio_clk_a>, <&audio_clk_b>,           /* CLKA, CLKB */
+                 <&audio_clk_c>, <&audio_clk_i>;           /* CLKC, CLKI */
+
+        clock-names = "ssi-all",
+                      "ssi.9", "ssi.8",
+                      "ssi.7", "ssi.6",
+                      "ssi.5", "ssi.4",
+                      "ssi.3", "ssi.2",
+                      "ssi.1", "ssi.0",
+                      "src.9", "src.8",
+                      "src.7", "src.6",
+                      "src.5", "src.4",
+                      "src.3", "src.2",
+                      "src.1", "src.0",
+                      "mix.1", "mix.0",
+                      "ctu.1", "ctu.0",
+                      "dvc.0", "dvc.1",
+                      "clk_a", "clk_b",
+                      "clk_c", "clk_i";
+
+        rcar_sound,dvc {
+               dvc0: dvc-0 {
+                    dmas = <&audma0 0xbc>;
+                    dma-names = "tx";
+               };
+               dvc1: dvc-1 {
+                    dmas = <&audma0 0xbe>;
+                    dma-names = "tx";
+               };
+        };
+
+        rcar_sound,mix {
+            mix0: mix-0 { };
+            mix1: mix-1 { };
+        };
+
+        rcar_sound,ctu {
+            ctu00: ctu-0 { };
+            ctu01: ctu-1 { };
+            ctu02: ctu-2 { };
+            ctu03: ctu-3 { };
+            ctu10: ctu-4 { };
+            ctu11: ctu-5 { };
+            ctu12: ctu-6 { };
+            ctu13: ctu-7 { };
+        };
+
+        rcar_sound,src {
+            src0: src-0 {
+                status = "disabled";
+            };
+            src1: src-1 {
+                interrupts = <0 353 0>;
+                dmas = <&audma0 0x87>, <&audma1 0x9c>;
+                dma-names = "rx", "tx";
+            };
+            /* skip after src-2 */
+        };
+
+        rcar_sound,ssiu {
+            ssiu00: ssiu-0 {
+                dmas = <&audma0 0x15>, <&audma1 0x16>;
+                dma-names = "rx", "tx";
+            };
+            ssiu01: ssiu-1 {
+                dmas = <&audma0 0x35>, <&audma1 0x36>;
+                dma-names = "rx", "tx";
+            };
+            /* skip after ssiu-2 */
+        };
+
+        rcar_sound,ssi {
+            ssi0: ssi-0 {
+                interrupts = <0 370 1>;
+                dmas = <&audma0 0x01>, <&audma1 0x02>;
+                dma-names = "rx", "tx";
+            };
+            ssi1: ssi-1 {
+                interrupts = <0 371 1>;
+                dmas = <&audma0 0x03>, <&audma1 0x04>;
+                dma-names = "rx", "tx";
+            };
+            /* skip other ssi-2 */
+        };
+
+        /* DAI base */
+        rcar_sound,dai {
+            dai0 {
+                playback = <&ssi5 &src5>;
+                capture  = <&ssi6>;
+            };
+            dai1 {
+                playback = <&ssi3>;
+            };
+            dai2 {
+                capture  = <&ssi4>;
+            };
+            dai3 {
+                playback = <&ssi7>;
+            };
+            dai4 {
+                capture  = <&ssi8>;
+            };
+        };
+
+        /* assume audio-graph */
+        port {
+            rsnd_endpoint: endpoint {
+                remote-endpoint = <&codec_endpoint>;
+
+                dai-format = "left_j";
+                bitclock-master = <&rsnd_endpoint0>;
+                frame-master = <&rsnd_endpoint0>;
+
+                playback = <&ssi0 &src0 &dvc0>;
+                capture  = <&ssi1 &src1 &dvc1>;
+            };
+        };
+    };
+
+
+    /* assume audio-graph */
+    codec {
+        port {
+            codec_endpoint: endpoint {
+                remote-endpoint = <&rsnd_endpoint>;
+            };
+        };
+    };
index 707fa98..9c5fadb 100644 (file)
@@ -44,6 +44,8 @@ Optional properties:
 - realtek,dmic-delay-ms : Set the delay time (ms) for the requirement of
   the particular DMIC.
 
+- realtek,dmic-clk-driving-high : Set the high drving of the DMIC clock out.
+
 Pins on the device (for linking into audio routes) for RT5682:
 
   * DMIC L1
diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
new file mode 100644 (file)
index 0000000..5986d1f
--- /dev/null
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/simple-audio-mux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Simple Audio Multiplexer
+
+maintainers:
+  - Alexandre Belloni <aleandre.belloni@bootlin.com>
+
+description: |
+  Simple audio multiplexers are driven using gpios, allowing to select which of
+  their input line is connected to the output line.
+
+properties:
+  compatible:
+    const: simple-audio-mux
+
+  mux-gpios:
+    description: |
+      GPIOs used to select the input line.
+
+  sound-name-prefix:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+
+required:
+  - compatible
+  - mux-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    mux {
+        compatible = "simple-audio-mux";
+        mux-gpios = <&gpio 3 0>;
+    };
index 35e6690..45fd9fd 100644 (file)
@@ -13,13 +13,11 @@ definitions:
 
   frame-master:
     description: Indicates dai-link frame master.
-    $ref: /schemas/types.yaml#/definitions/phandle-array
-    maxItems: 1
+    $ref: /schemas/types.yaml#/definitions/phandle
 
   bitclock-master:
     description: Indicates dai-link bit clock master
-    $ref: /schemas/types.yaml#/definitions/phandle-array
-    maxItems: 1
+    $ref: /schemas/types.yaml#/definitions/phandle
 
   frame-inversion:
     description: dai-link uses frame clock inversion
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
deleted file mode 100644 (file)
index 864f5b0..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM)
-
-The DFSDM allows PDM microphones capture through SPI interface. The Audio
-interface is seems as a sub block of the DFSDM device.
-For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.txt
-
-Required properties:
-  - compatible: "st,stm32h7-dfsdm-dai".
-
-  - #sound-dai-cells : Must be equal to 0
-
-  - io-channels : phandle to iio dfsdm instance node.
-
-Example of a sound card using audio DFSDM node.
-
-       sound_card {
-               compatible = "audio-graph-card";
-
-               dais = <&cpu_port>;
-       };
-
-       dfsdm: dfsdm@40017000 {
-               compatible = "st,stm32h7-dfsdm";
-               reg = <0x40017000 0x400>;
-               clocks = <&rcc DFSDM1_CK>;
-               clock-names = "dfsdm";
-               #interrupt-cells = <1>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               dfsdm_adc0: filter@0 {
-                       compatible = "st,stm32-dfsdm-dmic";
-                       reg = <0>;
-                       interrupts = <110>;
-                       dmas = <&dmamux1 101 0x400 0x00>;
-                       dma-names = "rx";
-                       st,adc-channels = <1>;
-                       st,adc-channel-names = "dmic0";
-                       st,adc-channel-types = "SPI_R";
-                       st,adc-channel-clk-src = "CLKOUT";
-                       st,filter-order = <5>;
-
-                       dfsdm_dai0: dfsdm-dai {
-                               compatible = "st,stm32h7-dfsdm-dai";
-                               #sound-dai-cells = <0>;
-                               io-channels = <&dfsdm_adc0 0>;
-                               cpu_port: port {
-                               dfsdm_endpoint: endpoint {
-                                       remote-endpoint = <&dmic0_endpoint>;
-                               };
-                       };
-               };
-       };
-
-       dmic0: dmic@0 {
-               compatible = "dmic-codec";
-               #sound-dai-cells = <0>;
-               port {
-                       dmic0_endpoint: endpoint {
-                               remote-endpoint = <&dfsdm_endpoint>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
deleted file mode 100644 (file)
index c42b91e..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-STMicroelectronics STM32 Serial Audio Interface (SAI).
-
-The SAI interface (Serial Audio Interface) offers a wide set of audio protocols
-as I2S standards, LSB or MSB-justified, PCM/DSP, TDM, and AC'97.
-The SAI contains two independent audio sub-blocks. Each sub-block has
-its own clock generator and I/O lines controller.
-
-Required properties:
-  - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai"
-  - reg: Base address and size of SAI common register set.
-  - clocks: Must contain phandle and clock specifier pairs for each entry
-       in clock-names.
-  - clock-names: Must contain "pclk" "x8k" and "x11k"
-       "pclk": Clock which feeds the peripheral bus interface.
-               Mandatory for "st,stm32h7-sai" compatible.
-               Not used for "st,stm32f4-sai" compatible.
-       "x8k": SAI parent clock for sampling rates multiple of 8kHz.
-       "x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
-  - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
-
-Optional properties:
-  - resets: Reference to a reset controller asserting the SAI
-
-SAI subnodes:
-Two subnodes corresponding to SAI sub-block instances A et B can be defined.
-Subnode can be omitted for unsused sub-block.
-
-SAI subnodes required properties:
-  - compatible: Should be "st,stm32-sai-sub-a" or "st,stm32-sai-sub-b"
-       for SAI sub-block A or B respectively.
-  - reg: Base address and size of SAI sub-block register set.
-  - clocks: Must contain one phandle and clock specifier pair
-       for sai_ck which feeds the internal clock generator.
-       If the SAI shares a master clock, with another SAI set as MCLK
-       clock provider, SAI provider phandle must be specified here.
-  - clock-names: Must contain "sai_ck".
-       Must also contain "MCLK", if SAI shares a master clock,
-       with a SAI set as MCLK clock provider.
-  - dmas: see Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
-  - dma-names: identifier string for each DMA request line
-       "tx": if sai sub-block is configured as playback DAI
-       "rx": if sai sub-block is configured as capture DAI
-  - pinctrl-names: should contain only value "default"
-  - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
-
-SAI subnodes Optional properties:
-  - st,sync: specify synchronization mode.
-       By default SAI sub-block is in asynchronous mode.
-       This property sets SAI sub-block as slave of another SAI sub-block.
-       Must contain the phandle and index of the sai sub-block providing
-       the synchronization.
-  - st,iec60958: support S/PDIF IEC6958 protocol for playback
-       IEC60958 protocol is not available for capture.
-       By default, custom protocol is assumed, meaning that protocol is
-       configured according to protocol defined in related DAI link node,
-       such as i2s, left justified, right justified, dsp and pdm protocols.
-       Note: ac97 protocol is not supported by SAI driver
-   - #clock-cells: should be 0. This property must be present if the SAI device
-       is a master clock provider, according to clocks bindings, described in
-       Documentation/devicetree/bindings/clock/clock-bindings.txt.
-
-The device node should contain one 'port' child node with one child 'endpoint'
-node, according to the bindings defined in Documentation/devicetree/bindings/
-graph.txt.
-
-Example:
-sound_card {
-       compatible = "audio-graph-card";
-       dais = <&sai1b_port>;
-};
-
-sai1: sai1@40015800 {
-       compatible = "st,stm32h7-sai";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       ranges = <0 0x40015800 0x400>;
-       reg = <0x40015800 0x4>;
-       clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
-       clock-names = "pclk", "x8k", "x11k";
-       interrupts = <87>;
-
-       sai1a: audio-controller@40015804 {
-               compatible = "st,stm32-sai-sub-a";
-               reg = <0x4 0x1C>;
-               clocks = <&rcc SAI1_CK>;
-               clock-names = "sai_ck";
-               dmas = <&dmamux1 1 87 0x400 0x0>;
-               dma-names = "tx";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_sai1a>;
-
-               sai1b_port: port {
-                       cpu_endpoint: endpoint {
-                               remote-endpoint = <&codec_endpoint>;
-                               format = "i2s";
-                       };
-               };
-       };
-};
-
-audio-codec {
-       codec_port: port {
-               codec_endpoint: endpoint {
-                       remote-endpoint = <&cpu_endpoint>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml
new file mode 100644 (file)
index 0000000..6ad48c7
--- /dev/null
@@ -0,0 +1,200 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/st,stm32-sai.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Serial Audio Interface (SAI)
+
+maintainers:
+  - Olivier Moysan <olivier.moysan@st.com>
+
+description:
+  The SAI interface (Serial Audio Interface) offers a wide set of audio
+  protocols as I2S standards, LSB or MSB-justified, PCM/DSP, TDM, and AC'97.
+  The SAI contains two independent audio sub-blocks. Each sub-block has
+  its own clock generator and I/O lines controller.
+
+properties:
+  compatible:
+    enum:
+      - st,stm32f4-sai
+      - st,stm32h7-sai
+
+  reg:
+    items:
+      - description: Base address and size of SAI common register set.
+      - description: Base address and size of SAI identification register set.
+    minItems: 1
+    maxItems: 2
+
+  ranges:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    maxItems: 3
+
+required:
+  - compatible
+  - reg
+  - ranges
+  - "#address-cells"
+  - "#size-cells"
+  - clocks
+  - clock-names
+
+patternProperties:
+  "^audio-controller@[0-9a-f]+$":
+    type: object
+    description:
+      Two subnodes corresponding to SAI sub-block instances A et B
+      can be defined. Subnode can be omitted for unsused sub-block.
+
+    properties:
+      compatible:
+        description: Compatible for SAI sub-block A or B.
+        pattern: "st,stm32-sai-sub-[ab]"
+
+      "#sound-dai-cells":
+        const: 0
+
+      reg:
+        maxItems: 1
+
+      clocks:
+        items:
+          - description: sai_ck clock feeding the internal clock generator.
+          - description: MCLK clock from a SAI set as master clock provider.
+        minItems: 1
+        maxItems: 2
+
+      clock-names:
+        items:
+          - const: sai_ck
+          - const: MCLK
+        minItems: 1
+        maxItems: 2
+
+      dmas:
+        maxItems: 1
+
+      dma-names:
+        description: |
+          rx: SAI sub-block is configured as a capture DAI.
+          tx: SAI sub-block is configured as a playback DAI.
+        enum: [ rx, tx ]
+
+      st,sync:
+        description:
+          Configure the SAI sub-block as slave of another SAI sub-block.
+          By default SAI sub-block is in asynchronous mode.
+          Must contain the phandle and index of the SAI sub-block providing
+          the synchronization.
+        allOf:
+          - $ref: /schemas/types.yaml#definitions/phandle-array
+          - maxItems: 1
+
+      st,iec60958:
+        description:
+          If set, support S/PDIF IEC6958 protocol for playback.
+          IEC60958 protocol is not available for capture.
+          By default, custom protocol is assumed, meaning that protocol is
+          configured according to protocol defined in related DAI link node,
+          such as i2s, left justified, right justified, dsp and pdm protocols.
+        allOf:
+          - $ref: /schemas/types.yaml#definitions/flag
+
+      "#clock-cells":
+        description: Configure the SAI device as master clock provider.
+        const: 0
+
+    required:
+      - compatible
+      - "#sound-dai-cells"
+      - reg
+      - clocks
+      - clock-names
+      - dmas
+      - dma-names
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32f4-sai
+
+  - then:
+      properties:
+        clocks:
+          items:
+            - description: x8k, SAI parent clock for sampling rates multiple of 8kHz.
+            - description: x11k, SAI parent clock for sampling rates multiple of 11.025kHz.
+
+        clock-names:
+          items:
+            - const: x8k
+            - const: x11k
+
+  - else:
+      properties:
+        clocks:
+          items:
+            - description: pclk feeds the peripheral bus interface.
+            - description: x8k, SAI parent clock for sampling rates multiple of 8kHz.
+            - description: x11k, SAI parent clock for sampling rates multiple of 11.025kHz.
+
+        clock-names:
+          items:
+            - const: pclk
+            - const: x8k
+            - const: x11k
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/reset/stm32mp1-resets.h>
+    sai2: sai@4400b000 {
+      compatible = "st,stm32h7-sai";
+      #address-cells = <1>;
+      #size-cells = <1>;
+      ranges = <0 0x4400b000 0x400>;
+      reg = <0x4400b000 0x4>, <0x4400b3f0 0x10>;
+      clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>;
+      clock-names = "pclk", "x8k", "x11k";
+      pinctrl-names = "default", "sleep";
+      pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_b>;
+      pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_b>;
+      status = "okay";
+
+      sai2a: audio-controller@4400b004 {
+        #sound-dai-cells = <0>;
+        compatible = "st,stm32-sai-sub-a";
+        reg = <0x4 0x1c>;
+        dmas = <&dmamux1 89 0x400 0x01>;
+        dma-names = "tx";
+        clocks = <&rcc SAI2_K>;
+        clock-names = "sai_ck";
+        status = "okay";
+      };
+    };
+
+...
diff --git a/Documentation/driver-api/auxiliary_bus.rst b/Documentation/driver-api/auxiliary_bus.rst
new file mode 100644 (file)
index 0000000..2312506
--- /dev/null
@@ -0,0 +1,234 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+=============
+Auxiliary Bus
+=============
+
+In some subsystems, the functionality of the core device (PCI/ACPI/other) is
+too complex for a single device to be managed by a monolithic driver
+(e.g. Sound Open Firmware), multiple devices might implement a common
+intersection of functionality (e.g. NICs + RDMA), or a driver may want to
+export an interface for another subsystem to drive (e.g. SIOV Physical Function
+export Virtual Function management).  A split of the functinoality into child-
+devices representing sub-domains of functionality makes it possible to
+compartmentalize, layer, and distribute domain-specific concerns via a Linux
+device-driver model.
+
+An example for this kind of requirement is the audio subsystem where a single
+IP is handling multiple entities such as HDMI, Soundwire, local devices such as
+mics/speakers etc. The split for the core's functionality can be arbitrary or
+be defined by the DSP firmware topology and include hooks for test/debug. This
+allows for the audio core device to be minimal and focused on hardware-specific
+control and communication.
+
+Each auxiliary_device represents a part of its parent functionality. The
+generic behavior can be extended and specialized as needed by encapsulating an
+auxiliary_device within other domain-specific structures and the use of .ops
+callbacks. Devices on the auxiliary bus do not share any structures and the use
+of a communication channel with the parent is domain-specific.
+
+Note that ops are intended as a way to augment instance behavior within a class
+of auxiliary devices, it is not the mechanism for exporting common
+infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey
+infrastructure from the parent module to the auxiliary module(s).
+
+
+When Should the Auxiliary Bus Be Used
+=====================================
+
+The auxiliary bus is to be used when a driver and one or more kernel modules,
+who share a common header file with the driver, need a mechanism to connect and
+provide access to a shared object allocated by the auxiliary_device's
+registering driver.  The registering driver for the auxiliary_device(s) and the
+kernel module(s) registering auxiliary_drivers can be from the same subsystem,
+or from multiple subsystems.
+
+The emphasis here is on a common generic interface that keeps subsystem
+customization out of the bus infrastructure.
+
+One example is a PCI network device that is RDMA-capable and exports a child
+device to be driven by an auxiliary_driver in the RDMA subsystem.  The PCI
+driver allocates and registers an auxiliary_device for each physical
+function on the NIC.  The RDMA driver registers an auxiliary_driver that claims
+each of these auxiliary_devices.  This conveys data/ops published by the parent
+PCI device/driver to the RDMA auxiliary_driver.
+
+Another use case is for the PCI device to be split out into multiple sub
+functions.  For each sub function an auxiliary_device is created.  A PCI sub
+function driver binds to such devices that creates its own one or more class
+devices.  A PCI sub function auxiliary device is likely to be contained in a
+struct with additional attributes such as user defined sub function number and
+optional attributes such as resources and a link to the parent device.  These
+attributes could be used by systemd/udev; and hence should be initialized
+before a driver binds to an auxiliary_device.
+
+A key requirement for utilizing the auxiliary bus is that there is no
+dependency on a physical bus, device, register accesses or regmap support.
+These individual devices split from the core cannot live on the platform bus as
+they are not physical devices that are controlled by DT/ACPI.  The same
+argument applies for not using MFD in this scenario as MFD relies on individual
+function devices being physical devices.
+
+Auxiliary Device
+================
+
+An auxiliary_device represents a part of its parent device's functionality. It
+is given a name that, combined with the registering drivers KBUILD_MODNAME,
+creates a match_name that is used for driver binding, and an id that combined
+with the match_name provide a unique name to register with the bus subsystem.
+
+Registering an auxiliary_device is a two-step process.  First call
+auxiliary_device_init(), which checks several aspects of the auxiliary_device
+struct and performs a device_initialize().  After this step completes, any
+error state must have a call to auxiliary_device_uninit() in its resolution path.
+The second step in registering an auxiliary_device is to perform a call to
+auxiliary_device_add(), which sets the name of the device and add the device to
+the bus.
+
+Unregistering an auxiliary_device is also a two-step process to mirror the
+register process.  First call auxiliary_device_delete(), then call
+auxiliary_device_uninit().
+
+.. code-block:: c
+
+       struct auxiliary_device {
+               struct device dev;
+                const char *name;
+               u32 id;
+       };
+
+If two auxiliary_devices both with a match_name "mod.foo" are registered onto
+the bus, they must have unique id values (e.g. "x" and "y") so that the
+registered devices names are "mod.foo.x" and "mod.foo.y".  If match_name + id
+are not unique, then the device_add fails and generates an error message.
+
+The auxiliary_device.dev.type.release or auxiliary_device.dev.release must be
+populated with a non-NULL pointer to successfully register the auxiliary_device.
+
+The auxiliary_device.dev.parent must also be populated.
+
+Auxiliary Device Memory Model and Lifespan
+------------------------------------------
+
+The registering driver is the entity that allocates memory for the
+auxiliary_device and register it on the auxiliary bus.  It is important to note
+that, as opposed to the platform bus, the registering driver is wholly
+responsible for the management for the memory used for the driver object.
+
+A parent object, defined in the shared header file, contains the
+auxiliary_device.  It also contains a pointer to the shared object(s), which
+also is defined in the shared header.  Both the parent object and the shared
+object(s) are allocated by the registering driver.  This layout allows the
+auxiliary_driver's registering module to perform a container_of() call to go
+from the pointer to the auxiliary_device, that is passed during the call to the
+auxiliary_driver's probe function, up to the parent object, and then have
+access to the shared object(s).
+
+The memory for the auxiliary_device is freed only in its release() callback
+flow as defined by its registering driver.
+
+The memory for the shared object(s) must have a lifespan equal to, or greater
+than, the lifespan of the memory for the auxiliary_device.  The auxiliary_driver
+should only consider that this shared object is valid as long as the
+auxiliary_device is still registered on the auxiliary bus.  It is up to the
+registering driver to manage (e.g. free or keep available) the memory for the
+shared object beyond the life of the auxiliary_device.
+
+The registering driver must unregister all auxiliary devices before its own
+driver.remove() is completed.
+
+Auxiliary Drivers
+=================
+
+Auxiliary drivers follow the standard driver model convention, where
+discovery/enumeration is handled by the core, and drivers
+provide probe() and remove() methods. They support power management
+and shutdown notifications using the standard conventions.
+
+.. code-block:: c
+
+       struct auxiliary_driver {
+               int (*probe)(struct auxiliary_device *,
+                             const struct auxiliary_device_id *id);
+               void (*remove)(struct auxiliary_device *);
+               void (*shutdown)(struct auxiliary_device *);
+               int (*suspend)(struct auxiliary_device *, pm_message_t);
+               int (*resume)(struct auxiliary_device *);
+               struct device_driver driver;
+               const struct auxiliary_device_id *id_table;
+       };
+
+Auxiliary drivers register themselves with the bus by calling
+auxiliary_driver_register(). The id_table contains the match_names of auxiliary
+devices that a driver can bind with.
+
+Example Usage
+=============
+
+Auxiliary devices are created and registered by a subsystem-level core device
+that needs to break up its functionality into smaller fragments. One way to
+extend the scope of an auxiliary_device is to encapsulate it within a domain-
+pecific structure defined by the parent device. This structure contains the
+auxiliary_device and any associated shared data/callbacks needed to establish
+the connection with the parent.
+
+An example is:
+
+.. code-block:: c
+
+        struct foo {
+               struct auxiliary_device auxdev;
+               void (*connect)(struct auxiliary_device *auxdev);
+               void (*disconnect)(struct auxiliary_device *auxdev);
+               void *data;
+        };
+
+The parent device then registers the auxiliary_device by calling
+auxiliary_device_init(), and then auxiliary_device_add(), with the pointer to
+the auxdev member of the above structure. The parent provides a name for the
+auxiliary_device that, combined with the parent's KBUILD_MODNAME, creates a
+match_name that is be used for matching and binding with a driver.
+
+Whenever an auxiliary_driver is registered, based on the match_name, the
+auxiliary_driver's probe() is invoked for the matching devices.  The
+auxiliary_driver can also be encapsulated inside custom drivers that make the
+core device's functionality extensible by adding additional domain-specific ops
+as follows:
+
+.. code-block:: c
+
+       struct my_ops {
+               void (*send)(struct auxiliary_device *auxdev);
+               void (*receive)(struct auxiliary_device *auxdev);
+       };
+
+
+       struct my_driver {
+               struct auxiliary_driver auxiliary_drv;
+               const struct my_ops ops;
+       };
+
+An example of this type of usage is:
+
+.. code-block:: c
+
+       const struct auxiliary_device_id my_auxiliary_id_table[] = {
+               { .name = "foo_mod.foo_dev" },
+               { },
+       };
+
+       const struct my_ops my_custom_ops = {
+               .send = my_tx,
+               .receive = my_rx,
+       };
+
+       const struct my_driver my_drv = {
+               .auxiliary_drv = {
+                       .name = "myauxiliarydrv",
+                       .id_table = my_auxiliary_id_table,
+                       .probe = my_probe,
+                       .remove = my_remove,
+                       .shutdown = my_shutdown,
+               },
+               .ops = my_custom_ops,
+       };
index f357f3e..86759a7 100644 (file)
@@ -72,6 +72,7 @@ available subsections can be seen below.
    thermal/index
    fpga/index
    acpi/index
+   auxiliary_bus
    backlight/lp855x-driver.rst
    connector
    console
index 8d70017..040be48 100644 (file)
@@ -1,6 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 menu "Generic Driver Options"
 
+config AUXILIARY_BUS
+       bool
+
 config UEVENT_HELPER
        bool "Support for uevent helper"
        help
index 41369fc..5e7bf96 100644 (file)
@@ -7,6 +7,7 @@ obj-y                   := component.o core.o bus.o dd.o syscore.o \
                           attribute_container.o transport_class.o \
                           topology.o container.o property.o cacheinfo.o \
                           swnode.o
+obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o
 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
 obj-y                  += power/
 obj-$(CONFIG_ISA_BUS_API)      += isa.o
diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c
new file mode 100644 (file)
index 0000000..f303daa
--- /dev/null
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020 Intel Corporation
+ *
+ * Please see Documentation/driver-api/auxiliary_bus.rst for more information.
+ */
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/auxiliary_bus.h>
+
+static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
+                                                           const struct auxiliary_device *auxdev)
+{
+       for (; id->name[0]; id++) {
+               const char *p = strrchr(dev_name(&auxdev->dev), '.');
+               int match_size;
+
+               if (!p)
+                       continue;
+               match_size = p - dev_name(&auxdev->dev);
+
+               /* use dev_name(&auxdev->dev) prefix before last '.' char to match to */
+               if (strlen(id->name) == match_size &&
+                   !strncmp(dev_name(&auxdev->dev), id->name, match_size))
+                       return id;
+       }
+       return NULL;
+}
+
+static int auxiliary_match(struct device *dev, struct device_driver *drv)
+{
+       struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+       struct auxiliary_driver *auxdrv = to_auxiliary_drv(drv);
+
+       return !!auxiliary_match_id(auxdrv->id_table, auxdev);
+}
+
+static int auxiliary_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       const char *name, *p;
+
+       name = dev_name(dev);
+       p = strrchr(name, '.');
+
+       return add_uevent_var(env, "MODALIAS=%s%.*s", AUXILIARY_MODULE_PREFIX,
+                             (int)(p - name), name);
+}
+
+static const struct dev_pm_ops auxiliary_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
+};
+
+static int auxiliary_bus_probe(struct device *dev)
+{
+       struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
+       struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+       int ret;
+
+       ret = dev_pm_domain_attach(dev, true);
+       if (ret) {
+               dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret);
+               return ret;
+       }
+
+       ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev));
+       if (ret)
+               dev_pm_domain_detach(dev, true);
+
+       return ret;
+}
+
+static int auxiliary_bus_remove(struct device *dev)
+{
+       struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
+       struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+
+       if (auxdrv->remove)
+               auxdrv->remove(auxdev);
+       dev_pm_domain_detach(dev, true);
+
+       return 0;
+}
+
+static void auxiliary_bus_shutdown(struct device *dev)
+{
+       struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
+       struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+
+       if (auxdrv->shutdown)
+               auxdrv->shutdown(auxdev);
+}
+
+static struct bus_type auxiliary_bus_type = {
+       .name = "auxiliary",
+       .probe = auxiliary_bus_probe,
+       .remove = auxiliary_bus_remove,
+       .shutdown = auxiliary_bus_shutdown,
+       .match = auxiliary_match,
+       .uevent = auxiliary_uevent,
+       .pm = &auxiliary_dev_pm_ops,
+};
+
+/**
+ * auxiliary_device_init - check auxiliary_device and initialize
+ * @auxdev: auxiliary device struct
+ *
+ * This is the first step in the two-step process to register an
+ * auxiliary_device.
+ *
+ * When this function returns an error code, then the device_initialize will
+ * *not* have been performed, and the caller will be responsible to free any
+ * memory allocated for the auxiliary_device in the error path directly.
+ *
+ * It returns 0 on success.  On success, the device_initialize has been
+ * performed.  After this point any error unwinding will need to include a call
+ * to auxiliary_device_uninit().  In this post-initialize error scenario, a call
+ * to the device's .release callback will be triggered, and all memory clean-up
+ * is expected to be handled there.
+ */
+int auxiliary_device_init(struct auxiliary_device *auxdev)
+{
+       struct device *dev = &auxdev->dev;
+
+       if (!dev->parent) {
+               pr_err("auxiliary_device has a NULL dev->parent\n");
+               return -EINVAL;
+       }
+
+       if (!auxdev->name) {
+               pr_err("auxiliary_device has a NULL name\n");
+               return -EINVAL;
+       }
+
+       dev->bus = &auxiliary_bus_type;
+       device_initialize(&auxdev->dev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(auxiliary_device_init);
+
+/**
+ * __auxiliary_device_add - add an auxiliary bus device
+ * @auxdev: auxiliary bus device to add to the bus
+ * @modname: name of the parent device's driver module
+ *
+ * This is the second step in the two-step process to register an
+ * auxiliary_device.
+ *
+ * This function must be called after a successful call to
+ * auxiliary_device_init(), which will perform the device_initialize.  This
+ * means that if this returns an error code, then a call to
+ * auxiliary_device_uninit() must be performed so that the .release callback
+ * will be triggered to free the memory associated with the auxiliary_device.
+ *
+ * The expectation is that users will call the "auxiliary_device_add" macro so
+ * that the caller's KBUILD_MODNAME is automatically inserted for the modname
+ * parameter.  Only if a user requires a custom name would this version be
+ * called directly.
+ */
+int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname)
+{
+       struct device *dev = &auxdev->dev;
+       int ret;
+
+       if (!modname) {
+               dev_err(dev, "auxiliary device modname is NULL\n");
+               return -EINVAL;
+       }
+
+       ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id);
+       if (ret) {
+               dev_err(dev, "auxiliary device dev_set_name failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = device_add(dev);
+       if (ret)
+               dev_err(dev, "adding auxiliary device failed!: %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__auxiliary_device_add);
+
+/**
+ * auxiliary_find_device - auxiliary device iterator for locating a particular device.
+ * @start: Device to begin with
+ * @data: Data to pass to match function
+ * @match: Callback function to check device
+ *
+ * This function returns a reference to a device that is 'found'
+ * for later use, as determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+ */
+struct auxiliary_device *auxiliary_find_device(struct device *start,
+                                              const void *data,
+                                              int (*match)(struct device *dev, const void *data))
+{
+       struct device *dev;
+
+       dev = bus_find_device(&auxiliary_bus_type, start, data, match);
+       if (!dev)
+               return NULL;
+
+       return to_auxiliary_dev(dev);
+}
+EXPORT_SYMBOL_GPL(auxiliary_find_device);
+
+/**
+ * __auxiliary_driver_register - register a driver for auxiliary bus devices
+ * @auxdrv: auxiliary_driver structure
+ * @owner: owning module/driver
+ * @modname: KBUILD_MODNAME for parent driver
+ */
+int __auxiliary_driver_register(struct auxiliary_driver *auxdrv,
+                               struct module *owner, const char *modname)
+{
+       if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table))
+               return -EINVAL;
+
+       if (auxdrv->name)
+               auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", modname,
+                                               auxdrv->name);
+       else
+               auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", modname);
+       if (!auxdrv->driver.name)
+               return -ENOMEM;
+
+       auxdrv->driver.owner = owner;
+       auxdrv->driver.bus = &auxiliary_bus_type;
+       auxdrv->driver.mod_name = modname;
+
+       return driver_register(&auxdrv->driver);
+}
+EXPORT_SYMBOL_GPL(__auxiliary_driver_register);
+
+/**
+ * auxiliary_driver_unregister - unregister a driver
+ * @auxdrv: auxiliary_driver structure
+ */
+void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
+{
+       driver_unregister(&auxdrv->driver);
+       kfree(auxdrv->driver.name);
+}
+EXPORT_SYMBOL_GPL(auxiliary_driver_unregister);
+
+static int __init auxiliary_bus_init(void)
+{
+       return bus_register(&auxiliary_bus_type);
+}
+
+static void __exit auxiliary_bus_exit(void)
+{
+       bus_unregister(&auxiliary_bus_type);
+}
+
+module_init(auxiliary_bus_init);
+module_exit(auxiliary_bus_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Auxiliary Bus");
+MODULE_AUTHOR("David Ertman <david.m.ertman@intel.com>");
+MODULE_AUTHOR("Kiran Patil <kiran.patil@intel.com>");
index bcb90d8..50b1e2d 100644 (file)
@@ -4,7 +4,7 @@
 # subsystems should select the appropriate symbols.
 
 config REGMAP
-       default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM)
+       default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM)
        select IRQ_DOMAIN if REGMAP_IRQ
        bool
 
@@ -46,6 +46,10 @@ config REGMAP_SOUNDWIRE
        tristate
        depends on SOUNDWIRE
 
+config REGMAP_SOUNDWIRE_MBQ
+       tristate
+       depends on SOUNDWIRE
+
 config REGMAP_SCCB
        tristate
        depends on I2C
index ac1b69e..33f63ad 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
 obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
 obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
 obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
+obj-$(CONFIG_REGMAP_SOUNDWIRE_MBQ) += regmap-sdw-mbq.o
 obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
 obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
 obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
diff --git a/drivers/base/regmap/regmap-sdw-mbq.c b/drivers/base/regmap/regmap-sdw-mbq.c
new file mode 100644 (file)
index 0000000..8ce3065
--- /dev/null
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2020 Intel Corporation.
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include "internal.h"
+
+static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct device *dev = context;
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       int ret;
+
+       ret = sdw_write(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
+       if (ret < 0)
+               return ret;
+
+       return sdw_write(slave, reg, val & 0xff);
+}
+
+static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct device *dev = context;
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       int read0;
+       int read1;
+
+       read0 = sdw_read(slave, reg);
+       if (read0 < 0)
+               return read0;
+
+       read1 = sdw_read(slave, SDW_SDCA_MBQ_CTL(reg));
+       if (read1 < 0)
+               return read1;
+
+       *val = (read1 << 8) | read0;
+
+       return 0;
+}
+
+static struct regmap_bus regmap_sdw_mbq = {
+       .reg_read = regmap_sdw_mbq_read,
+       .reg_write = regmap_sdw_mbq_write,
+       .reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
+       .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
+};
+
+static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
+{
+       /* MBQ-based controls are only 16-bits for now */
+       if (config->val_bits != 16)
+               return -ENOTSUPP;
+
+       /* Registers are 32 bits wide */
+       if (config->reg_bits != 32)
+               return -ENOTSUPP;
+
+       if (config->pad_bits != 0)
+               return -ENOTSUPP;
+
+       return 0;
+}
+
+struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
+                                    const struct regmap_config *config,
+                                    struct lock_class_key *lock_key,
+                                    const char *lock_name)
+{
+       int ret;
+
+       ret = regmap_sdw_mbq_config_check(config);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return __regmap_init(&sdw->dev, &regmap_sdw_mbq,
+                       &sdw->dev, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
+
+struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
+                                         const struct regmap_config *config,
+                                         struct lock_class_key *lock_key,
+                                         const char *lock_name)
+{
+       int ret;
+
+       ret = regmap_sdw_mbq_config_check(config);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return __devm_regmap_init(&sdw->dev, &regmap_sdw_mbq,
+                       &sdw->dev, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
+
+MODULE_DESCRIPTION("Regmap SoundWire MBQ Module");
+MODULE_LICENSE("GPL v2");
index 8eaf31e..ffe4600 100644 (file)
@@ -1424,6 +1424,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
        int port_num, stat, ret, count = 0;
        unsigned long port;
        bool slave_notify = false;
+       u8 sdca_cascade = 0;
        u8 buf, buf2[2], _buf, _buf2[2];
        bool parity_check;
        bool parity_quirk;
@@ -1453,6 +1454,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
                goto io_err;
        }
 
+       if (slave->prop.is_sdca) {
+               ret = sdw_read(slave, SDW_DP0_INT);
+               if (ret < 0) {
+                       dev_err(slave->bus->dev,
+                               "SDW_DP0_INT read failed:%d\n", ret);
+                       goto io_err;
+               }
+               sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+       }
+
        do {
                /*
                 * Check parity, bus clash and Slave (impl defined)
@@ -1489,6 +1500,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
                        clear |= SDW_SCP_INT1_IMPL_DEF;
                }
 
+               /* the SDCA interrupts are cleared in the codec driver .interrupt_callback() */
+               if (sdca_cascade)
+                       slave_notify = true;
+
                /* Check port 0 - 3 interrupts */
                port = buf & SDW_SCP_INT1_PORT0_3;
 
@@ -1526,6 +1541,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
                /* Update the Slave driver */
                if (slave_notify && slave->ops &&
                    slave->ops->interrupt_callback) {
+                       slave_intr.sdca_cascade = sdca_cascade;
                        slave_intr.control_port = clear;
                        memcpy(slave_intr.port, &port_status,
                               sizeof(slave_intr.port));
@@ -1563,11 +1579,21 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
                        goto io_err;
                }
 
+               if (slave->prop.is_sdca) {
+                       ret = sdw_read(slave, SDW_DP0_INT);
+                       if (ret < 0) {
+                               dev_err(slave->bus->dev,
+                                       "SDW_DP0_INT read failed:%d\n", ret);
+                               goto io_err;
+                       }
+                       sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+               }
+
                /* Make sure no interrupts are pending */
                buf &= _buf;
                buf2[0] &= _buf2[0];
                buf2[1] &= _buf2[1];
-               stat = buf || buf2[0] || buf2[1];
+               stat = buf || buf2[0] || buf2[1] || sdca_cascade;
 
                /*
                 * Exit loop if Slave is continuously in ALERT state even
index 05a721e..c4b6543 100644 (file)
@@ -37,6 +37,7 @@ static int field##_attribute_alloc(struct device *dev,                        \
                return -ENOMEM;                                         \
        dpn_attr->N = N;                                                \
        dpn_attr->dir = dir;                                            \
+       sysfs_attr_init(&dpn_attr->dev_attr.attr);                      \
        dpn_attr->format_string = format_string;                        \
        dpn_attr->dev_attr.attr.name = __stringify(field);              \
        dpn_attr->dev_attr.attr.mode = 0444;                            \
diff --git a/include/dt-bindings/sound/adi,adau1977.h b/include/dt-bindings/sound/adi,adau1977.h
new file mode 100644 (file)
index 0000000..8eebec6
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __DT_BINDINGS_ADI_ADAU1977_H__
+#define __DT_BINDINGS_ADI_ADAU1977_H__
+
+#define ADAU1977_MICBIAS_5V0   0x0
+#define ADAU1977_MICBIAS_5V5   0x1
+#define ADAU1977_MICBIAS_6V0   0x2
+#define ADAU1977_MICBIAS_6V5   0x3
+#define ADAU1977_MICBIAS_7V0   0x4
+#define ADAU1977_MICBIAS_7V5   0x5
+#define ADAU1977_MICBIAS_8V0   0x6
+#define ADAU1977_MICBIAS_8V5   0x7
+#define ADAU1977_MICBIAS_9V0   0x8
+
+#endif /* __DT_BINDINGS_ADI_ADAU1977_H__ */
diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h
new file mode 100644 (file)
index 0000000..fc51d45
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019-2020 Intel Corporation
+ *
+ * Please see Documentation/driver-api/auxiliary_bus.rst for more information.
+ */
+
+#ifndef _AUXILIARY_BUS_H_
+#define _AUXILIARY_BUS_H_
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct auxiliary_device {
+       struct device dev;
+       const char *name;
+       u32 id;
+};
+
+struct auxiliary_driver {
+       int (*probe)(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id);
+       void (*remove)(struct auxiliary_device *auxdev);
+       void (*shutdown)(struct auxiliary_device *auxdev);
+       int (*suspend)(struct auxiliary_device *auxdev, pm_message_t state);
+       int (*resume)(struct auxiliary_device *auxdev);
+       const char *name;
+       struct device_driver driver;
+       const struct auxiliary_device_id *id_table;
+};
+
+static inline struct auxiliary_device *to_auxiliary_dev(struct device *dev)
+{
+       return container_of(dev, struct auxiliary_device, dev);
+}
+
+static inline struct auxiliary_driver *to_auxiliary_drv(struct device_driver *drv)
+{
+       return container_of(drv, struct auxiliary_driver, driver);
+}
+
+int auxiliary_device_init(struct auxiliary_device *auxdev);
+int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname);
+#define auxiliary_device_add(auxdev) __auxiliary_device_add(auxdev, KBUILD_MODNAME)
+
+static inline void auxiliary_device_uninit(struct auxiliary_device *auxdev)
+{
+       put_device(&auxdev->dev);
+}
+
+static inline void auxiliary_device_delete(struct auxiliary_device *auxdev)
+{
+       device_del(&auxdev->dev);
+}
+
+int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *owner,
+                               const char *modname);
+#define auxiliary_driver_register(auxdrv) \
+       __auxiliary_driver_register(auxdrv, THIS_MODULE, KBUILD_MODNAME)
+
+void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv);
+
+/**
+ * module_auxiliary_driver() - Helper macro for registering an auxiliary driver
+ * @__auxiliary_driver: auxiliary driver struct
+ *
+ * Helper macro for auxiliary drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_auxiliary_driver(__auxiliary_driver) \
+       module_driver(__auxiliary_driver, auxiliary_driver_register, auxiliary_driver_unregister)
+
+struct auxiliary_device *auxiliary_find_device(struct device *start,
+                                              const void *data,
+                                              int (*match)(struct device *dev, const void *data));
+
+#endif /* _AUXILIARY_BUS_H_ */
index 5b08a47..c425290 100644 (file)
@@ -838,4 +838,12 @@ struct mhi_device_id {
        kernel_ulong_t driver_data;
 };
 
+#define AUXILIARY_NAME_SIZE 32
+#define AUXILIARY_MODULE_PREFIX "auxiliary:"
+
+struct auxiliary_device_id {
+       char name[AUXILIARY_NAME_SIZE];
+       kernel_ulong_t driver_data;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/platform_data/adau1977.h b/include/linux/platform_data/adau1977.h
deleted file mode 100644 (file)
index 8666723..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * ADAU1977/ADAU1978/ADAU1979 driver
- *
- * Copyright 2014 Analog Devices Inc.
- *  Author: Lars-Peter Clausen <lars@metafoo.de>
- */
-
-#ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__
-#define __LINUX_PLATFORM_DATA_ADAU1977_H__
-
-/**
- * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting
- * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V
- * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V
- * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V
- * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V
- * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V
- * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V
- * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V
- * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V
- * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V
- */
-enum adau1977_micbias {
-       ADAU1977_MICBIAS_5V0 = 0x0,
-       ADAU1977_MICBIAS_5V5 = 0x1,
-       ADAU1977_MICBIAS_6V0 = 0x2,
-       ADAU1977_MICBIAS_6V5 = 0x3,
-       ADAU1977_MICBIAS_7V0 = 0x4,
-       ADAU1977_MICBIAS_7V5 = 0x5,
-       ADAU1977_MICBIAS_8V0 = 0x6,
-       ADAU1977_MICBIAS_8V5 = 0x7,
-       ADAU1977_MICBIAS_9V0 = 0x8,
-};
-
-/**
- * struct adau1977_platform_data - Platform configuration data for the ADAU1977
- * @micbias: Specifies the voltage for the MICBIAS pin
- */
-struct adau1977_platform_data {
-       enum adau1977_micbias micbias;
-};
-
-#endif
index e7834d9..a652d14 100644 (file)
@@ -570,6 +570,10 @@ struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,
                                 const struct regmap_config *config,
                                 struct lock_class_key *lock_key,
                                 const char *lock_name);
+struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
+                                    const struct regmap_config *config,
+                                    struct lock_class_key *lock_key,
+                                    const char *lock_name);
 struct regmap *__regmap_init_spi_avmm(struct spi_device *spi,
                                      const struct regmap_config *config,
                                      struct lock_class_key *lock_key,
@@ -619,6 +623,10 @@ struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw,
                                 const struct regmap_config *config,
                                 struct lock_class_key *lock_key,
                                 const char *lock_name);
+struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
+                                         const struct regmap_config *config,
+                                         struct lock_class_key *lock_key,
+                                         const char *lock_name);
 struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus,
                                 const struct regmap_config *config,
                                 struct lock_class_key *lock_key,
@@ -817,6 +825,19 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
        __regmap_lockdep_wrapper(__regmap_init_sdw, #config,            \
                                sdw, config)
 
+/**
+ * regmap_init_sdw_mbq() - Initialise register map
+ *
+ * @sdw: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+#define regmap_init_sdw_mbq(sdw, config)                                       \
+       __regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #config,                \
+                               sdw, config)
+
 /**
  * regmap_init_spi_avmm() - Initialize register map for Intel SPI Slave
  * to AVMM Bus Bridge
@@ -989,6 +1010,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
        __regmap_lockdep_wrapper(__devm_regmap_init_sdw, #config,       \
                                sdw, config)
 
+/**
+ * devm_regmap_init_sdw_mbq() - Initialise managed register map
+ *
+ * @sdw: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+#define devm_regmap_init_sdw_mbq(sdw, config)                  \
+       __regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, #config,   \
+                               sdw, config)
+
 /**
  * devm_regmap_init_slimbus() - Initialise managed register map
  *
index 41cc119..f0b01b7 100644 (file)
@@ -359,6 +359,7 @@ struct sdw_dpn_prop {
  * @sink_dpn_prop: Sink Data Port N properties
  * @scp_int1_mask: SCP_INT1_MASK desired settings
  * @quirks: bitmask identifying deltas from the MIPI specification
+ * @is_sdca: the Slave supports the SDCA specification
  */
 struct sdw_slave_prop {
        u32 mipi_revision;
@@ -382,6 +383,7 @@ struct sdw_slave_prop {
        struct sdw_dpn_prop *sink_dpn_prop;
        u8 scp_int1_mask;
        u32 quirks;
+       bool is_sdca;
 };
 
 #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY        BIT(0)
@@ -479,10 +481,12 @@ struct sdw_slave_id {
 
 /**
  * struct sdw_slave_intr_status - Slave interrupt status
+ * @sdca_cascade: set if the Slave device reports an SDCA interrupt
  * @control_port: control port status
  * @port: data port status
  */
 struct sdw_slave_intr_status {
+       bool sdca_cascade;
        u8 control_port;
        u8 port[15];
 };
index f420e80..e14dff9 100644 (file)
 #define SDW_CASC_PORT_MASK_INTSTAT3            1
 #define SDW_CASC_PORT_REG_OFFSET_INTSTAT3      2
 
+/*
+ * v1.2 device - SDCA address mapping
+ *
+ * Spec definition
+ *     Bits            Contents
+ *     31              0 (required by addressing range)
+ *     30:26           0b10000 (Control Prefix)
+ *     25              0 (Reserved)
+ *     24:22           Function Number [2:0]
+ *     21              Entity[6]
+ *     20:19           Control Selector[5:4]
+ *     18              0 (Reserved)
+ *     17:15           Control Number[5:3]
+ *     14              Next
+ *     13              MBQ
+ *     12:7            Entity[5:0]
+ *     6:3             Control Selector[3:0]
+ *     2:0             Control Number[2:0]
+ */
+
+#define SDW_SDCA_CTL(fun, ent, ctl, ch)                (BIT(30) |                      \
+                                                (((fun) & 0x7) << 22) |        \
+                                                (((ent) & 0x40) << 15) |       \
+                                                (((ent) & 0x3f) << 7) |        \
+                                                (((ctl) & 0x30) << 15) |       \
+                                                (((ctl) & 0x0f) << 3) |        \
+                                                (((ch) & 0x38) << 12) |        \
+                                                ((ch) & 0x07))
+
+#define SDW_SDCA_MBQ_CTL(reg)                  ((reg) | BIT(13))
+#define SDW_SDCA_NEXT_CTL(reg)                 ((reg) | BIT(14))
+
 #endif /* __SDW_REGISTERS_H */
diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h
new file mode 100644 (file)
index 0000000..bbb5a13
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * ASoC audio graph card support
+ *
+ */
+
+#ifndef __GRAPH_CARD_H
+#define __GRAPH_CARD_H
+
+#include <sound/simple_card_utils.h>
+
+int graph_card_probe(struct snd_soc_card *card);
+
+int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
+
+#endif /* __GRAPH_CARD_H */
index c36622b..d460907 100644 (file)
@@ -21,6 +21,7 @@ enum {
 #if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)
 
 int snd_intel_dsp_driver_probe(struct pci_dev *pci);
+int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]);
 
 #else
 
@@ -29,6 +30,12 @@ static inline int snd_intel_dsp_driver_probe(struct pci_dev *pci)
        return SND_INTEL_DSP_DRIVER_ANY;
 }
 
+static inline
+int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
+{
+       return SND_INTEL_DSP_DRIVER_ANY;
+}
+
 #endif
 
 #endif
index e1f7905..3900a07 100644 (file)
@@ -40,6 +40,7 @@ struct rt5682_platform_data {
        unsigned int btndet_delay;
        unsigned int dmic_clk_rate;
        unsigned int dmic_delay;
+       bool dmic_clk_driving_high;
 
        const char *dai_clk_names[RT5682_DAI_NUM_CLKS];
 };
index 86a1e95..ba4a3e1 100644 (file)
@@ -56,6 +56,9 @@ struct asoc_simple_priv {
        struct asoc_simple_dai *dais;
        struct snd_soc_codec_conf *codec_conf;
        struct gpio_desc *pa_gpio;
+       const struct snd_soc_ops *ops;
+       unsigned int dpcm_selectable:1;
+       unsigned int force_dpcm:1;
 };
 #define simple_priv_to_card(priv)      (&(priv)->snd_card)
 #define simple_priv_to_props(priv, i)  ((priv)->dai_props + (i))
index 5c49e7d..59551b1 100644 (file)
@@ -29,12 +29,14 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[];
 
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[];
 
 /*
  * generic table used for HDA codec-based platforms, possibly with
index b16a844..9a43c44 100644 (file)
@@ -171,4 +171,10 @@ struct snd_soc_acpi_codecs {
        u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN];
 };
 
+static inline bool snd_soc_acpi_sof_parent(struct device *dev)
+{
+       return dev->parent && dev->parent->driver && dev->parent->driver->name &&
+               !strcmp(dev->parent->driver->name, "sof-audio-acpi");
+}
+
 #endif
index 2c790ce..0bce41f 100644 (file)
@@ -220,6 +220,9 @@ struct snd_soc_component {
        /* function mark */
        struct snd_pcm_substream *mark_module;
        struct snd_pcm_substream *mark_open;
+       struct snd_pcm_substream *mark_hw_params;
+       struct snd_pcm_substream *mark_trigger;
+       struct snd_compr_stream  *mark_compr_open;
        void *mark_pm;
 
 #ifdef CONFIG_DEBUG_FS
@@ -443,6 +446,27 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component,
 int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component,
                                        struct of_phandle_args *args,
                                        const char **dai_name);
+int snd_soc_component_compr_open(struct snd_compr_stream *cstream);
+void snd_soc_component_compr_free(struct snd_compr_stream *cstream,
+                                 int rollback);
+int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd);
+int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream,
+                                      struct snd_compr_params *params);
+int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream,
+                                      struct snd_codec *params);
+int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream,
+                                    struct snd_compr_caps *caps);
+int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream,
+                                          struct snd_compr_codec_caps *codec);
+int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes);
+int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream,
+                                   struct snd_compr_tstamp *tstamp);
+int snd_soc_component_compr_copy(struct snd_compr_stream *cstream,
+                                char __user *buf, size_t count);
+int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream,
+                                        struct snd_compr_metadata *metadata);
+int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream,
+                                        struct snd_compr_metadata *metadata);
 
 int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream);
 int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
@@ -459,12 +483,11 @@ int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd);
 void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd);
 int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream);
 int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
-                                   struct snd_pcm_hw_params *params,
-                                   struct snd_soc_component **last);
+                                   struct snd_pcm_hw_params *params);
 void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
-                                  struct snd_soc_component *last);
+                                  int rollback);
 int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
-                                 int cmd);
+                                 int cmd, int rollback);
 int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
                                         void *stream);
 void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
index 2150bd4..34d0dbf 100644 (file)
@@ -72,21 +72,29 @@ struct snd_compr_stream;
 #define SND_SOC_DAIFMT_IB_IF           (4 << 8) /* invert BCLK + FRM */
 
 /*
- * DAI hardware clock masters.
+ * DAI hardware clock providers/consumers
  *
  * This is wrt the codec, the inverse is true for the interface
- * i.e. if the codec is clk and FRM master then the interface is
- * clk and frame secondary.
+ * i.e. if the codec is clk and FRM provider then the interface is
+ * clk and frame consumer.
  */
-#define SND_SOC_DAIFMT_CBM_CFM         (1 << 12) /* codec clk & FRM master */
-#define SND_SOC_DAIFMT_CBS_CFM         (2 << 12) /* codec clk secondary & FRM master */
-#define SND_SOC_DAIFMT_CBM_CFS         (3 << 12) /* codec clk master & frame secondary */
-#define SND_SOC_DAIFMT_CBS_CFS         (4 << 12) /* codec clk & FRM secondary */
+#define SND_SOC_DAIFMT_CBP_CFP         (1 << 12) /* codec clk provider & frame provider */
+#define SND_SOC_DAIFMT_CBC_CFP         (2 << 12) /* codec clk consumer & frame provider */
+#define SND_SOC_DAIFMT_CBP_CFC         (3 << 12) /* codec clk provider & frame consumer */
+#define SND_SOC_DAIFMT_CBC_CFC         (4 << 12) /* codec clk consumer & frame follower */
 
-#define SND_SOC_DAIFMT_FORMAT_MASK     0x000f
-#define SND_SOC_DAIFMT_CLOCK_MASK      0x00f0
-#define SND_SOC_DAIFMT_INV_MASK                0x0f00
-#define SND_SOC_DAIFMT_MASTER_MASK     0xf000
+/* previous definitions kept for backwards-compatibility, do not use in new contributions */
+#define SND_SOC_DAIFMT_CBM_CFM         SND_SOC_DAIFMT_CBP_CFP
+#define SND_SOC_DAIFMT_CBS_CFM         SND_SOC_DAIFMT_CBC_CFP
+#define SND_SOC_DAIFMT_CBM_CFS         SND_SOC_DAIFMT_CBP_CFC
+#define SND_SOC_DAIFMT_CBS_CFS         SND_SOC_DAIFMT_CBC_CFC
+
+#define SND_SOC_DAIFMT_FORMAT_MASK             0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK              0x00f0
+#define SND_SOC_DAIFMT_INV_MASK                        0x0f00
+#define SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK     0xf000
+
+#define SND_SOC_DAIFMT_MASTER_MASK     SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK
 
 /*
  * Master Clock Directions
@@ -149,7 +157,8 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
                          struct snd_pcm_substream *substream,
                          struct snd_pcm_hw_params *params);
 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
-                        struct snd_pcm_substream *substream);
+                        struct snd_pcm_substream *substream,
+                        int rollback);
 int snd_soc_dai_startup(struct snd_soc_dai *dai,
                        struct snd_pcm_substream *substream);
 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
@@ -180,14 +189,16 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order);
 int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order);
 int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd);
 int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream);
-int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                           int rollback);
 int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
                                    int cmd);
 
 int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
                              struct snd_compr_stream *cstream);
 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
-                               struct snd_compr_stream *cstream);
+                               struct snd_compr_stream *cstream,
+                               int rollback);
 int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
                              struct snd_compr_stream *cstream, int cmd);
 int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
@@ -390,6 +401,9 @@ struct snd_soc_dai {
 
        /* function mark */
        struct snd_pcm_substream *mark_startup;
+       struct snd_pcm_substream *mark_hw_params;
+       struct snd_pcm_substream *mark_trigger;
+       struct snd_compr_stream  *mark_compr_startup;
 
        /* bit field */
        unsigned int probed:1;
diff --git a/include/sound/soc-jack.h b/include/sound/soc-jack.h
new file mode 100644 (file)
index 0000000..a0abb1e
--- /dev/null
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * soc-jack.h
+ *
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ */
+#ifndef __SOC_JACK_H
+#define __SOC_JACK_H
+
+/**
+ * struct snd_soc_jack_pin - Describes a pin to update based on jack detection
+ *
+ * @pin:    name of the pin to update
+ * @mask:   bits to check for in reported jack status
+ * @invert: if non-zero then pin is enabled when status is not reported
+ * @list:   internal list entry
+ */
+struct snd_soc_jack_pin {
+       struct list_head list;
+       const char *pin;
+       int mask;
+       bool invert;
+};
+
+/**
+ * struct snd_soc_jack_zone - Describes voltage zones of jack detection
+ *
+ * @min_mv: start voltage in mv
+ * @max_mv: end voltage in mv
+ * @jack_type: type of jack that is expected for this voltage
+ * @debounce_time: debounce_time for jack, codec driver should wait for this
+ *             duration before reading the adc for voltages
+ * @list:   internal list entry
+ */
+struct snd_soc_jack_zone {
+       unsigned int min_mv;
+       unsigned int max_mv;
+       unsigned int jack_type;
+       unsigned int debounce_time;
+       struct list_head list;
+};
+
+/**
+ * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
+ *
+ * @gpio:         legacy gpio number
+ * @idx:          gpio descriptor index within the function of the GPIO
+ *                consumer device
+ * @gpiod_dev:    GPIO consumer device
+ * @name:         gpio name. Also as connection ID for the GPIO consumer
+ *                device function name lookup
+ * @report:       value to report when jack detected
+ * @invert:       report presence in low state
+ * @debounce_time: debounce time in ms
+ * @wake:        enable as wake source
+ * @jack_status_check: callback function which overrides the detection
+ *                    to provide more complex checks (eg, reading an
+ *                    ADC).
+ */
+struct snd_soc_jack_gpio {
+       unsigned int gpio;
+       unsigned int idx;
+       struct device *gpiod_dev;
+       const char *name;
+       int report;
+       int invert;
+       int debounce_time;
+       bool wake;
+
+       /* private: */
+       struct snd_soc_jack *jack;
+       struct delayed_work work;
+       struct notifier_block pm_notifier;
+       struct gpio_desc *desc;
+
+       void *data;
+       /* public: */
+       int (*jack_status_check)(void *data);
+};
+
+struct snd_soc_jack {
+       struct mutex mutex;
+       struct snd_jack *jack;
+       struct snd_soc_card *card;
+       struct list_head pins;
+       int status;
+       struct blocking_notifier_head notifier;
+       struct list_head jack_zones;
+};
+
+/* Jack reporting */
+void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
+int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
+                         struct snd_soc_jack_pin *pins);
+void snd_soc_jack_notifier_register(struct snd_soc_jack *jack,
+                                   struct notifier_block *nb);
+void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack,
+                                     struct notifier_block *nb);
+int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count,
+                          struct snd_soc_jack_zone *zones);
+int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage);
+#ifdef CONFIG_GPIOLIB
+int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
+                          struct snd_soc_jack_gpio *gpios);
+int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
+                           struct snd_soc_jack *jack,
+                           int count, struct snd_soc_jack_gpio *gpios);
+void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+                            struct snd_soc_jack_gpio *gpios);
+#else
+static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
+                                        struct snd_soc_jack_gpio *gpios)
+{
+       return 0;
+}
+
+static inline int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
+                                         struct snd_soc_jack *jack,
+                                         int count,
+                                         struct snd_soc_jack_gpio *gpios)
+{
+       return 0;
+}
+
+static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+                                          struct snd_soc_jack_gpio *gpios)
+{
+}
+#endif
+
+#endif /* __SOC_JACK_H */
index dac6c0c..9314cde 100644 (file)
@@ -19,11 +19,14 @@ void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
 int snd_soc_link_prepare(struct snd_pcm_substream *substream);
 int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params);
-void snd_soc_link_hw_free(struct snd_pcm_substream *substream);
-int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd);
+void snd_soc_link_hw_free(struct snd_pcm_substream *substream,
+                         int rollback);
 
+int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
+                        int rollback);
 int snd_soc_link_compr_startup(struct snd_compr_stream *cstream);
-void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream);
+void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
+                                int rollback);
 int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream);
 
 #endif /* __SOC_LINK_H */
index 5223896..328cf76 100644 (file)
@@ -31,9 +31,6 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_soc_dapm_route;
 
-/* object scan be loaded and unloaded in groups with identfying indexes */
-#define SND_SOC_TPLG_INDEX_ALL 0       /* ID that matches all FW objects */
-
 /* dynamic object type */
 enum snd_soc_dobj_type {
        SND_SOC_DOBJ_NONE               = 0,    /* object is not dynamic */
@@ -181,14 +178,8 @@ static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
 
 /* Dynamic Object loading and removal for component drivers */
 int snd_soc_tplg_component_load(struct snd_soc_component *comp,
-       struct snd_soc_tplg_ops *ops, const struct firmware *fw,
-       u32 index);
-int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index);
-
-/* Widget removal - widgets also removed wth component API */
-void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w);
-void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
-       u32 index);
+       struct snd_soc_tplg_ops *ops, const struct firmware *fw);
+int snd_soc_tplg_component_remove(struct snd_soc_component *comp);
 
 /* Binds event handlers to dynamic widgets */
 int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
index 3b038c5..3fa6c40 100644 (file)
@@ -490,46 +490,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
        const struct snd_pcm_hardware *hw);
 
-/* Jack reporting */
-void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
-int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
-                         struct snd_soc_jack_pin *pins);
-void snd_soc_jack_notifier_register(struct snd_soc_jack *jack,
-                                   struct notifier_block *nb);
-void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack,
-                                     struct notifier_block *nb);
-int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count,
-                         struct snd_soc_jack_zone *zones);
-int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage);
-#ifdef CONFIG_GPIOLIB
-int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
-                       struct snd_soc_jack_gpio *gpios);
-int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
-                           struct snd_soc_jack *jack,
-                           int count, struct snd_soc_jack_gpio *gpios);
-void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
-                       struct snd_soc_jack_gpio *gpios);
-#else
-static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
-                                        struct snd_soc_jack_gpio *gpios)
-{
-       return 0;
-}
-
-static inline int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
-                                         struct snd_soc_jack *jack,
-                                         int count,
-                                         struct snd_soc_jack_gpio *gpios)
-{
-       return 0;
-}
-
-static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
-                                          struct snd_soc_jack_gpio *gpios)
-{
-}
-#endif
-
 struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
 struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
        unsigned int id, unsigned int id_mask);
@@ -616,87 +576,6 @@ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
 int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 
-/**
- * struct snd_soc_jack_pin - Describes a pin to update based on jack detection
- *
- * @pin:    name of the pin to update
- * @mask:   bits to check for in reported jack status
- * @invert: if non-zero then pin is enabled when status is not reported
- * @list:   internal list entry
- */
-struct snd_soc_jack_pin {
-       struct list_head list;
-       const char *pin;
-       int mask;
-       bool invert;
-};
-
-/**
- * struct snd_soc_jack_zone - Describes voltage zones of jack detection
- *
- * @min_mv: start voltage in mv
- * @max_mv: end voltage in mv
- * @jack_type: type of jack that is expected for this voltage
- * @debounce_time: debounce_time for jack, codec driver should wait for this
- *             duration before reading the adc for voltages
- * @list:   internal list entry
- */
-struct snd_soc_jack_zone {
-       unsigned int min_mv;
-       unsigned int max_mv;
-       unsigned int jack_type;
-       unsigned int debounce_time;
-       struct list_head list;
-};
-
-/**
- * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
- *
- * @gpio:         legacy gpio number
- * @idx:          gpio descriptor index within the function of the GPIO
- *                consumer device
- * @gpiod_dev:    GPIO consumer device
- * @name:         gpio name. Also as connection ID for the GPIO consumer
- *                device function name lookup
- * @report:       value to report when jack detected
- * @invert:       report presence in low state
- * @debounce_time: debounce time in ms
- * @wake:        enable as wake source
- * @jack_status_check: callback function which overrides the detection
- *                    to provide more complex checks (eg, reading an
- *                    ADC).
- */
-struct snd_soc_jack_gpio {
-       unsigned int gpio;
-       unsigned int idx;
-       struct device *gpiod_dev;
-       const char *name;
-       int report;
-       int invert;
-       int debounce_time;
-       bool wake;
-
-       /* private: */
-       struct snd_soc_jack *jack;
-       struct delayed_work work;
-       struct notifier_block pm_notifier;
-       struct gpio_desc *desc;
-
-       void *data;
-       /* public: */
-       int (*jack_status_check)(void *data);
-};
-
-struct snd_soc_jack {
-       struct mutex mutex;
-       struct snd_jack *jack;
-       struct snd_soc_card *card;
-       struct list_head pins;
-       int status;
-       struct blocking_notifier_head notifier;
-       struct list_head jack_zones;
-};
-
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
        const char *stream_name;
@@ -1084,6 +963,7 @@ struct snd_soc_card {
        unsigned int fully_routed:1;
        unsigned int disable_route_checks:1;
        unsigned int probed:1;
+       unsigned int component_chaining:1;
 
        void *drvdata;
 };
@@ -1161,6 +1041,9 @@ struct snd_soc_pcm_runtime {
 
        /* function mark */
        struct snd_pcm_substream *mark_startup;
+       struct snd_pcm_substream *mark_hw_params;
+       struct snd_pcm_substream *mark_trigger;
+       struct snd_compr_stream  *mark_compr_startup;
 
        /* bit field */
        unsigned int pop_wait:1;
@@ -1183,21 +1066,15 @@ struct snd_soc_pcm_runtime {
        for ((i) = 0;                                                   \
             ((i) < rtd->num_cpus) && ((dai) = asoc_rtd_to_cpu(rtd, i)); \
             (i)++)
-#define for_each_rtd_cpu_dais_rollback(rtd, i, dai)            \
-       for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_cpu(rtd, i));)
 #define for_each_rtd_codec_dais(rtd, i, dai)                           \
        for ((i) = 0;                                                   \
             ((i) < rtd->num_codecs) && ((dai) = asoc_rtd_to_codec(rtd, i)); \
             (i)++)
-#define for_each_rtd_codec_dais_rollback(rtd, i, dai)          \
-       for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_codec(rtd, i));)
 #define for_each_rtd_dais(rtd, i, dai)                                 \
        for ((i) = 0;                                                   \
             ((i) < (rtd)->num_cpus + (rtd)->num_codecs) &&             \
                     ((dai) = (rtd)->dais[i]);                          \
             (i)++)
-#define for_each_rtd_dais_rollback(rtd, i, dai)                \
-       for (; (--(i) >= 0) && ((dai) = (rtd)->dais[i]);)
 
 void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
 
@@ -1418,5 +1295,6 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
 
 #include <sound/soc-component.h>
 #include <sound/soc-card.h>
+#include <sound/soc-jack.h>
 
 #endif
index 9aa0552..646a655 100644 (file)
@@ -100,6 +100,8 @@ struct sof_dev_desc {
        const struct snd_sof_dsp_ops *ops;
 };
 
-int sof_nocodec_setup(struct device *dev,
-                     const struct snd_sof_dsp_ops *ops);
+int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops,
+                     int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+                                               struct snd_pcm_hw_params *params));
+
 #endif
index 34f135a..6bb403e 100644 (file)
 #define SOF_DAI_FMT_IB_NF      (3 << 8) /**< invert BCLK + nor FRM */
 #define SOF_DAI_FMT_IB_IF      (4 << 8) /**< invert BCLK + FRM */
 
-#define SOF_DAI_FMT_CBM_CFM    (0 << 12) /**< codec clk & FRM master */
-#define SOF_DAI_FMT_CBS_CFM    (2 << 12) /**< codec clk slave & FRM master */
-#define SOF_DAI_FMT_CBM_CFS    (3 << 12) /**< codec clk master & frame slave */
-#define SOF_DAI_FMT_CBS_CFS    (4 << 12) /**< codec clk & FRM slave */
+#define SOF_DAI_FMT_CBP_CFP    (0 << 12) /**< codec bclk provider & frame provider */
+#define SOF_DAI_FMT_CBC_CFP    (2 << 12) /**< codec bclk consumer & frame provider */
+#define SOF_DAI_FMT_CBP_CFC    (3 << 12) /**< codec bclk provider & frame consumer */
+#define SOF_DAI_FMT_CBC_CFC    (4 << 12) /**< codec bclk consumer & frame consumer */
+
+/* keep old definitions for backwards compatibility */
+#define SOF_DAI_FMT_CBM_CFM    SOF_DAI_FMT_CBP_CFP
+#define SOF_DAI_FMT_CBS_CFM    SOF_DAI_FMT_CBC_CFP
+#define SOF_DAI_FMT_CBM_CFS    SOF_DAI_FMT_CBP_CFC
+#define SOF_DAI_FMT_CBS_CFS    SOF_DAI_FMT_CBC_CFC
 
 #define SOF_DAI_FMT_FORMAT_MASK                0x000f
 #define SOF_DAI_FMT_CLOCK_MASK         0x00f0
 #define SOF_DAI_FMT_INV_MASK           0x0f00
-#define SOF_DAI_FMT_MASTER_MASK                0xf000
+#define SOF_DAI_FMT_CLOCK_PROVIDER_MASK        0xf000
 
 /** \brief Types of DAI */
 enum sof_ipc_dai_type {
diff --git a/include/sound/sof/debug.h b/include/sound/sof/debug.h
new file mode 100644 (file)
index 0000000..3ecb579
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ *
+ * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_SOUND_SOF_DEBUG_H__
+#define __INCLUDE_SOUND_SOF_DEBUG_H__
+
+#include <sound/sof/header.h>
+
+/** ABI3.18 */
+enum sof_ipc_dbg_mem_zone {
+       SOF_IPC_MEM_ZONE_SYS            = 0,    /**< System zone */
+       SOF_IPC_MEM_ZONE_SYS_RUNTIME    = 1,    /**< System-runtime zone */
+       SOF_IPC_MEM_ZONE_RUNTIME        = 2,    /**< Runtime zone */
+       SOF_IPC_MEM_ZONE_BUFFER         = 3,    /**< Buffer zone */
+};
+
+/** ABI3.18 */
+struct sof_ipc_dbg_mem_usage_elem {
+       uint32_t zone;          /**< see sof_ipc_dbg_mem_zone */
+       uint32_t id;            /**< heap index within zone */
+       uint32_t used;          /**< number of bytes used in zone */
+       uint32_t free;          /**< number of bytes free to use within zone */
+       uint32_t reserved;      /**< for future use */
+} __packed;
+
+/** ABI3.18 */
+struct sof_ipc_dbg_mem_usage {
+       struct sof_ipc_reply rhdr;                      /**< generic IPC reply header */
+       uint32_t reserved[4];                           /**< reserved for future use */
+       uint32_t num_elems;                             /**< elems[] counter */
+       struct sof_ipc_dbg_mem_usage_elem elems[];      /**< memory usage information */
+} __packed;
+
+#endif
index 342e86e..7abc4f0 100644 (file)
@@ -61,6 +61,8 @@ enum sof_ext_man_elem_type {
        SOF_EXT_MAN_ELEM_WINDOW                 = SOF_IPC_EXT_WINDOW,
        SOF_EXT_MAN_ELEM_CC_VERSION             = SOF_IPC_EXT_CC_INFO,
        SOF_EXT_MAN_ELEM_DBG_ABI                = SOF_IPC_EXT_USER_ABI_INFO,
+       SOF_EXT_MAN_ELEM_CONFIG_DATA            = 5, /**< ABI3.17 */
+       SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA   = 6,
 };
 
 /* extended manifest element header */
@@ -99,4 +101,23 @@ struct ext_man_dbg_abi {
        struct sof_ipc_user_abi_version dbg_abi;
 } __packed;
 
+/* EXT_MAN_ELEM_CONFIG_DATA elements identificators, ABI3.17 */
+enum config_elem_type {
+       SOF_EXT_MAN_CONFIG_EMPTY                = 0,
+       SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE         = 1,
+       SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN    = 2, /**< ABI 3.18 */
+};
+
+struct sof_config_elem {
+       uint32_t token;
+       uint32_t value;
+} __packed;
+
+/* firmware configuration information */
+struct sof_ext_man_config_data {
+       struct sof_ext_man_elem_header hdr;
+
+       struct sof_config_elem elems[];
+} __packed;
+
 #endif /* __SOF_FIRMWARE_EXT_MANIFEST_H__ */
index 2d35997..4c747c5 100644 (file)
 
 /* Global Message - Generic */
 #define SOF_GLB_TYPE_SHIFT                     28
-#define SOF_GLB_TYPE_MASK                      (0xf << SOF_GLB_TYPE_SHIFT)
+#define SOF_GLB_TYPE_MASK                      (0xfL << SOF_GLB_TYPE_SHIFT)
 #define SOF_GLB_TYPE(x)                                ((x) << SOF_GLB_TYPE_SHIFT)
 
 /* Command Message - Generic */
 #define SOF_CMD_TYPE_SHIFT                     16
-#define SOF_CMD_TYPE_MASK                      (0xfff << SOF_CMD_TYPE_SHIFT)
+#define SOF_CMD_TYPE_MASK                      (0xfffL << SOF_CMD_TYPE_SHIFT)
 #define SOF_CMD_TYPE(x)                                ((x) << SOF_CMD_TYPE_SHIFT)
 
 /* Global Message Types */
 #define SOF_IPC_FW_READY                       SOF_GLB_TYPE(0x7U)
 #define SOF_IPC_GLB_DAI_MSG                    SOF_GLB_TYPE(0x8U)
 #define SOF_IPC_GLB_TRACE_MSG                  SOF_GLB_TYPE(0x9U)
-#define SOF_IPC_GLB_GDB_DEBUG                   SOF_GLB_TYPE(0xAU)
+#define SOF_IPC_GLB_GDB_DEBUG                  SOF_GLB_TYPE(0xAU)
 #define SOF_IPC_GLB_TEST_MSG                   SOF_GLB_TYPE(0xBU)
 #define SOF_IPC_GLB_PROBE                      SOF_GLB_TYPE(0xCU)
+#define SOF_IPC_GLB_DEBUG                      SOF_GLB_TYPE(0xDU)
 
 /*
  * DSP Command Message Types
 #define SOF_IPC_PROBE_DMA_ADD                  SOF_CMD_TYPE(0x003)
 #define SOF_IPC_PROBE_DMA_INFO                 SOF_CMD_TYPE(0x004)
 #define SOF_IPC_PROBE_DMA_REMOVE               SOF_CMD_TYPE(0x005)
-#define SOF_IPC_PROBE_POINT_ADD                SOF_CMD_TYPE(0x006)
+#define SOF_IPC_PROBE_POINT_ADD                        SOF_CMD_TYPE(0x006)
 #define SOF_IPC_PROBE_POINT_INFO               SOF_CMD_TYPE(0x007)
 #define SOF_IPC_PROBE_POINT_REMOVE             SOF_CMD_TYPE(0x008)
 
 #define SOF_IPC_TRACE_DMA_PARAMS               SOF_CMD_TYPE(0x001)
 #define SOF_IPC_TRACE_DMA_POSITION             SOF_CMD_TYPE(0x002)
 #define SOF_IPC_TRACE_DMA_PARAMS_EXT           SOF_CMD_TYPE(0x003)
+#define SOF_IPC_TRACE_FILTER_UPDATE            SOF_CMD_TYPE(0x004) /**< ABI3.17 */
 
 /* debug */
-#define SOF_IPC_TEST_IPC_FLOOD                  SOF_CMD_TYPE(0x001)
+#define SOF_IPC_DEBUG_MEM_USAGE                        SOF_CMD_TYPE(0x001)
+
+/* test */
+#define SOF_IPC_TEST_IPC_FLOOD                 SOF_CMD_TYPE(0x001)
 
 /* Get message component id */
 #define SOF_IPC_MESSAGE_ID(x)                  ((x) & 0xffff)
index c31a94a..25ea99f 100644 (file)
@@ -43,6 +43,34 @@ struct sof_ipc_dma_trace_posn {
        uint32_t messages;      /* total trace messages */
 }  __packed;
 
+/* Values used in sof_ipc_trace_filter_elem: */
+
+/* bits 6..0 */
+#define SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL    0x01    /**< trace level for selected components */
+#define SOF_IPC_TRACE_FILTER_ELEM_BY_UUID      0x02    /**< filter by uuid key */
+#define SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE      0x03    /**< filter by pipeline */
+#define SOF_IPC_TRACE_FILTER_ELEM_BY_COMP      0x04    /**< filter by component id */
+
+/* bit 7 */
+#define SOF_IPC_TRACE_FILTER_ELEM_FIN          0x80    /**< mark last filter in set */
+
+/* bits 31..8: Unused */
+
+/** part of sof_ipc_trace_filter, ABI3.17 */
+struct sof_ipc_trace_filter_elem {
+       uint32_t key;           /**< SOF_IPC_TRACE_FILTER_ELEM_ {LEVEL, UUID, COMP, PIPE} */
+       uint32_t value;         /**< element value */
+} __packed;
+
+/** Runtime tracing filtration data - SOF_IPC_TRACE_FILTER_UPDATE, ABI3.17 */
+struct sof_ipc_trace_filter {
+       struct sof_ipc_cmd_hdr hdr;     /**< IPC command header */
+       uint32_t elem_cnt;              /**< number of entries in elems[] array */
+       uint32_t reserved[8];           /**< reserved for future usage */
+       /** variable size array with new filtering settings */
+       struct sof_ipc_trace_filter_elem elems[];
+} __packed;
+
 /*
  * Commom debug
  */
index 40c300f..4d8ef71 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
+#include <sound/jack.h>
 
 #define DAPM_DIRECT "(direct)"
 #define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-")
index a74ca23..da61398 100644 (file)
 #define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP            (1 << 3)
 
 /* DAI topology BCLK parameter
- * For the backwards capability, by default codec is bclk master
+ * For the backwards capability, by default codec is bclk provider
  */
-#define SND_SOC_TPLG_BCLK_CM         0 /* codec is bclk master */
-#define SND_SOC_TPLG_BCLK_CS         1 /* codec is bclk slave */
+#define SND_SOC_TPLG_BCLK_CP         0 /* codec is bclk provider */
+#define SND_SOC_TPLG_BCLK_CC         1 /* codec is bclk consumer */
+/* keep previous definitions for compatibility */
+#define SND_SOC_TPLG_BCLK_CM         SND_SOC_TPLG_BCLK_CP
+#define SND_SOC_TPLG_BCLK_CS         SND_SOC_TPLG_BCLK_CC
 
 /* DAI topology FSYNC parameter
- * For the backwards capability, by default codec is fsync master
+ * For the backwards capability, by default codec is fsync provider
  */
-#define SND_SOC_TPLG_FSYNC_CM         0 /* codec is fsync master */
-#define SND_SOC_TPLG_FSYNC_CS         1 /* codec is fsync slave */
+#define SND_SOC_TPLG_FSYNC_CP         0 /* codec is fsync provider */
+#define SND_SOC_TPLG_FSYNC_CC         1 /* codec is fsync consumer */
+/* keep previous definitions for compatibility */
+#define SND_SOC_TPLG_FSYNC_CM         SND_SOC_TPLG_FSYNC_CP
+#define SND_SOC_TPLG_FSYNC_CS         SND_SOC_TPLG_FSYNC_CC
 
 /*
  * Block Header.
@@ -336,8 +342,8 @@ struct snd_soc_tplg_hw_config {
        __u8 clock_gated;       /* SND_SOC_TPLG_DAI_CLK_GATE_ value */
        __u8 invert_bclk;       /* 1 for inverted BCLK, 0 for normal */
        __u8 invert_fsync;      /* 1 for inverted frame clock, 0 for normal */
-       __u8 bclk_master;       /* SND_SOC_TPLG_BCLK_ value */
-       __u8 fsync_master;      /* SND_SOC_TPLG_FSYNC_ value */
+       __u8 bclk_provider;     /* SND_SOC_TPLG_BCLK_ value */
+       __u8 fsync_provider;    /* SND_SOC_TPLG_FSYNC_ value */
        __u8 mclk_direction;    /* SND_SOC_TPLG_MCLK_ value */
        __le16 reserved;        /* for 32bit alignment */
        __le32 mclk_rate;       /* MCLK or SYSCLK freqency in Hz */
index 6af32f8..fe2cfae 100644 (file)
@@ -26,7 +26,7 @@
 
 /* SOF ABI version major, minor and patch numbers */
 #define SOF_ABI_MAJOR 3
-#define SOF_ABI_MINOR 17
+#define SOF_ABI_MINOR 18
 #define SOF_ABI_PATCH 0
 
 /* SOF ABI version number. Format within 32bit word is MMmmmppp */
index 27007c1..e377f52 100644 (file)
@@ -243,5 +243,8 @@ int main(void)
        DEVID(mhi_device_id);
        DEVID_FIELD(mhi_device_id, chan);
 
+       DEVID(auxiliary_device_id);
+       DEVID_FIELD(auxiliary_device_id, name);
+
        return 0;
 }
index 2417dd1..fb48270 100644 (file)
@@ -1364,6 +1364,13 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias)
 {
        DEF_FIELD_ADDR(symval, mhi_device_id, chan);
        sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan);
+       return 1;
+}
+
+static int do_auxiliary_entry(const char *filename, void *symval, char *alias)
+{
+       DEF_FIELD_ADDR(symval, auxiliary_device_id, name);
+       sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name);
 
        return 1;
 }
@@ -1442,6 +1449,7 @@ static const struct devtable devtable[] = {
        {"tee", SIZE_tee_client_device_id, do_tee_entry},
        {"wmi", SIZE_wmi_device_id, do_wmi_entry},
        {"mhi", SIZE_mhi_device_id, do_mhi_entry},
+       {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
 };
 
 /* Create MODULE_ALIAS() statements.
index 1c5114d..6a0d070 100644 (file)
@@ -29,6 +29,7 @@ MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=lega
 struct config_entry {
        u32 flags;
        u16 device;
+       u8 acpi_hid[ACPI_ID_LEN];
        const struct dmi_system_id *dmi_table;
 };
 
@@ -378,6 +379,20 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
        if (pci->vendor != 0x8086)
                return SND_INTEL_DSP_DRIVER_ANY;
 
+       /*
+        * Legacy devices don't have a PCI-based DSP and use HDaudio
+        * for HDMI/DP support, ignore kernel parameter
+        */
+       switch (pci->device) {
+       case 0x160c: /* Broadwell */
+       case 0x0a0c: /* Haswell */
+       case 0x0c0c:
+       case 0x0d0c:
+       case 0x0f04: /* Baytrail */
+       case 0x2284: /* Braswell */
+               return SND_INTEL_DSP_DRIVER_ANY;
+       }
+
        if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
                return dsp_driver;
 
@@ -433,6 +448,102 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
 }
 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
 
+/*
+ * configuration table
+ * - the order of similar ACPI ID entries is important!
+ * - the first successful match will win
+ */
+static const struct config_entry acpi_config_table[] = {
+/* BayTrail */
+#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
+       {
+               .flags = FLAG_SST,
+               .acpi_hid = "80860F28",
+       },
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
+       {
+               .flags = FLAG_SOF,
+               .acpi_hid = "80860F28",
+       },
+#endif
+/* CherryTrail */
+#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
+       {
+               .flags = FLAG_SST,
+               .acpi_hid = "808622A8",
+       },
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
+       {
+               .flags = FLAG_SOF,
+               .acpi_hid = "808622A8",
+       },
+#endif
+/* Broadwell */
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
+       {
+               .flags = FLAG_SST,
+               .acpi_hid = "INT3438"
+       },
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
+       {
+               .flags = FLAG_SOF,
+               .acpi_hid = "INT3438"
+       },
+#endif
+/* Haswell - not supported by SOF but added for consistency */
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
+       {
+               .flags = FLAG_SST,
+               .acpi_hid = "INT33C8"
+       },
+#endif
+};
+
+static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
+                                                                const struct config_entry *table,
+                                                                u32 len)
+{
+       for (; len > 0; len--, table++) {
+               if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
+                       continue;
+               if (table->dmi_table && !dmi_check_system(table->dmi_table))
+                       continue;
+               return table;
+       }
+       return NULL;
+}
+
+int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
+{
+       const struct config_entry *cfg;
+
+       if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
+               return dsp_driver;
+
+       if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
+               dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
+                        SND_INTEL_DSP_DRIVER_LEGACY);
+       }
+
+       /* find the configuration for the specific device */
+       cfg = snd_intel_acpi_dsp_find_config(acpi_hid,  acpi_config_table,
+                                            ARRAY_SIZE(acpi_config_table));
+       if (!cfg)
+               return SND_INTEL_DSP_DRIVER_ANY;
+
+       if (cfg->flags & FLAG_SST)
+               return SND_INTEL_DSP_DRIVER_SST;
+
+       if (cfg->flags & FLAG_SOF)
+               return SND_INTEL_DSP_DRIVER_SOF;
+
+       return SND_INTEL_DSP_DRIVER_SST;
+}
+EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel DSP config driver");
 MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);
index e321e3b..0236dc5 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SND_SOC_ADI
        tristate "Audio support for Analog Devices reference designs"
-       depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST
        help
          Audio support for various reference designs by Analog Devices.
 
index a7702e6..849288d 100644 (file)
@@ -73,8 +73,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       da7219_dai_wclk = clk_get(component->dev, "da7219-dai-wclk");
-       da7219_dai_bclk = clk_get(component->dev, "da7219-dai-bclk");
+       da7219_dai_wclk = devm_clk_get(component->dev, "da7219-dai-wclk");
+       if (IS_ERR(da7219_dai_wclk))
+               return PTR_ERR(da7219_dai_wclk);
+
+       da7219_dai_bclk = devm_clk_get(component->dev, "da7219-dai-bclk");
+       if (IS_ERR(da7219_dai_bclk))
+               return PTR_ERR(da7219_dai_bclk);
 
        ret = snd_soc_card_jack_new(card, "Headset Jack",
                                SND_JACK_HEADSET | SND_JACK_LINEOUT |
index 31b797c..8c138e4 100644 (file)
@@ -118,6 +118,10 @@ static int snd_acp3x_probe(struct pci_dev *pci,
        int ret, i;
        u32 addr, val;
 
+       /* Raven device detection */
+       if (pci->revision != 0x00)
+               return -ENODEV;
+
        if (pci_enable_device(pci)) {
                dev_err(&pci->dev, "pci_enable_device failed\n");
                return -ENODEV;
@@ -231,9 +235,8 @@ static int snd_acp3x_probe(struct pci_dev *pci,
                }
                break;
        default:
-               dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
-               ret = -ENODEV;
-               goto disable_msi;
+               dev_info(&pci->dev, "ACP audio mode : %d\n", val);
+               break;
        }
        pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
        pm_runtime_use_autosuspend(&pci->dev);
index b943e59..fa169bf 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -20,14 +21,13 @@ module_param(acp_power_gating, int, 0644);
 MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating");
 
 /**
- * dmic_acpi_check = -1 - Checks ACPI method to know DMIC hardware status runtime
- *                 = 0 - Skips the DMIC device creation and returns probe failure
- *                 = 1 - Assumes that platform has DMIC support and skips ACPI
- *                       method check
+ * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime
+ *                 =  0 - Skip the DMIC device creation and return probe failure
+ *                 =  1 - Force DMIC support
  */
 static int dmic_acpi_check = ACP_DMIC_AUTO;
 module_param(dmic_acpi_check, bint, 0644);
-MODULE_PARM_DESC(dmic_acpi_check, "checks Dmic hardware runtime");
+MODULE_PARM_DESC(dmic_acpi_check, "Digital microphone presence (-1=auto, 0=none, 1=force)");
 
 struct acp_dev_data {
        void __iomem *acp_base;
@@ -163,6 +163,17 @@ static int rn_acp_deinit(void __iomem *acp_base)
        return 0;
 }
 
+static const struct dmi_system_id rn_acp_quirk_table[] = {
+       {
+               /* Lenovo IdeaPad Flex 5 14ARE05, IdeaPad 5 15ARE05 */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "LNVNB161216"),
+               }
+       },
+       {}
+};
+
 static int snd_rn_acp_probe(struct pci_dev *pci,
                            const struct pci_device_id *pci_id)
 {
@@ -172,10 +183,15 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
        acpi_handle handle;
        acpi_integer dmic_status;
 #endif
+       const struct dmi_system_id *dmi_id;
        unsigned int irqflags;
        int ret, index;
        u32 addr;
 
+       /* Renoir device check */
+       if (pci->revision != 0x01)
+               return -ENODEV;
+
        if (pci_enable_device(pci)) {
                dev_err(&pci->dev, "pci_enable_device failed\n");
                return -ENODEV;
@@ -224,7 +240,7 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
                handle = ACPI_HANDLE(&pci->dev);
                ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
                if (ACPI_FAILURE(ret)) {
-                       ret = -EINVAL;
+                       ret = -ENODEV;
                        goto de_init;
                }
                if (!dmic_status) {
@@ -232,6 +248,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
                        goto de_init;
                }
 #endif
+               dmi_id = dmi_first_match(rn_acp_quirk_table);
+               if (dmi_id && !dmi_id->driver_data) {
+                       dev_info(&pci->dev, "ACPI settings override using DMI (ACP mic is not present)");
+                       ret = -ENODEV;
+                       goto de_init;
+               }
        }
 
        adata->res = devm_kzalloc(&pci->dev,
index bd8854b..142373e 100644 (file)
@@ -148,6 +148,7 @@ config SND_MCHP_SOC_SPDIFTX
 config SND_MCHP_SOC_SPDIFRX
        tristate "Microchip ASoC driver for boards using S/PDIF RX"
        depends on OF && (ARCH_AT91 || COMPILE_TEST)
+       depends on COMMON_CLK
        select SND_SOC_GENERIC_DMAENGINE_PCM
        select REGMAP_MMIO
        help
index bbe2b63..232300d 100644 (file)
@@ -563,8 +563,8 @@ static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
                err = PTR_ERR(muxclk);
                if (err == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
-               dev_warn(dev->dev,
-                        "failed to get the I2S clock control: %d\n", err);
+               dev_dbg(dev->dev,
+                       "failed to get the I2S clock control: %d\n", err);
                return 0;
        }
 
index dc34fe1..c2f7631 100644 (file)
@@ -797,7 +797,7 @@ static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
@@ -807,7 +807,7 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static const struct regmap_config bcm2835_regmap_config = {
index 34c6dd0..5e4e681 100644 (file)
@@ -23,6 +23,8 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_AD193X_I2C
        imply SND_SOC_AD1980
        imply SND_SOC_AD73311
+       imply SND_SOC_ADAU1372_I2C
+       imply SND_SOC_ADAU1372_SPI
        imply SND_SOC_ADAU1373
        imply SND_SOC_ADAU1761_I2C
        imply SND_SOC_ADAU1761_SPI
@@ -130,6 +132,7 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_MT6358
        imply SND_SOC_MT6359
        imply SND_SOC_MT6660
+       imply SND_SOC_NAU8315
        imply SND_SOC_NAU8540
        imply SND_SOC_NAU8810
        imply SND_SOC_NAU8822
@@ -177,10 +180,12 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_RT700_SDW
        imply SND_SOC_RT711_SDW
        imply SND_SOC_RT715_SDW
+       imply SND_SOC_RT715_SDCA_SDW
        imply SND_SOC_RT1308_SDW
        imply SND_SOC_SGTL5000
        imply SND_SOC_SI476X
        imply SND_SOC_SIMPLE_AMPLIFIER
+       imply SND_SOC_SIMPLE_MUX
        imply SND_SOC_SIRF_AUDIO_CODEC
        imply SND_SOC_SPDIF
        imply SND_SOC_SSM2305
@@ -363,6 +368,22 @@ config SND_SOC_AD73311
 config SND_SOC_ADAU_UTILS
        tristate
 
+config SND_SOC_ADAU1372
+       tristate
+       select SND_SOC_ADAU_UTILS
+
+config SND_SOC_ADAU1372_I2C
+       tristate "Analog Devices ADAU1372 CODEC (I2C)"
+       depends on I2C
+       select SND_SOC_ADAU1372
+       select REGMAP_I2C
+
+config SND_SOC_ADAU1372_SPI
+       tristate "Analog Devices ADAU1372 CODEC (SPI)"
+       depends on SPI
+       select SND_SOC_ADAU1372
+       select REGMAP_SPI
+
 config SND_SOC_ADAU1373
        tristate
        depends on I2C
@@ -517,7 +538,7 @@ config SND_SOC_AK5558
        select REGMAP_I2C
 
 config SND_SOC_ALC5623
-       tristate "Realtek ALC5623 CODEC"
+       tristate "Realtek ALC5623 CODEC"
        depends on I2C
 
 config SND_SOC_ALC5632
@@ -728,7 +749,7 @@ config SND_SOC_JZ4770_CODEC
          will be called snd-soc-jz4770-codec.
 
 config SND_SOC_L3
-       tristate
+       tristate
 
 config SND_SOC_DA7210
        tristate
@@ -768,10 +789,10 @@ config SND_SOC_HDMI_CODEC
        select HDMI
 
 config SND_SOC_ES7134
-       tristate "Everest Semi ES7134 CODEC"
+       tristate "Everest Semi ES7134 CODEC"
 
 config SND_SOC_ES7241
-       tristate "Everest Semi ES7241 CODEC"
+       tristate "Everest Semi ES7241 CODEC"
 
 config SND_SOC_ES8316
        tristate "Everest Semi ES8316 CODEC"
@@ -970,10 +991,10 @@ config SND_SOC_PCM186X_SPI
        select REGMAP_SPI
 
 config SND_SOC_PCM3008
-       tristate
+       tristate
 
 config SND_SOC_PCM3060
-       tristate
+       tristate
 
 config SND_SOC_PCM3060_I2C
        tristate "Texas Instruments PCM3060 CODEC - I2C"
@@ -1003,7 +1024,7 @@ config SND_SOC_PCM3168A_SPI
        select REGMAP_SPI
 
 config SND_SOC_PCM5102A
-       tristate
+       tristate "Texas Instruments PCM5102A CODEC"
 
 config SND_SOC_PCM512x
        tristate
@@ -1216,6 +1237,12 @@ config SND_SOC_RT715_SDW
        select SND_SOC_RT715
        select REGMAP_SOUNDWIRE
 
+config SND_SOC_RT715_SDCA_SDW
+       tristate "Realtek RT715 SDCA Codec - SDW"
+       depends on SOUNDWIRE
+       select REGMAP_SOUNDWIRE
+       select REGMAP_SOUNDWIRE_MBQ
+
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
        tristate "Freescale SGTL5000 CODEC"
@@ -1240,6 +1267,10 @@ config SND_SOC_SIMPLE_AMPLIFIER
        tristate "Simple Audio Amplifier"
        select GPIOLIB
 
+config SND_SOC_SIMPLE_MUX
+       tristate "Simple Audio Mux"
+       select GPIOLIB
+
 config SND_SOC_SIRF_AUDIO_CODEC
        tristate "SiRF SoC internal audio codec"
        select REGMAP_MMIO
@@ -1436,7 +1467,7 @@ config SND_SOC_UDA1334
          rate) and mute.
 
 config SND_SOC_UDA134X
-       tristate
+       tristate
 
 config SND_SOC_UDA1380
        tristate
@@ -1760,9 +1791,13 @@ config SND_SOC_MT6660
          Select N if you don't have MT6660 on board.
          Select M to build this as module.
 
+config SND_SOC_NAU8315
+       tristate "Nuvoton Technology Corporation NAU8315 CODEC"
+       depends on GPIOLIB
+
 config SND_SOC_NAU8540
-       tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
-       depends on I2C
+       tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
+       depends on I2C
 
 config SND_SOC_NAU8810
        tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
@@ -1784,4 +1819,12 @@ config SND_SOC_TPA6130A2
        tristate "Texas Instruments TPA6130A2 headphone amplifier"
        depends on I2C
 
+config SND_SOC_LPASS_WSA_MACRO
+       depends on COMMON_CLK
+       tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
+
+config SND_SOC_LPASS_VA_MACRO
+       depends on COMMON_CLK
+       tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)"
+
 endmenu
index 11ce98c..f255ec7 100644 (file)
@@ -9,6 +9,9 @@ snd-soc-ad193x-i2c-objs := ad193x-i2c.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-adau-utils-objs := adau-utils.o
+snd-soc-adau1372-objs := adau1372.o
+snd-soc-adau1372-i2c-objs := adau1372-i2c.o
+snd-soc-adau1372-spi-objs := adau1372-spi.o
 snd-soc-adau1373-objs := adau1373.o
 snd-soc-adau1701-objs := adau1701.o
 snd-soc-adau17x1-objs := adau17x1.o
@@ -103,6 +106,8 @@ snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
 snd-soc-lm49453-objs := lm49453.o
 snd-soc-lochnagar-sc-objs := lochnagar-sc.o
+snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o
+snd-soc-lpass-va-macro-objs := lpass-va-macro.o
 snd-soc-madera-objs := madera.o
 snd-soc-max9759-objs := max9759.o
 snd-soc-max9768-objs := max9768.o
@@ -129,6 +134,7 @@ snd-soc-mt6351-objs := mt6351.o
 snd-soc-mt6358-objs := mt6358.o
 snd-soc-mt6359-objs := mt6359.o
 snd-soc-mt6660-objs := mt6660.o
+snd-soc-nau8315-objs := nau8315.o
 snd-soc-nau8540-objs := nau8540.o
 snd-soc-nau8810-objs := nau8810.o
 snd-soc-nau8822-objs := nau8822.o
@@ -188,6 +194,7 @@ snd-soc-rt5682-i2c-objs := rt5682-i2c.o
 snd-soc-rt700-objs := rt700.o rt700-sdw.o
 snd-soc-rt711-objs := rt711.o rt711-sdw.o
 snd-soc-rt715-objs := rt715.o rt715-sdw.o
+snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
@@ -305,6 +312,8 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-tas2552-objs := tas2552.o
 snd-soc-tas2562-objs := tas2562.o
 snd-soc-tas2764-objs := tas2764.o
+# Mux
+snd-soc-simple-mux-objs := simple-mux.o
 
 obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AB8500_CODEC)     += snd-soc-ab8500-codec.o
@@ -316,6 +325,9 @@ obj-$(CONFIG_SND_SOC_AD193X_I2C)    += snd-soc-ad193x-i2c.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADAU_UTILS)       += snd-soc-adau-utils.o
+obj-$(CONFIG_SND_SOC_ADAU1372) += snd-soc-adau1372.o
+obj-$(CONFIG_SND_SOC_ADAU1372_I2C)     += snd-soc-adau1372-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU1372_SPI)     += snd-soc-adau1372-spi.o
 obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
 obj-$(CONFIG_SND_SOC_ADAU1701)         += snd-soc-adau1701.o
 obj-$(CONFIG_SND_SOC_ADAU17X1)         += snd-soc-adau17x1.o
@@ -438,6 +450,7 @@ obj-$(CONFIG_SND_SOC_MT6351)        += snd-soc-mt6351.o
 obj-$(CONFIG_SND_SOC_MT6358)   += snd-soc-mt6358.o
 obj-$(CONFIG_SND_SOC_MT6359)   += snd-soc-mt6359.o
 obj-$(CONFIG_SND_SOC_MT6660)   += snd-soc-mt6660.o
+obj-$(CONFIG_SND_SOC_NAU8315)   += snd-soc-nau8315.o
 obj-$(CONFIG_SND_SOC_NAU8540)   += snd-soc-nau8540.o
 obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8822)   += snd-soc-nau8822.o
@@ -498,6 +511,7 @@ obj-$(CONFIG_SND_SOC_RT5682_SDW)    += snd-soc-rt5682-sdw.o
 obj-$(CONFIG_SND_SOC_RT700)     += snd-soc-rt700.o
 obj-$(CONFIG_SND_SOC_RT711)     += snd-soc-rt711.o
 obj-$(CONFIG_SND_SOC_RT715)     += snd-soc-rt715.o
+obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW)     += snd-soc-rt715-sdca.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)     += snd-soc-sigmadsp-i2c.o
@@ -613,3 +627,8 @@ obj-$(CONFIG_SND_SOC_MAX9877)       += snd-soc-max9877.o
 obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
 obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)        += snd-soc-tpa6130a2.o
+obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO)  += snd-soc-lpass-wsa-macro.o
+obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO)   += snd-soc-lpass-va-macro.o
+
+# Mux
+obj-$(CONFIG_SND_SOC_SIMPLE_MUX)       += snd-soc-simple-mux.o
diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c
new file mode 100644 (file)
index 0000000..fc87a76
--- /dev/null
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for ADAU1372 codec
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1372.h"
+
+static int adau1372_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       return adau1372_probe(&client->dev,
+               devm_regmap_init_i2c(client, &adau1372_regmap_config), NULL);
+}
+
+static const struct i2c_device_id adau1372_i2c_ids[] = {
+       { "adau1372", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids);
+
+static struct i2c_driver adau1372_i2c_driver = {
+       .driver = {
+               .name = "adau1372",
+       },
+       .probe = adau1372_i2c_probe,
+       .id_table = adau1372_i2c_ids,
+};
+module_i2c_driver(adau1372_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1372 CODEC I2C driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c
new file mode 100644 (file)
index 0000000..51298e0
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for ADAU1372 codec
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1372.h"
+
+static void adau1372_spi_switch_mode(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       /*
+        * To get the device into SPI mode CLATCH has to be pulled low three
+        * times.  Do this by issuing three dummy reads.
+        */
+       spi_w8r8(spi, 0x00);
+       spi_w8r8(spi, 0x00);
+       spi_w8r8(spi, 0x00);
+}
+
+static int adau1372_spi_probe(struct spi_device *spi)
+{
+       struct regmap_config config;
+
+       config = adau1372_regmap_config;
+       config.read_flag_mask = 0x1;
+
+       return adau1372_probe(&spi->dev,
+               devm_regmap_init_spi(spi, &config), adau1372_spi_switch_mode);
+}
+
+static const struct spi_device_id adau1372_spi_id[] = {
+       { "adau1372", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, adau1372_spi_id);
+
+static struct spi_driver adau1372_spi_driver = {
+       .driver = {
+               .name = "adau1372",
+       },
+       .probe = adau1372_spi_probe,
+       .id_table = adau1372_spi_id,
+};
+module_spi_driver(adau1372_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1372 CODEC SPI driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
new file mode 100644 (file)
index 0000000..5ccbf1b
--- /dev/null
@@ -0,0 +1,1062 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices ADAU1372 Audio Codec driver
+ *
+ * Copyright 2016 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+
+#include "adau1372.h"
+#include "adau-utils.h"
+
+struct adau1372 {
+       struct clk *clk;
+       struct regmap *regmap;
+       void (*switch_mode)(struct device *dev);
+       bool use_pll;
+       bool enabled;
+       bool master;
+
+       struct snd_pcm_hw_constraint_list rate_constraints;
+       unsigned int slot_width;
+
+       struct clk *mclk;
+       struct gpio_desc *pd_gpio;
+       struct device *dev;
+};
+
+#define ADAU1372_REG_CLK_CTRL          0x00
+#define ADAU1372_REG_PLL(x)            (0x01 + (x))
+#define ADAU1372_REG_DAC_SOURCE                0x11
+#define ADAU1372_REG_SOUT_SOURCE_0_1   0x13
+#define ADAU1372_REG_SOUT_SOURCE_2_3   0x14
+#define ADAU1372_REG_SOUT_SOURCE_4_5   0x15
+#define ADAU1372_REG_SOUT_SOURCE_6_7   0x16
+#define ADAU1372_REG_ADC_SDATA_CH      0x17
+#define ADAU1372_REG_ASRCO_SOURCE_0_1  0x18
+#define ADAU1372_REG_ASRCO_SOURCE_2_3  0x19
+#define ADAU1372_REG_ASRC_MODE         0x1a
+#define ADAU1372_REG_ADC_CTRL0         0x1b
+#define ADAU1372_REG_ADC_CTRL1         0x1c
+#define ADAU1372_REG_ADC_CTRL2         0x1d
+#define ADAU1372_REG_ADC_CTRL3         0x1e
+#define ADAU1372_REG_ADC_VOL(x)                (0x1f + (x))
+#define ADAU1372_REG_PGA_CTRL(x)       (0x23 + (x))
+#define ADAU1372_REG_PGA_BOOST         0x28
+#define ADAU1372_REG_MICBIAS           0x2d
+#define ADAU1372_REG_DAC_CTRL          0x2e
+#define ADAU1372_REG_DAC_VOL(x)                (0x2f + (x))
+#define ADAU1372_REG_OP_STAGE_MUTE     0x31
+#define ADAU1372_REG_SAI0              0x32
+#define ADAU1372_REG_SAI1              0x33
+#define ADAU1372_REG_SOUT_CTRL         0x34
+#define ADAU1372_REG_MODE_MP(x)                (0x38 + (x))
+#define ADAU1372_REG_OP_STAGE_CTRL     0x43
+#define ADAU1372_REG_DECIM_PWR         0x44
+#define ADAU1372_REG_INTERP_PWR                0x45
+#define ADAU1372_REG_BIAS_CTRL0                0x46
+#define ADAU1372_REG_BIAS_CTRL1                0x47
+
+#define ADAU1372_CLK_CTRL_PLL_EN       BIT(7)
+#define ADAU1372_CLK_CTRL_XTAL_DIS     BIT(4)
+#define ADAU1372_CLK_CTRL_CLKSRC       BIT(3)
+#define ADAU1372_CLK_CTRL_CC_MDIV      BIT(1)
+#define ADAU1372_CLK_CTRL_MCLK_EN      BIT(0)
+
+#define ADAU1372_SAI0_DELAY1           (0x0 << 6)
+#define ADAU1372_SAI0_DELAY0           (0x1 << 6)
+#define ADAU1372_SAI0_DELAY_MASK       (0x3 << 6)
+#define ADAU1372_SAI0_SAI_I2S          (0x0 << 4)
+#define ADAU1372_SAI0_SAI_TDM2         (0x1 << 4)
+#define ADAU1372_SAI0_SAI_TDM4         (0x2 << 4)
+#define ADAU1372_SAI0_SAI_TDM8         (0x3 << 4)
+#define ADAU1372_SAI0_SAI_MASK         (0x3 << 4)
+#define ADAU1372_SAI0_FS_48            0x0
+#define ADAU1372_SAI0_FS_8             0x1
+#define ADAU1372_SAI0_FS_12            0x2
+#define ADAU1372_SAI0_FS_16            0x3
+#define ADAU1372_SAI0_FS_24            0x4
+#define ADAU1372_SAI0_FS_32            0x5
+#define ADAU1372_SAI0_FS_96            0x6
+#define ADAU1372_SAI0_FS_192           0x7
+#define ADAU1372_SAI0_FS_MASK          0xf
+
+#define ADAU1372_SAI1_TDM_TS           BIT(7)
+#define ADAU1372_SAI1_BCLK_TDMC                BIT(6)
+#define ADAU1372_SAI1_LR_MODE          BIT(5)
+#define ADAU1372_SAI1_LR_POL           BIT(4)
+#define ADAU1372_SAI1_BCLKRATE         BIT(2)
+#define ADAU1372_SAI1_BCLKEDGE         BIT(1)
+#define ADAU1372_SAI1_MS               BIT(0)
+
+static const unsigned int adau1372_rates[] = {
+       [ADAU1372_SAI0_FS_8] = 8000,
+       [ADAU1372_SAI0_FS_12] = 12000,
+       [ADAU1372_SAI0_FS_16] = 16000,
+       [ADAU1372_SAI0_FS_24] = 24000,
+       [ADAU1372_SAI0_FS_32] = 32000,
+       [ADAU1372_SAI0_FS_48] = 48000,
+       [ADAU1372_SAI0_FS_96] = 96000,
+       [ADAU1372_SAI0_FS_192] = 192000,
+};
+
+/* 8k, 12k, 24k, 48k */
+#define ADAU1372_RATE_MASK_TDM8 0x17
+/* + 16k, 96k */
+#define ADAU1372_RATE_MASK_TDM4_MASTER (ADAU1372_RATE_MASK_TDM8 | 0x48 | 0x20)
+/* +32k */
+#define ADAU1372_RATE_MASK_TDM4 (ADAU1372_RATE_MASK_TDM4_MASTER | 0x20)
+/* + 192k */
+#define ADAU1372_RATE_MASK_TDM2 (ADAU1372_RATE_MASK_TDM4 | 0x80)
+
+static const DECLARE_TLV_DB_MINMAX(adau1372_digital_tlv, -9563, 0);
+static const DECLARE_TLV_DB_SCALE(adau1372_pga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adau1372_pga_boost_tlv, 0, 1000, 0);
+
+static const char * const adau1372_bias_text[] = {
+       "Normal operation", "Extreme power saving", "Enhanced performance",
+       "Power saving",
+};
+
+static const unsigned int adau1372_bias_adc_values[] = {
+       0, 2, 3,
+};
+
+static const char * const adau1372_bias_adc_text[] = {
+       "Normal operation", "Enhanced performance", "Power saving",
+};
+
+static const char * const adau1372_bias_dac_text[] = {
+       "Normal operation", "Power saving", "Superior performance",
+       "Enhanced performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_hp_enum,
+       ADAU1372_REG_BIAS_CTRL0, 6, adau1372_bias_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe0_1_enum,
+       ADAU1372_REG_BIAS_CTRL0, 4, adau1372_bias_text);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc2_3_enum,
+       ADAU1372_REG_BIAS_CTRL0, 2, 0x3, adau1372_bias_adc_text,
+       adau1372_bias_adc_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc0_1_enum,
+       ADAU1372_REG_BIAS_CTRL0, 0, 0x3, adau1372_bias_adc_text,
+       adau1372_bias_adc_values);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe2_3_enum,
+       ADAU1372_REG_BIAS_CTRL1, 4, adau1372_bias_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_mic_enum,
+       ADAU1372_REG_BIAS_CTRL1, 2, adau1372_bias_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_dac_enum,
+       ADAU1372_REG_BIAS_CTRL1, 0, adau1372_bias_dac_text);
+
+static const char * const adau1372_hpf_text[] = {
+       "Off",
+       "1 Hz",
+       "4 Hz",
+       "8 Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_hpf0_1_enum, ADAU1372_REG_ADC_CTRL2, 5,
+                           adau1372_hpf_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_hpf2_3_enum, ADAU1372_REG_ADC_CTRL3, 5,
+                           adau1372_hpf_text);
+static const struct snd_kcontrol_new adau1372_controls[] = {
+       SOC_SINGLE_TLV("ADC 0 Capture Volume", ADAU1372_REG_ADC_VOL(0),
+                      0, 0xff, 1, adau1372_digital_tlv),
+       SOC_SINGLE_TLV("ADC 1 Capture Volume", ADAU1372_REG_ADC_VOL(1),
+                      0, 0xff, 1, adau1372_digital_tlv),
+       SOC_SINGLE_TLV("ADC 2 Capture Volume", ADAU1372_REG_ADC_VOL(2),
+                      0, 0xff, 1, adau1372_digital_tlv),
+       SOC_SINGLE_TLV("ADC 3 Capture Volume", ADAU1372_REG_ADC_VOL(3),
+                      0, 0xff, 1, adau1372_digital_tlv),
+       SOC_SINGLE("ADC 0 Capture Switch", ADAU1372_REG_ADC_CTRL0, 3, 1, 1),
+       SOC_SINGLE("ADC 1 Capture Switch", ADAU1372_REG_ADC_CTRL0, 4, 1, 1),
+       SOC_SINGLE("ADC 2 Capture Switch", ADAU1372_REG_ADC_CTRL1, 3, 1, 1),
+       SOC_SINGLE("ADC 3 Capture Switch", ADAU1372_REG_ADC_CTRL1, 4, 1, 1),
+
+       SOC_ENUM("ADC 0+1 High-Pass-Filter", adau1372_hpf0_1_enum),
+       SOC_ENUM("ADC 2+3 High-Pass-Filter", adau1372_hpf2_3_enum),
+
+       SOC_SINGLE_TLV("PGA 0 Capture Volume", ADAU1372_REG_PGA_CTRL(0),
+                      0, 0x3f, 0, adau1372_pga_tlv),
+       SOC_SINGLE_TLV("PGA 1 Capture Volume", ADAU1372_REG_PGA_CTRL(1),
+                      0, 0x3f, 0, adau1372_pga_tlv),
+       SOC_SINGLE_TLV("PGA 2 Capture Volume", ADAU1372_REG_PGA_CTRL(2),
+                      0, 0x3f, 0, adau1372_pga_tlv),
+       SOC_SINGLE_TLV("PGA 3 Capture Volume", ADAU1372_REG_PGA_CTRL(3),
+                      0, 0x3f, 0, adau1372_pga_tlv),
+       SOC_SINGLE_TLV("PGA 0 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+                      0, 1, 0, adau1372_pga_boost_tlv),
+       SOC_SINGLE_TLV("PGA 1 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+                      1, 1, 0, adau1372_pga_boost_tlv),
+       SOC_SINGLE_TLV("PGA 2 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+                      2, 1, 0, adau1372_pga_boost_tlv),
+       SOC_SINGLE_TLV("PGA 3 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+                      3, 1, 0, adau1372_pga_boost_tlv),
+       SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 1),
+       SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 1),
+       SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 1),
+       SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 1),
+
+       SOC_SINGLE_TLV("DAC 0 Playback Volume", ADAU1372_REG_DAC_VOL(0),
+                      0, 0xff, 1, adau1372_digital_tlv),
+       SOC_SINGLE_TLV("DAC 1 Playback Volume", ADAU1372_REG_DAC_VOL(1),
+                      0, 0xff, 1, adau1372_digital_tlv),
+       SOC_SINGLE("DAC 0 Playback Switch", ADAU1372_REG_DAC_CTRL, 3, 1, 1),
+       SOC_SINGLE("DAC 1 Playback Switch", ADAU1372_REG_DAC_CTRL, 4, 1, 1),
+
+       SOC_ENUM("Headphone Bias", adau1372_bias_hp_enum),
+       SOC_ENUM("Microphone Bias", adau1372_bias_mic_enum),
+       SOC_ENUM("AFE 0+1 Bias", adau1372_bias_afe0_1_enum),
+       SOC_ENUM("AFE 2+3 Bias", adau1372_bias_afe2_3_enum),
+       SOC_ENUM("ADC 0+1 Bias", adau1372_bias_adc0_1_enum),
+       SOC_ENUM("ADC 2+3 Bias", adau1372_bias_adc2_3_enum),
+       SOC_ENUM("DAC 0+1 Bias", adau1372_bias_dac_enum),
+};
+
+static const char * const adau1372_decimator_mux_text[] = {
+       "ADC",
+       "DMIC",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_decimator0_1_mux_enum, ADAU1372_REG_ADC_CTRL2,
+                           2, adau1372_decimator_mux_text);
+
+static const struct snd_kcontrol_new adau1372_decimator0_1_mux_control =
+       SOC_DAPM_ENUM("Decimator 0+1 Capture Mux", adau1372_decimator0_1_mux_enum);
+
+static SOC_ENUM_SINGLE_DECL(adau1372_decimator2_3_mux_enum, ADAU1372_REG_ADC_CTRL3,
+                           2, adau1372_decimator_mux_text);
+
+static const struct snd_kcontrol_new adau1372_decimator2_3_mux_control =
+       SOC_DAPM_ENUM("Decimator 2+3 Capture Mux", adau1372_decimator2_3_mux_enum);
+
+static const unsigned int adau1372_asrco_mux_values[] = {
+       4, 5, 6, 7,
+};
+
+static const char * const adau1372_asrco_mux_text[] = {
+       "Decimator0",
+       "Decimator1",
+       "Decimator2",
+       "Decimator3",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco0_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1,
+                                 0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco1_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1,
+                                 4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco2_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3,
+                                 0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco3_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3,
+                                 4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+
+static const struct snd_kcontrol_new adau1372_asrco0_mux_control =
+       SOC_DAPM_ENUM("Output ASRC0 Capture Mux", adau1372_asrco0_mux_enum);
+static const struct snd_kcontrol_new adau1372_asrco1_mux_control =
+       SOC_DAPM_ENUM("Output ASRC1 Capture Mux", adau1372_asrco1_mux_enum);
+static const struct snd_kcontrol_new adau1372_asrco2_mux_control =
+       SOC_DAPM_ENUM("Output ASRC2 Capture Mux", adau1372_asrco2_mux_enum);
+static const struct snd_kcontrol_new adau1372_asrco3_mux_control =
+       SOC_DAPM_ENUM("Output ASRC3 Capture Mux", adau1372_asrco3_mux_enum);
+
+static const unsigned int adau1372_sout_mux_values[] = {
+       4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const char * const adau1372_sout_mux_text[] = {
+       "Output ASRC0",
+       "Output ASRC1",
+       "Output ASRC2",
+       "Output ASRC3",
+       "Serial Input 0",
+       "Serial Input 1",
+       "Serial Input 2",
+       "Serial Input 3",
+       "Serial Input 4",
+       "Serial Input 5",
+       "Serial Input 6",
+       "Serial Input 7",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout0_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1,
+                                 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout1_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1,
+                                 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout2_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3,
+                                 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout3_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3,
+                                 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout4_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5,
+                                 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout5_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5,
+                                 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout6_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7,
+                                 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout7_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7,
+                                 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+
+static const struct snd_kcontrol_new adau1372_sout0_mux_control =
+       SOC_DAPM_ENUM("Serial Output 0 Capture Mux", adau1372_sout0_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout1_mux_control =
+       SOC_DAPM_ENUM("Serial Output 1 Capture Mux", adau1372_sout1_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout2_mux_control =
+       SOC_DAPM_ENUM("Serial Output 2 Capture Mux", adau1372_sout2_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout3_mux_control =
+       SOC_DAPM_ENUM("Serial Output 3 Capture Mux", adau1372_sout3_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout4_mux_control =
+       SOC_DAPM_ENUM("Serial Output 4 Capture Mux", adau1372_sout4_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout5_mux_control =
+       SOC_DAPM_ENUM("Serial Output 5 Capture Mux", adau1372_sout5_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout6_mux_control =
+       SOC_DAPM_ENUM("Serial Output 6 Capture Mux", adau1372_sout6_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout7_mux_control =
+       SOC_DAPM_ENUM("Serial Output 7 Capture Mux", adau1372_sout7_mux_enum);
+
+static const char * const adau1372_asrci_mux_text[] = {
+       "Serial Input 0+1",
+       "Serial Input 2+3",
+       "Serial Input 4+5",
+       "Serial Input 6+7",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_asrci_mux_enum,
+       ADAU1372_REG_ASRC_MODE, 2, adau1372_asrci_mux_text);
+
+static const struct snd_kcontrol_new adau1372_asrci_mux_control =
+       SOC_DAPM_ENUM("Input ASRC Playback Mux", adau1372_asrci_mux_enum);
+
+static const unsigned int adau1372_dac_mux_values[] = {
+       12, 13
+};
+
+static const char * const adau1372_dac_mux_text[] = {
+       "Input ASRC0",
+       "Input ASRC1",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac0_mux_enum, ADAU1372_REG_DAC_SOURCE,
+                                 0, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac1_mux_enum, ADAU1372_REG_DAC_SOURCE,
+                                 4, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values);
+
+static const struct snd_kcontrol_new adau1372_dac0_mux_control =
+       SOC_DAPM_ENUM("DAC 0 Playback Mux", adau1372_dac0_mux_enum);
+static const struct snd_kcontrol_new adau1372_dac1_mux_control =
+       SOC_DAPM_ENUM("DAC 1 Playback Mux", adau1372_dac1_mux_enum);
+
+static const struct snd_soc_dapm_widget adau1372_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("AIN0"),
+       SND_SOC_DAPM_INPUT("AIN1"),
+       SND_SOC_DAPM_INPUT("AIN2"),
+       SND_SOC_DAPM_INPUT("AIN3"),
+       SND_SOC_DAPM_INPUT("DMIC0_1"),
+       SND_SOC_DAPM_INPUT("DMIC2_3"),
+
+       SND_SOC_DAPM_SUPPLY("MICBIAS0", ADAU1372_REG_MICBIAS, 4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1372_REG_MICBIAS, 5, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 0, NULL, 0),
+       SND_SOC_DAPM_ADC("ADC0", NULL, ADAU1372_REG_ADC_CTRL2, 0, 0),
+       SND_SOC_DAPM_ADC("ADC1", NULL, ADAU1372_REG_ADC_CTRL2, 1, 0),
+       SND_SOC_DAPM_ADC("ADC2", NULL, ADAU1372_REG_ADC_CTRL3, 0, 0),
+       SND_SOC_DAPM_ADC("ADC3", NULL, ADAU1372_REG_ADC_CTRL3, 1, 0),
+
+       SND_SOC_DAPM_SUPPLY("ADC0 Filter", ADAU1372_REG_DECIM_PWR, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 Filter", ADAU1372_REG_DECIM_PWR, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC2 Filter", ADAU1372_REG_DECIM_PWR, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC3 Filter", ADAU1372_REG_DECIM_PWR, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Output ASRC0 Decimator", ADAU1372_REG_DECIM_PWR, 4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Output ASRC1 Decimator", ADAU1372_REG_DECIM_PWR, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Output ASRC2 Decimator", ADAU1372_REG_DECIM_PWR, 6, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Output ASRC3 Decimator", ADAU1372_REG_DECIM_PWR, 7, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("Decimator0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control),
+       SND_SOC_DAPM_MUX("Decimator1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control),
+       SND_SOC_DAPM_MUX("Decimator2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control),
+       SND_SOC_DAPM_MUX("Decimator3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control),
+
+       SND_SOC_DAPM_MUX("Output ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco0_mux_control),
+       SND_SOC_DAPM_MUX("Output ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco1_mux_control),
+       SND_SOC_DAPM_MUX("Output ASRC2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco2_mux_control),
+       SND_SOC_DAPM_MUX("Output ASRC3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco3_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 0 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout0_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 1 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout1_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 2 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout2_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 3 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout3_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 4 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout4_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 5 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout5_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 6 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout6_mux_control),
+       SND_SOC_DAPM_MUX("Serial Output 7 Capture Mux", SND_SOC_NOPM, 0, 0,
+                        &adau1372_sout7_mux_control),
+
+       SND_SOC_DAPM_AIF_IN("Serial Input 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 1", NULL, 1, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 2", NULL, 2, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 3", NULL, 3, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 4", NULL, 4, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 5", NULL, 5, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 6", NULL, 6, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("Serial Input 7", NULL, 7, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_OUT("Serial Output 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 1", NULL, 1, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 2", NULL, 2, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 3", NULL, 3, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 4", NULL, 4, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 5", NULL, 5, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 6", NULL, 6, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("Serial Output 7", NULL, 7, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SUPPLY("Output ASRC Supply", ADAU1372_REG_ASRC_MODE, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Input ASRC Supply", ADAU1372_REG_ASRC_MODE, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC1 Modulator", ADAU1372_REG_INTERP_PWR, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC0 Modulator", ADAU1372_REG_INTERP_PWR, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Input ASRC1 Interpolator", ADAU1372_REG_INTERP_PWR, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Input ASRC0 Interpolator", ADAU1372_REG_INTERP_PWR, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("Input ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control),
+       SND_SOC_DAPM_MUX("Input ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control),
+
+       SND_SOC_DAPM_MUX("DAC 0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac0_mux_control),
+       SND_SOC_DAPM_MUX("DAC 1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac1_mux_control),
+
+       SND_SOC_DAPM_DAC("DAC0", NULL, ADAU1372_REG_DAC_CTRL, 0, 0),
+       SND_SOC_DAPM_DAC("DAC1", NULL, ADAU1372_REG_DAC_CTRL, 1, 0),
+
+       SND_SOC_DAPM_OUT_DRV("OP_STAGE_LP", ADAU1372_REG_OP_STAGE_CTRL, 0, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("OP_STAGE_LN", ADAU1372_REG_OP_STAGE_CTRL, 1, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("OP_STAGE_RP", ADAU1372_REG_OP_STAGE_CTRL, 2, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("OP_STAGE_RN", ADAU1372_REG_OP_STAGE_CTRL, 3, 1, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("HPOUTL"),
+       SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+#define ADAU1372_SOUT_ROUTES(x) \
+       { "Serial Output " #x " Capture Mux", "Output ASRC0", "Output ASRC0 Mux" }, \
+       { "Serial Output " #x " Capture Mux", "Output ASRC1", "Output ASRC1 Mux" }, \
+       { "Serial Output " #x " Capture Mux", "Output ASRC2", "Output ASRC2 Mux" }, \
+       { "Serial Output " #x " Capture Mux", "Output ASRC3", "Output ASRC3 Mux" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 0", "Serial Input 0" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 1", "Serial Input 1" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 2", "Serial Input 2" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 3", "Serial Input 3" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 4", "Serial Input 4" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 5", "Serial Input 5" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 6", "Serial Input 6" }, \
+       { "Serial Output " #x " Capture Mux", "Serial Input 7", "Serial Input 7" }, \
+       { "Serial Output " #x, NULL, "Serial Output " #x " Capture Mux" }, \
+       { "Capture", NULL, "Serial Output " #x }
+
+#define ADAU1372_ASRCO_ROUTES(x) \
+       { "Output ASRC" #x " Mux", "Decimator0", "Decimator0 Mux" }, \
+       { "Output ASRC" #x " Mux", "Decimator1", "Decimator1 Mux" }, \
+       { "Output ASRC" #x " Mux", "Decimator2", "Decimator2 Mux" }, \
+       { "Output ASRC" #x " Mux", "Decimator3", "Decimator3 Mux" }
+
+static const struct snd_soc_dapm_route adau1372_dapm_routes[] = {
+       { "PGA0", NULL, "AIN0" },
+       { "PGA1", NULL, "AIN1" },
+       { "PGA2", NULL, "AIN2" },
+       { "PGA3", NULL, "AIN3" },
+
+       { "ADC0", NULL, "PGA0" },
+       { "ADC1", NULL, "PGA1" },
+       { "ADC2", NULL, "PGA2" },
+       { "ADC3", NULL, "PGA3" },
+
+       { "Decimator0 Mux", "ADC", "ADC0" },
+       { "Decimator1 Mux", "ADC", "ADC1" },
+       { "Decimator2 Mux", "ADC", "ADC2" },
+       { "Decimator3 Mux", "ADC", "ADC3" },
+
+       { "Decimator0 Mux", "DMIC", "DMIC0_1" },
+       { "Decimator1 Mux", "DMIC", "DMIC0_1" },
+       { "Decimator2 Mux", "DMIC", "DMIC2_3" },
+       { "Decimator3 Mux", "DMIC", "DMIC2_3" },
+
+       { "Decimator0 Mux", NULL, "ADC0 Filter" },
+       { "Decimator1 Mux", NULL, "ADC1 Filter" },
+       { "Decimator2 Mux", NULL, "ADC2 Filter" },
+       { "Decimator3 Mux", NULL, "ADC3 Filter" },
+
+       { "Output ASRC0 Mux", NULL, "Output ASRC Supply" },
+       { "Output ASRC1 Mux", NULL, "Output ASRC Supply" },
+       { "Output ASRC2 Mux", NULL, "Output ASRC Supply" },
+       { "Output ASRC3 Mux", NULL, "Output ASRC Supply" },
+       { "Output ASRC0 Mux", NULL, "Output ASRC0 Decimator" },
+       { "Output ASRC1 Mux", NULL, "Output ASRC1 Decimator" },
+       { "Output ASRC2 Mux", NULL, "Output ASRC2 Decimator" },
+       { "Output ASRC3 Mux", NULL, "Output ASRC3 Decimator" },
+
+       ADAU1372_ASRCO_ROUTES(0),
+       ADAU1372_ASRCO_ROUTES(1),
+       ADAU1372_ASRCO_ROUTES(2),
+       ADAU1372_ASRCO_ROUTES(3),
+
+       ADAU1372_SOUT_ROUTES(0),
+       ADAU1372_SOUT_ROUTES(1),
+       ADAU1372_SOUT_ROUTES(2),
+       ADAU1372_SOUT_ROUTES(3),
+       ADAU1372_SOUT_ROUTES(4),
+       ADAU1372_SOUT_ROUTES(5),
+       ADAU1372_SOUT_ROUTES(6),
+       ADAU1372_SOUT_ROUTES(7),
+
+       { "Serial Input 0", NULL, "Playback" },
+       { "Serial Input 1", NULL, "Playback" },
+       { "Serial Input 2", NULL, "Playback" },
+       { "Serial Input 3", NULL, "Playback" },
+       { "Serial Input 4", NULL, "Playback" },
+       { "Serial Input 5", NULL, "Playback" },
+       { "Serial Input 6", NULL, "Playback" },
+       { "Serial Input 7", NULL, "Playback" },
+
+       { "Input ASRC0 Mux", "Serial Input 0+1", "Serial Input 0" },
+       { "Input ASRC1 Mux", "Serial Input 0+1", "Serial Input 1" },
+       { "Input ASRC0 Mux", "Serial Input 2+3", "Serial Input 2" },
+       { "Input ASRC1 Mux", "Serial Input 2+3", "Serial Input 3" },
+       { "Input ASRC0 Mux", "Serial Input 4+5", "Serial Input 4" },
+       { "Input ASRC1 Mux", "Serial Input 4+5", "Serial Input 5" },
+       { "Input ASRC0 Mux", "Serial Input 6+7", "Serial Input 6" },
+       { "Input ASRC1 Mux", "Serial Input 6+7", "Serial Input 7" },
+       { "Input ASRC0 Mux", NULL, "Input ASRC Supply" },
+       { "Input ASRC1 Mux", NULL, "Input ASRC Supply" },
+       { "Input ASRC0 Mux", NULL, "Input ASRC0 Interpolator" },
+       { "Input ASRC1 Mux", NULL, "Input ASRC1 Interpolator" },
+
+       { "DAC 0 Mux", "Input ASRC0", "Input ASRC0 Mux" },
+       { "DAC 0 Mux", "Input ASRC1", "Input ASRC1 Mux" },
+       { "DAC 1 Mux", "Input ASRC0", "Input ASRC0 Mux" },
+       { "DAC 1 Mux", "Input ASRC1", "Input ASRC1 Mux" },
+
+       { "DAC0", NULL, "DAC 0 Mux" },
+       { "DAC1", NULL, "DAC 1 Mux" },
+       { "DAC0", NULL, "DAC0 Modulator" },
+       { "DAC1", NULL, "DAC1 Modulator" },
+
+       { "OP_STAGE_LP", NULL, "DAC0" },
+       { "OP_STAGE_LN", NULL, "DAC0" },
+       { "OP_STAGE_RP", NULL, "DAC1" },
+       { "OP_STAGE_RN", NULL, "DAC1" },
+
+       { "HPOUTL", NULL, "OP_STAGE_LP" },
+       { "HPOUTL", NULL, "OP_STAGE_LN" },
+       { "HPOUTR", NULL, "OP_STAGE_RP" },
+       { "HPOUTR", NULL, "OP_STAGE_RN" },
+};
+
+static int adau1372_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+       unsigned int sai0 = 0, sai1 = 0;
+       bool invert_lrclk = false;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               adau1372->master = true;
+               sai1 |= ADAU1372_SAI1_MS;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               adau1372->master = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               invert_lrclk = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               invert_lrclk = true;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               invert_lrclk = false;
+               sai1 |= ADAU1372_SAI1_BCLKEDGE;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               invert_lrclk = true;
+               sai1 |= ADAU1372_SAI1_BCLKEDGE;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               sai0 |= ADAU1372_SAI0_DELAY1;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               sai0 |= ADAU1372_SAI0_DELAY0;
+               invert_lrclk = !invert_lrclk;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               sai0 |= ADAU1372_SAI0_DELAY1;
+               sai1 |= ADAU1372_SAI1_LR_MODE;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               sai0 |= ADAU1372_SAI0_DELAY0;
+               sai1 |= ADAU1372_SAI1_LR_MODE;
+               break;
+       }
+
+       if (invert_lrclk)
+               sai1 |= ADAU1372_SAI1_LR_POL;
+
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_DELAY_MASK, sai0);
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1,
+                          ADAU1372_SAI1_MS | ADAU1372_SAI1_BCLKEDGE |
+                          ADAU1372_SAI1_LR_MODE | ADAU1372_SAI1_LR_POL, sai1);
+
+       return 0;
+}
+
+static int adau1372_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       unsigned int slot_width;
+       unsigned int sai0, sai1;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(adau1372_rates); i++) {
+               if (rate == adau1372_rates[i])
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(adau1372_rates))
+               return -EINVAL;
+
+       sai0 = i;
+
+       slot_width = adau1372->slot_width;
+       if (slot_width == 0)
+               slot_width = params_width(params);
+
+       switch (slot_width) {
+       case 16:
+               sai1 = ADAU1372_SAI1_BCLKRATE;
+               break;
+       case 32:
+               sai1 = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_FS_MASK, sai0);
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLKRATE, sai1);
+
+       return 0;
+}
+
+static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                                unsigned int rx_mask, int slots, int width)
+{
+       struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+       unsigned int sai0, sai1;
+
+       /* I2S mode */
+       if (slots == 0) {
+               /* The other settings dont matter in I2S mode */
+               regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0,
+                                  ADAU1372_SAI0_SAI_MASK, ADAU1372_SAI0_SAI_I2S);
+               adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2;
+               adau1372->slot_width = 0;
+               return 0;
+       }
+
+       /* We have 8 channels anything outside that is not supported */
+       if ((tx_mask & ~0xff) != 0 || (rx_mask & ~0xff) != 0)
+               return -EINVAL;
+
+       switch (width) {
+       case 16:
+               sai1 = ADAU1372_SAI1_BCLK_TDMC;
+               break;
+       case 32:
+               sai1 = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (slots) {
+       case 2:
+               sai0 = ADAU1372_SAI0_SAI_TDM2;
+               adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2;
+               break;
+       case 4:
+               sai0 = ADAU1372_SAI0_SAI_TDM4;
+               if (adau1372->master)
+                       adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4_MASTER;
+               else
+                       adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4;
+               break;
+       case 8:
+               sai0 = ADAU1372_SAI0_SAI_TDM8;
+               adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       adau1372->slot_width = width;
+
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_SAI_MASK, sai0);
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLK_TDMC, sai1);
+
+       /* Mask is inverted in hardware */
+       regmap_write(adau1372->regmap, ADAU1372_REG_SOUT_CTRL, ~tx_mask);
+
+       return 0;
+}
+
+static int adau1372_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+       struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+       unsigned int sai1;
+
+       if (tristate)
+               sai1 = ADAU1372_SAI1_TDM_TS;
+       else
+               sai1 = 0;
+
+       return regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_TDM_TS, sai1);
+}
+
+static int adau1372_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+
+       snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                  &adau1372->rate_constraints);
+
+       return 0;
+}
+
+static void adau1372_enable_pll(struct adau1372 *adau1372)
+{
+       unsigned int val, timeout = 0;
+       int ret;
+
+       regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
+                          ADAU1372_CLK_CTRL_PLL_EN, ADAU1372_CLK_CTRL_PLL_EN);
+       do {
+               /* Takes about 1ms to lock */
+               usleep_range(1000, 2000);
+               ret = regmap_read(adau1372->regmap, ADAU1372_REG_PLL(5), &val);
+               if (ret)
+                       break;
+               timeout++;
+       } while (!(val & 1) && timeout < 3);
+
+       if (ret < 0 || !(val & 1))
+               dev_err(adau1372->dev, "Failed to lock PLL\n");
+}
+
+static void adau1372_set_power(struct adau1372 *adau1372, bool enable)
+{
+       if (adau1372->enabled == enable)
+               return;
+
+       if (enable) {
+               unsigned int clk_ctrl = ADAU1372_CLK_CTRL_MCLK_EN;
+
+               clk_prepare_enable(adau1372->mclk);
+               if (adau1372->pd_gpio)
+                       gpiod_set_value(adau1372->pd_gpio, 0);
+
+               if (adau1372->switch_mode)
+                       adau1372->switch_mode(adau1372->dev);
+
+               regcache_cache_only(adau1372->regmap, false);
+
+               /*
+                * Clocks needs to be enabled before any other register can be
+                * accessed.
+                */
+               if (adau1372->use_pll) {
+                       adau1372_enable_pll(adau1372);
+                       clk_ctrl |= ADAU1372_CLK_CTRL_CLKSRC;
+               }
+
+               regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
+                                  ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_CLKSRC, clk_ctrl);
+               regcache_sync(adau1372->regmap);
+       } else {
+               if (adau1372->pd_gpio) {
+                       /*
+                        * This will turn everything off and reset the register
+                        * map. No need to do any register writes to manually
+                        * turn things off.
+                        */
+                       gpiod_set_value(adau1372->pd_gpio, 1);
+                       regcache_mark_dirty(adau1372->regmap);
+               } else {
+                       regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
+                                          ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_PLL_EN, 0);
+               }
+               clk_disable_unprepare(adau1372->mclk);
+               regcache_cache_only(adau1372->regmap, true);
+       }
+
+       adau1372->enabled = enable;
+}
+
+static int adau1372_set_bias_level(struct snd_soc_component *component,
+                                  enum snd_soc_bias_level level)
+{
+       struct adau1372 *adau1372 = snd_soc_component_get_drvdata(component);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               adau1372_set_power(adau1372, true);
+               break;
+       case SND_SOC_BIAS_OFF:
+               adau1372_set_power(adau1372, false);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver adau1372_driver = {
+       .set_bias_level = adau1372_set_bias_level,
+       .controls = adau1372_controls,
+       .num_controls = ARRAY_SIZE(adau1372_controls),
+       .dapm_widgets = adau1372_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(adau1372_dapm_widgets),
+       .dapm_routes = adau1372_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(adau1372_dapm_routes),
+};
+
+static const struct snd_soc_dai_ops adau1372_dai_ops = {
+       .set_fmt = adau1372_set_dai_fmt,
+       .set_tdm_slot = adau1372_set_tdm_slot,
+       .set_tristate = adau1372_set_tristate,
+       .hw_params = adau1372_hw_params,
+       .startup = adau1372_startup,
+};
+
+#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |    SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1372_dai_driver = {
+       .name = "adau1372",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = ADAU1372_FORMATS,
+               .sig_bits = 24,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = ADAU1372_FORMATS,
+               .sig_bits = 24,
+       },
+       .ops = &adau1372_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static int adau1372_setup_pll(struct adau1372 *adau1372, unsigned int rate)
+{
+       u8 regs[5];
+       unsigned int i;
+       int ret;
+
+       ret = adau_calc_pll_cfg(rate, 49152000, regs);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               regmap_write(adau1372->regmap, ADAU1372_REG_PLL(i), regs[i]);
+
+       return 0;
+}
+
+int adau1372_probe(struct device *dev, struct regmap *regmap,
+                  void (*switch_mode)(struct device *dev))
+{
+       struct adau1372 *adau1372;
+       unsigned int clk_ctrl;
+       unsigned long rate;
+       int ret;
+
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       adau1372 = devm_kzalloc(dev, sizeof(*adau1372), GFP_KERNEL);
+       if (!adau1372)
+               return -ENOMEM;
+
+       adau1372->clk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(adau1372->clk))
+               return PTR_ERR(adau1372->clk);
+
+       adau1372->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
+       if (IS_ERR(adau1372->pd_gpio))
+               return PTR_ERR(adau1372->pd_gpio);
+
+       adau1372->regmap = regmap;
+       adau1372->switch_mode = switch_mode;
+       adau1372->dev = dev;
+       adau1372->rate_constraints.list = adau1372_rates;
+       adau1372->rate_constraints.count = ARRAY_SIZE(adau1372_rates);
+       adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2;
+
+       dev_set_drvdata(dev, adau1372);
+
+       /*
+        * The datasheet says that the internal MCLK always needs to run at
+        * 12.288MHz. Automatically choose a valid configuration from the
+        * external clock.
+        */
+       rate = clk_get_rate(adau1372->clk);
+
+       switch (rate) {
+       case 12288000:
+               clk_ctrl = ADAU1372_CLK_CTRL_CC_MDIV;
+               break;
+       case 24576000:
+               clk_ctrl = 0;
+               break;
+       default:
+               clk_ctrl = 0;
+               ret = adau1372_setup_pll(adau1372, rate);
+               if (ret < 0)
+                       return ret;
+               adau1372->use_pll = true;
+               break;
+       }
+
+       /*
+        * Most of the registers are inaccessible unless the internal clock is
+        * enabled.
+        */
+       regcache_cache_only(regmap, true);
+
+       regmap_update_bits(regmap, ADAU1372_REG_CLK_CTRL, ADAU1372_CLK_CTRL_CC_MDIV, clk_ctrl);
+
+       /*
+        * No pinctrl support yet, put the multi-purpose pins in the most
+        * sensible mode for general purpose CODEC operation.
+        */
+       regmap_write(regmap, ADAU1372_REG_MODE_MP(1), 0x00); /* SDATA OUT */
+       regmap_write(regmap, ADAU1372_REG_MODE_MP(6), 0x12); /* CLOCKOUT */
+
+       regmap_write(regmap, ADAU1372_REG_OP_STAGE_MUTE, 0x0);
+
+       regmap_write(regmap, 0x7, 0x01); /* CLOCK OUT */
+
+       return  devm_snd_soc_register_component(dev, &adau1372_driver, &adau1372_dai_driver, 1);
+}
+EXPORT_SYMBOL(adau1372_probe);
+
+static const struct reg_default adau1372_reg_defaults[] = {
+       { ADAU1372_REG_CLK_CTRL,                0x00 },
+       { ADAU1372_REG_PLL(0),                  0x00 },
+       { ADAU1372_REG_PLL(1),                  0x00 },
+       { ADAU1372_REG_PLL(2),                  0x00 },
+       { ADAU1372_REG_PLL(3),                  0x00 },
+       { ADAU1372_REG_PLL(4),                  0x00 },
+       { ADAU1372_REG_PLL(5),                  0x00 },
+       { ADAU1372_REG_DAC_SOURCE,              0x10 },
+       { ADAU1372_REG_SOUT_SOURCE_0_1,         0x54 },
+       { ADAU1372_REG_SOUT_SOURCE_2_3,         0x76 },
+       { ADAU1372_REG_SOUT_SOURCE_4_5,         0x54 },
+       { ADAU1372_REG_SOUT_SOURCE_6_7,         0x76 },
+       { ADAU1372_REG_ADC_SDATA_CH,            0x04 },
+       { ADAU1372_REG_ASRCO_SOURCE_0_1,        0x10 },
+       { ADAU1372_REG_ASRCO_SOURCE_2_3,        0x32 },
+       { ADAU1372_REG_ASRC_MODE,               0x00 },
+       { ADAU1372_REG_ADC_CTRL0,               0x19 },
+       { ADAU1372_REG_ADC_CTRL1,               0x19 },
+       { ADAU1372_REG_ADC_CTRL2,               0x00 },
+       { ADAU1372_REG_ADC_CTRL3,               0x00 },
+       { ADAU1372_REG_ADC_VOL(0),              0x00 },
+       { ADAU1372_REG_ADC_VOL(1),              0x00 },
+       { ADAU1372_REG_ADC_VOL(2),              0x00 },
+       { ADAU1372_REG_ADC_VOL(3),              0x00 },
+       { ADAU1372_REG_PGA_CTRL(0),             0x40 },
+       { ADAU1372_REG_PGA_CTRL(1),             0x40 },
+       { ADAU1372_REG_PGA_CTRL(2),             0x40 },
+       { ADAU1372_REG_PGA_CTRL(3),             0x40 },
+       { ADAU1372_REG_PGA_BOOST,               0x00 },
+       { ADAU1372_REG_MICBIAS,                 0x00 },
+       { ADAU1372_REG_DAC_CTRL,                0x18 },
+       { ADAU1372_REG_DAC_VOL(0),              0x00 },
+       { ADAU1372_REG_DAC_VOL(1),              0x00 },
+       { ADAU1372_REG_OP_STAGE_MUTE,           0x0f },
+       { ADAU1372_REG_SAI0,                    0x00 },
+       { ADAU1372_REG_SAI1,                    0x00 },
+       { ADAU1372_REG_SOUT_CTRL,               0x00 },
+       { ADAU1372_REG_MODE_MP(0),              0x00 },
+       { ADAU1372_REG_MODE_MP(1),              0x10 },
+       { ADAU1372_REG_MODE_MP(4),              0x00 },
+       { ADAU1372_REG_MODE_MP(5),              0x00 },
+       { ADAU1372_REG_MODE_MP(6),              0x11 },
+       { ADAU1372_REG_OP_STAGE_CTRL,           0x0f },
+       { ADAU1372_REG_DECIM_PWR,               0x00 },
+       { ADAU1372_REG_INTERP_PWR,              0x00 },
+       { ADAU1372_REG_BIAS_CTRL0,              0x00 },
+       { ADAU1372_REG_BIAS_CTRL1,              0x00 },
+};
+
+static bool adau1372_volatile_register(struct device *dev, unsigned int reg)
+{
+       if (reg == ADAU1372_REG_PLL(5))
+               return true;
+
+       return false;
+}
+
+const struct regmap_config adau1372_regmap_config = {
+       .val_bits = 8,
+       .reg_bits = 16,
+       .max_register = 0x4d,
+
+       .reg_defaults = adau1372_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults),
+       .volatile_reg = adau1372_volatile_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(adau1372_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h
new file mode 100644 (file)
index 0000000..a9d2c59
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ADAU1372 driver
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#ifndef SOUND_SOC_CODECS_ADAU1372_H
+#define SOUND_SOC_CODECS_ADAU1372_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+int adau1372_probe(struct device *dev, struct regmap *regmap,
+                  void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1372_regmap_config;
+
+#endif
index 0a36e52..8260f49 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/platform_data/adau1977.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -24,6 +23,8 @@
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
+#include <dt-bindings/sound/adi,adau1977.h>
+
 #include "adau1977.h"
 
 #define ADAU1977_REG_POWER             0x00
@@ -881,13 +882,9 @@ static const struct snd_soc_component_driver adau1977_component_driver = {
 
 static int adau1977_setup_micbias(struct adau1977 *adau1977)
 {
-       struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
        unsigned int micbias;
 
-       if (pdata)
-               micbias = pdata->micbias;
-       else if (device_property_read_u32(adau1977->dev, "adi,micbias",
-                                         &micbias))
+       if (device_property_read_u32(adau1977->dev, "adi,micbias", &micbias))
                micbias = ADAU1977_MICBIAS_8V5;
 
        if (micbias > ADAU1977_MICBIAS_9V0) {
index 4fd9928..75a6491 100644 (file)
@@ -373,6 +373,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        case SND_SOC_DAIFMT_CBM_CFM:
                capture |= ADAV80X_CAPTURE_MODE_MASTER;
                playback |= ADAV80X_PLAYBACK_MODE_MASTER;
+               break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
        default:
index f44d9a4..5d46ae8 100644 (file)
@@ -404,11 +404,13 @@ static int ak4118_i2c_probe(struct i2c_client *i2c,
                                &soc_component_drv_ak4118, &ak4118_dai, 1);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id ak4118_of_match[] = {
        { .compatible = "asahi-kasei,ak4118", },
        {}
 };
 MODULE_DEVICE_TABLE(of, ak4118_of_match);
+#endif
 
 static const struct i2c_device_id ak4118_id_table[] = {
        { "ak4118", 0 },
index 2f076d5..8a32b01 100644 (file)
@@ -415,7 +415,7 @@ static int ak5558_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
-static const struct of_device_id ak5558_i2c_dt_ids[] = {
+static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = {
        { .compatible = "asahi-kasei,ak5558"},
        { }
 };
index 3d1761a..54f4898 100644 (file)
@@ -1068,11 +1068,13 @@ static const struct i2c_device_id alc5623_i2c_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table);
 
+#ifdef CONFIG_OF
 static const struct of_device_id alc5623_of_match[] = {
        { .compatible = "realtek,alc5623", },
        { }
 };
 MODULE_DEVICE_TABLE(of, alc5623_of_match);
+#endif
 
 /*  i2c codec control layer */
 static struct i2c_driver alc5623_i2c_driver = {
index 9d6dcd3..bde5ded 100644 (file)
@@ -1167,11 +1167,13 @@ static const struct i2c_device_id alc5632_i2c_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table);
 
+#ifdef CONFIG_OF
 static const struct of_device_id alc5632_of_match[] = {
        { .compatible = "realtek,alc5632", },
        { }
 };
 MODULE_DEVICE_TABLE(of, alc5632_of_match);
+#endif
 
 /* i2c codec control layer */
 static struct i2c_driver alc5632_i2c_driver = {
index 1228f2d..e32871b 100644 (file)
@@ -1034,6 +1034,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                                priv->out_down_delay++;
                                break;
                        }
+                       break;
                default:
                        break;
                }
index 31904ef..a6267cb 100644 (file)
@@ -222,7 +222,7 @@ static int bd28623_probe(struct platform_device *pdev)
                                               &soc_dai_bd, 1);
 }
 
-static const struct of_device_id bd28623_of_match[] = {
+static const struct of_device_id bd28623_of_match[] __maybe_unused = {
        { .compatible = "rohm,bd28623", },
        {}
 };
index 28f039a..5c3b7e5 100644 (file)
@@ -332,7 +332,7 @@ static int i2s_rx_event(struct snd_soc_dapm_widget *w,
                snd_soc_dapm_to_component(w->dapm);
        struct cros_ec_codec_priv *priv =
                snd_soc_component_get_drvdata(component);
-       struct ec_param_ec_codec_i2s_rx p;
+       struct ec_param_ec_codec_i2s_rx p = {};
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
index f772628..796b894 100644 (file)
@@ -944,6 +944,7 @@ static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
        case SND_BELL:
                if (hz)
                        hz = 261;
+               break;
        case SND_TONE:
                break;
        default:
index 97024a6..bb9599c 100644 (file)
@@ -1008,6 +1008,7 @@ static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
        case SND_BELL:
                if (hz)
                        hz = 261;
+               break;
        case SND_TONE:
                break;
        default:
index 6e34106..52dc299 100644 (file)
@@ -201,6 +201,7 @@ static int cs47l92_outclk_ev(struct snd_soc_dapm_widget *w,
                default:
                        break;
                }
+               break;
        default:
                break;
        }
index 2ad00ed..2f10991 100644 (file)
@@ -1579,7 +1579,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
                .id     = CX2072X_DAI_DSP,
                .probe = cx2072x_dsp_dai_probe,
                .playback = {
-                       .stream_name = "Playback",
+                       .stream_name = "DSP Playback",
                        .channels_min = 2,
                        .channels_max = 2,
                        .rates = CX2072X_RATES_DSP,
@@ -1591,7 +1591,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
                .name = "cx2072x-aec",
                .id     = 3,
                .capture = {
-                       .stream_name = "Capture",
+                       .stream_name = "AEC Capture",
                        .channels_min = 2,
                        .channels_max = 2,
                        .rates = CX2072X_RATES_DSP,
index 6d78bcc..2bfafbe 100644 (file)
@@ -2278,12 +2278,14 @@ static irqreturn_t da7218_irq_thread(int irq, void *data)
  * DT
  */
 
+#ifdef CONFIG_OF
 static const struct of_device_id da7218_of_match[] = {
        { .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
        { .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
        { }
 };
 MODULE_DEVICE_TABLE(of, da7218_of_match);
+#endif
 
 static inline int da7218_of_get_id(struct device *dev)
 {
index 0b3b790..e9b45da 100644 (file)
@@ -1702,11 +1702,13 @@ static struct snd_soc_dai_driver da7219_dai = {
  * DT/ACPI
  */
 
+#ifdef CONFIG_OF
 static const struct of_device_id da7219_of_match[] = {
        { .compatible = "dlg,da7219", },
        { }
 };
 MODULE_DEVICE_TABLE(of, da7219_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id da7219_acpi_match[] = {
index b0d9ca6..aed92f6 100644 (file)
@@ -1519,11 +1519,13 @@ static const struct i2c_device_id da9055_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id da9055_of_match[] = {
        { .compatible = "dlg,da9055-codec", },
        { }
 };
 MODULE_DEVICE_TABLE(of, da9055_of_match);
+#endif
 
 /* I2C codec control layer */
 static struct i2c_driver da9055_i2c_driver = {
index 0051840..e2b7987 100644 (file)
@@ -183,7 +183,7 @@ static const struct snd_soc_dapm_route es7134_extra_routes[] = {
        { "Playback", NULL, "VDD", }
 };
 
-static const struct es7134_chip es7134_chip = {
+static const struct es7134_chip es7134_chip __maybe_unused = {
        .dai_drv = &es7134_dai,
        .modes = es7134_modes,
        .mode_num = ARRAY_SIZE(es7134_modes),
@@ -261,7 +261,7 @@ static const struct snd_soc_dapm_route es7154_extra_routes[] = {
        { "Playback", NULL, "PVDD", }
 };
 
-static const struct es7134_chip es7154_chip = {
+static const struct es7134_chip es7154_chip __maybe_unused = {
        .dai_drv = &es7154_dai,
        .modes = es7154_modes,
        .mode_num = ARRAY_SIZE(es7154_modes),
index 87991bd..2344a0b 100644 (file)
@@ -203,7 +203,7 @@ static const struct es7241_clock_mode es7241_modes[] = {
        },
 };
 
-static const struct es7241_chip es7241_chip = {
+static const struct es7241_chip es7241_chip __maybe_unused = {
        .modes = es7241_modes,
        .mode_num = ARRAY_SIZE(es7241_modes),
 };
index bd5d230..f9ec5cf 100644 (file)
@@ -834,11 +834,13 @@ static const struct i2c_device_id es8316_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id es8316_of_match[] = {
        { .compatible = "everest,es8316", },
        {},
 };
 MODULE_DEVICE_TABLE(of, es8316_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id es8316_acpi_match[] = {
index ae9e1c7..e1235e6 100644 (file)
@@ -87,7 +87,7 @@ static int gtm601_platform_probe(struct platform_device *pdev)
                        (struct snd_soc_dai_driver *)dai_driver, 1);
 }
 
-static const struct of_device_id gtm601_codec_of_match[] = {
+static const struct of_device_id gtm601_codec_of_match[] __maybe_unused = {
        { .compatible = "option,gtm601", .data = (void *)&gtm601_dai },
        { .compatible = "broadmobi,bm818", .data = (void *)&bm818_dai },
        {},
index 403d4c6..d5fcc4d 100644 (file)
@@ -282,6 +282,7 @@ struct hdmi_codec_priv {
 
 static const struct snd_soc_dapm_widget hdmi_widgets[] = {
        SND_SOC_DAPM_OUTPUT("TX"),
+       SND_SOC_DAPM_OUTPUT("RX"),
 };
 
 enum {
@@ -389,6 +390,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
        struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        int ret = 0;
 
        mutex_lock(&hcp->lock);
@@ -404,7 +406,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
                        goto err;
        }
 
-       if (hcp->hcd.ops->get_eld) {
+       if (tx && hcp->hcd.ops->get_eld) {
                ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
                                            hcp->eld, sizeof(hcp->eld));
                if (ret)
@@ -660,14 +662,20 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
 {
        struct snd_soc_dapm_context *dapm;
        struct hdmi_codec_daifmt *daifmt;
-       struct snd_soc_dapm_route route = {
-               .sink = "TX",
-               .source = dai->driver->playback.stream_name,
+       struct snd_soc_dapm_route route[] = {
+               {
+                       .sink = "TX",
+                       .source = dai->driver->playback.stream_name,
+               },
+               {
+                       .sink = dai->driver->capture.stream_name,
+                       .source = "RX",
+               },
        };
        int ret;
 
        dapm = snd_soc_component_get_dapm(dai->component);
-       ret = snd_soc_dapm_add_routes(dapm, &route, 1);
+       ret = snd_soc_dapm_add_routes(dapm, route, 2);
        if (ret)
                return ret;
 
@@ -692,10 +700,16 @@ static void plugged_cb(struct device *dev, bool plugged)
 {
        struct hdmi_codec_priv *hcp = dev_get_drvdata(dev);
 
-       if (plugged)
+       if (plugged) {
+               if (hcp->hcd.ops->get_eld) {
+                       hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data,
+                                           hcp->eld, sizeof(hcp->eld));
+               }
                hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT);
-       else
+       } else {
                hdmi_codec_jack_report(hcp, 0);
+               memset(hcp->eld, 0, sizeof(hcp->eld));
+       }
 }
 
 static int hdmi_codec_set_jack(struct snd_soc_component *component,
@@ -751,6 +765,14 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
                .formats = I2S_FORMATS,
                .sig_bits = 24,
        },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = HDMI_RATES,
+               .formats = I2S_FORMATS,
+               .sig_bits = 24,
+       },
        .ops = &hdmi_codec_i2s_dai_ops,
        .pcm_new = hdmi_codec_pcm_new,
 };
@@ -767,6 +789,13 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
                .rates = HDMI_RATES,
                .formats = SPDIF_FORMATS,
        },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = HDMI_RATES,
+               .formats = SPDIF_FORMATS,
+       },
        .ops = &hdmi_codec_spdif_dai_ops,
        .pcm_new = hdmi_codec_pcm_new,
 };
index d0e8f0d..4dbce24 100644 (file)
@@ -467,7 +467,7 @@ static int rk3036_codec_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id rk3036_codec_of_match[] = {
+static const struct of_device_id rk3036_codec_of_match[] __maybe_unused = {
        { .compatible = "rockchip,rk3036-codec", },
        {}
 };
index e49374c..5201a8f 100644 (file)
@@ -198,15 +198,15 @@ static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR,
-                                         BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0);
+               return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
+                                        BIT(REG_IFR_RAMP_UP_DONE_OFFSET));
        case SND_SOC_DAPM_POST_PMU:
                return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
                               val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET),
                               100000, 500000);
        case SND_SOC_DAPM_PRE_PMD:
-               return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR,
-                               BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0);
+               return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
+                               BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET));
        case SND_SOC_DAPM_POST_PMD:
                return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
                               val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET),
@@ -303,24 +303,22 @@ static int jz4725b_codec_set_bias_level(struct snd_soc_component *component,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-                                  BIT(REG_PMR2_SB_SLEEP_OFFSET), 0);
+               regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
+                                 BIT(REG_PMR2_SB_SLEEP_OFFSET));
                break;
        case SND_SOC_BIAS_PREPARE:
                /* Enable sound hardware */
-               regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-                                  BIT(REG_PMR2_SB_OFFSET), 0);
+               regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
+                                 BIT(REG_PMR2_SB_OFFSET));
                msleep(224);
                break;
        case SND_SOC_BIAS_STANDBY:
-               regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-                                  BIT(REG_PMR2_SB_SLEEP_OFFSET),
-                                  BIT(REG_PMR2_SB_SLEEP_OFFSET));
+               regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
+                               BIT(REG_PMR2_SB_SLEEP_OFFSET));
                break;
        case SND_SOC_BIAS_OFF:
-               regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-                                  BIT(REG_PMR2_SB_OFFSET),
-                                  BIT(REG_PMR2_SB_OFFSET));
+               regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
+                               BIT(REG_PMR2_SB_OFFSET));
                break;
        }
 
index c9900d1..5e58bfe 100644 (file)
@@ -219,12 +219,11 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {
 
 static void jz4740_codec_wakeup(struct regmap *regmap)
 {
-       regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
-               JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
+       regmap_set_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_RESET);
        udelay(2);
 
-       regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
-               JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
+       regmap_clear_bits(regmap, JZ4740_REG_CODEC_1,
+                         JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET);
 
        regcache_sync(regmap);
 }
@@ -235,7 +234,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
        struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
        struct regmap *regmap = jz4740_codec->regmap;
        unsigned int mask;
-       unsigned int value;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -244,9 +242,8 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
                mask = JZ4740_CODEC_1_VREF_DISABLE |
                                JZ4740_CODEC_1_VREF_AMP_DISABLE |
                                JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
-               value = 0;
 
-               regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+               regmap_clear_bits(regmap, JZ4740_REG_CODEC_1, mask);
                break;
        case SND_SOC_BIAS_STANDBY:
                /* The only way to clear the suspend flag is to reset the codec */
@@ -256,17 +253,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
                mask = JZ4740_CODEC_1_VREF_DISABLE |
                        JZ4740_CODEC_1_VREF_AMP_DISABLE |
                        JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
-               value = JZ4740_CODEC_1_VREF_DISABLE |
-                       JZ4740_CODEC_1_VREF_AMP_DISABLE |
-                       JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
 
-               regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+               regmap_set_bits(regmap, JZ4740_REG_CODEC_1, mask);
                break;
        case SND_SOC_BIAS_OFF:
                mask = JZ4740_CODEC_1_SUSPEND;
-               value = JZ4740_CODEC_1_SUSPEND;
-
-               regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+               regmap_set_bits(regmap, JZ4740_REG_CODEC_1, mask);
                regcache_mark_dirty(regmap);
                break;
        default:
index 298689a..c9fe7f7 100644 (file)
@@ -98,7 +98,7 @@ enum {
 #define REG_CR_HP_MUTE                 BIT(7)
 #define REG_CR_HP_LOAD                 BIT(6)
 #define REG_CR_HP_SB_OFFSET            4
-#define REG_CR_HP_SB_HPCM              BIT(3)
+#define REG_CR_HP_SB_HPCM_OFFSET       3
 #define REG_CR_HP_SEL_OFFSET           0
 #define REG_CR_HP_SEL_MASK             (0x3 << REG_CR_HP_SEL_OFFSET)
 
@@ -190,18 +190,21 @@ static int jz4770_codec_set_bias_level(struct snd_soc_component *codec,
 
        switch (level) {
        case SND_SOC_BIAS_PREPARE:
-               regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-                                  REG_CR_VIC_SB, 0);
+               /* Reset all interrupt flags. */
+               regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK);
+
+               regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+                                 REG_CR_VIC_SB);
                msleep(250);
-               regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-                                  REG_CR_VIC_SB_SLEEP, 0);
+               regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+                                 REG_CR_VIC_SB_SLEEP);
                msleep(400);
                break;
        case SND_SOC_BIAS_STANDBY:
-               regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-                                  REG_CR_VIC_SB_SLEEP, REG_CR_VIC_SB_SLEEP);
-               regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-                                  REG_CR_VIC_SB, REG_CR_VIC_SB);
+               regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+                               REG_CR_VIC_SB_SLEEP);
+               regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+                               REG_CR_VIC_SB);
                fallthrough;
        default:
                break;
@@ -284,7 +287,7 @@ static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direc
                err = regmap_read_poll_timeout(jz_codec->regmap,
                                               JZ4770_CODEC_REG_IFR,
                                               val, val & gain_bit,
-                                              1000, 100 * USEC_PER_MSEC);
+                                              1000, 1 * USEC_PER_SEC);
                if (err) {
                        dev_err(jz_codec->dev,
                                "Timeout while setting digital mute: %d", err);
@@ -292,8 +295,8 @@ static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direc
                }
 
                /* clear GUP/GDO flag */
-               regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
-                                  gain_bit, gain_bit);
+               regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
+                               gain_bit);
        }
 
        return 0;
@@ -368,9 +371,9 @@ static int hpout_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               /* set cap-less, unmute HP */
-               regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
-                                  REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE, 0);
+               /* unmute HP */
+               regmap_clear_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
+                                 REG_CR_HP_MUTE);
                break;
 
        case SND_SOC_DAPM_POST_PMU:
@@ -378,36 +381,35 @@ static int hpout_event(struct snd_soc_dapm_widget *w,
                err = regmap_read_poll_timeout(jz_codec->regmap,
                                               JZ4770_CODEC_REG_IFR,
                                               val, val & REG_IFR_RUP,
-                                              1000, 100 * USEC_PER_MSEC);
+                                              1000, 1 * USEC_PER_SEC);
                if (err) {
                        dev_err(jz_codec->dev, "RUP timeout: %d", err);
                        return err;
                }
 
                /* clear RUP flag */
-               regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
-                                  REG_IFR_RUP, REG_IFR_RUP);
+               regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
+                               REG_IFR_RUP);
 
                break;
 
        case SND_SOC_DAPM_POST_PMD:
-               /* set cap-couple, mute HP */
-               regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
-                                  REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE,
-                                  REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE);
+               /* mute HP */
+               regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
+                               REG_CR_HP_MUTE);
 
                err = regmap_read_poll_timeout(jz_codec->regmap,
                                               JZ4770_CODEC_REG_IFR,
                                               val, val & REG_IFR_RDO,
-                                              1000, 100 * USEC_PER_MSEC);
+                                              1000, 1 * USEC_PER_SEC);
                if (err) {
                        dev_err(jz_codec->dev, "RDO timeout: %d", err);
                        return err;
                }
 
                /* clear RDO flag */
-               regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
-                                  REG_IFR_RDO, REG_IFR_RDO);
+               regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
+                               REG_IFR_RDO);
 
                break;
        }
@@ -517,6 +519,9 @@ static const struct snd_soc_dapm_widget jz4770_codec_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("MICBIAS", JZ4770_CODEC_REG_CR_MIC,
                            REG_CR_MIC_BIAS_SB_OFFSET, 1, NULL, 0),
 
+       SND_SOC_DAPM_SUPPLY("Cap-less", JZ4770_CODEC_REG_CR_HP,
+                           REG_CR_HP_SB_HPCM_OFFSET, 1, NULL, 0),
+
        SND_SOC_DAPM_INPUT("MIC1P"),
        SND_SOC_DAPM_INPUT("MIC1N"),
        SND_SOC_DAPM_INPUT("MIC2P"),
@@ -592,70 +597,58 @@ static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec)
        regcache_cache_only(regmap, true);
 
        /* default HP output to PCM */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
-                          REG_CR_HP_SEL_MASK, REG_CR_HP_SEL_MASK);
+       regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_SEL_MASK);
 
        /* default line output to PCM */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_LO,
-                          REG_CR_LO_SEL_MASK, REG_CR_LO_SEL_MASK);
+       regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_LO, REG_CR_LO_SEL_MASK);
 
        /* Disable stereo mic */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_MIC,
-                          BIT(REG_CR_MIC_STEREO_OFFSET), 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_MIC,
+                         BIT(REG_CR_MIC_STEREO_OFFSET));
 
        /* Set mic 1 as default source for ADC */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
-                          REG_CR_ADC_IN_SEL_MASK, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
+                         REG_CR_ADC_IN_SEL_MASK);
 
        /* ADC/DAC: serial + i2s */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_ADC,
-                          REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S,
-                          REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S);
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_DAC,
-                          REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S,
-                          REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
+       regmap_set_bits(regmap, JZ4770_CODEC_REG_AICR_ADC,
+                       REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S);
+       regmap_set_bits(regmap, JZ4770_CODEC_REG_AICR_DAC,
+                       REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
 
        /* The generated IRQ is a high level */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_ICR,
-                          REG_ICR_INT_FORM_MASK, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_ICR, REG_ICR_INT_FORM_MASK);
        regmap_update_bits(regmap, JZ4770_CODEC_REG_IMR, REG_IMR_ALL_MASK,
                           REG_IMR_JACK_MASK | REG_IMR_RUP_MASK |
                           REG_IMR_RDO_MASK | REG_IMR_GUP_MASK |
                           REG_IMR_GDO_MASK);
 
        /* 12M oscillator */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CCR,
-                          REG_CCR_CRYSTAL_MASK, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_CCR, REG_CCR_CRYSTAL_MASK);
 
        /* 0: 16ohm/220uF, 1: 10kohm/1uF */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
-                          REG_CR_HP_LOAD, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_LOAD);
 
        /* disable automatic gain */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN);
 
        /* Disable DAC lrswap */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_DAC,
-                          REG_CR_DAC_LRSWAP, REG_CR_DAC_LRSWAP);
+       regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_DAC, REG_CR_DAC_LRSWAP);
 
        /* Independent L/R DAC gain control */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_GCR_DACL,
-                          REG_GCR_DACL_RLGOD, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_GCR_DACL,
+                         REG_GCR_DACL_RLGOD);
 
        /* Disable ADC lrswap */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
-                          REG_CR_ADC_LRSWAP, REG_CR_ADC_LRSWAP);
+       regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_ADC, REG_CR_ADC_LRSWAP);
 
        /* default to cap-less mode(0) */
-       regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
-                          REG_CR_HP_SB_HPCM, 0);
+       regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP,
+                         BIT(REG_CR_HP_SB_HPCM_OFFSET));
 
        /* Send collected updates. */
        regcache_cache_only(regmap, false);
        regcache_sync(regmap);
-
-       /* Reset all interrupt flags. */
-       regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK);
 }
 
 static int jz4770_codec_codec_probe(struct snd_soc_component *codec)
@@ -814,7 +807,7 @@ static int jz4770_codec_io_wait(struct jz_codec *codec)
 
        return readl_poll_timeout(codec->base + ICDC_RGADW_OFFSET, reg,
                                  !(reg & ICDC_RGADW_RGWR),
-                                 1000, 10 * USEC_PER_MSEC);
+                                 1000, 1 * USEC_PER_SEC);
 }
 
 static int jz4770_codec_reg_read(void *context, unsigned int reg,
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
new file mode 100644 (file)
index 0000000..91e6890
--- /dev/null
@@ -0,0 +1,1497 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_clk.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+/* VA macro registers */
+#define CDC_VA_CLK_RST_CTRL_MCLK_CONTROL       (0x0000)
+#define CDC_VA_MCLK_CONTROL_EN                 BIT(0)
+#define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL     (0x0004)
+#define CDC_VA_FS_CONTROL_EN                   BIT(0)
+#define CDC_VA_CLK_RST_CTRL_SWR_CONTROL                (0x0008)
+#define CDC_VA_TOP_CSR_TOP_CFG0                        (0x0080)
+#define CDC_VA_FS_BROADCAST_EN                 BIT(1)
+#define CDC_VA_TOP_CSR_DMIC0_CTL               (0x0084)
+#define CDC_VA_TOP_CSR_DMIC1_CTL               (0x0088)
+#define CDC_VA_TOP_CSR_DMIC2_CTL               (0x008C)
+#define CDC_VA_TOP_CSR_DMIC3_CTL               (0x0090)
+#define CDC_VA_DMIC_EN_MASK                    BIT(0)
+#define CDC_VA_DMIC_ENABLE                     BIT(0)
+#define CDC_VA_DMIC_CLK_SEL_MASK               GENMASK(3, 1)
+#define CDC_VA_DMIC_CLK_SEL_SHFT               1
+#define CDC_VA_DMIC_CLK_SEL_DIV0               0x0
+#define CDC_VA_DMIC_CLK_SEL_DIV1               0x2
+#define CDC_VA_DMIC_CLK_SEL_DIV2               0x4
+#define CDC_VA_DMIC_CLK_SEL_DIV3               0x6
+#define CDC_VA_DMIC_CLK_SEL_DIV4               0x8
+#define CDC_VA_DMIC_CLK_SEL_DIV5               0xa
+#define CDC_VA_TOP_CSR_DMIC_CFG                        (0x0094)
+#define CDC_VA_RESET_ALL_DMICS_MASK            BIT(7)
+#define CDC_VA_RESET_ALL_DMICS_RESET           BIT(7)
+#define CDC_VA_RESET_ALL_DMICS_DISABLE         0
+#define CDC_VA_DMIC3_FREQ_CHANGE_MASK          BIT(3)
+#define CDC_VA_DMIC3_FREQ_CHANGE_EN            BIT(3)
+#define CDC_VA_DMIC2_FREQ_CHANGE_MASK          BIT(2)
+#define CDC_VA_DMIC2_FREQ_CHANGE_EN            BIT(2)
+#define CDC_VA_DMIC1_FREQ_CHANGE_MASK          BIT(1)
+#define CDC_VA_DMIC1_FREQ_CHANGE_EN            BIT(1)
+#define CDC_VA_DMIC0_FREQ_CHANGE_MASK          BIT(0)
+#define CDC_VA_DMIC0_FREQ_CHANGE_EN            BIT(0)
+#define CDC_VA_DMIC_FREQ_CHANGE_DISABLE                0
+#define CDC_VA_TOP_CSR_DEBUG_BUS               (0x009C)
+#define CDC_VA_TOP_CSR_DEBUG_EN                        (0x00A0)
+#define CDC_VA_TOP_CSR_TX_I2S_CTL              (0x00A4)
+#define CDC_VA_TOP_CSR_I2S_CLK                 (0x00A8)
+#define CDC_VA_TOP_CSR_I2S_RESET               (0x00AC)
+#define CDC_VA_TOP_CSR_CORE_ID_0               (0x00C0)
+#define CDC_VA_TOP_CSR_CORE_ID_1               (0x00C4)
+#define CDC_VA_TOP_CSR_CORE_ID_2               (0x00C8)
+#define CDC_VA_TOP_CSR_CORE_ID_3               (0x00CC)
+#define CDC_VA_TOP_CSR_SWR_MIC_CTL0            (0x00D0)
+#define CDC_VA_TOP_CSR_SWR_MIC_CTL1            (0x00D4)
+#define CDC_VA_TOP_CSR_SWR_MIC_CTL2            (0x00D8)
+#define CDC_VA_TOP_CSR_SWR_CTRL                        (0x00DC)
+#define CDC_VA_INP_MUX_ADC_MUX0_CFG0           (0x0100)
+#define CDC_VA_INP_MUX_ADC_MUX0_CFG1           (0x0104)
+#define CDC_VA_INP_MUX_ADC_MUX1_CFG0           (0x0108)
+#define CDC_VA_INP_MUX_ADC_MUX1_CFG1           (0x010C)
+#define CDC_VA_INP_MUX_ADC_MUX2_CFG0           (0x0110)
+#define CDC_VA_INP_MUX_ADC_MUX2_CFG1           (0x0114)
+#define CDC_VA_INP_MUX_ADC_MUX3_CFG0           (0x0118)
+#define CDC_VA_INP_MUX_ADC_MUX3_CFG1           (0x011C)
+#define CDC_VA_TX0_TX_PATH_CTL                 (0x0400)
+#define CDC_VA_TX_PATH_CLK_EN_MASK             BIT(5)
+#define CDC_VA_TX_PATH_CLK_EN                  BIT(5)
+#define CDC_VA_TX_PATH_CLK_DISABLE             0
+#define CDC_VA_TX_PATH_PGA_MUTE_EN_MASK                BIT(4)
+#define CDC_VA_TX_PATH_PGA_MUTE_EN             BIT(4)
+#define CDC_VA_TX_PATH_PGA_MUTE_DISABLE                0
+#define CDC_VA_TX0_TX_PATH_CFG0                        (0x0404)
+#define CDC_VA_ADC_MODE_MASK                   GENMASK(2, 1)
+#define CDC_VA_ADC_MODE_SHIFT                  1
+#define  TX_HPF_CUT_OFF_FREQ_MASK              GENMASK(6, 5)
+#define  CF_MIN_3DB_4HZ                        0x0
+#define  CF_MIN_3DB_75HZ               0x1
+#define  CF_MIN_3DB_150HZ              0x2
+#define CDC_VA_TX0_TX_PATH_CFG1                        (0x0408)
+#define CDC_VA_TX0_TX_VOL_CTL                  (0x040C)
+#define CDC_VA_TX0_TX_PATH_SEC0                        (0x0410)
+#define CDC_VA_TX0_TX_PATH_SEC1                        (0x0414)
+#define CDC_VA_TX0_TX_PATH_SEC2                        (0x0418)
+#define CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK  BIT(1)
+#define CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ   BIT(1)
+#define CDC_VA_TX_HPF_ZERO_GATE_MASK           BIT(0)
+#define CDC_VA_TX_HPF_ZERO_NO_GATE             BIT(0)
+#define CDC_VA_TX_HPF_ZERO_GATE                        0
+#define CDC_VA_TX0_TX_PATH_SEC3                        (0x041C)
+#define CDC_VA_TX0_TX_PATH_SEC4                        (0x0420)
+#define CDC_VA_TX0_TX_PATH_SEC5                        (0x0424)
+#define CDC_VA_TX0_TX_PATH_SEC6                        (0x0428)
+#define CDC_VA_TX0_TX_PATH_SEC7                        (0x042C)
+#define CDC_VA_TX1_TX_PATH_CTL                 (0x0480)
+#define CDC_VA_TX1_TX_PATH_CFG0                        (0x0484)
+#define CDC_VA_TX1_TX_PATH_CFG1                        (0x0488)
+#define CDC_VA_TX1_TX_VOL_CTL                  (0x048C)
+#define CDC_VA_TX1_TX_PATH_SEC0                        (0x0490)
+#define CDC_VA_TX1_TX_PATH_SEC1                        (0x0494)
+#define CDC_VA_TX1_TX_PATH_SEC2                        (0x0498)
+#define CDC_VA_TX1_TX_PATH_SEC3                        (0x049C)
+#define CDC_VA_TX1_TX_PATH_SEC4                        (0x04A0)
+#define CDC_VA_TX1_TX_PATH_SEC5                        (0x04A4)
+#define CDC_VA_TX1_TX_PATH_SEC6                        (0x04A8)
+#define CDC_VA_TX2_TX_PATH_CTL                 (0x0500)
+#define CDC_VA_TX2_TX_PATH_CFG0                        (0x0504)
+#define CDC_VA_TX2_TX_PATH_CFG1                        (0x0508)
+#define CDC_VA_TX2_TX_VOL_CTL                  (0x050C)
+#define CDC_VA_TX2_TX_PATH_SEC0                        (0x0510)
+#define CDC_VA_TX2_TX_PATH_SEC1                        (0x0514)
+#define CDC_VA_TX2_TX_PATH_SEC2                        (0x0518)
+#define CDC_VA_TX2_TX_PATH_SEC3                        (0x051C)
+#define CDC_VA_TX2_TX_PATH_SEC4                        (0x0520)
+#define CDC_VA_TX2_TX_PATH_SEC5                        (0x0524)
+#define CDC_VA_TX2_TX_PATH_SEC6                        (0x0528)
+#define CDC_VA_TX3_TX_PATH_CTL                 (0x0580)
+#define CDC_VA_TX3_TX_PATH_CFG0                        (0x0584)
+#define CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK       BIT(7)
+#define CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC       BIT(7)
+#define CDC_VA_TX_PATH_ADC_DMIC_SEL_ADC                0
+#define CDC_VA_TX3_TX_PATH_CFG1                        (0x0588)
+#define CDC_VA_TX3_TX_VOL_CTL                  (0x058C)
+#define CDC_VA_TX3_TX_PATH_SEC0                        (0x0590)
+#define CDC_VA_TX3_TX_PATH_SEC1                        (0x0594)
+#define CDC_VA_TX3_TX_PATH_SEC2                        (0x0598)
+#define CDC_VA_TX3_TX_PATH_SEC3                        (0x059C)
+#define CDC_VA_TX3_TX_PATH_SEC4                        (0x05A0)
+#define CDC_VA_TX3_TX_PATH_SEC5                        (0x05A4)
+#define CDC_VA_TX3_TX_PATH_SEC6                        (0x05A8)
+
+#define VA_MAX_OFFSET                          (0x07A8)
+
+#define VA_MACRO_NUM_DECIMATORS 4
+#define VA_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define VA_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE |\
+               SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define VA_MACRO_MCLK_FREQ 9600000
+#define VA_MACRO_TX_PATH_OFFSET 0x80
+#define VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
+#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x8
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+enum {
+       VA_MACRO_AIF_INVALID = 0,
+       VA_MACRO_AIF1_CAP,
+       VA_MACRO_AIF2_CAP,
+       VA_MACRO_AIF3_CAP,
+       VA_MACRO_MAX_DAIS,
+};
+
+enum {
+       VA_MACRO_DEC0,
+       VA_MACRO_DEC1,
+       VA_MACRO_DEC2,
+       VA_MACRO_DEC3,
+       VA_MACRO_DEC4,
+       VA_MACRO_DEC5,
+       VA_MACRO_DEC6,
+       VA_MACRO_DEC7,
+       VA_MACRO_DEC_MAX,
+};
+
+enum {
+       VA_MACRO_CLK_DIV_2,
+       VA_MACRO_CLK_DIV_3,
+       VA_MACRO_CLK_DIV_4,
+       VA_MACRO_CLK_DIV_6,
+       VA_MACRO_CLK_DIV_8,
+       VA_MACRO_CLK_DIV_16,
+};
+
+#define VA_NUM_CLKS_MAX                3
+
+struct va_macro {
+       struct device *dev;
+       unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
+       unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
+       unsigned long active_decimator[VA_MACRO_MAX_DAIS];
+       u16 dmic_clk_div;
+
+       int dec_mode[VA_MACRO_NUM_DECIMATORS];
+       struct regmap *regmap;
+       struct clk_bulk_data clks[VA_NUM_CLKS_MAX];
+       struct clk_hw hw;
+
+       s32 dmic_0_1_clk_cnt;
+       s32 dmic_2_3_clk_cnt;
+       s32 dmic_4_5_clk_cnt;
+       s32 dmic_6_7_clk_cnt;
+       u8 dmic_0_1_clk_div;
+       u8 dmic_2_3_clk_div;
+       u8 dmic_4_5_clk_div;
+       u8 dmic_6_7_clk_div;
+};
+
+#define to_va_macro(_hw) container_of(_hw, struct va_macro, hw)
+
+static bool va_is_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_VA_TOP_CSR_CORE_ID_0:
+       case CDC_VA_TOP_CSR_CORE_ID_1:
+       case CDC_VA_TOP_CSR_CORE_ID_2:
+       case CDC_VA_TOP_CSR_CORE_ID_3:
+       case CDC_VA_TOP_CSR_DMIC0_CTL:
+       case CDC_VA_TOP_CSR_DMIC1_CTL:
+       case CDC_VA_TOP_CSR_DMIC2_CTL:
+       case CDC_VA_TOP_CSR_DMIC3_CTL:
+               return true;
+       }
+       return false;
+}
+
+static const struct reg_default va_defaults[] = {
+       /* VA macro */
+       { CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00},
+       { CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00},
+       { CDC_VA_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+       { CDC_VA_TOP_CSR_TOP_CFG0, 0x00},
+       { CDC_VA_TOP_CSR_DMIC0_CTL, 0x00},
+       { CDC_VA_TOP_CSR_DMIC1_CTL, 0x00},
+       { CDC_VA_TOP_CSR_DMIC2_CTL, 0x00},
+       { CDC_VA_TOP_CSR_DMIC3_CTL, 0x00},
+       { CDC_VA_TOP_CSR_DMIC_CFG, 0x80},
+       { CDC_VA_TOP_CSR_DEBUG_BUS, 0x00},
+       { CDC_VA_TOP_CSR_DEBUG_EN, 0x00},
+       { CDC_VA_TOP_CSR_TX_I2S_CTL, 0x0C},
+       { CDC_VA_TOP_CSR_I2S_CLK, 0x00},
+       { CDC_VA_TOP_CSR_I2S_RESET, 0x00},
+       { CDC_VA_TOP_CSR_CORE_ID_0, 0x00},
+       { CDC_VA_TOP_CSR_CORE_ID_1, 0x00},
+       { CDC_VA_TOP_CSR_CORE_ID_2, 0x00},
+       { CDC_VA_TOP_CSR_CORE_ID_3, 0x00},
+       { CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE},
+       { CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE},
+       { CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE},
+       { CDC_VA_TOP_CSR_SWR_CTRL, 0x06},
+
+       /* VA core */
+       { CDC_VA_INP_MUX_ADC_MUX0_CFG0, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX0_CFG1, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX1_CFG0, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX1_CFG1, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX2_CFG0, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX2_CFG1, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX3_CFG0, 0x00},
+       { CDC_VA_INP_MUX_ADC_MUX3_CFG1, 0x00},
+       { CDC_VA_TX0_TX_PATH_CTL, 0x04},
+       { CDC_VA_TX0_TX_PATH_CFG0, 0x10},
+       { CDC_VA_TX0_TX_PATH_CFG1, 0x0B},
+       { CDC_VA_TX0_TX_VOL_CTL, 0x00},
+       { CDC_VA_TX0_TX_PATH_SEC0, 0x00},
+       { CDC_VA_TX0_TX_PATH_SEC1, 0x00},
+       { CDC_VA_TX0_TX_PATH_SEC2, 0x01},
+       { CDC_VA_TX0_TX_PATH_SEC3, 0x3C},
+       { CDC_VA_TX0_TX_PATH_SEC4, 0x20},
+       { CDC_VA_TX0_TX_PATH_SEC5, 0x00},
+       { CDC_VA_TX0_TX_PATH_SEC6, 0x00},
+       { CDC_VA_TX0_TX_PATH_SEC7, 0x25},
+       { CDC_VA_TX1_TX_PATH_CTL, 0x04},
+       { CDC_VA_TX1_TX_PATH_CFG0, 0x10},
+       { CDC_VA_TX1_TX_PATH_CFG1, 0x0B},
+       { CDC_VA_TX1_TX_VOL_CTL, 0x00},
+       { CDC_VA_TX1_TX_PATH_SEC0, 0x00},
+       { CDC_VA_TX1_TX_PATH_SEC1, 0x00},
+       { CDC_VA_TX1_TX_PATH_SEC2, 0x01},
+       { CDC_VA_TX1_TX_PATH_SEC3, 0x3C},
+       { CDC_VA_TX1_TX_PATH_SEC4, 0x20},
+       { CDC_VA_TX1_TX_PATH_SEC5, 0x00},
+       { CDC_VA_TX1_TX_PATH_SEC6, 0x00},
+       { CDC_VA_TX2_TX_PATH_CTL, 0x04},
+       { CDC_VA_TX2_TX_PATH_CFG0, 0x10},
+       { CDC_VA_TX2_TX_PATH_CFG1, 0x0B},
+       { CDC_VA_TX2_TX_VOL_CTL, 0x00},
+       { CDC_VA_TX2_TX_PATH_SEC0, 0x00},
+       { CDC_VA_TX2_TX_PATH_SEC1, 0x00},
+       { CDC_VA_TX2_TX_PATH_SEC2, 0x01},
+       { CDC_VA_TX2_TX_PATH_SEC3, 0x3C},
+       { CDC_VA_TX2_TX_PATH_SEC4, 0x20},
+       { CDC_VA_TX2_TX_PATH_SEC5, 0x00},
+       { CDC_VA_TX2_TX_PATH_SEC6, 0x00},
+       { CDC_VA_TX3_TX_PATH_CTL, 0x04},
+       { CDC_VA_TX3_TX_PATH_CFG0, 0x10},
+       { CDC_VA_TX3_TX_PATH_CFG1, 0x0B},
+       { CDC_VA_TX3_TX_VOL_CTL, 0x00},
+       { CDC_VA_TX3_TX_PATH_SEC0, 0x00},
+       { CDC_VA_TX3_TX_PATH_SEC1, 0x00},
+       { CDC_VA_TX3_TX_PATH_SEC2, 0x01},
+       { CDC_VA_TX3_TX_PATH_SEC3, 0x3C},
+       { CDC_VA_TX3_TX_PATH_SEC4, 0x20},
+       { CDC_VA_TX3_TX_PATH_SEC5, 0x00},
+       { CDC_VA_TX3_TX_PATH_SEC6, 0x00},
+};
+
+static bool va_is_rw_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_VA_CLK_RST_CTRL_MCLK_CONTROL:
+       case CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL:
+       case CDC_VA_CLK_RST_CTRL_SWR_CONTROL:
+       case CDC_VA_TOP_CSR_TOP_CFG0:
+       case CDC_VA_TOP_CSR_DMIC0_CTL:
+       case CDC_VA_TOP_CSR_DMIC1_CTL:
+       case CDC_VA_TOP_CSR_DMIC2_CTL:
+       case CDC_VA_TOP_CSR_DMIC3_CTL:
+       case CDC_VA_TOP_CSR_DMIC_CFG:
+       case CDC_VA_TOP_CSR_DEBUG_BUS:
+       case CDC_VA_TOP_CSR_DEBUG_EN:
+       case CDC_VA_TOP_CSR_TX_I2S_CTL:
+       case CDC_VA_TOP_CSR_I2S_CLK:
+       case CDC_VA_TOP_CSR_I2S_RESET:
+       case CDC_VA_INP_MUX_ADC_MUX0_CFG0:
+       case CDC_VA_INP_MUX_ADC_MUX0_CFG1:
+       case CDC_VA_INP_MUX_ADC_MUX1_CFG0:
+       case CDC_VA_INP_MUX_ADC_MUX1_CFG1:
+       case CDC_VA_INP_MUX_ADC_MUX2_CFG0:
+       case CDC_VA_INP_MUX_ADC_MUX2_CFG1:
+       case CDC_VA_INP_MUX_ADC_MUX3_CFG0:
+       case CDC_VA_INP_MUX_ADC_MUX3_CFG1:
+       case CDC_VA_TX0_TX_PATH_CTL:
+       case CDC_VA_TX0_TX_PATH_CFG0:
+       case CDC_VA_TX0_TX_PATH_CFG1:
+       case CDC_VA_TX0_TX_VOL_CTL:
+       case CDC_VA_TX0_TX_PATH_SEC0:
+       case CDC_VA_TX0_TX_PATH_SEC1:
+       case CDC_VA_TX0_TX_PATH_SEC2:
+       case CDC_VA_TX0_TX_PATH_SEC3:
+       case CDC_VA_TX0_TX_PATH_SEC4:
+       case CDC_VA_TX0_TX_PATH_SEC5:
+       case CDC_VA_TX0_TX_PATH_SEC6:
+       case CDC_VA_TX0_TX_PATH_SEC7:
+       case CDC_VA_TX1_TX_PATH_CTL:
+       case CDC_VA_TX1_TX_PATH_CFG0:
+       case CDC_VA_TX1_TX_PATH_CFG1:
+       case CDC_VA_TX1_TX_VOL_CTL:
+       case CDC_VA_TX1_TX_PATH_SEC0:
+       case CDC_VA_TX1_TX_PATH_SEC1:
+       case CDC_VA_TX1_TX_PATH_SEC2:
+       case CDC_VA_TX1_TX_PATH_SEC3:
+       case CDC_VA_TX1_TX_PATH_SEC4:
+       case CDC_VA_TX1_TX_PATH_SEC5:
+       case CDC_VA_TX1_TX_PATH_SEC6:
+       case CDC_VA_TX2_TX_PATH_CTL:
+       case CDC_VA_TX2_TX_PATH_CFG0:
+       case CDC_VA_TX2_TX_PATH_CFG1:
+       case CDC_VA_TX2_TX_VOL_CTL:
+       case CDC_VA_TX2_TX_PATH_SEC0:
+       case CDC_VA_TX2_TX_PATH_SEC1:
+       case CDC_VA_TX2_TX_PATH_SEC2:
+       case CDC_VA_TX2_TX_PATH_SEC3:
+       case CDC_VA_TX2_TX_PATH_SEC4:
+       case CDC_VA_TX2_TX_PATH_SEC5:
+       case CDC_VA_TX2_TX_PATH_SEC6:
+       case CDC_VA_TX3_TX_PATH_CTL:
+       case CDC_VA_TX3_TX_PATH_CFG0:
+       case CDC_VA_TX3_TX_PATH_CFG1:
+       case CDC_VA_TX3_TX_VOL_CTL:
+       case CDC_VA_TX3_TX_PATH_SEC0:
+       case CDC_VA_TX3_TX_PATH_SEC1:
+       case CDC_VA_TX3_TX_PATH_SEC2:
+       case CDC_VA_TX3_TX_PATH_SEC3:
+       case CDC_VA_TX3_TX_PATH_SEC4:
+       case CDC_VA_TX3_TX_PATH_SEC5:
+       case CDC_VA_TX3_TX_PATH_SEC6:
+               return true;
+       }
+
+       return false;
+}
+
+static bool va_is_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_VA_TOP_CSR_CORE_ID_0:
+       case CDC_VA_TOP_CSR_CORE_ID_1:
+       case CDC_VA_TOP_CSR_CORE_ID_2:
+       case CDC_VA_TOP_CSR_CORE_ID_3:
+               return true;
+       }
+
+       return va_is_rw_register(dev, reg);
+}
+
+static const struct regmap_config va_regmap_config = {
+       .name = "va_macro",
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .cache_type = REGCACHE_FLAT,
+       .reg_defaults = va_defaults,
+       .num_reg_defaults = ARRAY_SIZE(va_defaults),
+       .max_register = VA_MAX_OFFSET,
+       .volatile_reg = va_is_volatile_register,
+       .readable_reg = va_is_readable_register,
+       .writeable_reg = va_is_rw_register,
+};
+
+static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable)
+{
+       struct regmap *regmap = va->regmap;
+
+       if (enable) {
+               regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
+                                  CDC_VA_MCLK_CONTROL_EN,
+                                  CDC_VA_MCLK_CONTROL_EN);
+
+               regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                  CDC_VA_FS_CONTROL_EN,
+                                  CDC_VA_FS_CONTROL_EN);
+
+               regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0,
+                                  CDC_VA_FS_BROADCAST_EN,
+                                  CDC_VA_FS_BROADCAST_EN);
+       } else {
+               regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
+                                  CDC_VA_MCLK_CONTROL_EN, 0x0);
+
+               regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                  CDC_VA_FS_CONTROL_EN, 0x0);
+
+               regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0,
+                                  CDC_VA_FS_BROADCAST_EN, 0x0);
+       }
+
+       return 0;
+}
+
+static int va_macro_mclk_enable(struct va_macro *va, bool mclk_enable)
+{
+       struct regmap *regmap = va->regmap;
+
+       if (mclk_enable) {
+               va_clk_rsc_fs_gen_request(va, true);
+               regcache_mark_dirty(regmap);
+               regcache_sync_region(regmap, 0x0, VA_MAX_OFFSET);
+       } else {
+               va_clk_rsc_fs_gen_request(va, false);
+       }
+
+       return 0;
+}
+
+static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+       struct va_macro *va = snd_soc_component_get_drvdata(comp);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return va_macro_mclk_enable(va, true);
+       case SND_SOC_DAPM_POST_PMD:
+               return va_macro_mclk_enable(va, false);
+       }
+
+       return 0;
+}
+
+static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget =
+               snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(widget->dapm);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int val;
+       u16 mic_sel_reg;
+
+       val = ucontrol->value.enumerated.item[0];
+
+       switch (e->reg) {
+       case CDC_VA_INP_MUX_ADC_MUX0_CFG0:
+               mic_sel_reg = CDC_VA_TX0_TX_PATH_CFG0;
+               break;
+       case CDC_VA_INP_MUX_ADC_MUX1_CFG0:
+               mic_sel_reg = CDC_VA_TX1_TX_PATH_CFG0;
+               break;
+       case CDC_VA_INP_MUX_ADC_MUX2_CFG0:
+               mic_sel_reg = CDC_VA_TX2_TX_PATH_CFG0;
+               break;
+       case CDC_VA_INP_MUX_ADC_MUX3_CFG0:
+               mic_sel_reg = CDC_VA_TX3_TX_PATH_CFG0;
+               break;
+       default:
+               dev_err(component->dev, "%s: e->reg: 0x%x not expected\n",
+                       __func__, e->reg);
+               return -EINVAL;
+       }
+
+       if (val != 0)
+               snd_soc_component_update_bits(component, mic_sel_reg,
+                                             CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK,
+                                             CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC);
+
+       return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget =
+               snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component =
+                               snd_soc_dapm_to_component(widget->dapm);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       u32 dai_id = widget->shift;
+       u32 dec_id = mc->shift;
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+       if (test_bit(dec_id, &va->active_ch_mask[dai_id]))
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget =
+                                       snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component =
+                               snd_soc_dapm_to_component(widget->dapm);
+       struct snd_soc_dapm_update *update = NULL;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       u32 dai_id = widget->shift;
+       u32 dec_id = mc->shift;
+       u32 enable = ucontrol->value.integer.value[0];
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+       if (enable) {
+               set_bit(dec_id, &va->active_ch_mask[dai_id]);
+               va->active_ch_cnt[dai_id]++;
+               va->active_decimator[dai_id] = dec_id;
+       } else {
+               clear_bit(dec_id, &va->active_ch_mask[dai_id]);
+               va->active_ch_cnt[dai_id]--;
+               va->active_decimator[dai_id] = -1;
+       }
+
+       snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
+
+       return 0;
+}
+
+static int va_dmic_clk_enable(struct snd_soc_component *component,
+                             u32 dmic, bool enable)
+{
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+       u16 dmic_clk_reg;
+       s32 *dmic_clk_cnt;
+       u8 *dmic_clk_div;
+       u8 freq_change_mask;
+       u8 clk_div;
+
+       switch (dmic) {
+       case 0:
+       case 1:
+               dmic_clk_cnt = &(va->dmic_0_1_clk_cnt);
+               dmic_clk_div = &(va->dmic_0_1_clk_div);
+               dmic_clk_reg = CDC_VA_TOP_CSR_DMIC0_CTL;
+               freq_change_mask = CDC_VA_DMIC0_FREQ_CHANGE_MASK;
+               break;
+       case 2:
+       case 3:
+               dmic_clk_cnt = &(va->dmic_2_3_clk_cnt);
+               dmic_clk_div = &(va->dmic_2_3_clk_div);
+               dmic_clk_reg = CDC_VA_TOP_CSR_DMIC1_CTL;
+               freq_change_mask = CDC_VA_DMIC1_FREQ_CHANGE_MASK;
+               break;
+       case 4:
+       case 5:
+               dmic_clk_cnt = &(va->dmic_4_5_clk_cnt);
+               dmic_clk_div = &(va->dmic_4_5_clk_div);
+               dmic_clk_reg = CDC_VA_TOP_CSR_DMIC2_CTL;
+               freq_change_mask = CDC_VA_DMIC2_FREQ_CHANGE_MASK;
+               break;
+       case 6:
+       case 7:
+               dmic_clk_cnt = &(va->dmic_6_7_clk_cnt);
+               dmic_clk_div = &(va->dmic_6_7_clk_div);
+               dmic_clk_reg = CDC_VA_TOP_CSR_DMIC3_CTL;
+               freq_change_mask = CDC_VA_DMIC3_FREQ_CHANGE_MASK;
+               break;
+       default:
+               dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       if (enable) {
+               clk_div = va->dmic_clk_div;
+               (*dmic_clk_cnt)++;
+               if (*dmic_clk_cnt == 1) {
+                       snd_soc_component_update_bits(component,
+                                             CDC_VA_TOP_CSR_DMIC_CFG,
+                                             CDC_VA_RESET_ALL_DMICS_MASK,
+                                             CDC_VA_RESET_ALL_DMICS_DISABLE);
+                       snd_soc_component_update_bits(component, dmic_clk_reg,
+                                       CDC_VA_DMIC_CLK_SEL_MASK,
+                                       clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+                       snd_soc_component_update_bits(component, dmic_clk_reg,
+                                                     CDC_VA_DMIC_EN_MASK,
+                                                     CDC_VA_DMIC_ENABLE);
+               } else {
+                       if (*dmic_clk_div > clk_div) {
+                               snd_soc_component_update_bits(component,
+                                               CDC_VA_TOP_CSR_DMIC_CFG,
+                                               freq_change_mask,
+                                               freq_change_mask);
+                               snd_soc_component_update_bits(component, dmic_clk_reg,
+                                               CDC_VA_DMIC_CLK_SEL_MASK,
+                                               clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+                               snd_soc_component_update_bits(component,
+                                             CDC_VA_TOP_CSR_DMIC_CFG,
+                                             freq_change_mask,
+                                             CDC_VA_DMIC_FREQ_CHANGE_DISABLE);
+                       } else {
+                               clk_div = *dmic_clk_div;
+                       }
+               }
+               *dmic_clk_div = clk_div;
+       } else {
+               (*dmic_clk_cnt)--;
+               if (*dmic_clk_cnt  == 0) {
+                       snd_soc_component_update_bits(component, dmic_clk_reg,
+                                                     CDC_VA_DMIC_EN_MASK, 0);
+                       clk_div = 0;
+                       snd_soc_component_update_bits(component, dmic_clk_reg,
+                                               CDC_VA_DMIC_CLK_SEL_MASK,
+                                               clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+               } else {
+                       clk_div = va->dmic_clk_div;
+                       if (*dmic_clk_div > clk_div) {
+                               clk_div = va->dmic_clk_div;
+                               snd_soc_component_update_bits(component,
+                                                       CDC_VA_TOP_CSR_DMIC_CFG,
+                                                       freq_change_mask,
+                                                       freq_change_mask);
+                               snd_soc_component_update_bits(component, dmic_clk_reg,
+                                               CDC_VA_DMIC_CLK_SEL_MASK,
+                                               clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+                               snd_soc_component_update_bits(component,
+                                                     CDC_VA_TOP_CSR_DMIC_CFG,
+                                                     freq_change_mask,
+                                                     CDC_VA_DMIC_FREQ_CHANGE_DISABLE);
+                       } else {
+                               clk_div = *dmic_clk_div;
+                       }
+               }
+               *dmic_clk_div = clk_div;
+       }
+
+       return 0;
+}
+
+static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+       unsigned int dmic = w->shift;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               va_dmic_clk_enable(comp, dmic, true);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               va_dmic_clk_enable(comp, dmic, false);
+               break;
+       }
+
+       return 0;
+}
+
+static int va_macro_enable_dec(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+       unsigned int decimator;
+       u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg;
+       u16 tx_gain_ctl_reg;
+       u8 hpf_cut_off_freq;
+
+       struct va_macro *va = snd_soc_component_get_drvdata(comp);
+
+       decimator = w->shift;
+
+       tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
+                               VA_MACRO_TX_PATH_OFFSET * decimator;
+       hpf_gate_reg = CDC_VA_TX0_TX_PATH_SEC2 +
+                               VA_MACRO_TX_PATH_OFFSET * decimator;
+       dec_cfg_reg = CDC_VA_TX0_TX_PATH_CFG0 +
+                               VA_MACRO_TX_PATH_OFFSET * decimator;
+       tx_gain_ctl_reg = CDC_VA_TX0_TX_VOL_CTL +
+                               VA_MACRO_TX_PATH_OFFSET * decimator;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_component_update_bits(comp,
+                       dec_cfg_reg, CDC_VA_ADC_MODE_MASK,
+                       va->dec_mode[decimator] << CDC_VA_ADC_MODE_SHIFT);
+               /* Enable TX PGA Mute */
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /* Enable TX CLK */
+               snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+                                             CDC_VA_TX_PATH_CLK_EN_MASK,
+                                             CDC_VA_TX_PATH_CLK_EN);
+               snd_soc_component_update_bits(comp, hpf_gate_reg,
+                                             CDC_VA_TX_HPF_ZERO_GATE_MASK,
+                                             CDC_VA_TX_HPF_ZERO_GATE);
+
+               usleep_range(1000, 1010);
+               hpf_cut_off_freq = (snd_soc_component_read(comp, dec_cfg_reg) &
+                                   TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+
+               if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+                       snd_soc_component_update_bits(comp, dec_cfg_reg,
+                                                     TX_HPF_CUT_OFF_FREQ_MASK,
+                                                     CF_MIN_3DB_150HZ << 5);
+
+                       snd_soc_component_update_bits(comp, hpf_gate_reg,
+                                     CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK,
+                                     CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ);
+
+                       /*
+                        * Minimum 1 clk cycle delay is required as per HW spec
+                        */
+                       usleep_range(1000, 1010);
+
+                       snd_soc_component_update_bits(comp,
+                               hpf_gate_reg,
+                               CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK,
+                               0x0);
+               }
+
+
+               usleep_range(1000, 1010);
+               snd_soc_component_update_bits(comp, hpf_gate_reg,
+                                             CDC_VA_TX_HPF_ZERO_GATE_MASK,
+                                             CDC_VA_TX_HPF_ZERO_NO_GATE);
+               /*
+                * 6ms delay is required as per HW spec
+                */
+               usleep_range(6000, 6010);
+               /* apply gain after decimator is enabled */
+               snd_soc_component_write(comp, tx_gain_ctl_reg,
+                       snd_soc_component_read(comp, tx_gain_ctl_reg));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Disable TX CLK */
+               snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+                                               CDC_VA_TX_PATH_CLK_EN_MASK,
+                                               CDC_VA_TX_PATH_CLK_DISABLE);
+               break;
+       }
+       return 0;
+}
+
+static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct va_macro *va = snd_soc_component_get_drvdata(comp);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int path = e->shift_l;
+
+       ucontrol->value.integer.value[0] = va->dec_mode[path];
+
+       return 0;
+}
+
+static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       int value = ucontrol->value.integer.value[0];
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int path = e->shift_l;
+       struct va_macro *va = snd_soc_component_get_drvdata(comp);
+
+       va->dec_mode[path] = value;
+
+       return 0;
+}
+
+static int va_macro_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params,
+                             struct snd_soc_dai *dai)
+{
+       int tx_fs_rate;
+       struct snd_soc_component *component = dai->component;
+       u32 decimator, sample_rate;
+       u16 tx_fs_reg;
+       struct device *va_dev = component->dev;
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+       sample_rate = params_rate(params);
+       switch (sample_rate) {
+       case 8000:
+               tx_fs_rate = 0;
+               break;
+       case 16000:
+               tx_fs_rate = 1;
+               break;
+       case 32000:
+               tx_fs_rate = 3;
+               break;
+       case 48000:
+               tx_fs_rate = 4;
+               break;
+       case 96000:
+               tx_fs_rate = 5;
+               break;
+       case 192000:
+               tx_fs_rate = 6;
+               break;
+       case 384000:
+               tx_fs_rate = 7;
+               break;
+       default:
+               dev_err(va_dev, "%s: Invalid TX sample rate: %d\n",
+                       __func__, params_rate(params));
+               return -EINVAL;
+       }
+
+       for_each_set_bit(decimator, &va->active_ch_mask[dai->id],
+                        VA_MACRO_DEC_MAX) {
+               tx_fs_reg = CDC_VA_TX0_TX_PATH_CTL +
+                           VA_MACRO_TX_PATH_OFFSET * decimator;
+               snd_soc_component_update_bits(component, tx_fs_reg, 0x0F,
+                                             tx_fs_rate);
+       }
+       return 0;
+}
+
+static int va_macro_get_channel_map(struct snd_soc_dai *dai,
+                                   unsigned int *tx_num, unsigned int *tx_slot,
+                                   unsigned int *rx_num, unsigned int *rx_slot)
+{
+       struct snd_soc_component *component = dai->component;
+       struct device *va_dev = component->dev;
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+       switch (dai->id) {
+       case VA_MACRO_AIF1_CAP:
+       case VA_MACRO_AIF2_CAP:
+       case VA_MACRO_AIF3_CAP:
+               *tx_slot = va->active_ch_mask[dai->id];
+               *tx_num = va->active_ch_cnt[dai->id];
+               break;
+       default:
+               dev_err(va_dev, "%s: Invalid AIF\n", __func__);
+               break;
+       }
+       return 0;
+}
+
+static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct snd_soc_component *component = dai->component;
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+       u16 tx_vol_ctl_reg, decimator;
+
+       decimator = va->active_decimator[dai->id];
+
+       tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
+                               VA_MACRO_TX_PATH_OFFSET * decimator;
+       if (mute)
+               snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+                                             CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
+                                             CDC_VA_TX_PATH_PGA_MUTE_EN);
+       else
+               snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+                                             CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
+                                             CDC_VA_TX_PATH_PGA_MUTE_DISABLE);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops va_macro_dai_ops = {
+       .hw_params = va_macro_hw_params,
+       .get_channel_map = va_macro_get_channel_map,
+       .mute_stream = va_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver va_macro_dais[] = {
+       {
+               .name = "va_macro_tx1",
+               .id = VA_MACRO_AIF1_CAP,
+               .capture = {
+                       .stream_name = "VA_AIF1 Capture",
+                       .rates = VA_MACRO_RATES,
+                       .formats = VA_MACRO_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 8,
+               },
+               .ops = &va_macro_dai_ops,
+       },
+       {
+               .name = "va_macro_tx2",
+               .id = VA_MACRO_AIF2_CAP,
+               .capture = {
+                       .stream_name = "VA_AIF2 Capture",
+                       .rates = VA_MACRO_RATES,
+                       .formats = VA_MACRO_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 8,
+               },
+               .ops = &va_macro_dai_ops,
+       },
+       {
+               .name = "va_macro_tx3",
+               .id = VA_MACRO_AIF3_CAP,
+               .capture = {
+                       .stream_name = "VA_AIF3 Capture",
+                       .rates = VA_MACRO_RATES,
+                       .formats = VA_MACRO_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 8,
+               },
+               .ops = &va_macro_dai_ops,
+       },
+};
+
+static const char * const adc_mux_text[] = {
+       "VA_DMIC", "SWR_MIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(va_dec0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(va_dec1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(va_dec2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG1,
+                  0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(va_dec3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG1,
+                  0, adc_mux_text);
+
+static const struct snd_kcontrol_new va_dec0_mux = SOC_DAPM_ENUM("va_dec0",
+                                                                va_dec0_enum);
+static const struct snd_kcontrol_new va_dec1_mux = SOC_DAPM_ENUM("va_dec1",
+                                                                va_dec1_enum);
+static const struct snd_kcontrol_new va_dec2_mux = SOC_DAPM_ENUM("va_dec2",
+                                                                va_dec2_enum);
+static const struct snd_kcontrol_new va_dec3_mux = SOC_DAPM_ENUM("va_dec3",
+                                                                va_dec3_enum);
+
+static const char * const dmic_mux_text[] = {
+       "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
+       "DMIC4", "DMIC5", "DMIC6", "DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(va_dmic0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(va_dmic1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(va_dmic2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(va_dmic3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG0,
+                       4, dmic_mux_text);
+
+static const struct snd_kcontrol_new va_dmic0_mux = SOC_DAPM_ENUM_EXT("va_dmic0",
+                        va_dmic0_enum, snd_soc_dapm_get_enum_double,
+                        va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_dmic1_mux = SOC_DAPM_ENUM_EXT("va_dmic1",
+                        va_dmic1_enum, snd_soc_dapm_get_enum_double,
+                        va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_dmic2_mux = SOC_DAPM_ENUM_EXT("va_dmic2",
+                        va_dmic2_enum, snd_soc_dapm_get_enum_double,
+                        va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_dmic3_mux = SOC_DAPM_ENUM_EXT("va_dmic3",
+                        va_dmic3_enum, snd_soc_dapm_get_enum_double,
+                        va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_aif1_cap_mixer[] = {
+       SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif2_cap_mixer[] = {
+       SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif3_cap_mixer[] = {
+       SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+       SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0,
+                       va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_OUT("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
+               SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0),
+
+       SND_SOC_DAPM_AIF_OUT("VA_AIF2 CAP", "VA_AIF2 Capture", 0,
+               SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0),
+
+       SND_SOC_DAPM_AIF_OUT("VA_AIF3 CAP", "VA_AIF3 Capture", 0,
+               SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0),
+
+       SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM,
+               VA_MACRO_AIF1_CAP, 0,
+               va_aif1_cap_mixer, ARRAY_SIZE(va_aif1_cap_mixer)),
+
+       SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM,
+               VA_MACRO_AIF2_CAP, 0,
+               va_aif2_cap_mixer, ARRAY_SIZE(va_aif2_cap_mixer)),
+
+       SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM,
+               VA_MACRO_AIF3_CAP, 0,
+               va_aif3_cap_mixer, ARRAY_SIZE(va_aif3_cap_mixer)),
+
+       SND_SOC_DAPM_MUX("VA DMIC MUX0", SND_SOC_NOPM, 0, 0, &va_dmic0_mux),
+       SND_SOC_DAPM_MUX("VA DMIC MUX1", SND_SOC_NOPM, 0, 0, &va_dmic1_mux),
+       SND_SOC_DAPM_MUX("VA DMIC MUX2", SND_SOC_NOPM, 0, 0, &va_dmic2_mux),
+       SND_SOC_DAPM_MUX("VA DMIC MUX3", SND_SOC_NOPM, 0, 0, &va_dmic3_mux),
+
+       SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micb", 0, 0),
+       SND_SOC_DAPM_INPUT("DMIC0 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC3 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC4 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC5 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC6 Pin"),
+       SND_SOC_DAPM_INPUT("DMIC7 Pin"),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC1", NULL, SND_SOC_NOPM, 1, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC2", NULL, SND_SOC_NOPM, 2, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC3", NULL, SND_SOC_NOPM, 3, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC4", NULL, SND_SOC_NOPM, 4, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC5", NULL, SND_SOC_NOPM, 5, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC6", NULL, SND_SOC_NOPM, 6, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("VA DMIC7", NULL, SND_SOC_NOPM, 7, 0,
+               va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_INPUT("VA SWR_ADC0"),
+       SND_SOC_DAPM_INPUT("VA SWR_ADC1"),
+       SND_SOC_DAPM_INPUT("VA SWR_ADC2"),
+       SND_SOC_DAPM_INPUT("VA SWR_ADC3"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC0"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC1"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC2"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC3"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC4"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC5"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC6"),
+       SND_SOC_DAPM_INPUT("VA SWR_MIC7"),
+
+       SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0,
+                          &va_dec0_mux, va_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, VA_MACRO_DEC1, 0,
+                          &va_dec1_mux, va_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, VA_MACRO_DEC2, 0,
+                          &va_dec2_mux, va_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, VA_MACRO_DEC3, 0,
+                          &va_dec3_mux, va_macro_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0,
+                             va_macro_mclk_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route va_audio_map[] = {
+       {"VA_AIF1 CAP", NULL, "VA_MCLK"},
+       {"VA_AIF2 CAP", NULL, "VA_MCLK"},
+       {"VA_AIF3 CAP", NULL, "VA_MCLK"},
+
+       {"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"},
+       {"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"},
+       {"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"},
+
+       {"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+       {"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+       {"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+       {"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+       {"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+       {"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+       {"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+       {"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+       {"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+       {"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+       {"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+       {"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+       {"VA DEC0 MUX", "VA_DMIC", "VA DMIC MUX0"},
+       {"VA DMIC MUX0", "DMIC0", "VA DMIC0"},
+       {"VA DMIC MUX0", "DMIC1", "VA DMIC1"},
+       {"VA DMIC MUX0", "DMIC2", "VA DMIC2"},
+       {"VA DMIC MUX0", "DMIC3", "VA DMIC3"},
+       {"VA DMIC MUX0", "DMIC4", "VA DMIC4"},
+       {"VA DMIC MUX0", "DMIC5", "VA DMIC5"},
+       {"VA DMIC MUX0", "DMIC6", "VA DMIC6"},
+       {"VA DMIC MUX0", "DMIC7", "VA DMIC7"},
+
+       {"VA DEC1 MUX", "VA_DMIC", "VA DMIC MUX1"},
+       {"VA DMIC MUX1", "DMIC0", "VA DMIC0"},
+       {"VA DMIC MUX1", "DMIC1", "VA DMIC1"},
+       {"VA DMIC MUX1", "DMIC2", "VA DMIC2"},
+       {"VA DMIC MUX1", "DMIC3", "VA DMIC3"},
+       {"VA DMIC MUX1", "DMIC4", "VA DMIC4"},
+       {"VA DMIC MUX1", "DMIC5", "VA DMIC5"},
+       {"VA DMIC MUX1", "DMIC6", "VA DMIC6"},
+       {"VA DMIC MUX1", "DMIC7", "VA DMIC7"},
+
+       {"VA DEC2 MUX", "VA_DMIC", "VA DMIC MUX2"},
+       {"VA DMIC MUX2", "DMIC0", "VA DMIC0"},
+       {"VA DMIC MUX2", "DMIC1", "VA DMIC1"},
+       {"VA DMIC MUX2", "DMIC2", "VA DMIC2"},
+       {"VA DMIC MUX2", "DMIC3", "VA DMIC3"},
+       {"VA DMIC MUX2", "DMIC4", "VA DMIC4"},
+       {"VA DMIC MUX2", "DMIC5", "VA DMIC5"},
+       {"VA DMIC MUX2", "DMIC6", "VA DMIC6"},
+       {"VA DMIC MUX2", "DMIC7", "VA DMIC7"},
+
+       {"VA DEC3 MUX", "VA_DMIC", "VA DMIC MUX3"},
+       {"VA DMIC MUX3", "DMIC0", "VA DMIC0"},
+       {"VA DMIC MUX3", "DMIC1", "VA DMIC1"},
+       {"VA DMIC MUX3", "DMIC2", "VA DMIC2"},
+       {"VA DMIC MUX3", "DMIC3", "VA DMIC3"},
+       {"VA DMIC MUX3", "DMIC4", "VA DMIC4"},
+       {"VA DMIC MUX3", "DMIC5", "VA DMIC5"},
+       {"VA DMIC MUX3", "DMIC6", "VA DMIC6"},
+       {"VA DMIC MUX3", "DMIC7", "VA DMIC7"},
+
+       { "VA DMIC0", NULL, "DMIC0 Pin" },
+       { "VA DMIC1", NULL, "DMIC1 Pin" },
+       { "VA DMIC2", NULL, "DMIC2 Pin" },
+       { "VA DMIC3", NULL, "DMIC3 Pin" },
+       { "VA DMIC4", NULL, "DMIC4 Pin" },
+       { "VA DMIC5", NULL, "DMIC5 Pin" },
+       { "VA DMIC6", NULL, "DMIC6 Pin" },
+       { "VA DMIC7", NULL, "DMIC7 Pin" },
+};
+
+static const char * const dec_mode_mux_text[] = {
+       "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum[] = {
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 2,  ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(dec_mode_mux_text),
+                       dec_mode_mux_text),
+};
+
+static const struct snd_kcontrol_new va_macro_snd_controls[] = {
+       SOC_SINGLE_S8_TLV("VA_DEC0 Volume", CDC_VA_TX0_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("VA_DEC1 Volume", CDC_VA_TX1_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("VA_DEC2 Volume", CDC_VA_TX2_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("VA_DEC3 Volume", CDC_VA_TX3_TX_VOL_CTL,
+                         -84, 40, digital_gain),
+
+       SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum[0],
+                    va_macro_dec_mode_get, va_macro_dec_mode_put),
+       SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum[1],
+                    va_macro_dec_mode_get, va_macro_dec_mode_put),
+       SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum[2],
+                    va_macro_dec_mode_get, va_macro_dec_mode_put),
+       SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum[3],
+                    va_macro_dec_mode_get, va_macro_dec_mode_put),
+};
+
+static int va_macro_component_probe(struct snd_soc_component *component)
+{
+       struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+       snd_soc_component_init_regmap(component, va->regmap);
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver va_macro_component_drv = {
+       .name = "VA MACRO",
+       .probe = va_macro_component_probe,
+       .controls = va_macro_snd_controls,
+       .num_controls = ARRAY_SIZE(va_macro_snd_controls),
+       .dapm_widgets = va_macro_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(va_macro_dapm_widgets),
+       .dapm_routes = va_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(va_audio_map),
+};
+
+static int fsgen_gate_enable(struct clk_hw *hw)
+{
+       return va_macro_mclk_enable(to_va_macro(hw), true);
+}
+
+static void fsgen_gate_disable(struct clk_hw *hw)
+{
+       va_macro_mclk_enable(to_va_macro(hw), false);
+}
+
+static int fsgen_gate_is_enabled(struct clk_hw *hw)
+{
+       struct va_macro *va = to_va_macro(hw);
+       int val;
+
+       regmap_read(va->regmap, CDC_VA_TOP_CSR_TOP_CFG0, &val);
+
+       return  !!(val & CDC_VA_FS_BROADCAST_EN);
+}
+
+static const struct clk_ops fsgen_gate_ops = {
+       .prepare = fsgen_gate_enable,
+       .unprepare = fsgen_gate_disable,
+       .is_enabled = fsgen_gate_is_enabled,
+};
+
+static int va_macro_register_fsgen_output(struct va_macro *va)
+{
+       struct clk *parent = va->clks[2].clk;
+       struct device *dev = va->dev;
+       struct device_node *np = dev->of_node;
+       const char *parent_clk_name;
+       const char *clk_name = "fsgen";
+       struct clk_init_data init;
+       int ret;
+
+       parent_clk_name = __clk_get_name(parent);
+
+       of_property_read_string(np, "clock-output-names", &clk_name);
+
+       init.name = clk_name;
+       init.ops = &fsgen_gate_ops;
+       init.flags = 0;
+       init.parent_names = &parent_clk_name;
+       init.num_parents = 1;
+       va->hw.init = &init;
+       ret = devm_clk_hw_register(va->dev, &va->hw);
+       if (ret)
+               return ret;
+
+       return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk);
+}
+
+static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
+                                             struct va_macro *va)
+{
+       u32 div_factor;
+       u32 mclk_rate = VA_MACRO_MCLK_FREQ;
+
+       if (!dmic_sample_rate || mclk_rate % dmic_sample_rate != 0)
+               goto undefined_rate;
+
+       div_factor = mclk_rate / dmic_sample_rate;
+
+       switch (div_factor) {
+       case 2:
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_2;
+               break;
+       case 3:
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_3;
+               break;
+       case 4:
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_4;
+               break;
+       case 6:
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_6;
+               break;
+       case 8:
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_8;
+               break;
+       case 16:
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_16;
+               break;
+       default:
+               /* Any other DIV factor is invalid */
+               goto undefined_rate;
+       }
+
+       return dmic_sample_rate;
+
+undefined_rate:
+       dev_err(va->dev, "%s: Invalid rate %d, for mclk %d\n",
+               __func__, dmic_sample_rate, mclk_rate);
+       dmic_sample_rate = 0;
+
+       return dmic_sample_rate;
+}
+
+static int va_macro_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct va_macro *va;
+       void __iomem *base;
+       u32 sample_rate = 0;
+       int ret;
+
+       va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL);
+       if (!va)
+               return -ENOMEM;
+
+       va->dev = dev;
+       va->clks[0].id = "macro";
+       va->clks[1].id = "dcodec";
+       va->clks[2].id = "mclk";
+
+       ret = devm_clk_bulk_get(dev, VA_NUM_CLKS_MAX, va->clks);
+       if (ret) {
+               dev_err(dev, "Error getting VA Clocks (%d)\n", ret);
+               return ret;
+       }
+
+       ret = of_property_read_u32(dev->of_node, "qcom,dmic-sample-rate",
+                                  &sample_rate);
+       if (ret) {
+               dev_err(dev, "qcom,dmic-sample-rate dt entry missing\n");
+               va->dmic_clk_div = VA_MACRO_CLK_DIV_2;
+       } else {
+               ret = va_macro_validate_dmic_sample_rate(sample_rate, va);
+               if (!ret)
+                       return -EINVAL;
+       }
+
+       /* mclk rate */
+       clk_set_rate(va->clks[1].clk, VA_MACRO_MCLK_FREQ);
+       ret = clk_bulk_prepare_enable(VA_NUM_CLKS_MAX, va->clks);
+       if (ret)
+               return ret;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base)) {
+               ret = PTR_ERR(base);
+               goto err;
+       }
+
+       va->regmap = devm_regmap_init_mmio(dev, base,  &va_regmap_config);
+       if (IS_ERR(va->regmap)) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dev_set_drvdata(dev, va);
+       ret = va_macro_register_fsgen_output(va);
+       if (ret)
+               goto err;
+
+       ret = devm_snd_soc_register_component(dev, &va_macro_component_drv,
+                                             va_macro_dais,
+                                             ARRAY_SIZE(va_macro_dais));
+       if (ret)
+               goto soc_err;
+
+       return ret;
+
+soc_err:
+       of_clk_del_provider(pdev->dev.of_node);
+err:
+       clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
+
+       return ret;
+}
+
+static int va_macro_remove(struct platform_device *pdev)
+{
+       struct va_macro *va = dev_get_drvdata(&pdev->dev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+       clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
+
+       return 0;
+}
+
+static const struct of_device_id va_macro_dt_match[] = {
+       { .compatible = "qcom,sm8250-lpass-va-macro" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, va_macro_dt_match);
+
+static struct platform_driver va_macro_driver = {
+       .driver = {
+               .name = "va_macro",
+               .of_match_table = va_macro_dt_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = va_macro_probe,
+       .remove = va_macro_remove,
+};
+
+module_platform_driver(va_macro_driver);
+MODULE_DESCRIPTION("VA macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
new file mode 100644 (file)
index 0000000..25f1df2
--- /dev/null
@@ -0,0 +1,2464 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/of_platform.h>
+#include <sound/tlv.h>
+#include "lpass-wsa-macro.h"
+
+#define CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL      (0x0000)
+#define CDC_WSA_MCLK_EN_MASK                   BIT(0)
+#define CDC_WSA_MCLK_ENABLE                    BIT(0)
+#define CDC_WSA_MCLK_DISABLE                   0
+#define CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL    (0x0004)
+#define CDC_WSA_FS_CNT_EN_MASK                 BIT(0)
+#define CDC_WSA_FS_CNT_ENABLE                  BIT(0)
+#define CDC_WSA_FS_CNT_DISABLE                 0
+#define CDC_WSA_CLK_RST_CTRL_SWR_CONTROL       (0x0008)
+#define CDC_WSA_SWR_CLK_EN_MASK                        BIT(0)
+#define CDC_WSA_SWR_CLK_ENABLE                 BIT(0)
+#define CDC_WSA_SWR_RST_EN_MASK                        BIT(1)
+#define CDC_WSA_SWR_RST_ENABLE                 BIT(1)
+#define CDC_WSA_SWR_RST_DISABLE                        0
+#define CDC_WSA_TOP_TOP_CFG0                   (0x0080)
+#define CDC_WSA_TOP_TOP_CFG1                   (0x0084)
+#define CDC_WSA_TOP_FREQ_MCLK                  (0x0088)
+#define CDC_WSA_TOP_DEBUG_BUS_SEL              (0x008C)
+#define CDC_WSA_TOP_DEBUG_EN0                  (0x0090)
+#define CDC_WSA_TOP_DEBUG_EN1                  (0x0094)
+#define CDC_WSA_TOP_DEBUG_DSM_LB               (0x0098)
+#define CDC_WSA_TOP_RX_I2S_CTL                 (0x009C)
+#define CDC_WSA_TOP_TX_I2S_CTL                 (0x00A0)
+#define CDC_WSA_TOP_I2S_CLK                    (0x00A4)
+#define CDC_WSA_TOP_I2S_RESET                  (0x00A8)
+#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0                (0x0100)
+#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK    GENMASK(5, 3)
+#define CDC_WSA_RX_INTX_2_SEL_MASK             GENMASK(2, 0)
+#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1                (0x0104)
+#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0                (0x0108)
+#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1                (0x010C)
+#define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0         (0x0110)
+#define CDC_WSA_RX_MIX_TX1_SEL_MASK            GENMASK(5, 3)
+#define CDC_WSA_RX_MIX_TX1_SEL_SHFT            3
+#define CDC_WSA_RX_MIX_TX0_SEL_MASK            GENMASK(2, 0)
+#define CDC_WSA_RX_INP_MUX_RX_EC_CFG0          (0x0114)
+#define CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0       (0x0118)
+#define CDC_WSA_TX0_SPKR_PROT_PATH_CTL         (0x0244)
+#define CDC_WSA_TX_SPKR_PROT_RESET_MASK                BIT(5)
+#define CDC_WSA_TX_SPKR_PROT_RESET             BIT(5)
+#define CDC_WSA_TX_SPKR_PROT_NO_RESET          0
+#define CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK       BIT(4)
+#define CDC_WSA_TX_SPKR_PROT_CLK_ENABLE                BIT(4)
+#define CDC_WSA_TX_SPKR_PROT_CLK_DISABLE       0
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK     GENMASK(3, 0)
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K       0
+#define CDC_WSA_TX0_SPKR_PROT_PATH_CFG0                (0x0248)
+#define CDC_WSA_TX1_SPKR_PROT_PATH_CTL         (0x0264)
+#define CDC_WSA_TX1_SPKR_PROT_PATH_CFG0                (0x0268)
+#define CDC_WSA_TX2_SPKR_PROT_PATH_CTL         (0x0284)
+#define CDC_WSA_TX2_SPKR_PROT_PATH_CFG0                (0x0288)
+#define CDC_WSA_TX3_SPKR_PROT_PATH_CTL         (0x02A4)
+#define CDC_WSA_TX3_SPKR_PROT_PATH_CFG0                (0x02A8)
+#define CDC_WSA_INTR_CTRL_CFG                  (0x0340)
+#define CDC_WSA_INTR_CTRL_CLR_COMMIT           (0x0344)
+#define CDC_WSA_INTR_CTRL_PIN1_MASK0           (0x0360)
+#define CDC_WSA_INTR_CTRL_PIN1_STATUS0         (0x0368)
+#define CDC_WSA_INTR_CTRL_PIN1_CLEAR0          (0x0370)
+#define CDC_WSA_INTR_CTRL_PIN2_MASK0           (0x0380)
+#define CDC_WSA_INTR_CTRL_PIN2_STATUS0         (0x0388)
+#define CDC_WSA_INTR_CTRL_PIN2_CLEAR0          (0x0390)
+#define CDC_WSA_INTR_CTRL_LEVEL0               (0x03C0)
+#define CDC_WSA_INTR_CTRL_BYPASS0              (0x03C8)
+#define CDC_WSA_INTR_CTRL_SET0                 (0x03D0)
+#define CDC_WSA_RX0_RX_PATH_CTL                        (0x0400)
+#define CDC_WSA_RX_PATH_CLK_EN_MASK            BIT(5)
+#define CDC_WSA_RX_PATH_CLK_ENABLE             BIT(5)
+#define CDC_WSA_RX_PATH_CLK_DISABLE            0
+#define CDC_WSA_RX_PATH_PGA_MUTE_EN_MASK       BIT(4)
+#define CDC_WSA_RX_PATH_PGA_MUTE_ENABLE                BIT(4)
+#define CDC_WSA_RX_PATH_PGA_MUTE_DISABLE       0
+#define CDC_WSA_RX0_RX_PATH_CFG0               (0x0404)
+#define CDC_WSA_RX_PATH_COMP_EN_MASK           BIT(1)
+#define CDC_WSA_RX_PATH_COMP_ENABLE            BIT(1)
+#define CDC_WSA_RX_PATH_HD2_EN_MASK            BIT(2)
+#define CDC_WSA_RX_PATH_HD2_ENABLE             BIT(2)
+#define CDC_WSA_RX_PATH_SPKR_RATE_MASK         BIT(3)
+#define CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072 BIT(3)
+#define CDC_WSA_RX0_RX_PATH_CFG1               (0x0408)
+#define CDC_WSA_RX_PATH_SMART_BST_EN_MASK      BIT(0)
+#define CDC_WSA_RX_PATH_SMART_BST_ENABLE       BIT(0)
+#define CDC_WSA_RX_PATH_SMART_BST_DISABLE      0
+#define CDC_WSA_RX0_RX_PATH_CFG2               (0x040C)
+#define CDC_WSA_RX0_RX_PATH_CFG3               (0x0410)
+#define CDC_WSA_RX_DC_DCOEFF_MASK              GENMASK(1, 0)
+#define CDC_WSA_RX0_RX_VOL_CTL                 (0x0414)
+#define CDC_WSA_RX0_RX_PATH_MIX_CTL            (0x0418)
+#define CDC_WSA_RX_PATH_MIX_CLK_EN_MASK                BIT(5)
+#define CDC_WSA_RX_PATH_MIX_CLK_ENABLE         BIT(5)
+#define CDC_WSA_RX_PATH_MIX_CLK_DISABLE                0
+#define CDC_WSA_RX0_RX_PATH_MIX_CFG            (0x041C)
+#define CDC_WSA_RX0_RX_VOL_MIX_CTL             (0x0420)
+#define CDC_WSA_RX0_RX_PATH_SEC0               (0x0424)
+#define CDC_WSA_RX0_RX_PATH_SEC1               (0x0428)
+#define CDC_WSA_RX_PGA_HALF_DB_MASK            BIT(0)
+#define CDC_WSA_RX_PGA_HALF_DB_ENABLE          BIT(0)
+#define CDC_WSA_RX_PGA_HALF_DB_DISABLE         0
+#define CDC_WSA_RX0_RX_PATH_SEC2               (0x042C)
+#define CDC_WSA_RX0_RX_PATH_SEC3               (0x0430)
+#define CDC_WSA_RX_PATH_HD2_SCALE_MASK         GENMASK(1, 0)
+#define CDC_WSA_RX_PATH_HD2_ALPHA_MASK         GENMASK(5, 2)
+#define CDC_WSA_RX0_RX_PATH_SEC5               (0x0438)
+#define CDC_WSA_RX0_RX_PATH_SEC6               (0x043C)
+#define CDC_WSA_RX0_RX_PATH_SEC7               (0x0440)
+#define CDC_WSA_RX0_RX_PATH_MIX_SEC0           (0x0444)
+#define CDC_WSA_RX0_RX_PATH_MIX_SEC1           (0x0448)
+#define CDC_WSA_RX0_RX_PATH_DSMDEM_CTL         (0x044C)
+#define CDC_WSA_RX_DSMDEM_CLK_EN_MASK          BIT(0)
+#define CDC_WSA_RX_DSMDEM_CLK_ENABLE           BIT(0)
+#define CDC_WSA_RX1_RX_PATH_CTL                        (0x0480)
+#define CDC_WSA_RX1_RX_PATH_CFG0               (0x0484)
+#define CDC_WSA_RX1_RX_PATH_CFG1               (0x0488)
+#define CDC_WSA_RX1_RX_PATH_CFG2               (0x048C)
+#define CDC_WSA_RX1_RX_PATH_CFG3               (0x0490)
+#define CDC_WSA_RX1_RX_VOL_CTL                 (0x0494)
+#define CDC_WSA_RX1_RX_PATH_MIX_CTL            (0x0498)
+#define CDC_WSA_RX1_RX_PATH_MIX_CFG            (0x049C)
+#define CDC_WSA_RX1_RX_VOL_MIX_CTL             (0x04A0)
+#define CDC_WSA_RX1_RX_PATH_SEC0               (0x04A4)
+#define CDC_WSA_RX1_RX_PATH_SEC1               (0x04A8)
+#define CDC_WSA_RX1_RX_PATH_SEC2               (0x04AC)
+#define CDC_WSA_RX1_RX_PATH_SEC3               (0x04B0)
+#define CDC_WSA_RX1_RX_PATH_SEC5               (0x04B8)
+#define CDC_WSA_RX1_RX_PATH_SEC6               (0x04BC)
+#define CDC_WSA_RX1_RX_PATH_SEC7               (0x04C0)
+#define CDC_WSA_RX1_RX_PATH_MIX_SEC0           (0x04C4)
+#define CDC_WSA_RX1_RX_PATH_MIX_SEC1           (0x04C8)
+#define CDC_WSA_RX1_RX_PATH_DSMDEM_CTL         (0x04CC)
+#define CDC_WSA_BOOST0_BOOST_PATH_CTL          (0x0500)
+#define CDC_WSA_BOOST_PATH_CLK_EN_MASK         BIT(4)
+#define CDC_WSA_BOOST_PATH_CLK_ENABLE          BIT(4)
+#define CDC_WSA_BOOST_PATH_CLK_DISABLE         0
+#define CDC_WSA_BOOST0_BOOST_CTL               (0x0504)
+#define CDC_WSA_BOOST0_BOOST_CFG1              (0x0508)
+#define CDC_WSA_BOOST0_BOOST_CFG2              (0x050C)
+#define CDC_WSA_BOOST1_BOOST_PATH_CTL          (0x0540)
+#define CDC_WSA_BOOST1_BOOST_CTL               (0x0544)
+#define CDC_WSA_BOOST1_BOOST_CFG1              (0x0548)
+#define CDC_WSA_BOOST1_BOOST_CFG2              (0x054C)
+#define CDC_WSA_COMPANDER0_CTL0                        (0x0580)
+#define CDC_WSA_COMPANDER_CLK_EN_MASK          BIT(0)
+#define CDC_WSA_COMPANDER_CLK_ENABLE           BIT(0)
+#define CDC_WSA_COMPANDER_SOFT_RST_MASK                BIT(1)
+#define CDC_WSA_COMPANDER_SOFT_RST_ENABLE      BIT(1)
+#define CDC_WSA_COMPANDER_HALT_MASK            BIT(2)
+#define CDC_WSA_COMPANDER_HALT                 BIT(2)
+#define CDC_WSA_COMPANDER0_CTL1                        (0x0584)
+#define CDC_WSA_COMPANDER0_CTL2                        (0x0588)
+#define CDC_WSA_COMPANDER0_CTL3                        (0x058C)
+#define CDC_WSA_COMPANDER0_CTL4                        (0x0590)
+#define CDC_WSA_COMPANDER0_CTL5                        (0x0594)
+#define CDC_WSA_COMPANDER0_CTL6                        (0x0598)
+#define CDC_WSA_COMPANDER0_CTL7                        (0x059C)
+#define CDC_WSA_COMPANDER1_CTL0                        (0x05C0)
+#define CDC_WSA_COMPANDER1_CTL1                        (0x05C4)
+#define CDC_WSA_COMPANDER1_CTL2                        (0x05C8)
+#define CDC_WSA_COMPANDER1_CTL3                        (0x05CC)
+#define CDC_WSA_COMPANDER1_CTL4                        (0x05D0)
+#define CDC_WSA_COMPANDER1_CTL5                        (0x05D4)
+#define CDC_WSA_COMPANDER1_CTL6                        (0x05D8)
+#define CDC_WSA_COMPANDER1_CTL7                        (0x05DC)
+#define CDC_WSA_SOFTCLIP0_CRC                  (0x0600)
+#define CDC_WSA_SOFTCLIP_CLK_EN_MASK           BIT(0)
+#define CDC_WSA_SOFTCLIP_CLK_ENABLE            BIT(0)
+#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL                (0x0604)
+#define CDC_WSA_SOFTCLIP_EN_MASK               BIT(0)
+#define CDC_WSA_SOFTCLIP_ENABLE                        BIT(0)
+#define CDC_WSA_SOFTCLIP1_CRC                  (0x0640)
+#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL                (0x0644)
+#define CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL      (0x0680)
+#define CDC_WSA_EC_HQ_EC_CLK_EN_MASK           BIT(0)
+#define CDC_WSA_EC_HQ_EC_CLK_ENABLE            BIT(0)
+#define CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0          (0x0684)
+#define CDC_WSA_EC_HQ_EC_REF_PCM_RATE_MASK     GENMASK(4, 1)
+#define CDC_WSA_EC_HQ_EC_REF_PCM_RATE_48K      BIT(3)
+#define CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL      (0x06C0)
+#define CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0          (0x06C4)
+#define CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL       (0x0700)
+#define CDC_WSA_SPLINE_ASRC0_CTL0              (0x0704)
+#define CDC_WSA_SPLINE_ASRC0_CTL1              (0x0708)
+#define CDC_WSA_SPLINE_ASRC0_FIFO_CTL          (0x070C)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB      (0x0710)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB      (0x0714)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB      (0x0718)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB      (0x071C)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FIFO               (0x0720)
+#define CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL               (0x0740)
+#define CDC_WSA_SPLINE_ASRC1_CTL0              (0x0744)
+#define CDC_WSA_SPLINE_ASRC1_CTL1              (0x0748)
+#define CDC_WSA_SPLINE_ASRC1_FIFO_CTL          (0x074C)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB (0x0750)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB (0x0754)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB (0x0758)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB (0x075C)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO       (0x0760)
+#define WSA_MAX_OFFSET                         (0x0760)
+
+#define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define WSA_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define WSA_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE |\
+               SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define WSA_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_48000)
+#define WSA_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE |\
+               SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define NUM_INTERPOLATORS 2
+#define WSA_NUM_CLKS_MAX       5
+#define WSA_MACRO_MCLK_FREQ 19200000
+#define WSA_MACRO_MUX_INP_SHFT 0x3
+#define WSA_MACRO_MUX_INP_MASK1 0x07
+#define WSA_MACRO_MUX_INP_MASK2 0x38
+#define WSA_MACRO_MUX_CFG_OFFSET 0x8
+#define WSA_MACRO_MUX_CFG1_OFFSET 0x4
+#define WSA_MACRO_RX_COMP_OFFSET 0x40
+#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40
+#define WSA_MACRO_RX_PATH_OFFSET 0x80
+#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10
+#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C
+#define WSA_MACRO_FS_RATE_MASK 0x0F
+#define WSA_MACRO_EC_MIX_TX0_MASK 0x03
+#define WSA_MACRO_EC_MIX_TX1_MASK 0x18
+#define WSA_MACRO_MAX_DMA_CH_PER_PORT 0x2
+
+enum {
+       WSA_MACRO_GAIN_OFFSET_M1P5_DB,
+       WSA_MACRO_GAIN_OFFSET_0_DB,
+};
+enum {
+       WSA_MACRO_RX0 = 0,
+       WSA_MACRO_RX1,
+       WSA_MACRO_RX_MIX,
+       WSA_MACRO_RX_MIX0 = WSA_MACRO_RX_MIX,
+       WSA_MACRO_RX_MIX1,
+       WSA_MACRO_RX_MAX,
+};
+
+enum {
+       WSA_MACRO_TX0 = 0,
+       WSA_MACRO_TX1,
+       WSA_MACRO_TX_MAX,
+};
+
+enum {
+       WSA_MACRO_EC0_MUX = 0,
+       WSA_MACRO_EC1_MUX,
+       WSA_MACRO_EC_MUX_MAX,
+};
+
+enum {
+       WSA_MACRO_COMP1, /* SPK_L */
+       WSA_MACRO_COMP2, /* SPK_R */
+       WSA_MACRO_COMP_MAX
+};
+
+enum {
+       WSA_MACRO_SOFTCLIP0, /* RX0 */
+       WSA_MACRO_SOFTCLIP1, /* RX1 */
+       WSA_MACRO_SOFTCLIP_MAX
+};
+
+enum {
+       INTn_1_INP_SEL_ZERO = 0,
+       INTn_1_INP_SEL_RX0,
+       INTn_1_INP_SEL_RX1,
+       INTn_1_INP_SEL_RX2,
+       INTn_1_INP_SEL_RX3,
+       INTn_1_INP_SEL_DEC0,
+       INTn_1_INP_SEL_DEC1,
+};
+
+enum {
+       INTn_2_INP_SEL_ZERO = 0,
+       INTn_2_INP_SEL_RX0,
+       INTn_2_INP_SEL_RX1,
+       INTn_2_INP_SEL_RX2,
+       INTn_2_INP_SEL_RX3,
+};
+
+struct interp_sample_rate {
+       int sample_rate;
+       int rate_val;
+};
+
+static struct interp_sample_rate int_prim_sample_rate_val[] = {
+       {8000, 0x0},    /* 8K */
+       {16000, 0x1},   /* 16K */
+       {24000, -EINVAL},/* 24K */
+       {32000, 0x3},   /* 32K */
+       {48000, 0x4},   /* 48K */
+       {96000, 0x5},   /* 96K */
+       {192000, 0x6},  /* 192K */
+       {384000, 0x7},  /* 384K */
+       {44100, 0x8}, /* 44.1K */
+};
+
+static struct interp_sample_rate int_mix_sample_rate_val[] = {
+       {48000, 0x4},   /* 48K */
+       {96000, 0x5},   /* 96K */
+       {192000, 0x6},  /* 192K */
+};
+
+enum {
+       WSA_MACRO_AIF_INVALID = 0,
+       WSA_MACRO_AIF1_PB,
+       WSA_MACRO_AIF_MIX1_PB,
+       WSA_MACRO_AIF_VI,
+       WSA_MACRO_AIF_ECHO,
+       WSA_MACRO_MAX_DAIS,
+};
+
+struct wsa_macro {
+       struct device *dev;
+       int comp_enabled[WSA_MACRO_COMP_MAX];
+       int ec_hq[WSA_MACRO_RX1 + 1];
+       u16 prim_int_users[WSA_MACRO_RX1 + 1];
+       u16 wsa_mclk_users;
+       bool reset_swr;
+       unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS];
+       unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS];
+       int rx_port_value[WSA_MACRO_RX_MAX];
+       int ear_spkr_gain;
+       int spkr_gain_offset;
+       int spkr_mode;
+       int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
+       int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
+       struct regmap *regmap;
+       struct clk_bulk_data clks[WSA_NUM_CLKS_MAX];
+       struct clk_hw hw;
+};
+#define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw)
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+static const char *const rx_text[] = {
+       "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1"
+};
+
+static const char *const rx_mix_text[] = {
+       "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1"
+};
+
+static const char *const rx_mix_ec_text[] = {
+       "ZERO", "RX_MIX_TX0", "RX_MIX_TX1"
+};
+
+static const char *const rx_mux_text[] = {
+       "ZERO", "AIF1_PB", "AIF_MIX1_PB"
+};
+
+static const char *const rx_sidetone_mix_text[] = {
+       "ZERO", "SRC0"
+};
+
+static const char * const wsa_macro_ear_spkr_pa_gain_text[] = {
+       "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+       "G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum,
+                               wsa_macro_ear_spkr_pa_gain_text);
+
+/* RX INT0 */
+static const struct soc_enum rx0_prim_inp0_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+               0, 7, rx_text);
+
+static const struct soc_enum rx0_prim_inp1_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+               3, 7, rx_text);
+
+static const struct soc_enum rx0_prim_inp2_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+               3, 7, rx_text);
+
+static const struct soc_enum rx0_mix_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+               0, 5, rx_mix_text);
+
+static const struct soc_enum rx0_sidetone_mix_enum =
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text);
+
+static const struct snd_kcontrol_new rx0_prim_inp0_mux =
+       SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux =
+       SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx0_prim_inp2_mux =
+       SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx0_mix_mux =
+       SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx0_sidetone_mix_mux =
+       SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum);
+
+/* RX INT1 */
+static const struct soc_enum rx1_prim_inp0_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+               0, 7, rx_text);
+
+static const struct soc_enum rx1_prim_inp1_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+               3, 7, rx_text);
+
+static const struct soc_enum rx1_prim_inp2_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+               3, 7, rx_text);
+
+static const struct soc_enum rx1_mix_chain_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+               0, 5, rx_mix_text);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux =
+       SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx1_prim_inp1_mux =
+       SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux =
+       SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix_mux =
+       SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum);
+
+static const struct soc_enum rx_mix_ec0_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+               0, 3, rx_mix_ec_text);
+
+static const struct soc_enum rx_mix_ec1_enum =
+       SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+               3, 3, rx_mix_ec_text);
+
+static const struct snd_kcontrol_new rx_mix_ec0_mux =
+       SOC_DAPM_ENUM("WSA RX_MIX EC0_Mux", rx_mix_ec0_enum);
+
+static const struct snd_kcontrol_new rx_mix_ec1_mux =
+       SOC_DAPM_ENUM("WSA RX_MIX EC1_Mux", rx_mix_ec1_enum);
+
+static const struct reg_default wsa_defaults[] = {
+       /* WSA Macro */
+       { CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00},
+       { CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00},
+       { CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+       { CDC_WSA_TOP_TOP_CFG0, 0x00},
+       { CDC_WSA_TOP_TOP_CFG1, 0x00},
+       { CDC_WSA_TOP_FREQ_MCLK, 0x00},
+       { CDC_WSA_TOP_DEBUG_BUS_SEL, 0x00},
+       { CDC_WSA_TOP_DEBUG_EN0, 0x00},
+       { CDC_WSA_TOP_DEBUG_EN1, 0x00},
+       { CDC_WSA_TOP_DEBUG_DSM_LB, 0x88},
+       { CDC_WSA_TOP_RX_I2S_CTL, 0x0C},
+       { CDC_WSA_TOP_TX_I2S_CTL, 0x0C},
+       { CDC_WSA_TOP_I2S_CLK, 0x02},
+       { CDC_WSA_TOP_I2S_RESET, 0x00},
+       { CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, 0x00},
+       { CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0x00},
+       { CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, 0x00},
+       { CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0x00},
+       { CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00},
+       { CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00},
+       { CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00},
+       { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
+       { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
+       { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
+       { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
+       { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
+       { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
+       { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
+       { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
+       { CDC_WSA_INTR_CTRL_CFG, 0x00},
+       { CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00},
+       { CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF},
+       { CDC_WSA_INTR_CTRL_PIN1_STATUS0, 0x00},
+       { CDC_WSA_INTR_CTRL_PIN1_CLEAR0, 0x00},
+       { CDC_WSA_INTR_CTRL_PIN2_MASK0, 0xFF},
+       { CDC_WSA_INTR_CTRL_PIN2_STATUS0, 0x00},
+       { CDC_WSA_INTR_CTRL_PIN2_CLEAR0, 0x00},
+       { CDC_WSA_INTR_CTRL_LEVEL0, 0x00},
+       { CDC_WSA_INTR_CTRL_BYPASS0, 0x00},
+       { CDC_WSA_INTR_CTRL_SET0, 0x00},
+       { CDC_WSA_RX0_RX_PATH_CTL, 0x04},
+       { CDC_WSA_RX0_RX_PATH_CFG0, 0x00},
+       { CDC_WSA_RX0_RX_PATH_CFG1, 0x64},
+       { CDC_WSA_RX0_RX_PATH_CFG2, 0x8F},
+       { CDC_WSA_RX0_RX_PATH_CFG3, 0x00},
+       { CDC_WSA_RX0_RX_VOL_CTL, 0x00},
+       { CDC_WSA_RX0_RX_PATH_MIX_CTL, 0x04},
+       { CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x7E},
+       { CDC_WSA_RX0_RX_VOL_MIX_CTL, 0x00},
+       { CDC_WSA_RX0_RX_PATH_SEC0, 0x04},
+       { CDC_WSA_RX0_RX_PATH_SEC1, 0x08},
+       { CDC_WSA_RX0_RX_PATH_SEC2, 0x00},
+       { CDC_WSA_RX0_RX_PATH_SEC3, 0x00},
+       { CDC_WSA_RX0_RX_PATH_SEC5, 0x00},
+       { CDC_WSA_RX0_RX_PATH_SEC6, 0x00},
+       { CDC_WSA_RX0_RX_PATH_SEC7, 0x00},
+       { CDC_WSA_RX0_RX_PATH_MIX_SEC0, 0x08},
+       { CDC_WSA_RX0_RX_PATH_MIX_SEC1, 0x00},
+       { CDC_WSA_RX0_RX_PATH_DSMDEM_CTL, 0x00},
+       { CDC_WSA_RX1_RX_PATH_CFG0, 0x00},
+       { CDC_WSA_RX1_RX_PATH_CFG1, 0x64},
+       { CDC_WSA_RX1_RX_PATH_CFG2, 0x8F},
+       { CDC_WSA_RX1_RX_PATH_CFG3, 0x00},
+       { CDC_WSA_RX1_RX_VOL_CTL, 0x00},
+       { CDC_WSA_RX1_RX_PATH_MIX_CTL, 0x04},
+       { CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x7E},
+       { CDC_WSA_RX1_RX_VOL_MIX_CTL, 0x00},
+       { CDC_WSA_RX1_RX_PATH_SEC0, 0x04},
+       { CDC_WSA_RX1_RX_PATH_SEC1, 0x08},
+       { CDC_WSA_RX1_RX_PATH_SEC2, 0x00},
+       { CDC_WSA_RX1_RX_PATH_SEC3, 0x00},
+       { CDC_WSA_RX1_RX_PATH_SEC5, 0x00},
+       { CDC_WSA_RX1_RX_PATH_SEC6, 0x00},
+       { CDC_WSA_RX1_RX_PATH_SEC7, 0x00},
+       { CDC_WSA_RX1_RX_PATH_MIX_SEC0, 0x08},
+       { CDC_WSA_RX1_RX_PATH_MIX_SEC1, 0x00},
+       { CDC_WSA_RX1_RX_PATH_DSMDEM_CTL, 0x00},
+       { CDC_WSA_BOOST0_BOOST_PATH_CTL, 0x00},
+       { CDC_WSA_BOOST0_BOOST_CTL, 0xD0},
+       { CDC_WSA_BOOST0_BOOST_CFG1, 0x89},
+       { CDC_WSA_BOOST0_BOOST_CFG2, 0x04},
+       { CDC_WSA_BOOST1_BOOST_PATH_CTL, 0x00},
+       { CDC_WSA_BOOST1_BOOST_CTL, 0xD0},
+       { CDC_WSA_BOOST1_BOOST_CFG1, 0x89},
+       { CDC_WSA_BOOST1_BOOST_CFG2, 0x04},
+       { CDC_WSA_COMPANDER0_CTL0, 0x60},
+       { CDC_WSA_COMPANDER0_CTL1, 0xDB},
+       { CDC_WSA_COMPANDER0_CTL2, 0xFF},
+       { CDC_WSA_COMPANDER0_CTL3, 0x35},
+       { CDC_WSA_COMPANDER0_CTL4, 0xFF},
+       { CDC_WSA_COMPANDER0_CTL5, 0x00},
+       { CDC_WSA_COMPANDER0_CTL6, 0x01},
+       { CDC_WSA_COMPANDER0_CTL7, 0x28},
+       { CDC_WSA_COMPANDER1_CTL0, 0x60},
+       { CDC_WSA_COMPANDER1_CTL1, 0xDB},
+       { CDC_WSA_COMPANDER1_CTL2, 0xFF},
+       { CDC_WSA_COMPANDER1_CTL3, 0x35},
+       { CDC_WSA_COMPANDER1_CTL4, 0xFF},
+       { CDC_WSA_COMPANDER1_CTL5, 0x00},
+       { CDC_WSA_COMPANDER1_CTL6, 0x01},
+       { CDC_WSA_COMPANDER1_CTL7, 0x28},
+       { CDC_WSA_SOFTCLIP0_CRC, 0x00},
+       { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+       { CDC_WSA_SOFTCLIP1_CRC, 0x00},
+       { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+       { CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00},
+       { CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01},
+       { CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00},
+       { CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0, 0x01},
+       { CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_CTL0, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_CTL1, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_FIFO_CTL, 0xA8},
+       { CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC0_STATUS_FIFO, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_CTL0, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_CTL1, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_FIFO_CTL, 0xA8},
+       { CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00},
+       { CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00},
+};
+
+static bool wsa_is_wronly_register(struct device *dev,
+                                       unsigned int reg)
+{
+       switch (reg) {
+       case CDC_WSA_INTR_CTRL_CLR_COMMIT:
+       case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
+       case CDC_WSA_INTR_CTRL_PIN2_CLEAR0:
+               return true;
+       }
+
+       return false;
+}
+
+static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL:
+       case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL:
+       case CDC_WSA_CLK_RST_CTRL_SWR_CONTROL:
+       case CDC_WSA_TOP_TOP_CFG0:
+       case CDC_WSA_TOP_TOP_CFG1:
+       case CDC_WSA_TOP_FREQ_MCLK:
+       case CDC_WSA_TOP_DEBUG_BUS_SEL:
+       case CDC_WSA_TOP_DEBUG_EN0:
+       case CDC_WSA_TOP_DEBUG_EN1:
+       case CDC_WSA_TOP_DEBUG_DSM_LB:
+       case CDC_WSA_TOP_RX_I2S_CTL:
+       case CDC_WSA_TOP_TX_I2S_CTL:
+       case CDC_WSA_TOP_I2S_CLK:
+       case CDC_WSA_TOP_I2S_RESET:
+       case CDC_WSA_RX_INP_MUX_RX_INT0_CFG0:
+       case CDC_WSA_RX_INP_MUX_RX_INT0_CFG1:
+       case CDC_WSA_RX_INP_MUX_RX_INT1_CFG0:
+       case CDC_WSA_RX_INP_MUX_RX_INT1_CFG1:
+       case CDC_WSA_RX_INP_MUX_RX_MIX_CFG0:
+       case CDC_WSA_RX_INP_MUX_RX_EC_CFG0:
+       case CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0:
+       case CDC_WSA_TX0_SPKR_PROT_PATH_CTL:
+       case CDC_WSA_TX0_SPKR_PROT_PATH_CFG0:
+       case CDC_WSA_TX1_SPKR_PROT_PATH_CTL:
+       case CDC_WSA_TX1_SPKR_PROT_PATH_CFG0:
+       case CDC_WSA_TX2_SPKR_PROT_PATH_CTL:
+       case CDC_WSA_TX2_SPKR_PROT_PATH_CFG0:
+       case CDC_WSA_TX3_SPKR_PROT_PATH_CTL:
+       case CDC_WSA_TX3_SPKR_PROT_PATH_CFG0:
+       case CDC_WSA_INTR_CTRL_CFG:
+       case CDC_WSA_INTR_CTRL_PIN1_MASK0:
+       case CDC_WSA_INTR_CTRL_PIN2_MASK0:
+       case CDC_WSA_INTR_CTRL_LEVEL0:
+       case CDC_WSA_INTR_CTRL_BYPASS0:
+       case CDC_WSA_INTR_CTRL_SET0:
+       case CDC_WSA_RX0_RX_PATH_CTL:
+       case CDC_WSA_RX0_RX_PATH_CFG0:
+       case CDC_WSA_RX0_RX_PATH_CFG1:
+       case CDC_WSA_RX0_RX_PATH_CFG2:
+       case CDC_WSA_RX0_RX_PATH_CFG3:
+       case CDC_WSA_RX0_RX_VOL_CTL:
+       case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+       case CDC_WSA_RX0_RX_PATH_MIX_CFG:
+       case CDC_WSA_RX0_RX_VOL_MIX_CTL:
+       case CDC_WSA_RX0_RX_PATH_SEC0:
+       case CDC_WSA_RX0_RX_PATH_SEC1:
+       case CDC_WSA_RX0_RX_PATH_SEC2:
+       case CDC_WSA_RX0_RX_PATH_SEC3:
+       case CDC_WSA_RX0_RX_PATH_SEC5:
+       case CDC_WSA_RX0_RX_PATH_SEC6:
+       case CDC_WSA_RX0_RX_PATH_SEC7:
+       case CDC_WSA_RX0_RX_PATH_MIX_SEC0:
+       case CDC_WSA_RX0_RX_PATH_MIX_SEC1:
+       case CDC_WSA_RX0_RX_PATH_DSMDEM_CTL:
+       case CDC_WSA_RX1_RX_PATH_CTL:
+       case CDC_WSA_RX1_RX_PATH_CFG0:
+       case CDC_WSA_RX1_RX_PATH_CFG1:
+       case CDC_WSA_RX1_RX_PATH_CFG2:
+       case CDC_WSA_RX1_RX_PATH_CFG3:
+       case CDC_WSA_RX1_RX_VOL_CTL:
+       case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+       case CDC_WSA_RX1_RX_PATH_MIX_CFG:
+       case CDC_WSA_RX1_RX_VOL_MIX_CTL:
+       case CDC_WSA_RX1_RX_PATH_SEC0:
+       case CDC_WSA_RX1_RX_PATH_SEC1:
+       case CDC_WSA_RX1_RX_PATH_SEC2:
+       case CDC_WSA_RX1_RX_PATH_SEC3:
+       case CDC_WSA_RX1_RX_PATH_SEC5:
+       case CDC_WSA_RX1_RX_PATH_SEC6:
+       case CDC_WSA_RX1_RX_PATH_SEC7:
+       case CDC_WSA_RX1_RX_PATH_MIX_SEC0:
+       case CDC_WSA_RX1_RX_PATH_MIX_SEC1:
+       case CDC_WSA_RX1_RX_PATH_DSMDEM_CTL:
+       case CDC_WSA_BOOST0_BOOST_PATH_CTL:
+       case CDC_WSA_BOOST0_BOOST_CTL:
+       case CDC_WSA_BOOST0_BOOST_CFG1:
+       case CDC_WSA_BOOST0_BOOST_CFG2:
+       case CDC_WSA_BOOST1_BOOST_PATH_CTL:
+       case CDC_WSA_BOOST1_BOOST_CTL:
+       case CDC_WSA_BOOST1_BOOST_CFG1:
+       case CDC_WSA_BOOST1_BOOST_CFG2:
+       case CDC_WSA_COMPANDER0_CTL0:
+       case CDC_WSA_COMPANDER0_CTL1:
+       case CDC_WSA_COMPANDER0_CTL2:
+       case CDC_WSA_COMPANDER0_CTL3:
+       case CDC_WSA_COMPANDER0_CTL4:
+       case CDC_WSA_COMPANDER0_CTL5:
+       case CDC_WSA_COMPANDER0_CTL7:
+       case CDC_WSA_COMPANDER1_CTL0:
+       case CDC_WSA_COMPANDER1_CTL1:
+       case CDC_WSA_COMPANDER1_CTL2:
+       case CDC_WSA_COMPANDER1_CTL3:
+       case CDC_WSA_COMPANDER1_CTL4:
+       case CDC_WSA_COMPANDER1_CTL5:
+       case CDC_WSA_COMPANDER1_CTL7:
+       case CDC_WSA_SOFTCLIP0_CRC:
+       case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+       case CDC_WSA_SOFTCLIP1_CRC:
+       case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+       case CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL:
+       case CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0:
+       case CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL:
+       case CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0:
+       case CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL:
+       case CDC_WSA_SPLINE_ASRC0_CTL0:
+       case CDC_WSA_SPLINE_ASRC0_CTL1:
+       case CDC_WSA_SPLINE_ASRC0_FIFO_CTL:
+       case CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL:
+       case CDC_WSA_SPLINE_ASRC1_CTL0:
+       case CDC_WSA_SPLINE_ASRC1_CTL1:
+       case CDC_WSA_SPLINE_ASRC1_FIFO_CTL:
+               return true;
+       }
+
+       return false;
+}
+
+static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
+{
+       bool ret;
+
+       ret = wsa_is_rw_register(dev, reg);
+       if (!ret)
+               return wsa_is_wronly_register(dev, reg);
+
+       return ret;
+}
+
+static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CDC_WSA_INTR_CTRL_CLR_COMMIT:
+       case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
+       case CDC_WSA_INTR_CTRL_PIN2_CLEAR0:
+       case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
+       case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
+       case CDC_WSA_COMPANDER0_CTL6:
+       case CDC_WSA_COMPANDER1_CTL6:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FIFO:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
+               return true;
+       }
+
+       return wsa_is_rw_register(dev, reg);
+}
+
+static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
+{
+       /* Update volatile list for rx/tx macros */
+       switch (reg) {
+       case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
+       case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
+       case CDC_WSA_COMPANDER0_CTL6:
+       case CDC_WSA_COMPANDER1_CTL6:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC0_STATUS_FIFO:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB:
+       case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
+               return true;
+       }
+       return false;
+}
+
+static const struct regmap_config wsa_regmap_config = {
+       .name = "wsa_macro",
+       .reg_bits = 16,
+       .val_bits = 32, /* 8 but with 32 bit read/write */
+       .reg_stride = 4,
+       .cache_type = REGCACHE_FLAT,
+       .reg_defaults = wsa_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wsa_defaults),
+       .max_register = WSA_MAX_OFFSET,
+       .writeable_reg = wsa_is_writeable_register,
+       .volatile_reg = wsa_is_volatile_register,
+       .readable_reg = wsa_is_readable_register,
+};
+
+/**
+ * wsa_macro_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @component: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode)
+{
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       wsa->spkr_mode = mode;
+
+       switch (mode) {
+       case WSA_MACRO_SPKR_MODE_1:
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00);
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00);
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00);
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00);
+               snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44);
+               snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44);
+               break;
+       default:
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80);
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80);
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01);
+               snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01);
+               snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58);
+               snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58);
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(wsa_macro_set_spkr_mode);
+
+static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+                                               u8 int_prim_fs_rate_reg_val,
+                                               u32 sample_rate)
+{
+       u8 int_1_mix1_inp;
+       u32 j, port;
+       u16 int_mux_cfg0, int_mux_cfg1;
+       u16 int_fs_reg;
+       u8 int_mux_cfg0_val, int_mux_cfg1_val;
+       u8 inp0_sel, inp1_sel, inp2_sel;
+       struct snd_soc_component *component = dai->component;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) {
+               int_1_mix1_inp = port;
+               if ((int_1_mix1_inp < WSA_MACRO_RX0) || (int_1_mix1_inp > WSA_MACRO_RX_MIX1)) {
+                       dev_err(component->dev, "%s: Invalid RX port, Dai ID is %d\n",
+                               __func__, dai->id);
+                       return -EINVAL;
+               }
+
+               int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0;
+
+               /*
+                * Loop through all interpolator MUX inputs and find out
+                * to which interpolator input, the cdc_dma rx port
+                * is connected
+                */
+               for (j = 0; j < NUM_INTERPOLATORS; j++) {
+                       int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
+                       int_mux_cfg0_val = snd_soc_component_read(component,
+                                                                 int_mux_cfg0);
+                       int_mux_cfg1_val = snd_soc_component_read(component,
+                                                                 int_mux_cfg1);
+                       inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1;
+                       inp1_sel = (int_mux_cfg0_val >> WSA_MACRO_MUX_INP_SHFT) &
+                                               WSA_MACRO_MUX_INP_MASK1;
+                       inp2_sel = (int_mux_cfg1_val >> WSA_MACRO_MUX_INP_SHFT) &
+                                               WSA_MACRO_MUX_INP_MASK1;
+                       if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+                           (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+                           (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
+                               int_fs_reg = CDC_WSA_RX0_RX_PATH_CTL +
+                                            WSA_MACRO_RX_PATH_OFFSET * j;
+                               /* sample_rate is in Hz */
+                               snd_soc_component_update_bits(component, int_fs_reg,
+                                                             WSA_MACRO_FS_RATE_MASK,
+                                                             int_prim_fs_rate_reg_val);
+                       }
+                       int_mux_cfg0 += WSA_MACRO_MUX_CFG_OFFSET;
+               }
+       }
+
+       return 0;
+}
+
+static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+                                              u8 int_mix_fs_rate_reg_val,
+                                              u32 sample_rate)
+{
+       u8 int_2_inp;
+       u32 j, port;
+       u16 int_mux_cfg1, int_fs_reg;
+       u8 int_mux_cfg1_val;
+       struct snd_soc_component *component = dai->component;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) {
+               int_2_inp = port;
+               if ((int_2_inp < WSA_MACRO_RX0) || (int_2_inp > WSA_MACRO_RX_MIX1)) {
+                       dev_err(component->dev, "%s: Invalid RX port, Dai ID is %d\n",
+                               __func__, dai->id);
+                       return -EINVAL;
+               }
+
+               int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1;
+               for (j = 0; j < NUM_INTERPOLATORS; j++) {
+                       int_mux_cfg1_val = snd_soc_component_read(component,
+                                                       int_mux_cfg1) &
+                                                       WSA_MACRO_MUX_INP_MASK1;
+                       if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
+                               int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL +
+                                       WSA_MACRO_RX_PATH_OFFSET * j;
+
+                               snd_soc_component_update_bits(component,
+                                                     int_fs_reg,
+                                                     WSA_MACRO_FS_RATE_MASK,
+                                                     int_mix_fs_rate_reg_val);
+                       }
+                       int_mux_cfg1 += WSA_MACRO_MUX_CFG_OFFSET;
+               }
+       }
+       return 0;
+}
+
+static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai,
+                                          u32 sample_rate)
+{
+       int rate_val = 0;
+       int i, ret;
+
+       /* set mixing path rate */
+       for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) {
+               if (sample_rate == int_mix_sample_rate_val[i].sample_rate) {
+                       rate_val = int_mix_sample_rate_val[i].rate_val;
+                       break;
+               }
+       }
+       if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || (rate_val < 0))
+               goto prim_rate;
+
+       ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate);
+prim_rate:
+       /* set primary path sample rate */
+       for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
+               if (sample_rate == int_prim_sample_rate_val[i].sample_rate) {
+                       rate_val = int_prim_sample_rate_val[i].rate_val;
+                       break;
+               }
+       }
+       if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || (rate_val < 0))
+               return -EINVAL;
+
+       ret = wsa_macro_set_prim_interpolator_rate(dai, (u8) rate_val, sample_rate);
+
+       return ret;
+}
+
+static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
+                              struct snd_pcm_hw_params *params,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       int ret;
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               ret = wsa_macro_set_interpolator_rate(dai, params_rate(params));
+               if (ret) {
+                       dev_err(component->dev,
+                               "%s: cannot set sample rate: %u\n",
+                               __func__, params_rate(params));
+                       return ret;
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+                                    unsigned int *tx_num, unsigned int *tx_slot,
+                                    unsigned int *rx_num, unsigned int *rx_slot)
+{
+       struct snd_soc_component *component = dai->component;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       u16 val, mask = 0, cnt = 0, temp;
+
+       switch (dai->id) {
+       case WSA_MACRO_AIF_VI:
+               *tx_slot = wsa->active_ch_mask[dai->id];
+               *tx_num = wsa->active_ch_cnt[dai->id];
+               break;
+       case WSA_MACRO_AIF1_PB:
+       case WSA_MACRO_AIF_MIX1_PB:
+               for_each_set_bit(temp, &wsa->active_ch_mask[dai->id],
+                                       WSA_MACRO_RX_MAX) {
+                       mask |= (1 << temp);
+                       if (++cnt == WSA_MACRO_MAX_DMA_CH_PER_PORT)
+                               break;
+               }
+               if (mask & 0x0C)
+                       mask = mask >> 0x2;
+               *rx_slot = mask;
+               *rx_num = cnt;
+               break;
+       case WSA_MACRO_AIF_ECHO:
+               val = snd_soc_component_read(component, CDC_WSA_RX_INP_MUX_RX_MIX_CFG0);
+               if (val & WSA_MACRO_EC_MIX_TX1_MASK) {
+                       mask |= 0x2;
+                       cnt++;
+               }
+               if (val & WSA_MACRO_EC_MIX_TX0_MASK) {
+                       mask |= 0x1;
+                       cnt++;
+               }
+               *tx_slot = mask;
+               *tx_num = cnt;
+               break;
+       default:
+               dev_err(component->dev, "%s: Invalid AIF\n", __func__);
+               break;
+       }
+       return 0;
+}
+
+static struct snd_soc_dai_ops wsa_macro_dai_ops = {
+       .hw_params = wsa_macro_hw_params,
+       .get_channel_map = wsa_macro_get_channel_map,
+};
+
+static struct snd_soc_dai_driver wsa_macro_dai[] = {
+       {
+               .name = "wsa_macro_rx1",
+               .id = WSA_MACRO_AIF1_PB,
+               .playback = {
+                       .stream_name = "WSA_AIF1 Playback",
+                       .rates = WSA_MACRO_RX_RATES,
+                       .formats = WSA_MACRO_RX_FORMATS,
+                       .rate_max = 384000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &wsa_macro_dai_ops,
+       },
+       {
+               .name = "wsa_macro_rx_mix",
+               .id = WSA_MACRO_AIF_MIX1_PB,
+               .playback = {
+                       .stream_name = "WSA_AIF_MIX1 Playback",
+                       .rates = WSA_MACRO_RX_MIX_RATES,
+                       .formats = WSA_MACRO_RX_FORMATS,
+                       .rate_max = 192000,
+                       .rate_min = 48000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &wsa_macro_dai_ops,
+       },
+       {
+               .name = "wsa_macro_vifeedback",
+               .id = WSA_MACRO_AIF_VI,
+               .capture = {
+                       .stream_name = "WSA_AIF_VI Capture",
+                       .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+                       .formats = WSA_MACRO_RX_FORMATS,
+                       .rate_max = 48000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 4,
+               },
+               .ops = &wsa_macro_dai_ops,
+       },
+       {
+               .name = "wsa_macro_echo",
+               .id = WSA_MACRO_AIF_ECHO,
+               .capture = {
+                       .stream_name = "WSA_AIF_ECHO Capture",
+                       .rates = WSA_MACRO_ECHO_RATES,
+                       .formats = WSA_MACRO_ECHO_FORMATS,
+                       .rate_max = 48000,
+                       .rate_min = 8000,
+                       .channels_min = 1,
+                       .channels_max = 2,
+               },
+               .ops = &wsa_macro_dai_ops,
+       },
+};
+
+static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable)
+{
+       struct regmap *regmap = wsa->regmap;
+
+       if (mclk_enable) {
+               if (wsa->wsa_mclk_users == 0) {
+                       regcache_mark_dirty(regmap);
+                       regcache_sync(regmap);
+                       /* 9.6MHz MCLK, set value 0x00 if other frequency */
+                       regmap_update_bits(regmap, CDC_WSA_TOP_FREQ_MCLK, 0x01, 0x01);
+                       regmap_update_bits(regmap,
+                                          CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
+                                          CDC_WSA_MCLK_EN_MASK,
+                                          CDC_WSA_MCLK_ENABLE);
+                       regmap_update_bits(regmap,
+                                          CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_WSA_FS_CNT_EN_MASK,
+                                          CDC_WSA_FS_CNT_ENABLE);
+               }
+               wsa->wsa_mclk_users++;
+       } else {
+               if (wsa->wsa_mclk_users <= 0) {
+                       dev_err(wsa->dev, "clock already disabled\n");
+                       wsa->wsa_mclk_users = 0;
+                       return;
+               }
+               wsa->wsa_mclk_users--;
+               if (wsa->wsa_mclk_users == 0) {
+                       regmap_update_bits(regmap,
+                                          CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL,
+                                          CDC_WSA_FS_CNT_EN_MASK,
+                                          CDC_WSA_FS_CNT_DISABLE);
+                       regmap_update_bits(regmap,
+                                          CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
+                                          CDC_WSA_MCLK_EN_MASK,
+                                          CDC_WSA_MCLK_DISABLE);
+               }
+       }
+}
+
+static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU);
+       return 0;
+}
+
+static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       u32 tx_reg0, tx_reg1;
+
+       if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+               tx_reg0 = CDC_WSA_TX0_SPKR_PROT_PATH_CTL;
+               tx_reg1 = CDC_WSA_TX1_SPKR_PROT_PATH_CTL;
+       } else if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+               tx_reg0 = CDC_WSA_TX2_SPKR_PROT_PATH_CTL;
+               tx_reg1 = CDC_WSA_TX3_SPKR_PROT_PATH_CTL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+                       /* Enable V&I sensing */
+               snd_soc_component_update_bits(component, tx_reg0,
+                                             CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_RESET);
+               snd_soc_component_update_bits(component, tx_reg1,
+                                             CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_RESET);
+               snd_soc_component_update_bits(component, tx_reg0,
+                                             CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+               snd_soc_component_update_bits(component, tx_reg1,
+                                             CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+               snd_soc_component_update_bits(component, tx_reg0,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_ENABLE);
+               snd_soc_component_update_bits(component, tx_reg1,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_ENABLE);
+               snd_soc_component_update_bits(component, tx_reg0,
+                                             CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_NO_RESET);
+               snd_soc_component_update_bits(component, tx_reg1,
+                                             CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_NO_RESET);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Disable V&I sensing */
+               snd_soc_component_update_bits(component, tx_reg0,
+                                             CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_RESET);
+               snd_soc_component_update_bits(component, tx_reg1,
+                                             CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_RESET);
+               snd_soc_component_update_bits(component, tx_reg0,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_DISABLE);
+               snd_soc_component_update_bits(component, tx_reg1,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+                                             CDC_WSA_TX_SPKR_PROT_CLK_DISABLE);
+               break;
+       }
+
+       return 0;
+}
+
+static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
+                                    struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 gain_reg;
+       int val;
+
+       switch (w->reg) {
+       case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+               gain_reg = CDC_WSA_RX0_RX_VOL_MIX_CTL;
+               break;
+       case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+               gain_reg = CDC_WSA_RX1_RX_VOL_MIX_CTL;
+               break;
+       default:
+               return 0;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               val = snd_soc_component_read(component, gain_reg);
+               snd_soc_component_write(component, gain_reg, val);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component, w->reg,
+                                             CDC_WSA_RX_PATH_MIX_CLK_EN_MASK,
+                                             CDC_WSA_RX_PATH_MIX_CLK_DISABLE);
+               break;
+       }
+
+       return 0;
+}
+
+static void wsa_macro_hd2_control(struct snd_soc_component *component,
+                                 u16 reg, int event)
+{
+       u16 hd2_scale_reg;
+       u16 hd2_enable_reg;
+
+       if (reg == CDC_WSA_RX0_RX_PATH_CTL) {
+               hd2_scale_reg = CDC_WSA_RX0_RX_PATH_SEC3;
+               hd2_enable_reg = CDC_WSA_RX0_RX_PATH_CFG0;
+       }
+       if (reg == CDC_WSA_RX1_RX_PATH_CTL) {
+               hd2_scale_reg = CDC_WSA_RX1_RX_PATH_SEC3;
+               hd2_enable_reg = CDC_WSA_RX1_RX_PATH_CFG0;
+       }
+
+       if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+               snd_soc_component_update_bits(component, hd2_scale_reg,
+                                             CDC_WSA_RX_PATH_HD2_ALPHA_MASK,
+                                             0x10);
+               snd_soc_component_update_bits(component, hd2_scale_reg,
+                                             CDC_WSA_RX_PATH_HD2_SCALE_MASK,
+                                             0x1);
+               snd_soc_component_update_bits(component, hd2_enable_reg,
+                                             CDC_WSA_RX_PATH_HD2_EN_MASK,
+                                             CDC_WSA_RX_PATH_HD2_ENABLE);
+       }
+
+       if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_update_bits(component, hd2_enable_reg,
+                                             CDC_WSA_RX_PATH_HD2_EN_MASK, 0);
+               snd_soc_component_update_bits(component, hd2_scale_reg,
+                                             CDC_WSA_RX_PATH_HD2_SCALE_MASK,
+                                             0);
+               snd_soc_component_update_bits(component, hd2_scale_reg,
+                                             CDC_WSA_RX_PATH_HD2_ALPHA_MASK,
+                                             0);
+       }
+}
+
+static int wsa_macro_config_compander(struct snd_soc_component *component,
+                                     int comp, int event)
+{
+       u16 comp_ctl0_reg, rx_path_cfg0_reg;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       if (!wsa->comp_enabled[comp])
+               return 0;
+
+       comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 +
+                                       (comp * WSA_MACRO_RX_COMP_OFFSET);
+       rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 +
+                                       (comp * WSA_MACRO_RX_PATH_OFFSET);
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* Enable Compander Clock */
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_CLK_EN_MASK,
+                                             CDC_WSA_COMPANDER_CLK_ENABLE);
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_SOFT_RST_MASK,
+                                             CDC_WSA_COMPANDER_SOFT_RST_ENABLE);
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_SOFT_RST_MASK,
+                                             0);
+               snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+                                             CDC_WSA_RX_PATH_COMP_EN_MASK,
+                                             CDC_WSA_RX_PATH_COMP_ENABLE);
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_HALT_MASK,
+                                             CDC_WSA_COMPANDER_HALT);
+               snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+                                             CDC_WSA_RX_PATH_COMP_EN_MASK, 0);
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_SOFT_RST_MASK,
+                                             CDC_WSA_COMPANDER_SOFT_RST_ENABLE);
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_SOFT_RST_MASK,
+                                             0);
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_CLK_EN_MASK, 0);
+               snd_soc_component_update_bits(component, comp_ctl0_reg,
+                                             CDC_WSA_COMPANDER_HALT_MASK, 0);
+       }
+
+       return 0;
+}
+
+static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component,
+                                        struct wsa_macro *wsa,
+                                        int path,
+                                        bool enable)
+{
+       u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC +
+                       (path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+       u8 softclip_mux_mask = (1 << path);
+       u8 softclip_mux_value = (1 << path);
+
+       if (enable) {
+               if (wsa->softclip_clk_users[path] == 0) {
+                       snd_soc_component_update_bits(component,
+                                               softclip_clk_reg,
+                                               CDC_WSA_SOFTCLIP_CLK_EN_MASK,
+                                               CDC_WSA_SOFTCLIP_CLK_ENABLE);
+                       snd_soc_component_update_bits(component,
+                               CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0,
+                               softclip_mux_mask, softclip_mux_value);
+               }
+               wsa->softclip_clk_users[path]++;
+       } else {
+               wsa->softclip_clk_users[path]--;
+               if (wsa->softclip_clk_users[path] == 0) {
+                       snd_soc_component_update_bits(component,
+                                               softclip_clk_reg,
+                                               CDC_WSA_SOFTCLIP_CLK_EN_MASK,
+                                               0);
+                       snd_soc_component_update_bits(component,
+                               CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0,
+                               softclip_mux_mask, 0x00);
+               }
+       }
+}
+
+static int wsa_macro_config_softclip(struct snd_soc_component *component,
+                                    int path, int event)
+{
+       u16 softclip_ctrl_reg;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       int softclip_path = 0;
+
+       if (path == WSA_MACRO_COMP1)
+               softclip_path = WSA_MACRO_SOFTCLIP0;
+       else if (path == WSA_MACRO_COMP2)
+               softclip_path = WSA_MACRO_SOFTCLIP1;
+
+       if (!wsa->is_softclip_on[softclip_path])
+               return 0;
+
+       softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL +
+                               (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* Enable Softclip clock and mux */
+               wsa_macro_enable_softclip_clk(component, wsa, softclip_path,
+                                             true);
+               /* Enable Softclip control */
+               snd_soc_component_update_bits(component, softclip_ctrl_reg,
+                                             CDC_WSA_SOFTCLIP_EN_MASK,
+                                             CDC_WSA_SOFTCLIP_ENABLE);
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               snd_soc_component_update_bits(component, softclip_ctrl_reg,
+                                             CDC_WSA_SOFTCLIP_EN_MASK, 0);
+               wsa_macro_enable_softclip_clk(component, wsa, softclip_path,
+                                             false);
+       }
+
+       return 0;
+}
+
+static bool wsa_macro_adie_lb(struct snd_soc_component *component,
+                             int interp_idx)
+{
+       u16 int_mux_cfg0,  int_mux_cfg1;
+       u8 int_mux_cfg0_val, int_mux_cfg1_val;
+       u8 int_n_inp0, int_n_inp1, int_n_inp2;
+
+       int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
+       int_mux_cfg1 = int_mux_cfg0 + 4;
+       int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+       int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+       int_n_inp0 = int_mux_cfg0_val & 0x0F;
+       if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
+               int_n_inp0 == INTn_1_INP_SEL_DEC1)
+               return true;
+
+       int_n_inp1 = int_mux_cfg0_val >> 4;
+       if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
+               int_n_inp1 == INTn_1_INP_SEL_DEC1)
+               return true;
+
+       int_n_inp2 = int_mux_cfg1_val >> 4;
+       if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
+               int_n_inp2 == INTn_1_INP_SEL_DEC1)
+               return true;
+
+       return false;
+}
+
+static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w,
+                                     struct snd_kcontrol *kcontrol,
+                                     int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 reg;
+
+       reg = CDC_WSA_RX0_RX_PATH_CTL + WSA_MACRO_RX_PATH_OFFSET * w->shift;
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (wsa_macro_adie_lb(component, w->shift)) {
+                       snd_soc_component_update_bits(component, reg,
+                                            CDC_WSA_RX_PATH_CLK_EN_MASK,
+                                            CDC_WSA_RX_PATH_CLK_ENABLE);
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind)
+{
+       u16 prim_int_reg = 0;
+
+       switch (reg) {
+       case CDC_WSA_RX0_RX_PATH_CTL:
+       case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+               prim_int_reg = CDC_WSA_RX0_RX_PATH_CTL;
+               *ind = 0;
+               break;
+       case CDC_WSA_RX1_RX_PATH_CTL:
+       case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+               prim_int_reg = CDC_WSA_RX1_RX_PATH_CTL;
+               *ind = 1;
+               break;
+       }
+
+       return prim_int_reg;
+}
+
+static int wsa_macro_enable_prim_interpolator(struct snd_soc_component *component,
+                                             u16 reg, int event)
+{
+       u16 prim_int_reg;
+       u16 ind = 0;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       prim_int_reg = wsa_macro_interp_get_primary_reg(reg, &ind);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wsa->prim_int_users[ind]++;
+               if (wsa->prim_int_users[ind] == 1) {
+                       snd_soc_component_update_bits(component,
+                                                     prim_int_reg + WSA_MACRO_RX_PATH_CFG3_OFFSET,
+                                                     CDC_WSA_RX_DC_DCOEFF_MASK,
+                                                     0x3);
+                       snd_soc_component_update_bits(component, prim_int_reg,
+                                       CDC_WSA_RX_PATH_PGA_MUTE_EN_MASK,
+                                       CDC_WSA_RX_PATH_PGA_MUTE_ENABLE);
+                       wsa_macro_hd2_control(component, prim_int_reg, event);
+                       snd_soc_component_update_bits(component,
+                               prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET,
+                               CDC_WSA_RX_DSMDEM_CLK_EN_MASK,
+                               CDC_WSA_RX_DSMDEM_CLK_ENABLE);
+               }
+               if ((reg != prim_int_reg) &&
+                   ((snd_soc_component_read(
+                               component, prim_int_reg)) & 0x10))
+                       snd_soc_component_update_bits(component, reg,
+                                       0x10, 0x10);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               wsa->prim_int_users[ind]--;
+               if (wsa->prim_int_users[ind] == 0) {
+                       snd_soc_component_update_bits(component,
+                               prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET,
+                               CDC_WSA_RX_DSMDEM_CLK_EN_MASK, 0);
+                       wsa_macro_hd2_control(component, prim_int_reg, event);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component,
+                                         struct wsa_macro *wsa,
+                                         int event, int gain_reg)
+{
+       int comp_gain_offset, val;
+
+       switch (wsa->spkr_mode) {
+       /* Compander gain in WSA_MACRO_SPKR_MODE1 case is 12 dB */
+       case WSA_MACRO_SPKR_MODE_1:
+               comp_gain_offset = -12;
+               break;
+       /* Default case compander gain is 15 dB */
+       default:
+               comp_gain_offset = -15;
+               break;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* Apply ear spkr gain only if compander is enabled */
+               if (wsa->comp_enabled[WSA_MACRO_COMP1] &&
+                   (gain_reg == CDC_WSA_RX0_RX_VOL_CTL) &&
+                   (wsa->ear_spkr_gain != 0)) {
+                       /* For example, val is -8(-12+5-1) for 4dB of gain */
+                       val = comp_gain_offset + wsa->ear_spkr_gain - 1;
+                       snd_soc_component_write(component, gain_reg, val);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /*
+                * Reset RX0 volume to 0 dB if compander is enabled and
+                * ear_spkr_gain is non-zero.
+                */
+               if (wsa->comp_enabled[WSA_MACRO_COMP1] &&
+                   (gain_reg == CDC_WSA_RX0_RX_VOL_CTL) &&
+                   (wsa->ear_spkr_gain != 0)) {
+                       snd_soc_component_write(component, gain_reg, 0x0);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
+                                        struct snd_kcontrol *kcontrol,
+                                        int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 gain_reg;
+       u16 reg;
+       int val;
+       int offset_val = 0;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       if (w->shift == WSA_MACRO_COMP1) {
+               reg = CDC_WSA_RX0_RX_PATH_CTL;
+               gain_reg = CDC_WSA_RX0_RX_VOL_CTL;
+       } else if (w->shift == WSA_MACRO_COMP2) {
+               reg = CDC_WSA_RX1_RX_PATH_CTL;
+               gain_reg = CDC_WSA_RX1_RX_VOL_CTL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Reset if needed */
+               wsa_macro_enable_prim_interpolator(component, reg, event);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               wsa_macro_config_compander(component, w->shift, event);
+               wsa_macro_config_softclip(component, w->shift, event);
+               /* apply gain after int clk is enabled */
+               if ((wsa->spkr_gain_offset == WSA_MACRO_GAIN_OFFSET_M1P5_DB) &&
+                   (wsa->comp_enabled[WSA_MACRO_COMP1] ||
+                    wsa->comp_enabled[WSA_MACRO_COMP2])) {
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX0_RX_PATH_SEC1,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX0_RX_PATH_MIX_SEC0,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX1_RX_PATH_SEC1,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX1_RX_PATH_MIX_SEC0,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+                       offset_val = -2;
+               }
+               val = snd_soc_component_read(component, gain_reg);
+               val += offset_val;
+               snd_soc_component_write(component, gain_reg, val);
+               wsa_macro_config_ear_spkr_gain(component, wsa,
+                                               event, gain_reg);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               wsa_macro_config_compander(component, w->shift, event);
+               wsa_macro_config_softclip(component, w->shift, event);
+               wsa_macro_enable_prim_interpolator(component, reg, event);
+               if ((wsa->spkr_gain_offset == WSA_MACRO_GAIN_OFFSET_M1P5_DB) &&
+                   (wsa->comp_enabled[WSA_MACRO_COMP1] ||
+                    wsa->comp_enabled[WSA_MACRO_COMP2])) {
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX0_RX_PATH_SEC1,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX0_RX_PATH_MIX_SEC0,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX1_RX_PATH_SEC1,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+                       snd_soc_component_update_bits(component,
+                                       CDC_WSA_RX1_RX_PATH_MIX_SEC0,
+                                       CDC_WSA_RX_PGA_HALF_DB_MASK,
+                                       CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+                       offset_val = 2;
+                       val = snd_soc_component_read(component, gain_reg);
+                       val += offset_val;
+                       snd_soc_component_write(component, gain_reg, val);
+               }
+               wsa_macro_config_ear_spkr_gain(component, wsa,
+                                               event, gain_reg);
+               break;
+       }
+
+       return 0;
+}
+
+static int wsa_macro_spk_boost_event(struct snd_soc_dapm_widget *w,
+                                    struct snd_kcontrol *kcontrol,
+                                    int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       u16 boost_path_ctl, boost_path_cfg1;
+       u16 reg, reg_mix;
+
+       if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) {
+               boost_path_ctl = CDC_WSA_BOOST0_BOOST_PATH_CTL;
+               boost_path_cfg1 = CDC_WSA_RX0_RX_PATH_CFG1;
+               reg = CDC_WSA_RX0_RX_PATH_CTL;
+               reg_mix = CDC_WSA_RX0_RX_PATH_MIX_CTL;
+       } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) {
+               boost_path_ctl = CDC_WSA_BOOST1_BOOST_PATH_CTL;
+               boost_path_cfg1 = CDC_WSA_RX1_RX_PATH_CFG1;
+               reg = CDC_WSA_RX1_RX_PATH_CTL;
+               reg_mix = CDC_WSA_RX1_RX_PATH_MIX_CTL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_component_update_bits(component, boost_path_cfg1,
+                                             CDC_WSA_RX_PATH_SMART_BST_EN_MASK,
+                                             CDC_WSA_RX_PATH_SMART_BST_ENABLE);
+               snd_soc_component_update_bits(component, boost_path_ctl,
+                                             CDC_WSA_BOOST_PATH_CLK_EN_MASK,
+                                             CDC_WSA_BOOST_PATH_CLK_ENABLE);
+               if ((snd_soc_component_read(component, reg_mix)) & 0x10)
+                       snd_soc_component_update_bits(component, reg_mix,
+                                               0x10, 0x00);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_component_update_bits(component, reg, 0x10, 0x00);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component, boost_path_ctl,
+                                             CDC_WSA_BOOST_PATH_CLK_EN_MASK,
+                                             CDC_WSA_BOOST_PATH_CLK_DISABLE);
+               snd_soc_component_update_bits(component, boost_path_cfg1,
+                                             CDC_WSA_RX_PATH_SMART_BST_EN_MASK,
+                                             CDC_WSA_RX_PATH_SMART_BST_DISABLE);
+               break;
+       }
+
+       return 0;
+}
+
+static int wsa_macro_enable_echo(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *kcontrol,
+                                int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       u16 val, ec_tx, ec_hq_reg;
+
+       val = snd_soc_component_read(component, CDC_WSA_RX_INP_MUX_RX_MIX_CFG0);
+
+       switch (w->shift) {
+       case WSA_MACRO_EC0_MUX:
+               val = val & CDC_WSA_RX_MIX_TX0_SEL_MASK;
+               ec_tx = val - 1;
+               break;
+       case WSA_MACRO_EC1_MUX:
+               val = val & CDC_WSA_RX_MIX_TX1_SEL_MASK;
+               ec_tx = (val >> CDC_WSA_RX_MIX_TX1_SEL_SHFT) - 1;
+               break;
+       }
+
+       if (wsa->ec_hq[ec_tx]) {
+               ec_hq_reg = CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL + 0x40 * ec_tx;
+               snd_soc_component_update_bits(component, ec_hq_reg,
+                                            CDC_WSA_EC_HQ_EC_CLK_EN_MASK,
+                                            CDC_WSA_EC_HQ_EC_CLK_ENABLE);
+               ec_hq_reg = CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 + 0x40 * ec_tx;
+               /* default set to 48k */
+               snd_soc_component_update_bits(component, ec_hq_reg,
+                                     CDC_WSA_EC_HQ_EC_REF_PCM_RATE_MASK,
+                                     CDC_WSA_EC_HQ_EC_REF_PCM_RATE_48K);
+       }
+
+       return 0;
+}
+
+static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = wsa->ec_hq[ec_tx];
+
+       return 0;
+}
+
+static int wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+       int value = ucontrol->value.integer.value[0];
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       wsa->ec_hq[ec_tx] = value;
+
+       return 0;
+}
+
+static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = wsa->comp_enabled[comp];
+       return 0;
+}
+
+static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+       int value = ucontrol->value.integer.value[0];
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       wsa->comp_enabled[comp] = value;
+
+       return 0;
+}
+
+static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = wsa->ear_spkr_gain;
+
+       return 0;
+}
+
+static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       wsa->ear_spkr_gain =  ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget =
+               snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component =
+                               snd_soc_dapm_to_component(widget->dapm);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] =
+                       wsa->rx_port_value[widget->shift];
+       return 0;
+}
+
+static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget =
+               snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component =
+                               snd_soc_dapm_to_component(widget->dapm);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       struct snd_soc_dapm_update *update = NULL;
+       u32 rx_port_value = ucontrol->value.integer.value[0];
+       u32 bit_input;
+       u32 aif_rst;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+       aif_rst = wsa->rx_port_value[widget->shift];
+       if (!rx_port_value) {
+               if (aif_rst == 0) {
+                       dev_err(component->dev, "%s: AIF reset already\n", __func__);
+                       return 0;
+               }
+               if (aif_rst >= WSA_MACRO_RX_MAX) {
+                       dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
+                       return 0;
+               }
+       }
+       wsa->rx_port_value[widget->shift] = rx_port_value;
+
+       bit_input = widget->shift;
+
+       switch (rx_port_value) {
+       case 0:
+               if (wsa->active_ch_cnt[aif_rst]) {
+                       clear_bit(bit_input,
+                                 &wsa->active_ch_mask[aif_rst]);
+                       wsa->active_ch_cnt[aif_rst]--;
+               }
+               break;
+       case 1:
+       case 2:
+               set_bit(bit_input,
+                       &wsa->active_ch_mask[rx_port_value]);
+               wsa->active_ch_cnt[rx_port_value]++;
+               break;
+       default:
+               dev_err(component->dev,
+                       "%s: Invalid AIF_ID for WSA RX MUX %d\n",
+                       __func__, rx_port_value);
+               return -EINVAL;
+       }
+
+       snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+                                       rx_port_value, e, update);
+       return 0;
+}
+
+static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       int path = ((struct soc_mixer_control *)kcontrol->private_value)->shift;
+
+       ucontrol->value.integer.value[0] = wsa->is_softclip_on[path];
+
+       return 0;
+}
+
+static int wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       int path = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+
+       wsa->is_softclip_on[path] =  ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wsa_macro_snd_controls[] = {
+       SOC_ENUM_EXT("EAR SPKR PA Gain", wsa_macro_ear_spkr_pa_gain_enum,
+                    wsa_macro_ear_spkr_pa_gain_get,
+                    wsa_macro_ear_spkr_pa_gain_put),
+       SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM,
+                       WSA_MACRO_SOFTCLIP0, 1, 0,
+                       wsa_macro_soft_clip_enable_get,
+                       wsa_macro_soft_clip_enable_put),
+       SOC_SINGLE_EXT("WSA_Softclip1 Enable", SND_SOC_NOPM,
+                       WSA_MACRO_SOFTCLIP1, 1, 0,
+                       wsa_macro_soft_clip_enable_get,
+                       wsa_macro_soft_clip_enable_put),
+
+       SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume", CDC_WSA_RX0_RX_VOL_CTL,
+                         -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume", CDC_WSA_RX1_RX_VOL_CTL,
+                         -84, 40, digital_gain),
+
+       SOC_SINGLE("WSA_RX0 Digital Mute", CDC_WSA_RX0_RX_PATH_CTL, 4, 1, 0),
+       SOC_SINGLE("WSA_RX1 Digital Mute", CDC_WSA_RX1_RX_PATH_CTL, 4, 1, 0),
+       SOC_SINGLE("WSA_RX0_MIX Digital Mute", CDC_WSA_RX0_RX_PATH_MIX_CTL, 4,
+                  1, 0),
+       SOC_SINGLE("WSA_RX1_MIX Digital Mute", CDC_WSA_RX1_RX_PATH_MIX_CTL, 4,
+                  1, 0),
+       SOC_SINGLE_EXT("WSA_COMP1 Switch", SND_SOC_NOPM, WSA_MACRO_COMP1, 1, 0,
+                      wsa_macro_get_compander, wsa_macro_set_compander),
+       SOC_SINGLE_EXT("WSA_COMP2 Switch", SND_SOC_NOPM, WSA_MACRO_COMP2, 1, 0,
+                      wsa_macro_get_compander, wsa_macro_set_compander),
+       SOC_SINGLE_EXT("WSA_RX0 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX0, 1, 0,
+                      wsa_macro_get_ec_hq, wsa_macro_set_ec_hq),
+       SOC_SINGLE_EXT("WSA_RX1 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX1, 1, 0,
+                      wsa_macro_get_ec_hq, wsa_macro_set_ec_hq),
+};
+
+static const struct soc_enum rx_mux_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text);
+
+static const struct snd_kcontrol_new rx_mux[WSA_MACRO_RX_MAX] = {
+       SOC_DAPM_ENUM_EXT("WSA RX0 Mux", rx_mux_enum,
+                         wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+       SOC_DAPM_ENUM_EXT("WSA RX1 Mux", rx_mux_enum,
+                         wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+       SOC_DAPM_ENUM_EXT("WSA RX_MIX0 Mux", rx_mux_enum,
+                         wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+       SOC_DAPM_ENUM_EXT("WSA RX_MIX1 Mux", rx_mux_enum,
+                         wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+};
+
+static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       u32 spk_tx_id = mixer->shift;
+       u32 dai_id = widget->shift;
+
+       if (test_bit(spk_tx_id, &wsa->active_ch_mask[dai_id]))
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+       struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+       u32 enable = ucontrol->value.integer.value[0];
+       u32 spk_tx_id = mixer->shift;
+
+       if (enable) {
+               if (spk_tx_id == WSA_MACRO_TX0 &&
+                       !test_bit(WSA_MACRO_TX0,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+                       set_bit(WSA_MACRO_TX0,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+                       wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+               }
+               if (spk_tx_id == WSA_MACRO_TX1 &&
+                       !test_bit(WSA_MACRO_TX1,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+                       set_bit(WSA_MACRO_TX1,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+                       wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+               }
+       } else {
+               if (spk_tx_id == WSA_MACRO_TX0 &&
+                       test_bit(WSA_MACRO_TX0,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+                       clear_bit(WSA_MACRO_TX0,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+                       wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+               }
+               if (spk_tx_id == WSA_MACRO_TX1 &&
+                       test_bit(WSA_MACRO_TX1,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+                       clear_bit(WSA_MACRO_TX1,
+                               &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+                       wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+               }
+       }
+       snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new aif_vi_mixer[] = {
+       SOC_SINGLE_EXT("WSA_SPKR_VI_1", SND_SOC_NOPM, WSA_MACRO_TX0, 1, 0,
+                       wsa_macro_vi_feed_mixer_get,
+                       wsa_macro_vi_feed_mixer_put),
+       SOC_SINGLE_EXT("WSA_SPKR_VI_2", SND_SOC_NOPM, WSA_MACRO_TX1, 1, 0,
+                       wsa_macro_vi_feed_mixer_get,
+                       wsa_macro_vi_feed_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("WSA AIF1 PB", "WSA_AIF1 Playback", 0,
+                           SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("WSA AIF_MIX1 PB", "WSA_AIF_MIX1 Playback", 0,
+                           SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_OUT_E("WSA AIF_VI", "WSA_AIF_VI Capture", 0,
+                              SND_SOC_NOPM, WSA_MACRO_AIF_VI, 0,
+                              wsa_macro_enable_vi_feedback,
+                              SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_OUT("WSA AIF_ECHO", "WSA_AIF_ECHO Capture", 0,
+                            SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_MIXER("WSA_AIF_VI Mixer", SND_SOC_NOPM, WSA_MACRO_AIF_VI,
+                          0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)),
+       SND_SOC_DAPM_MUX_E("WSA RX_MIX EC0_MUX", SND_SOC_NOPM,
+                          WSA_MACRO_EC0_MUX, 0,
+                          &rx_mix_ec0_mux, wsa_macro_enable_echo,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("WSA RX_MIX EC1_MUX", SND_SOC_NOPM,
+                          WSA_MACRO_EC1_MUX, 0,
+                          &rx_mix_ec1_mux, wsa_macro_enable_echo,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX("WSA RX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX0, 0,
+                        &rx_mux[WSA_MACRO_RX0]),
+       SND_SOC_DAPM_MUX("WSA RX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX1, 0,
+                        &rx_mux[WSA_MACRO_RX1]),
+       SND_SOC_DAPM_MUX("WSA RX_MIX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, 0,
+                        &rx_mux[WSA_MACRO_RX_MIX0]),
+       SND_SOC_DAPM_MUX("WSA RX_MIX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, 0,
+                        &rx_mux[WSA_MACRO_RX_MIX1]),
+
+       SND_SOC_DAPM_MIXER("WSA RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("WSA RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux),
+       SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux),
+       SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux),
+       SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", CDC_WSA_RX0_RX_PATH_MIX_CTL,
+                          0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux),
+       SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux),
+       SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux),
+       SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", CDC_WSA_RX1_RX_PATH_MIX_CTL,
+                          0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0,
+                            wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0,
+                            wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("WSA_RX0 INT0 SIDETONE MIX", CDC_WSA_RX0_RX_PATH_CFG1,
+                        4, 0, &rx0_sidetone_mix_mux),
+
+       SND_SOC_DAPM_INPUT("WSA SRC0_INP"),
+       SND_SOC_DAPM_INPUT("WSA_TX DEC0_INP"),
+       SND_SOC_DAPM_INPUT("WSA_TX DEC1_INP"),
+
+       SND_SOC_DAPM_MIXER_E("WSA_RX INT0 INTERP", SND_SOC_NOPM,
+                            WSA_MACRO_COMP1, 0, NULL, 0,
+                            wsa_macro_enable_interpolator,
+                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER_E("WSA_RX INT1 INTERP", SND_SOC_NOPM,
+                            WSA_MACRO_COMP2, 0, NULL, 0,
+                            wsa_macro_enable_interpolator,
+                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER_E("WSA_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0,
+                            NULL, 0, wsa_macro_spk_boost_event,
+                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER_E("WSA_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0,
+                            NULL, 0, wsa_macro_spk_boost_event,
+                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_INPUT("VIINPUT_WSA"),
+       SND_SOC_DAPM_OUTPUT("WSA_SPK1 OUT"),
+       SND_SOC_DAPM_OUTPUT("WSA_SPK2 OUT"),
+
+       SND_SOC_DAPM_SUPPLY("WSA_RX0_CLK", CDC_WSA_RX0_RX_PATH_CTL, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("WSA_RX1_CLK", CDC_WSA_RX1_RX_PATH_CTL, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("WSA_RX_MIX0_CLK", CDC_WSA_RX0_RX_PATH_MIX_CTL, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("WSA_RX_MIX1_CLK", CDC_WSA_RX1_RX_PATH_MIX_CTL, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("WSA_MCLK", 0, SND_SOC_NOPM, 0, 0,
+                             wsa_macro_mclk_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route wsa_audio_map[] = {
+       /* VI Feedback */
+       {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"},
+       {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_2", "VIINPUT_WSA"},
+       {"WSA AIF_VI", NULL, "WSA_AIF_VI Mixer"},
+       {"WSA AIF_VI", NULL, "WSA_MCLK"},
+
+       {"WSA RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"},
+       {"WSA RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"},
+       {"WSA RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"},
+       {"WSA RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"},
+       {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC0_MUX"},
+       {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC1_MUX"},
+       {"WSA AIF_ECHO", NULL, "WSA_MCLK"},
+
+       {"WSA AIF1 PB", NULL, "WSA_MCLK"},
+       {"WSA AIF_MIX1 PB", NULL, "WSA_MCLK"},
+
+       {"WSA RX0 MUX", "AIF1_PB", "WSA AIF1 PB"},
+       {"WSA RX1 MUX", "AIF1_PB", "WSA AIF1 PB"},
+       {"WSA RX_MIX0 MUX", "AIF1_PB", "WSA AIF1 PB"},
+       {"WSA RX_MIX1 MUX", "AIF1_PB", "WSA AIF1 PB"},
+
+       {"WSA RX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+       {"WSA RX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+       {"WSA RX_MIX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+       {"WSA RX_MIX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+
+       {"WSA RX0", NULL, "WSA RX0 MUX"},
+       {"WSA RX1", NULL, "WSA RX1 MUX"},
+       {"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"},
+       {"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"},
+
+       {"WSA RX0", NULL, "WSA_RX0_CLK"},
+       {"WSA RX1", NULL, "WSA_RX1_CLK"},
+       {"WSA RX_MIX0", NULL, "WSA_RX_MIX0_CLK"},
+       {"WSA RX_MIX1", NULL, "WSA_RX_MIX1_CLK"},
+
+       {"WSA_RX0 INP0", "RX0", "WSA RX0"},
+       {"WSA_RX0 INP0", "RX1", "WSA RX1"},
+       {"WSA_RX0 INP0", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX0 INP0", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX0 INP0", "DEC0", "WSA_TX DEC0_INP"},
+       {"WSA_RX0 INP0", "DEC1", "WSA_TX DEC1_INP"},
+       {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP0"},
+
+       {"WSA_RX0 INP1", "RX0", "WSA RX0"},
+       {"WSA_RX0 INP1", "RX1", "WSA RX1"},
+       {"WSA_RX0 INP1", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX0 INP1", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX0 INP1", "DEC0", "WSA_TX DEC0_INP"},
+       {"WSA_RX0 INP1", "DEC1", "WSA_TX DEC1_INP"},
+       {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP1"},
+
+       {"WSA_RX0 INP2", "RX0", "WSA RX0"},
+       {"WSA_RX0 INP2", "RX1", "WSA RX1"},
+       {"WSA_RX0 INP2", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX0 INP2", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX0 INP2", "DEC0", "WSA_TX DEC0_INP"},
+       {"WSA_RX0 INP2", "DEC1", "WSA_TX DEC1_INP"},
+       {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP2"},
+
+       {"WSA_RX0 MIX INP", "RX0", "WSA RX0"},
+       {"WSA_RX0 MIX INP", "RX1", "WSA RX1"},
+       {"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"},
+
+       {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"},
+       {"WSA_RX INT0 INTERP", NULL, "WSA_RX INT0 SEC MIX"},
+       {"WSA_RX0 INT0 SIDETONE MIX", "SRC0", "WSA SRC0_INP"},
+       {"WSA_RX INT0 INTERP", NULL, "WSA_RX0 INT0 SIDETONE MIX"},
+       {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 INTERP"},
+
+       {"WSA_SPK1 OUT", NULL, "WSA_RX INT0 CHAIN"},
+       {"WSA_SPK1 OUT", NULL, "WSA_MCLK"},
+
+       {"WSA_RX1 INP0", "RX0", "WSA RX0"},
+       {"WSA_RX1 INP0", "RX1", "WSA RX1"},
+       {"WSA_RX1 INP0", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX1 INP0", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX1 INP0", "DEC0", "WSA_TX DEC0_INP"},
+       {"WSA_RX1 INP0", "DEC1", "WSA_TX DEC1_INP"},
+       {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP0"},
+
+       {"WSA_RX1 INP1", "RX0", "WSA RX0"},
+       {"WSA_RX1 INP1", "RX1", "WSA RX1"},
+       {"WSA_RX1 INP1", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX1 INP1", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX1 INP1", "DEC0", "WSA_TX DEC0_INP"},
+       {"WSA_RX1 INP1", "DEC1", "WSA_TX DEC1_INP"},
+       {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP1"},
+
+       {"WSA_RX1 INP2", "RX0", "WSA RX0"},
+       {"WSA_RX1 INP2", "RX1", "WSA RX1"},
+       {"WSA_RX1 INP2", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX1 INP2", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX1 INP2", "DEC0", "WSA_TX DEC0_INP"},
+       {"WSA_RX1 INP2", "DEC1", "WSA_TX DEC1_INP"},
+       {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP2"},
+
+       {"WSA_RX1 MIX INP", "RX0", "WSA RX0"},
+       {"WSA_RX1 MIX INP", "RX1", "WSA RX1"},
+       {"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
+       {"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+       {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"},
+
+       {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"},
+       {"WSA_RX INT1 INTERP", NULL, "WSA_RX INT1 SEC MIX"},
+
+       {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 INTERP"},
+       {"WSA_SPK2 OUT", NULL, "WSA_RX INT1 CHAIN"},
+       {"WSA_SPK2 OUT", NULL, "WSA_MCLK"},
+};
+
+static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
+{
+       struct regmap *regmap = wsa->regmap;
+
+       if (enable) {
+               wsa_macro_mclk_enable(wsa, true);
+
+               /* reset swr ip */
+               if (wsa->reset_swr)
+                       regmap_update_bits(regmap,
+                                          CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+                                          CDC_WSA_SWR_RST_EN_MASK,
+                                          CDC_WSA_SWR_RST_ENABLE);
+
+               regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+                                  CDC_WSA_SWR_CLK_EN_MASK,
+                                  CDC_WSA_SWR_CLK_ENABLE);
+
+               /* Bring out of reset */
+               if (wsa->reset_swr)
+                       regmap_update_bits(regmap,
+                                          CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+                                          CDC_WSA_SWR_RST_EN_MASK,
+                                          CDC_WSA_SWR_RST_DISABLE);
+               wsa->reset_swr = false;
+       } else {
+               regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+                                  CDC_WSA_SWR_CLK_EN_MASK, 0);
+               wsa_macro_mclk_enable(wsa, false);
+       }
+
+       return 0;
+}
+
+static int wsa_macro_component_probe(struct snd_soc_component *comp)
+{
+       struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp);
+
+       snd_soc_component_init_regmap(comp, wsa->regmap);
+
+       wsa->spkr_gain_offset = WSA_MACRO_GAIN_OFFSET_M1P5_DB;
+
+       /* set SPKR rate to FS_2P4_3P072 */
+       snd_soc_component_update_bits(comp, CDC_WSA_RX0_RX_PATH_CFG1,
+                               CDC_WSA_RX_PATH_SPKR_RATE_MASK,
+                               CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072);
+
+       snd_soc_component_update_bits(comp, CDC_WSA_RX1_RX_PATH_CFG1,
+                               CDC_WSA_RX_PATH_SPKR_RATE_MASK,
+                               CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072);
+
+       wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1);
+
+       return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+       return wsa_swrm_clock(to_wsa_macro(hw), true);
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+       wsa_swrm_clock(to_wsa_macro(hw), false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+       struct wsa_macro *wsa = to_wsa_macro(hw);
+       int ret, val;
+
+       regmap_read(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val);
+       ret = val & BIT(0);
+
+       return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+                                      unsigned long parent_rate)
+{
+       return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+       .prepare = swclk_gate_enable,
+       .unprepare = swclk_gate_disable,
+       .is_enabled = swclk_gate_is_enabled,
+       .recalc_rate = swclk_recalc_rate,
+};
+
+static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)
+{
+       struct device *dev = wsa->dev;
+       struct device_node *np = dev->of_node;
+       const char *parent_clk_name;
+       const char *clk_name = "mclk";
+       struct clk_hw *hw;
+       struct clk_init_data init;
+       int ret;
+
+       parent_clk_name = __clk_get_name(wsa->clks[2].clk);
+
+       init.name = clk_name;
+       init.ops = &swclk_gate_ops;
+       init.flags = 0;
+       init.parent_names = &parent_clk_name;
+       init.num_parents = 1;
+       wsa->hw.init = &init;
+       hw = &wsa->hw;
+       ret = clk_hw_register(wsa->dev, hw);
+       if (ret)
+               return ERR_PTR(ret);
+
+       of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+       return NULL;
+}
+
+static const struct snd_soc_component_driver wsa_macro_component_drv = {
+       .name = "WSA MACRO",
+       .probe = wsa_macro_component_probe,
+       .controls = wsa_macro_snd_controls,
+       .num_controls = ARRAY_SIZE(wsa_macro_snd_controls),
+       .dapm_widgets = wsa_macro_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets),
+       .dapm_routes = wsa_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wsa_audio_map),
+};
+
+static int wsa_macro_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct wsa_macro *wsa;
+       void __iomem *base;
+       int ret;
+
+       wsa = devm_kzalloc(dev, sizeof(*wsa), GFP_KERNEL);
+       if (!wsa)
+               return -ENOMEM;
+
+       wsa->clks[0].id = "macro";
+       wsa->clks[1].id = "dcodec";
+       wsa->clks[2].id = "mclk";
+       wsa->clks[3].id = "npl";
+       wsa->clks[4].id = "fsgen";
+
+       ret = devm_clk_bulk_get(dev, WSA_NUM_CLKS_MAX, wsa->clks);
+       if (ret) {
+               dev_err(dev, "Error getting WSA Clocks (%d)\n", ret);
+               return ret;
+       }
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config);
+
+       dev_set_drvdata(dev, wsa);
+
+       wsa->reset_swr = true;
+       wsa->dev = dev;
+
+       /* set MCLK and NPL rates */
+       clk_set_rate(wsa->clks[2].clk, WSA_MACRO_MCLK_FREQ);
+       clk_set_rate(wsa->clks[3].clk, WSA_MACRO_MCLK_FREQ);
+
+       ret = clk_bulk_prepare_enable(WSA_NUM_CLKS_MAX, wsa->clks);
+       if (ret)
+               return ret;
+
+       wsa_macro_register_mclk_output(wsa);
+
+       ret = devm_snd_soc_register_component(dev, &wsa_macro_component_drv,
+                                             wsa_macro_dai,
+                                             ARRAY_SIZE(wsa_macro_dai));
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
+
+       return ret;
+
+}
+
+static int wsa_macro_remove(struct platform_device *pdev)
+{
+       struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+
+       clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
+
+       return 0;
+}
+
+static const struct of_device_id wsa_macro_dt_match[] = {
+       {.compatible = "qcom,sm8250-lpass-wsa-macro"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, wsa_macro_dt_match);
+
+static struct platform_driver wsa_macro_driver = {
+       .driver = {
+               .name = "wsa_macro",
+               .of_match_table = wsa_macro_dt_match,
+       },
+       .probe = wsa_macro_probe,
+       .remove = wsa_macro_remove,
+};
+
+module_platform_driver(wsa_macro_driver);
+MODULE_DESCRIPTION("WSA macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-wsa-macro.h b/sound/soc/codecs/lpass-wsa-macro.h
new file mode 100644 (file)
index 0000000..d3d62b3
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LPASS_WSA_MACRO_H__
+#define __LPASS_WSA_MACRO_H__
+
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+       WSA_MACRO_SPKR_MODE_DEFAULT,
+       WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode);
+
+#endif /* __LPASS_WSA_MACRO_H__ */
index 680f31a..f4ed7e0 100644 (file)
@@ -3019,11 +3019,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream,
                tar = 2 << MADERA_AIF1_RATE_SHIFT;
                break;
        case MADERA_CLK_ASYNCCLK_1:
-               reg = MADERA_ASYNC_SAMPLE_RATE_1,
+               reg = MADERA_ASYNC_SAMPLE_RATE_1;
                tar = 8 << MADERA_AIF1_RATE_SHIFT;
                break;
        case MADERA_CLK_ASYNCCLK_2:
-               reg = MADERA_ASYNC_SAMPLE_RATE_2,
+               reg = MADERA_ASYNC_SAMPLE_RATE_2;
                tar = 9 << MADERA_AIF1_RATE_SHIFT;
                break;
        default:
index 945a79e..06276ff 100644 (file)
@@ -2668,12 +2668,14 @@ static const struct i2c_device_id max98090_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98090_of_match[] = {
        { .compatible = "maxim,max98090", },
        { .compatible = "maxim,max98091", },
        { }
 };
 MODULE_DEVICE_TABLE(of, max98090_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id max98090_acpi_match[] = {
index 9bdc639..736cd70 100644 (file)
@@ -2148,11 +2148,13 @@ static const struct i2c_device_id max98095_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98095_of_match[] = {
        { .compatible = "maxim,max98095", },
        { }
 };
 MODULE_DEVICE_TABLE(of, max98095_of_match);
+#endif
 
 static struct i2c_driver max98095_i2c_driver = {
        .driver = {
index dfee05f..e424779 100644 (file)
@@ -408,16 +408,17 @@ static const struct i2c_device_id max98371_i2c_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98371_of_match[] = {
        { .compatible = "maxim,max98371", },
        { }
 };
 MODULE_DEVICE_TABLE(of, max98371_of_match);
+#endif
 
 static struct i2c_driver max98371_i2c_driver = {
        .driver = {
                .name = "max98371",
-               .pm = NULL,
                .of_match_table = of_match_ptr(max98371_of_match),
        },
        .probe  = max98371_i2c_probe,
index fa589d8..ec2e79c 100644 (file)
@@ -247,7 +247,7 @@ static __maybe_unused int max98373_suspend(struct device *dev)
        struct max98373_priv *max98373 = dev_get_drvdata(dev);
 
        regcache_cache_only(max98373->regmap, true);
-       regcache_mark_dirty(max98373->regmap);
+
        return 0;
 }
 
index ff5cc9b..bb736c4 100644 (file)
@@ -784,6 +784,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
        if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) {
                dev_err(component->dev,
                        "param fw is invalid.\n");
+               ret = -EINVAL;
                goto err_alloc;
        }
        dsm_param = (char *)fw->data;
@@ -794,6 +795,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
                fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) {
                dev_err(component->dev,
                        "param fw is invalid.\n");
+               ret = -EINVAL;
                goto err_alloc;
        }
        regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80);
index aef2746..512e6f2 100644 (file)
@@ -649,11 +649,13 @@ static const struct i2c_device_id max9867_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max9867_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max9867_of_match[] = {
        { .compatible = "maxim,max9867", },
        { }
 };
 MODULE_DEVICE_TABLE(of, max9867_of_match);
+#endif
 
 static struct i2c_driver max9867_i2c_driver = {
        .driver = {
index b3e1a54..ddaccc2 100644 (file)
@@ -627,17 +627,18 @@ static const struct i2c_device_id max98925_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98925_of_match[] = {
        { .compatible = "maxim,max98925", },
        { }
 };
 MODULE_DEVICE_TABLE(of, max98925_of_match);
+#endif
 
 static struct i2c_driver max98925_i2c_driver = {
        .driver = {
                .name = "max98925",
                .of_match_table = of_match_ptr(max98925_of_match),
-               .pm = NULL,
        },
        .probe  = max98925_i2c_probe,
        .id_table = max98925_i2c_id,
index c4dfa8a..f286e57 100644 (file)
@@ -571,17 +571,18 @@ static const struct i2c_device_id max98926_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98926_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98926_of_match[] = {
        { .compatible = "maxim,max98926", },
        { }
 };
 MODULE_DEVICE_TABLE(of, max98926_of_match);
+#endif
 
 static struct i2c_driver max98926_i2c_driver = {
        .driver = {
                .name = "max98926",
                .of_match_table = of_match_ptr(max98926_of_match),
-               .pm = NULL,
        },
        .probe  = max98926_i2c_probe,
        .id_table = max98926_i2c_id,
index 81aafb5..6de0d74 100644 (file)
@@ -68,6 +68,38 @@ static void mt6359_reset_capture_gpio(struct mt6359_priv *priv)
                           0x3 << 0, 0x0);
 }
 
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
+{
+       regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
+                          0x1 << RG_XO_AUDIO_EN_M_SFT,
+                          (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
+}
+
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_clksq(struct mt6359_priv *priv, bool enable)
+{
+       /* Enable/disable CLKSQ 26MHz */
+       regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23,
+                          RG_CLKSQ_EN_MASK_SFT,
+                          (enable ? 1 : 0) << RG_CLKSQ_EN_SFT);
+}
+
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_aud_global_bias(struct mt6359_priv *priv, bool enable)
+{
+       regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13,
+                          RG_AUDGLB_PWRDN_VA32_MASK_SFT,
+                          (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA32_SFT);
+}
+
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_topck(struct mt6359_priv *priv, bool enable)
+{
+       regmap_update_bits(priv->regmap, MT6359_AUD_TOP_CKPDN_CON0,
+                          0x0066, enable ? 0x0 : 0x66);
+}
+
 static void mt6359_set_decoder_clk(struct mt6359_priv *priv, bool enable)
 {
        regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13,
@@ -122,6 +154,84 @@ static void mt6359_mtkaif_tx_disable(struct mt6359_priv *priv)
                           0xff00, 0x3000);
 }
 
+void mt6359_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
+                               int mtkaif_protocol)
+{
+       struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+       priv->mtkaif_protocol = mtkaif_protocol;
+}
+EXPORT_SYMBOL_GPL(mt6359_set_mtkaif_protocol);
+
+void mt6359_mtkaif_calibration_enable(struct snd_soc_component *cmpnt)
+{
+       struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+       mt6359_set_playback_gpio(priv);
+       mt6359_set_capture_gpio(priv);
+       mt6359_mtkaif_tx_enable(priv);
+
+       mt6359_set_dcxo(priv, true);
+       mt6359_set_aud_global_bias(priv, true);
+       mt6359_set_clksq(priv, true);
+       mt6359_set_topck(priv, true);
+
+       /* set dat_miso_loopback on */
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+                          RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
+                          1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+                          RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
+                          1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1,
+                          RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT,
+                          1 << RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT);
+}
+EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable);
+
+void mt6359_mtkaif_calibration_disable(struct snd_soc_component *cmpnt)
+{
+       struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+       /* set dat_miso_loopback off */
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+                          RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
+                          0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+                          RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
+                          0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1,
+                          RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT,
+                          0 << RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT);
+
+       mt6359_set_topck(priv, false);
+       mt6359_set_clksq(priv, false);
+       mt6359_set_aud_global_bias(priv, false);
+       mt6359_set_dcxo(priv, false);
+
+       mt6359_mtkaif_tx_disable(priv);
+       mt6359_reset_playback_gpio(priv);
+       mt6359_reset_capture_gpio(priv);
+}
+EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_disable);
+
+void mt6359_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
+                                        int phase_1, int phase_2, int phase_3)
+{
+       struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+                          RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT,
+                          phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT);
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+                          RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT,
+                          phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT);
+       regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1,
+                          RG_AUD_PAD_TOP_PHASE_MODE3_MASK_SFT,
+                          phase_3 << RG_AUD_PAD_TOP_PHASE_MODE3_SFT);
+}
+EXPORT_SYMBOL_GPL(mt6359_set_mtkaif_calibration_phase);
+
 static void zcd_disable(struct mt6359_priv *priv)
 {
        regmap_write(priv->regmap, MT6359_ZCD_CON0, 0x0000);
@@ -1833,9 +1943,6 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF,
                              MT6359_DCXO_CW12,
                              RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY_S("LDO_VAUD18", SUPPLY_SEQ_LDO_VAUD18,
-                             MT6359_LDO_VAUD18_CON0,
-                             RG_LDO_VAUD18_EN_SFT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB,
                              MT6359_AUDDEC_ANA_CON13,
                              RG_AUDGLB_PWRDN_VA32_SFT, 1, NULL, 0),
@@ -1855,6 +1962,8 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK,
                              MT6359_AUD_TOP_CKPDN_CON0,
                              RG_AUDIF_CK_PDN_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("vaud18", 0, 0),
+
        /* Digital Clock */
        SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST,
                              MT6359_AUDIO_TOP_CON0,
@@ -2204,7 +2313,7 @@ static int mt_dcc_clk_connect(struct snd_soc_dapm_widget *source,
 static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
        /* Capture */
        {"AIFTX_Supply", NULL, "CLK_BUF"},
-       {"AIFTX_Supply", NULL, "LDO_VAUD18"},
+       {"AIFTX_Supply", NULL, "vaud18"},
        {"AIFTX_Supply", NULL, "AUDGLB"},
        {"AIFTX_Supply", NULL, "CLKSQ Audio"},
        {"AIFTX_Supply", NULL, "AUD_CK"},
@@ -2332,7 +2441,7 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
 
        /* DL Supply */
        {"DL Power Supply", NULL, "CLK_BUF"},
-       {"DL Power Supply", NULL, "LDO_VAUD18"},
+       {"DL Power Supply", NULL, "vaud18"},
        {"DL Power Supply", NULL, "AUDGLB"},
        {"DL Power Supply", NULL, "CLKSQ Audio"},
        {"DL Power Supply", NULL, "AUDNCP_CK"},
@@ -2697,20 +2806,6 @@ static int mt6359_platform_driver_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, priv);
        priv->dev = &pdev->dev;
 
-       priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18");
-       if (IS_ERR(priv->avdd_reg)) {
-               dev_err(&pdev->dev, "%s(), have no vaud18 supply: %ld",
-                       __func__, PTR_ERR(priv->avdd_reg));
-               return PTR_ERR(priv->avdd_reg);
-       }
-
-       ret = regulator_enable(priv->avdd_reg);
-       if (ret) {
-               dev_err(&pdev->dev, "%s(), failed to enable regulator!\n",
-                       __func__);
-               return ret;
-       }
-
        ret = mt6359_parse_dt(priv);
        if (ret) {
                dev_warn(&pdev->dev, "%s() failed to parse dts\n", __func__);
@@ -2723,30 +2818,11 @@ static int mt6359_platform_driver_probe(struct platform_device *pdev)
                                               ARRAY_SIZE(mt6359_dai_driver));
 }
 
-static int mt6359_platform_driver_remove(struct platform_device *pdev)
-{
-       struct mt6359_priv *priv = dev_get_drvdata(&pdev->dev);
-       int ret;
-
-       dev_dbg(&pdev->dev, "%s(), dev name %s\n",
-               __func__, dev_name(&pdev->dev));
-
-       ret = regulator_disable(priv->avdd_reg);
-       if (ret) {
-               dev_err(&pdev->dev, "%s(), failed to disable regulator!\n",
-                       __func__);
-               return ret;
-       }
-
-       return 0;
-}
-
 static struct platform_driver mt6359_platform_driver = {
        .driver = {
                .name = "mt6359-sound",
        },
        .probe = mt6359_platform_driver_probe,
-       .remove = mt6359_platform_driver_remove,
 };
 
 module_platform_driver(mt6359_platform_driver)
index 3792e53..35f806b 100644 (file)
 /* MT6359_DCXO_CW12 */
 #define RG_XO_AUDIO_EN_M_SFT                           13
 
-/* LDO_VAUD18_CON0 */
-#define RG_LDO_VAUD18_EN_SFT                           0
-#define RG_LDO_VAUD18_EN_MASK                          0x1
-#define RG_LDO_VAUD18_EN_MASK_SFT                      (0x1 << 0)
-
 /* AUD_TOP_CKPDN_CON0 */
 #define RG_VOW13M_CK_PDN_SFT                           13
 #define RG_VOW13M_CK_PDN_MASK                          0x1
 
 #define MT6359_DCXO_CW11                               0x7a6
 #define MT6359_DCXO_CW12                               0x7a8
-#define MT6359_LDO_VAUD18_CON0                         0x1c98
 
 #define MT6359_GPIO_MODE0                              0xcc
 #define MT6359_GPIO_MODE0_SET                          0xce
@@ -2469,7 +2463,6 @@ enum {
 enum {
        /* common */
        SUPPLY_SEQ_CLK_BUF,
-       SUPPLY_SEQ_LDO_VAUD18,
        SUPPLY_SEQ_AUD_GLB,
        SUPPLY_SEQ_HP_PULL_DOWN,
        SUPPLY_SEQ_CLKSQ,
@@ -2629,7 +2622,6 @@ struct mt6359_priv {
        int hp_gain_ctl;
        int hp_hifi_mode;
        int mtkaif_protocol;
-       struct regulator *avdd_reg;
 };
 
 #define CODEC_MT6359_NAME "mtk-codec-mt6359"
@@ -2637,4 +2629,11 @@ struct mt6359_priv {
                           (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \
                           (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE)
 
+void mt6359_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
+                               int mtkaif_protocol);
+void mt6359_mtkaif_calibration_enable(struct snd_soc_component *cmpnt);
+void mt6359_mtkaif_calibration_disable(struct snd_soc_component *cmpnt);
+void mt6359_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
+                                        int phase_1, int phase_2, int phase_3);
+
 #endif/* end _MT6359_H_ */
diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c
new file mode 100644 (file)
index 0000000..2b66e3f
--- /dev/null
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// nau8315.c  --  NAU8315 ALSA SoC Audio Amplifier Driver
+//
+// Copyright 2020 Nuvoton Technology Crop.
+//
+// Author: David Lin <ctlin0@nuvoton.com>
+//
+// Based on MAX98357A.c
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+
+struct nau8315_priv {
+       struct gpio_desc *enable;
+       int enpin_switch;
+};
+
+static int nau8315_daiops_trigger(struct snd_pcm_substream *substream,
+               int cmd, struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct nau8315_priv *nau8315 =
+               snd_soc_component_get_drvdata(component);
+
+       if (!nau8315->enable)
+               return 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (nau8315->enpin_switch) {
+                       gpiod_set_value(nau8315->enable, 1);
+                       dev_dbg(component->dev, "set enable to 1");
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               gpiod_set_value(nau8315->enable, 0);
+               dev_dbg(component->dev, "set enable to 0");
+               break;
+       }
+
+       return 0;
+}
+
+static int nau8315_enpin_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+       struct nau8315_priv *nau8315 =
+               snd_soc_component_get_drvdata(component);
+
+       if (event & SND_SOC_DAPM_PRE_PMU)
+               nau8315->enpin_switch = 1;
+       else if (event & SND_SOC_DAPM_POST_PMD)
+               nau8315->enpin_switch = 0;
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget nau8315_dapm_widgets[] = {
+       SND_SOC_DAPM_OUTPUT("Speaker"),
+       SND_SOC_DAPM_OUT_DRV_E("EN_Pin", SND_SOC_NOPM, 0, 0, NULL, 0,
+                       nau8315_enpin_event,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route nau8315_dapm_routes[] = {
+       {"EN_Pin", NULL, "HiFi Playback"},
+       {"Speaker", NULL, "EN_Pin"},
+};
+
+static const struct snd_soc_component_driver nau8315_component_driver = {
+       .dapm_widgets           = nau8315_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(nau8315_dapm_widgets),
+       .dapm_routes            = nau8315_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(nau8315_dapm_routes),
+       .idle_bias_on           = 1,
+       .use_pmdown_time        = 1,
+       .endianness             = 1,
+       .non_legacy_dai_naming  = 1,
+};
+
+static const struct snd_soc_dai_ops nau8315_dai_ops = {
+       .trigger        = nau8315_daiops_trigger,
+};
+
+#define NAU8315_RATES SNDRV_PCM_RATE_8000_96000
+#define NAU8315_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE)
+
+static struct snd_soc_dai_driver nau8315_dai_driver = {
+       .name = "nau8315-hifi",
+       .playback = {
+               .stream_name    = "HiFi Playback",
+               .formats        = NAU8315_FORMATS,
+               .rates          = NAU8315_RATES,
+               .channels_min   = 1,
+               .channels_max   = 2,
+       },
+       .ops    = &nau8315_dai_ops,
+};
+
+static int nau8315_platform_probe(struct platform_device *pdev)
+{
+       struct nau8315_priv *nau8315;
+
+       nau8315 = devm_kzalloc(&pdev->dev, sizeof(*nau8315), GFP_KERNEL);
+       if (!nau8315)
+               return -ENOMEM;
+
+       nau8315->enable = devm_gpiod_get_optional(&pdev->dev,
+                               "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(nau8315->enable))
+               return PTR_ERR(nau8315->enable);
+
+       dev_set_drvdata(&pdev->dev, nau8315);
+
+       return devm_snd_soc_register_component(&pdev->dev,
+                       &nau8315_component_driver,
+                       &nau8315_dai_driver, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8315_device_id[] = {
+       { .compatible = "nuvoton,nau8315" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, nau8315_device_id);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id nau8315_acpi_match[] = {
+       { "NVTN2010", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match);
+#endif
+
+static struct platform_driver nau8315_platform_driver = {
+       .driver = {
+               .name = "nau8315",
+               .of_match_table = of_match_ptr(nau8315_device_id),
+               .acpi_match_table = ACPI_PTR(nau8315_acpi_match),
+       },
+       .probe  = nau8315_platform_probe,
+};
+module_platform_driver(nau8315_platform_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8315 Mono Class-D Amplifier Driver");
+MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
index 327ec58..7a6be45 100644 (file)
@@ -33,11 +33,13 @@ static int pcm1789_i2c_remove(struct i2c_client *client)
        return pcm1789_common_exit(&client->dev);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id pcm1789_of_match[] = {
        { .compatible = "ti,pcm1789", },
        { }
 };
 MODULE_DEVICE_TABLE(of, pcm1789_of_match);
+#endif
 
 static const struct i2c_device_id pcm1789_i2c_ids[] = {
        { "pcm1789", 0 },
index 36e0167..34a3d59 100644 (file)
@@ -30,11 +30,13 @@ static int pcm179x_i2c_probe(struct i2c_client *client,
        return pcm179x_common_init(&client->dev, regmap);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id pcm179x_of_match[] = {
        { .compatible = "ti,pcm1792a", },
        { }
 };
 MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+#endif
 
 static const struct i2c_device_id pcm179x_i2c_ids[] = {
        { "pcm179x", 0 },
index 8153d3d..4dc844f 100644 (file)
@@ -1168,8 +1168,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
        struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
        int alen;
        int gpio;
-       int clock_output;
-       int master_mode;
        int ret;
 
        dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
@@ -1195,19 +1193,15 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               ret = regmap_update_bits(pcm512x->regmap,
-                                        PCM512x_BCLK_LRCLK_CFG,
-                                        PCM512x_BCKP
-                                        | PCM512x_BCKO | PCM512x_LRKO,
-                                        0);
-               if (ret != 0) {
-                       dev_err(component->dev,
-                               "Failed to enable slave mode: %d\n", ret);
-                       return ret;
-               }
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+                                PCM512x_ALEN, alen);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to set frame size: %d\n", ret);
+               return ret;
+       }
 
+       if ((pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+           SND_SOC_DAIFMT_CBS_CFS) {
                ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
                                         PCM512x_DCAS, 0);
                if (ret != 0) {
@@ -1216,24 +1210,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                                ret);
                        return ret;
                }
-               return 0;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               clock_output = PCM512x_BCKO | PCM512x_LRKO;
-               master_mode = PCM512x_RLRK | PCM512x_RBCK;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               clock_output = PCM512x_BCKO;
-               master_mode = PCM512x_RBCK;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
-                                PCM512x_ALEN, alen);
-       if (ret != 0) {
-               dev_err(component->dev, "Failed to set frame size: %d\n", ret);
-               return ret;
+               goto skip_pll;
        }
 
        if (pcm512x->pll_out) {
@@ -1316,25 +1293,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                        dev_err(component->dev, "Failed to enable pll: %d\n", ret);
                        return ret;
                }
-       }
 
-       ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
-                                PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
-                                clock_output);
-       if (ret != 0) {
-               dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
-               return ret;
-       }
-
-       ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
-                                PCM512x_RLRK | PCM512x_RBCK,
-                                master_mode);
-       if (ret != 0) {
-               dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
-               return ret;
-       }
-
-       if (pcm512x->pll_out) {
                gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
                ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
                                         gpio, gpio);
@@ -1368,6 +1327,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+skip_pll:
        return 0;
 }
 
@@ -1375,6 +1335,80 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_component *component = dai->component;
        struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+       int afmt;
+       int offset = 0;
+       int clock_output;
+       int master_mode;
+       int ret;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               clock_output = 0;
+               master_mode = 0;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clock_output = PCM512x_BCKO | PCM512x_LRKO;
+               master_mode = PCM512x_RLRK | PCM512x_RBCK;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               clock_output = PCM512x_BCKO;
+               master_mode = PCM512x_RBCK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+                                PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+                                clock_output);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+                                PCM512x_RLRK | PCM512x_RBCK,
+                                master_mode);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
+               return ret;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               afmt = PCM512x_AFMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               afmt = PCM512x_AFMT_RTJ;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               afmt = PCM512x_AFMT_LTJ;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               offset = 1;
+               fallthrough;
+       case SND_SOC_DAIFMT_DSP_B:
+               afmt = PCM512x_AFMT_DSP;
+               break;
+       default:
+               dev_err(component->dev, "unsupported DAI format: 0x%x\n",
+                       pcm512x->fmt);
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+                                PCM512x_AFMT, afmt);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to set data format: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_2,
+                                0xFF, offset);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to set data offset: %d\n", ret);
+               return ret;
+       }
 
        pcm512x->fmt = fmt;
 
index 940a2fa..bfefefc 100644 (file)
@@ -499,7 +499,7 @@ static int rk3328_platform_probe(struct platform_device *pdev)
                                               ARRAY_SIZE(rk3328_dai));
 }
 
-static const struct of_device_id rk3328_codec_of_match[] = {
+static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = {
                { .compatible = "rockchip,rk3328-codec", },
                {},
 };
index 3db0729..32e6bcf 100644 (file)
@@ -497,18 +497,40 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
        snd_soc_dapm_mutex_lock(&component->dapm);
        regcache_cache_bypass(regmap, true);
 
-       regmap_write(regmap, RT1015_PWR1, 0xd7df);
-       regmap_write(regmap, RT1015_PWR4, 0x00b2);
-       regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2008);
+       regmap_write(regmap, RT1015_PWR9, 0xAA60);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0089);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008A);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008C);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008D);
+       regmap_write(regmap, RT1015_PWR4, 0x80B2);
+       regmap_write(regmap, RT1015_CLASSD_SEQ, 0x5797);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2100);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0100);
+       regmap_write(regmap, RT1015_PWR5, 0x2175);
+       regmap_write(regmap, RT1015_MIXER1, 0x005D);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12F7);
+       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x1205);
+       msleep(200);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2000);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0180);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
+       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x0A05);
+       msleep(200);
+       regmap_write(regmap, RT1015_PWR4, 0x00B2);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028);
        regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
-       regmap_write(regmap, RT1015_GAT_BOOST, 0x0efe);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000d);
-       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000e);
-       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a00);
-       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a01);
-       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a05);
-       msleep(500);
-       regmap_write(regmap, RT1015_PWR1, 0x0);
+       regmap_write(regmap, RT1015_PWR5, 0x0175);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x1721);
+       regmap_write(regmap, RT1015_CLASSD_SEQ, 0x570E);
+       regmap_write(regmap, RT1015_MIXER1, 0x203D);
+       regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5A01);
+       regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12FF);
+       regmap_write(regmap, RT1015_GAT_BOOST, 0x0eFE);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008E);
+       regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0088);
+       regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
+       regmap_write(regmap, RT1015_SYS_RST2, 0x0b9a);
 
        regcache_cache_bypass(regmap, false);
        regcache_mark_dirty(regmap);
@@ -603,6 +625,8 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
                if (rt1015->bypass_boost == RT1015_Enable_Boost) {
                        snd_soc_component_write(component,
                                RT1015_SYS_RST1, 0x05f7);
+                       snd_soc_component_write(component,
+                               RT1015_SYS_RST2, 0x0b0a);
                        snd_soc_component_write(component,
                                RT1015_GAT_BOOST, 0xacfe);
                        snd_soc_component_write(component,
@@ -610,10 +634,14 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
                        snd_soc_component_write(component,
                                RT1015_GAT_BOOST, 0xecfe);
                } else {
+                       snd_soc_component_write(component,
+                               0x032d, 0xaa60);
                        snd_soc_component_write(component,
                                RT1015_SYS_RST1, 0x05f7);
                        snd_soc_component_write(component,
-                               RT1015_PWR_STATE_CTRL, 0x026e);
+                               RT1015_SYS_RST2, 0x0b0a);
+                       snd_soc_component_write(component,
+                               RT1015_PWR_STATE_CTRL, 0x008e);
                }
                break;
 
@@ -627,11 +655,17 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
                                RT1015_PWR9, 0xa800);
                        snd_soc_component_write(component,
                                RT1015_SYS_RST1, 0x05f5);
+                       snd_soc_component_write(component,
+                               RT1015_SYS_RST2, 0x0b9a);
                } else {
                        snd_soc_component_write(component,
-                               RT1015_PWR_STATE_CTRL, 0x0268);
+                               0x032d, 0xaa60);
+                       snd_soc_component_write(component,
+                               RT1015_PWR_STATE_CTRL, 0x0088);
                        snd_soc_component_write(component,
                                RT1015_SYS_RST1, 0x05f5);
+                       snd_soc_component_write(component,
+                               RT1015_SYS_RST2, 0x0b9a);
                }
                rt1015->dac_is_used = 0;
 
@@ -664,38 +698,12 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w,
 }
 
 static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
-       SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_SUPPLY("INT RC CLK", RT1015_PWR1, RT1015_PWR_INTCLK_BIT,
-               0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("ISENSE", RT1015_PWR1, RT1015_PWR_ISENSE_BIT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_SUPPLY("VSENSE", RT1015_PWR1, RT1015_PWR_VSENSE_BIT, 0,
-               NULL, 0),
        SND_SOC_DAPM_SUPPLY("PLL", RT1015_PWR1, RT1015_PWR_PLL_BIT, 0,
                NULL, 0),
-       SND_SOC_DAPM_SUPPLY("BG1 BG2", RT1015_PWR1, RT1015_PWR_BG_1_2_BIT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_SUPPLY("MBIAS BG", RT1015_PWR1, RT1015_PWR_MBIAS_BG_BIT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_SUPPLY("VBAT", RT1015_PWR1, RT1015_PWR_VBAT_BIT, 0, NULL,
-               0),
-       SND_SOC_DAPM_SUPPLY("MBIAS", RT1015_PWR1, RT1015_PWR_MBIAS_BIT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_SUPPLY("ADCV", RT1015_PWR1, RT1015_PWR_ADCV_BIT, 0, NULL,
-               0),
-       SND_SOC_DAPM_SUPPLY("MIXERV", RT1015_PWR1, RT1015_PWR_MIXERV_BIT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_SUPPLY("SUMV", RT1015_PWR1, RT1015_PWR_SUMV_BIT, 0, NULL,
-               0),
-       SND_SOC_DAPM_SUPPLY("VREFLV", RT1015_PWR1, RT1015_PWR_VREFLV_BIT, 0,
-               NULL, 0),
-
        SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC_E("DAC", NULL, RT1015_PWR1, RT1015_PWR_DAC_BIT, 0,
+       SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
                r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
                SND_SOC_DAPM_POST_PMD),
-
        SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0,
                        rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_OUTPUT("SPO"),
@@ -703,19 +711,7 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route rt1015_dapm_routes[] = {
        { "DAC", NULL, "AIFRX" },
-       { "DAC", NULL, "LDO2" },
        { "DAC", NULL, "PLL", rt1015_is_sys_clk_from_pll},
-       { "DAC", NULL, "INT RC CLK" },
-       { "DAC", NULL, "ISENSE" },
-       { "DAC", NULL, "VSENSE" },
-       { "DAC", NULL, "BG1 BG2" },
-       { "DAC", NULL, "MBIAS BG" },
-       { "DAC", NULL, "VBAT" },
-       { "DAC", NULL, "MBIAS" },
-       { "DAC", NULL, "ADCV" },
-       { "DAC", NULL, "MIXERV" },
-       { "DAC", NULL, "SUMV" },
-       { "DAC", NULL, "VREFLV" },
        { "Amp Drv", NULL, "DAC" },
        { "SPO", NULL, "Amp Drv" },
 };
@@ -950,6 +946,106 @@ static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
        return 0;
 }
 
+static int rt1015_set_tdm_slot(struct snd_soc_dai *dai,
+       unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_component *component = dai->component;
+       unsigned int val = 0, rx_slotnum, tx_slotnum;
+       int ret = 0, first_bit;
+
+       switch (slots) {
+       case 2:
+               val |= RT1015_I2S_TX_2CH;
+               break;
+       case 4:
+               val |= RT1015_I2S_TX_4CH;
+               break;
+       case 6:
+               val |= RT1015_I2S_TX_6CH;
+               break;
+       case 8:
+               val |= RT1015_I2S_TX_8CH;
+               break;
+       default:
+               ret = -EINVAL;
+               goto _set_tdm_err_;
+       }
+
+       switch (slot_width) {
+       case 16:
+               val |= RT1015_I2S_CH_TX_LEN_16B;
+               break;
+       case 20:
+               val |= RT1015_I2S_CH_TX_LEN_20B;
+               break;
+       case 24:
+               val |= RT1015_I2S_CH_TX_LEN_24B;
+               break;
+       case 32:
+               val |= RT1015_I2S_CH_TX_LEN_32B;
+               break;
+       default:
+               ret = -EINVAL;
+               goto _set_tdm_err_;
+       }
+
+       /* Rx slot configuration */
+       rx_slotnum = hweight_long(rx_mask);
+       if (rx_slotnum != 1) {
+               ret = -EINVAL;
+               dev_err(component->dev, "too many rx slots or zero slot\n");
+               goto _set_tdm_err_;
+       }
+
+       /* This is an assumption that the system sends stereo audio to the amplifier typically.
+        * And the stereo audio is placed in slot 0/2/4/6 as the starting slot.
+        * The users could select the channel from L/R/L+R by "Mono LR Select" control.
+        */
+       first_bit = __ffs(rx_mask);
+       switch (first_bit) {
+       case 0:
+       case 2:
+       case 4:
+       case 6:
+               snd_soc_component_update_bits(component,
+                       RT1015_TDM1_4,
+                       RT1015_TDM_I2S_TX_L_DAC1_1_MASK |
+                       RT1015_TDM_I2S_TX_R_DAC1_1_MASK,
+                       (first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) |
+                       ((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT));
+               break;
+       case 1:
+       case 3:
+       case 5:
+       case 7:
+               snd_soc_component_update_bits(component,
+                       RT1015_TDM1_4,
+                       RT1015_TDM_I2S_TX_L_DAC1_1_MASK |
+                       RT1015_TDM_I2S_TX_R_DAC1_1_MASK,
+                       ((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) |
+                       (first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT));
+               break;
+       default:
+               ret = -EINVAL;
+               goto _set_tdm_err_;
+       }
+
+       /* Tx slot configuration */
+       tx_slotnum = hweight_long(tx_mask);
+       if (tx_slotnum) {
+               ret = -EINVAL;
+               dev_err(component->dev, "doesn't need to support tx slots\n");
+               goto _set_tdm_err_;
+       }
+
+       snd_soc_component_update_bits(component, RT1015_TDM1_1,
+               RT1015_I2S_CH_TX_MASK | RT1015_I2S_CH_RX_MASK |
+               RT1015_I2S_CH_TX_LEN_MASK | RT1015_I2S_CH_RX_LEN_MASK, val);
+
+_set_tdm_err_:
+       return ret;
+}
+
 static int rt1015_probe(struct snd_soc_component *component)
 {
        struct rt1015_priv *rt1015 =
@@ -958,7 +1054,6 @@ static int rt1015_probe(struct snd_soc_component *component)
        rt1015->component = component;
        rt1015->bclk_ratio = 0;
        rt1015->cali_done = 0;
-       snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c);
 
        INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work);
 
@@ -981,6 +1076,7 @@ static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
        .hw_params = rt1015_hw_params,
        .set_fmt = rt1015_set_dai_fmt,
        .set_bclk_ratio = rt1015_set_bclk_ratio,
+       .set_tdm_slot = rt1015_set_tdm_slot,
 };
 
 static struct snd_soc_dai_driver rt1015_dai[] = {
@@ -1111,8 +1207,13 @@ static int rt1015_i2c_probe(struct i2c_client *i2c,
 
        rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28;
 
-       regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
-       if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) {
+       ret = regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
+       if (ret) {
+               dev_err(&i2c->dev,
+                       "Failed to read device register: %d\n", ret);
+               return ret;
+       } else if ((val != RT1015_DEVICE_ID_VAL) &&
+                       (val != RT1015_DEVICE_ID_VAL2)) {
                dev_err(&i2c->dev,
                        "Device with ID register %x is not rt1015\n", val);
                return -ENODEV;
index 15cadb3..b6ea753 100644 (file)
 #define RT1015_ID_VERA                         0x0
 #define RT1015_ID_VERB                         0x1
 
+/* 0x00f2 */
+#define RT1015_MONO_LR_SEL_MASK                        (0x3 << 4)
+#define RT1015_MONO_L_CHANNEL                  (0x0 << 4)
+#define RT1015_MONO_R_CHANNEL                  (0x1 << 4)
+#define RT1015_MONO_LR_MIX_CHANNEL                     (0x2 << 4)
+
 /* 0x0102 */
 #define RT1015_DAC_VOL_MASK                    (0x7f << 9)
 #define RT1015_DAC_VOL_SFT                     9
 #define RT1015_TDM_INV_BCLK_MASK               (0x1 << 15)
 #define RT1015_TDM_INV_BCLK_SFT                        15
 #define RT1015_TDM_INV_BCLK                    (0x1 << 15)
+#define RT1015_I2S_CH_TX_MASK                  (0x3 << 10)
+#define RT1015_I2S_CH_TX_SFT                   10
+#define RT1015_I2S_TX_2CH                      (0x0 << 10)
+#define RT1015_I2S_TX_4CH                      (0x1 << 10)
+#define RT1015_I2S_TX_6CH                      (0x2 << 10)
+#define RT1015_I2S_TX_8CH                      (0x3 << 10)
+#define RT1015_I2S_CH_RX_MASK                  (0x3 << 8)
+#define RT1015_I2S_CH_RX_SFT                   8
+#define RT1015_I2S_RX_2CH                      (0x0 << 8)
+#define RT1015_I2S_RX_4CH                      (0x1 << 8)
+#define RT1015_I2S_RX_6CH                      (0x2 << 8)
+#define RT1015_I2S_RX_8CH                      (0x3 << 8)
+#define RT1015_I2S_LR_CH_SEL_MASK                      (0x1 << 7)
+#define RT1015_I2S_LR_CH_SEL_SFT                       7
+#define RT1015_I2S_LEFT_CH_SEL                 (0x0 << 7)
+#define RT1015_I2S_RIGHT_CH_SEL                        (0x1 << 7)
+#define RT1015_I2S_CH_TX_LEN_MASK                      (0x7 << 4)
+#define RT1015_I2S_CH_TX_LEN_SFT                       4
+#define RT1015_I2S_CH_TX_LEN_16B                       (0x0 << 4)
+#define RT1015_I2S_CH_TX_LEN_20B                       (0x1 << 4)
+#define RT1015_I2S_CH_TX_LEN_24B                       (0x2 << 4)
+#define RT1015_I2S_CH_TX_LEN_32B                       (0x3 << 4)
+#define RT1015_I2S_CH_TX_LEN_8B                        (0x4 << 4)
+#define RT1015_I2S_CH_RX_LEN_MASK                      (0x7 << 0)
+#define RT1015_I2S_CH_RX_LEN_SFT                       0
+#define RT1015_I2S_CH_RX_LEN_16B                       (0x0 << 0)
+#define RT1015_I2S_CH_RX_LEN_20B                       (0x1 << 0)
+#define RT1015_I2S_CH_RX_LEN_24B                       (0x2 << 0)
+#define RT1015_I2S_CH_RX_LEN_32B                       (0x3 << 0)
+#define RT1015_I2S_CH_RX_LEN_8B                        (0x4 << 0)
+
+/* TDM1 Setting-4 (0x011a) */
+#define RT1015_TDM_I2S_TX_L_DAC1_1_MASK                        (0x7 << 12)
+#define RT1015_TDM_I2S_TX_R_DAC1_1_MASK                        (0x7 << 8)
+#define RT1015_TDM_I2S_TX_L_DAC1_1_SFT 12
+#define RT1015_TDM_I2S_TX_R_DAC1_1_SFT 8
 
 /* 0x0330 */
 #define RT1015_ABST_AUTO_EN_MASK               (0x1 << 13)
index 59bb606..671f2a2 100644 (file)
@@ -4,6 +4,7 @@
 //
 // Copyright 2020 The Linux Foundation. All rights reserved.
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 
 struct rt1015p_priv {
        struct gpio_desc *sdb;
-       int sdb_switch;
+       bool calib_done;
 };
 
-static int rt1015p_daiops_trigger(struct snd_pcm_substream *substream,
-               int cmd, struct snd_soc_dai *dai)
+static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_component *component = dai->component;
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
        struct rt1015p_priv *rt1015p =
                snd_soc_component_get_drvdata(component);
 
        if (!rt1015p->sdb)
                return 0;
 
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (rt1015p->sdb_switch) {
-                       gpiod_set_value(rt1015p->sdb, 1);
-                       dev_dbg(component->dev, "set sdb to 1");
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               gpiod_set_value_cansleep(rt1015p->sdb, 1);
+               dev_dbg(component->dev, "set sdb to 1");
+
+               if (!rt1015p->calib_done) {
+                       msleep(300);
+                       rt1015p->calib_done = true;
                }
                break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               gpiod_set_value(rt1015p->sdb, 0);
+       case SND_SOC_DAPM_POST_PMD:
+               gpiod_set_value_cansleep(rt1015p->sdb, 0);
                dev_dbg(component->dev, "set sdb to 0");
                break;
+       default:
+               break;
        }
 
        return 0;
 }
 
-static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_component *component =
-               snd_soc_dapm_to_component(w->dapm);
-       struct rt1015p_priv *rt1015p =
-               snd_soc_component_get_drvdata(component);
-
-       if (event & SND_SOC_DAPM_POST_PMU)
-               rt1015p->sdb_switch = 1;
-       else if (event & SND_SOC_DAPM_POST_PMD)
-               rt1015p->sdb_switch = 0;
-
-       return 0;
-}
-
 static const struct snd_soc_dapm_widget rt1015p_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("Speaker"),
        SND_SOC_DAPM_OUT_DRV_E("SDB", SND_SOC_NOPM, 0, 0, NULL, 0,
                        rt1015p_sdb_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {
@@ -80,7 +67,20 @@ static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {
        {"Speaker", NULL, "SDB"},
 };
 
+#ifdef CONFIG_PM
+static int rt1015p_suspend(struct snd_soc_component *component)
+{
+       struct rt1015p_priv *rt1015p = snd_soc_component_get_drvdata(component);
+
+       rt1015p->calib_done = false;
+       return 0;
+}
+#else
+#define rt1015p_suspend NULL
+#endif
+
 static const struct snd_soc_component_driver rt1015p_component_driver = {
+       .suspend                = rt1015p_suspend,
        .dapm_widgets           = rt1015p_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(rt1015p_dapm_widgets),
        .dapm_routes            = rt1015p_dapm_routes,
@@ -91,10 +91,6 @@ static const struct snd_soc_component_driver rt1015p_component_driver = {
        .non_legacy_dai_naming  = 1,
 };
 
-static const struct snd_soc_dai_ops rt1015p_dai_ops = {
-       .trigger        = rt1015p_daiops_trigger,
-};
-
 static struct snd_soc_dai_driver rt1015p_dai_driver = {
        .name = "HiFi",
        .playback = {
@@ -104,7 +100,6 @@ static struct snd_soc_dai_driver rt1015p_dai_driver = {
                .channels_min   = 1,
                .channels_max   = 2,
        },
-       .ops    = &rt1015p_dai_ops,
 };
 
 static int rt1015p_platform_probe(struct platform_device *pdev)
index c2621b0..ec5564f 100644 (file)
@@ -475,7 +475,7 @@ static int rt1308_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
        if (!stream)
                return -ENOMEM;
 
-       stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+       stream->sdw_stream = sdw_stream;
 
        /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
index 9e3813f..0edf09d 100644 (file)
@@ -1235,11 +1235,13 @@ static const struct i2c_device_id rt5660_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id rt5660_of_match[] = {
        { .compatible = "realtek,rt5660", },
        {},
 };
 MODULE_DEVICE_TABLE(of, rt5660_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id rt5660_acpi_match[] = {
index 6b4e0eb..37d1312 100644 (file)
@@ -221,6 +221,11 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
                case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
                        regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
                                RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
+                       if (rt5682->pdata.dmic_clk_driving_high)
+                               regmap_update_bits(rt5682->regmap,
+                                       RT5682_PAD_DRIVING_CTRL,
+                                       RT5682_PAD_DRV_GP3_MASK,
+                                       2 << RT5682_PAD_DRV_GP3_SFT);
                        break;
 
                default:
index 58fb131..4d707e8 100644 (file)
@@ -103,7 +103,7 @@ static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
        if (!stream)
                return -ENOMEM;
 
-       stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+       stream->sdw_stream = sdw_stream;
 
        /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
index d987817..4d865ed 100644 (file)
@@ -2990,6 +2990,9 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
                         rt5682->pdata.dai_clk_names[RT5682_DAI_WCLK_IDX],
                         rt5682->pdata.dai_clk_names[RT5682_DAI_BCLK_IDX]);
 
+       rt5682->pdata.dmic_clk_driving_high = device_property_read_bool(dev,
+               "realtek,dmic-clk-driving-high");
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt5682_parse_dt);
index 354acd7..99b85cf 100644 (file)
 #define RT5682_CP_CLK_HP_300KHZ                        (0x2 << 4)
 #define RT5682_CP_CLK_HP_600KHZ                        (0x3 << 4)
 
+/* Pad Driving Control (0x0136) */
+#define RT5682_PAD_DRV_GP1_MASK                        (0x3 << 14)
+#define RT5682_PAD_DRV_GP1_SFT                 14
+#define RT5682_PAD_DRV_GP2_MASK                        (0x3 << 12)
+#define RT5682_PAD_DRV_GP2_SFT                 12
+#define RT5682_PAD_DRV_GP3_MASK                        (0x3 << 10)
+#define RT5682_PAD_DRV_GP3_SFT                 10
+#define RT5682_PAD_DRV_GP4_MASK                        (0x3 << 8)
+#define RT5682_PAD_DRV_GP4_SFT                 8
+#define RT5682_PAD_DRV_GP5_MASK                        (0x3 << 6)
+#define RT5682_PAD_DRV_GP5_SFT                 6
+#define RT5682_PAD_DRV_GP6_MASK                        (0x3 << 4)
+#define RT5682_PAD_DRV_GP6_SFT                 4
+
 /* Chopper and Clock control for DAC (0x013a)*/
 #define RT5682_CKXEN_DAC1_MASK                 (0x1 << 13)
 #define RT5682_CKXEN_DAC1_SFT                  13
index 687ac21..66ec395 100644 (file)
@@ -867,7 +867,7 @@ static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
        if (!stream)
                return -ENOMEM;
 
-       stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+       stream->sdw_stream = sdw_stream;
 
        /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
index f0a0691..fc7df79 100644 (file)
@@ -338,7 +338,8 @@ static int rt711_update_status(struct sdw_slave *slave,
 static int rt711_read_prop(struct sdw_slave *slave)
 {
        struct sdw_slave_prop *prop = &slave->prop;
-       int nval, i;
+       int nval;
+       int i, j;
        u32 bit;
        unsigned long addr;
        struct sdw_dpn_prop *dpn;
@@ -379,15 +380,15 @@ static int rt711_read_prop(struct sdw_slave *slave)
        if (!prop->sink_dpn_prop)
                return -ENOMEM;
 
-       i = 0;
+       j = 0;
        dpn = prop->sink_dpn_prop;
        addr = prop->sink_ports;
        for_each_set_bit(bit, &addr, 32) {
-               dpn[i].num = bit;
-               dpn[i].type = SDW_DPN_FULL;
-               dpn[i].simple_ch_prep_sm = true;
-               dpn[i].ch_prep_timeout = 10;
-               i++;
+               dpn[j].num = bit;
+               dpn[j].type = SDW_DPN_FULL;
+               dpn[j].simple_ch_prep_sm = true;
+               dpn[j].ch_prep_timeout = 10;
+               j++;
        }
 
        /* set the timeout values */
index 65b59db..5771c02 100644 (file)
@@ -913,7 +913,7 @@ static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
        if (!stream)
                return -ENOMEM;
 
-       stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+       stream->sdw_stream = sdw_stream;
 
        /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
new file mode 100644 (file)
index 0000000..889b6b3
--- /dev/null
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt715-sdca-sdw.c -- rt715 ALSA SoC audio driver
+//
+// Copyright(c) 2020 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "rt715-sdca.h"
+#include "rt715-sdca-sdw.h"
+
+static bool rt715_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x201a ... 0x2027:
+       case 0x2029 ... 0x202a:
+       case 0x202d ... 0x2034:
+       case 0x2200 ... 0x2204:
+       case 0x2206 ... 0x2212:
+       case 0x2230 ... 0x2239:
+       case 0x2f5b:
+       case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+               RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00):
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt715_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x201b:
+       case 0x201c:
+       case 0x201d:
+       case 0x201f:
+       case 0x2021:
+       case 0x2023:
+       case 0x2230:
+       case 0x202d ... 0x202f: /* BRA */
+       case 0x2200 ... 0x2212: /* i2c debug */
+       case 0x2f07:
+       case 0x2f1b ... 0x2f1e:
+       case 0x2f30 ... 0x2f34:
+       case 0x2f50 ... 0x2f51:
+       case 0x2f53 ... 0x2f59:
+       case 0x2f5c ... 0x2f5f:
+       case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+               RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): /* VAD Searching status */
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x2000000:
+       case 0x200002b:
+       case 0x2000036:
+       case 0x2000037:
+       case 0x2000039:
+       case 0x6100000:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt715_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x2000000:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config rt715_sdca_regmap = {
+       .reg_bits = 32,
+       .val_bits = 8,
+       .readable_reg = rt715_sdca_readable_register,
+       .volatile_reg = rt715_sdca_volatile_register,
+       .max_register = 0x43ffffff,
+       .reg_defaults = rt715_reg_defaults_sdca,
+       .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca),
+       .cache_type = REGCACHE_RBTREE,
+       .use_single_read = true,
+       .use_single_write = true,
+};
+
+static const struct regmap_config rt715_sdca_mbq_regmap = {
+       .name = "sdw-mbq",
+       .reg_bits = 32,
+       .val_bits = 16,
+       .readable_reg = rt715_sdca_mbq_readable_register,
+       .volatile_reg = rt715_sdca_mbq_volatile_register,
+       .max_register = 0x43ffffff,
+       .reg_defaults = rt715_mbq_reg_defaults_sdca,
+       .num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca),
+       .cache_type = REGCACHE_RBTREE,
+       .use_single_read = true,
+       .use_single_write = true,
+};
+
+static int rt715_update_status(struct sdw_slave *slave,
+                               enum sdw_slave_status status)
+{
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       /* Update the status */
+       rt715->status = status;
+
+       /*
+        * Perform initialization only if slave status is present and
+        * hw_init flag is false
+        */
+       if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED)
+               return 0;
+
+       /* perform I/O transfers required for Slave initialization */
+       return rt715_io_init(&slave->dev, slave);
+}
+
+static int rt715_read_prop(struct sdw_slave *slave)
+{
+       struct sdw_slave_prop *prop = &slave->prop;
+       int nval, i;
+       u32 bit;
+       unsigned long addr;
+       struct sdw_dpn_prop *dpn;
+
+       prop->paging_support = true;
+
+       /* first we need to allocate memory for set bits in port lists */
+       prop->source_ports = 0x50;/* BITMAP: 01010000 */
+       prop->sink_ports = 0x0; /* BITMAP:  00000000 */
+
+       nval = hweight32(prop->source_ports);
+       prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+                                       sizeof(*prop->src_dpn_prop),
+                                       GFP_KERNEL);
+       if (!prop->src_dpn_prop)
+               return -ENOMEM;
+
+       dpn = prop->src_dpn_prop;
+       i = 0;
+       addr = prop->source_ports;
+       for_each_set_bit(bit, &addr, 32) {
+               dpn[i].num = bit;
+               dpn[i].simple_ch_prep_sm = true;
+               dpn[i].ch_prep_timeout = 10;
+               i++;
+       }
+
+       /* set the timeout values */
+       prop->clk_stop_timeout = 20;
+
+       return 0;
+}
+
+static struct sdw_slave_ops rt715_sdca_slave_ops = {
+       .read_prop = rt715_read_prop,
+       .update_status = rt715_update_status,
+};
+
+static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
+                          const struct sdw_device_id *id)
+{
+       struct regmap *mbq_regmap, *regmap;
+
+       slave->ops = &rt715_sdca_slave_ops;
+
+       /* Regmap Initialization */
+       mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap);
+       if (!mbq_regmap)
+               return -EINVAL;
+
+       regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap);
+       if (!regmap)
+               return -EINVAL;
+
+       return rt715_init(&slave->dev, mbq_regmap, regmap, slave);
+}
+
+static const struct sdw_device_id rt715_sdca_id[] = {
+       SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0),
+       SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0),
+       {},
+};
+MODULE_DEVICE_TABLE(sdw, rt715_sdca_id);
+
+static int __maybe_unused rt715_dev_suspend(struct device *dev)
+{
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+
+       if (!rt715->hw_init)
+               return 0;
+
+       regcache_cache_only(rt715->regmap, true);
+       regcache_mark_dirty(rt715->regmap);
+       regcache_cache_only(rt715->mbq_regmap, true);
+       regcache_mark_dirty(rt715->mbq_regmap);
+
+       return 0;
+}
+
+#define RT715_PROBE_TIMEOUT 2000
+
+static int __maybe_unused rt715_dev_resume(struct device *dev)
+{
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+       unsigned long time;
+
+       if (!rt715->hw_init)
+               return 0;
+
+       if (!slave->unattach_request)
+               goto regmap_sync;
+
+       time = wait_for_completion_timeout(&slave->enumeration_complete,
+                                          msecs_to_jiffies(RT715_PROBE_TIMEOUT));
+       if (!time) {
+               dev_err(&slave->dev, "Enumeration not complete, timed out\n");
+               return -ETIMEDOUT;
+       }
+
+regmap_sync:
+       slave->unattach_request = 0;
+       regcache_cache_only(rt715->regmap, false);
+       regcache_sync_region(rt715->regmap,
+               SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL,
+                       CH_00),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+                       RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00));
+       regcache_cache_only(rt715->mbq_regmap, false);
+       regcache_sync_region(rt715->mbq_regmap, 0x2000000, 0x61020ff);
+       regcache_sync_region(rt715->mbq_regmap,
+               SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL,
+                       CH_00),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+                       RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00));
+
+       return 0;
+}
+
+static const struct dev_pm_ops rt715_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
+       SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
+};
+
+static struct sdw_driver rt715_sdw_driver = {
+       .driver = {
+               .name = "rt715-sdca",
+               .owner = THIS_MODULE,
+               .pm = &rt715_pm,
+       },
+       .probe = rt715_sdca_sdw_probe,
+       .ops = &rt715_sdca_slave_ops,
+       .id_table = rt715_sdca_id,
+};
+module_sdw_driver(rt715_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT715 driver SDW SDCA");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h
new file mode 100644 (file)
index 0000000..cd365bb
--- /dev/null
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt715-sdca-sdw.h -- RT715 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2020 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT715_SDW_SDCA_H__
+#define __RT715_SDW_SDCA_H__
+
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt715_reg_defaults_sdca[] = {
+       { 0x201a, 0x00 },
+       { 0x201e, 0x00 },
+       { 0x2020, 0x00 },
+       { 0x2021, 0x00 },
+       { 0x2022, 0x00 },
+       { 0x2023, 0x00 },
+       { 0x2024, 0x00 },
+       { 0x2025, 0x01 },
+       { 0x2026, 0x00 },
+       { 0x2027, 0x00 },
+       { 0x2029, 0x00 },
+       { 0x202a, 0x00 },
+       { 0x202d, 0x00 },
+       { 0x202e, 0x00 },
+       { 0x202f, 0x00 },
+       { 0x2030, 0x00 },
+       { 0x2031, 0x00 },
+       { 0x2032, 0x00 },
+       { 0x2033, 0x00 },
+       { 0x2034, 0x00 },
+       { 0x2230, 0x00 },
+       { 0x2231, 0x2f },
+       { 0x2232, 0x80 },
+       { 0x2233, 0x00 },
+       { 0x2234, 0x00 },
+       { 0x2235, 0x00 },
+       { 0x2236, 0x00 },
+       { 0x2237, 0x00 },
+       { 0x2238, 0x00 },
+       { 0x2239, 0x00 },
+       { 0x2f01, 0x00 },
+       { 0x2f02, 0x09 },
+       { 0x2f03, 0x0b },
+       { 0x2f04, 0x00 },
+       { 0x2f05, 0x0e },
+       { 0x2f06, 0x01 },
+       { 0x2f08, 0x00 },
+       { 0x2f09, 0x00 },
+       { 0x2f0a, 0x00 },
+       { 0x2f0b, 0x00 },
+       { 0x2f0c, 0x00 },
+       { 0x2f0d, 0x00 },
+       { 0x2f0e, 0x12 },
+       { 0x2f0f, 0x00 },
+       { 0x2f10, 0x00 },
+       { 0x2f11, 0x00 },
+       { 0x2f12, 0x00 },
+       { 0x2f13, 0x00 },
+       { 0x2f14, 0x00 },
+       { 0x2f15, 0x00 },
+       { 0x2f16, 0x00 },
+       { 0x2f17, 0x00 },
+       { 0x2f18, 0x00 },
+       { 0x2f19, 0x03 },
+       { 0x2f1a, 0x00 },
+       { 0x2f1f, 0x10 },
+       { 0x2f20, 0x00 },
+       { 0x2f21, 0x00 },
+       { 0x2f22, 0x00 },
+       { 0x2f23, 0x00 },
+       { 0x2f24, 0x00 },
+       { 0x2f25, 0x00 },
+       { 0x2f52, 0x01 },
+       { 0x2f5a, 0x02 },
+       { 0x2f5b, 0x05 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+               RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+               RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+               RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+               RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+};
+
+static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
+       { 0x200002b, 0x0420 },
+       { 0x2000036, 0x0000 },
+       { 0x2000037, 0x0000 },
+       { 0x2000039, 0xaa81 },
+       { 0x6100000, 0x0100 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+               RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+       { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+               RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
+};
+#endif /* __RT715_SDW_SDCA_H__ */
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
new file mode 100644 (file)
index 0000000..b843e47
--- /dev/null
@@ -0,0 +1,936 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt715-sdca.c -- rt715 ALSA SoC audio driver
+//
+// Copyright(c) 2020 Realtek Semiconductor Corp.
+//
+//
+//
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.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 <linux/soundwire/sdw_registers.h>
+
+#include "rt715-sdca.h"
+
+static int rt715_index_write(struct rt715_sdca_priv *rt715, unsigned int nid,
+               unsigned int reg, unsigned int value)
+{
+       struct regmap *regmap = rt715->mbq_regmap;
+       unsigned int addr;
+       int ret;
+
+       addr = (nid << 20) | reg;
+
+       ret = regmap_write(regmap, addr, value);
+       if (ret < 0)
+               dev_err(&rt715->slave->dev,
+                               "Failed to set private value: %08x <= %04x %d\n", ret, addr,
+                               value);
+
+       return ret;
+}
+
+static int rt715_index_read(struct rt715_sdca_priv *rt715,
+               unsigned int nid, unsigned int reg, unsigned int *value)
+{
+       struct regmap *regmap = rt715->mbq_regmap;
+       unsigned int addr;
+       int ret;
+
+       addr = (nid << 20) | reg;
+
+       ret = regmap_read(regmap, addr, value);
+       if (ret < 0)
+               dev_err(&rt715->slave->dev,
+                               "Failed to get private value: %06x => %04x ret=%d\n",
+                               addr, *value, ret);
+
+       return ret;
+}
+
+static int rt715_index_update_bits(struct rt715_sdca_priv *rt715,
+       unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+       unsigned int tmp;
+       int ret;
+
+       ret = rt715_index_read(rt715, nid, reg, &tmp);
+       if (ret < 0)
+               return ret;
+
+       set_mask_bits(&tmp, mask, val);
+
+       return rt715_index_write(rt715, nid, reg, tmp);
+}
+
+/* SDCA Volume/Boost control */
+static int rt715_set_amp_gain_put_sdca(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+       unsigned int val_l, val_r, gain_l_val, gain_r_val;
+       int ret;
+
+       /* control value to 2s complement */
+       /* L channel */
+       gain_l_val = ucontrol->value.integer.value[0];
+       if (gain_l_val > mc->max)
+               gain_l_val = mc->max;
+       val_l = gain_l_val;
+
+       if (mc->shift == 8) {
+               gain_l_val = (gain_l_val * 10) << mc->shift;
+       } else {
+               gain_l_val =
+                       ((abs(gain_l_val - mc->shift) * RT715_SDCA_DB_STEP) << 8) / 1000;
+               if (val_l <= mc->shift) {
+                       gain_l_val = ~gain_l_val;
+                       gain_l_val += 1;
+               }
+               gain_l_val &= 0xffff;
+       }
+
+       /* R channel */
+       gain_r_val = ucontrol->value.integer.value[1];
+       if (gain_r_val > mc->max)
+               gain_r_val = mc->max;
+       val_r = gain_r_val;
+
+       if (mc->shift == 8) {
+               gain_r_val = (gain_r_val * 10) << mc->shift;
+       } else {
+               gain_r_val =
+                       ((abs(gain_r_val - mc->shift) * RT715_SDCA_DB_STEP) << 8) / 1000;
+               if (val_r <= mc->shift) {
+                       gain_r_val = ~gain_r_val;
+                       gain_r_val += 1;
+               }
+               gain_r_val &= 0xffff;
+       }
+
+       /* Lch*/
+       ret = regmap_write(rt715->mbq_regmap, mc->reg, gain_l_val);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to write 0x%x=0x%x\n", mc->reg,
+                       gain_l_val);
+               return ret;
+       }
+       /* Rch */
+       ret = regmap_write(rt715->mbq_regmap, mc->rreg, gain_r_val);
+       if (ret != 0) {
+               dev_err(component->dev, "Failed to write 0x%x=0x%x\n", mc->rreg,
+                       gain_r_val);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rt715_set_amp_gain_get_sdca(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+       unsigned int val_l, val_r, ctl_l, ctl_r, neg_flag = 0;
+       int ret;
+
+       ret = regmap_read(rt715->mbq_regmap, mc->reg, &val_l);
+       if (ret < 0)
+               dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", mc->reg, ret);
+       ret = regmap_read(rt715->mbq_regmap, mc->rreg, &val_r);
+       if (ret < 0)
+               dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", mc->rreg,
+                               ret);
+
+       /* L channel */
+       if (mc->shift == 8) {
+               ctl_l = (val_l >> mc->shift) / 10;
+       } else {
+               ctl_l = val_l;
+               if (ctl_l & BIT(15)) {
+                       ctl_l = ~(val_l - 1) & 0xffff;
+                       neg_flag = 1;
+               }
+               ctl_l *= 1000;
+               ctl_l >>= 8;
+               if (neg_flag)
+                       ctl_l = mc->shift - ctl_l / RT715_SDCA_DB_STEP;
+               else
+                       ctl_l = mc->shift + ctl_l / RT715_SDCA_DB_STEP;
+       }
+
+       neg_flag = 0;
+       /* R channel */
+       if (mc->shift == 8) {
+               ctl_r = (val_r >> mc->shift) / 10;
+       } else {
+               ctl_r = val_r;
+               if (ctl_r & BIT(15)) {
+                       ctl_r = ~(val_r - 1) & 0xffff;
+                       neg_flag = 1;
+               }
+               ctl_r *= 1000;
+               ctl_r >>= 8;
+               if (neg_flag)
+                       ctl_r = mc->shift - ctl_r / RT715_SDCA_DB_STEP;
+               else
+                       ctl_r = mc->shift + ctl_r / RT715_SDCA_DB_STEP;
+       }
+
+       ucontrol->value.integer.value[0] = ctl_l;
+       ucontrol->value.integer.value[1] = ctl_r;
+
+       return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
+        xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
+                                           xmax, xinvert) }
+
+static const struct snd_kcontrol_new rt715_snd_controls_sdca[] = {
+       /* Capture switch */
+       SOC_DOUBLE_R("FU0A Capture Switch",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_02),
+                       0, 1, 1),
+       SOC_DOUBLE_R("FU02 1_2 Capture Switch",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_02),
+                       0, 1, 1),
+       SOC_DOUBLE_R("FU02 3_4 Capture Switch",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_03),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_04),
+                       0, 1, 1),
+       SOC_DOUBLE_R("FU06 1_2 Capture Switch",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_02),
+                       0, 1, 1),
+       SOC_DOUBLE_R("FU06 3_4 Capture Switch",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_03),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_MUTE_CTRL, CH_04),
+                       0, 1, 1),
+       /* Volume Control */
+       SOC_DOUBLE_R_EXT_TLV("FU0A Capture Volume",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+                       RT715_SDCA_FU_VOL_CTRL, CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+                       RT715_SDCA_FU_VOL_CTRL, CH_02),
+                       0x2f, 0x7f, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               in_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU02 1_2 Capture Volume",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_VOL_CTRL, CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_VOL_CTRL, CH_02),
+                       0x2f, 0x7f, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               in_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU02 3_4 Capture Volume",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_VOL_CTRL,
+                       CH_03),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+                       RT715_SDCA_FU_VOL_CTRL,
+                       CH_04), 0x2f, 0x7f, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               in_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU06 1_2 Capture Volume",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_VOL_CTRL,
+                       CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_VOL_CTRL,
+                       CH_02), 0x2f, 0x7f, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               in_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU06 3_4 Capture Volume",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_VOL_CTRL,
+                       CH_03),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+                       RT715_SDCA_FU_VOL_CTRL,
+                       CH_04), 0x2f, 0x7f, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               in_vol_tlv),
+       /* MIC Boost Control */
+       SOC_DOUBLE_R_EXT_TLV("FU0E 1_2 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_02), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0E 3_4 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_03),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_04), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0E 5_6 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_05),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_06), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0E 7_8 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_07),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_08), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0C 1_2 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_01),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_02), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0C 3_4 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_03),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_04), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0C 5_6 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_05),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_06), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+       SOC_DOUBLE_R_EXT_TLV("FU0C 7_8 Boost",
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_07),
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+                       RT715_SDCA_FU_DMIC_GAIN_CTRL,
+                       CH_08), 8, 3, 0,
+               rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+               mic_vol_tlv),
+};
+
+static int rt715_mux_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_kcontrol_component(kcontrol);
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+       unsigned int val, mask_sft;
+
+       if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+               mask_sft = 12;
+       else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+               mask_sft = 8;
+       else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+               mask_sft = 4;
+       else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+               mask_sft = 0;
+       else
+               return -EINVAL;
+
+       rt715_index_read(rt715, RT715_VENDOR_HDA_CTL,
+               RT715_HDA_LEGACY_MUX_CTL1, &val);
+       val = (val >> mask_sft) & 0xf;
+
+       /*
+        * The first two indices of ADC Mux 24/25 are routed to the same
+        * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2.
+        * To have a unique set of inputs, we skip the index1 of the muxes.
+        */
+       if ((strstr(ucontrol->id.name, "ADC 24 Mux") ||
+               strstr(ucontrol->id.name, "ADC 25 Mux")) && val > 0)
+               val -= 1;
+       ucontrol->value.enumerated.item[0] = val;
+
+       return 0;
+}
+
+static int rt715_mux_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_kcontrol_component(kcontrol);
+       struct snd_soc_dapm_context *dapm =
+                               snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int *item = ucontrol->value.enumerated.item;
+       unsigned int val, val2 = 0, change, mask_sft;
+
+       if (item[0] >= e->items)
+               return -EINVAL;
+
+       if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+               mask_sft = 12;
+       else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+               mask_sft = 8;
+       else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+               mask_sft = 4;
+       else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+               mask_sft = 0;
+       else
+               return -EINVAL;
+
+       /* Verb ID = 0x701h, nid = e->reg */
+       val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+       rt715_index_read(rt715, RT715_VENDOR_HDA_CTL,
+               RT715_HDA_LEGACY_MUX_CTL1, &val2);
+       val2 = (val2 >> mask_sft) & 0xf;
+
+       change = val != val2;
+
+       if (change)
+               rt715_index_update_bits(rt715, RT715_VENDOR_HDA_CTL,
+                       RT715_HDA_LEGACY_MUX_CTL1, 0xf << mask_sft, val << mask_sft);
+
+       snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL);
+
+       return change;
+}
+
+static const char * const adc_22_23_mux_text[] = {
+       "MIC1",
+       "MIC2",
+       "LINE1",
+       "LINE2",
+       "DMIC1",
+       "DMIC2",
+       "DMIC3",
+       "DMIC4",
+};
+
+/*
+ * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and
+ * 1 will be connected to the same dmic source, therefore we skip index 1 to
+ * avoid misunderstanding on usage of dapm routing.
+ */
+static int rt715_adc_24_25_values[] = {
+       0,
+       2,
+       3,
+       4,
+       5,
+};
+
+static const char * const adc_24_mux_text[] = {
+       "MIC2",
+       "DMIC1",
+       "DMIC2",
+       "DMIC3",
+       "DMIC4",
+};
+
+static const char * const adc_25_mux_text[] = {
+       "MIC1",
+       "DMIC1",
+       "DMIC2",
+       "DMIC3",
+       "DMIC4",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt715_adc22_enum, SND_SOC_NOPM, 0,
+       adc_22_23_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rt715_adc23_enum, SND_SOC_NOPM, 0,
+       adc_22_23_mux_text);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum,
+       SND_SOC_NOPM, 0, 0xf,
+       adc_24_mux_text, rt715_adc_24_25_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum,
+       SND_SOC_NOPM, 0, 0xf,
+       adc_25_mux_text, rt715_adc_24_25_values);
+
+static const struct snd_kcontrol_new rt715_adc22_mux =
+       SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum,
+                       rt715_mux_get, rt715_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc23_mux =
+       SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum,
+                       rt715_mux_get, rt715_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc24_mux =
+       SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum,
+                       rt715_mux_get, rt715_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc25_mux =
+       SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum,
+                       rt715_mux_get, rt715_mux_put);
+
+static int rt715_pde23_24_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_write(rt715->regmap,
+                       SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN,
+                               RT715_SDCA_REQ_POW_CTRL,
+                               CH_00), 0x00);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_write(rt715->regmap,
+                       SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN,
+                               RT715_SDCA_REQ_POW_CTRL,
+                               CH_00), 0x03);
+               break;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt715_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("DMIC1"),
+       SND_SOC_DAPM_INPUT("DMIC2"),
+       SND_SOC_DAPM_INPUT("DMIC3"),
+       SND_SOC_DAPM_INPUT("DMIC4"),
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("LINE1"),
+       SND_SOC_DAPM_INPUT("LINE2"),
+
+       SND_SOC_DAPM_SUPPLY("PDE23_24", SND_SOC_NOPM, 0, 0,
+               rt715_pde23_24_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_ADC("ADC 07", NULL, SND_SOC_NOPM, 4, 0),
+       SND_SOC_DAPM_ADC("ADC 08", NULL, SND_SOC_NOPM, 4, 0),
+       SND_SOC_DAPM_ADC("ADC 09", NULL, SND_SOC_NOPM, 4, 0),
+       SND_SOC_DAPM_ADC("ADC 27", NULL, SND_SOC_NOPM, 4, 0),
+       SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
+               &rt715_adc22_mux),
+       SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
+               &rt715_adc23_mux),
+       SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0,
+               &rt715_adc24_mux),
+       SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0,
+               &rt715_adc25_mux),
+       SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt715_audio_map[] = {
+       {"DP6TX", NULL, "ADC 09"},
+       {"DP6TX", NULL, "ADC 08"},
+       {"DP4TX", NULL, "ADC 07"},
+       {"DP4TX", NULL, "ADC 27"},
+       {"DP4TX", NULL, "ADC 09"},
+       {"DP4TX", NULL, "ADC 08"},
+
+       {"LINE1", NULL, "PDE23_24"},
+       {"LINE2", NULL, "PDE23_24"},
+       {"MIC1", NULL, "PDE23_24"},
+       {"MIC2", NULL, "PDE23_24"},
+       {"DMIC1", NULL, "PDE23_24"},
+       {"DMIC2", NULL, "PDE23_24"},
+       {"DMIC3", NULL, "PDE23_24"},
+       {"DMIC4", NULL, "PDE23_24"},
+
+       {"ADC 09", NULL, "ADC 22 Mux"},
+       {"ADC 08", NULL, "ADC 23 Mux"},
+       {"ADC 07", NULL, "ADC 24 Mux"},
+       {"ADC 27", NULL, "ADC 25 Mux"},
+       {"ADC 22 Mux", "MIC1", "MIC1"},
+       {"ADC 22 Mux", "MIC2", "MIC2"},
+       {"ADC 22 Mux", "LINE1", "LINE1"},
+       {"ADC 22 Mux", "LINE2", "LINE2"},
+       {"ADC 22 Mux", "DMIC1", "DMIC1"},
+       {"ADC 22 Mux", "DMIC2", "DMIC2"},
+       {"ADC 22 Mux", "DMIC3", "DMIC3"},
+       {"ADC 22 Mux", "DMIC4", "DMIC4"},
+       {"ADC 23 Mux", "MIC1", "MIC1"},
+       {"ADC 23 Mux", "MIC2", "MIC2"},
+       {"ADC 23 Mux", "LINE1", "LINE1"},
+       {"ADC 23 Mux", "LINE2", "LINE2"},
+       {"ADC 23 Mux", "DMIC1", "DMIC1"},
+       {"ADC 23 Mux", "DMIC2", "DMIC2"},
+       {"ADC 23 Mux", "DMIC3", "DMIC3"},
+       {"ADC 23 Mux", "DMIC4", "DMIC4"},
+       {"ADC 24 Mux", "MIC2", "MIC2"},
+       {"ADC 24 Mux", "DMIC1", "DMIC1"},
+       {"ADC 24 Mux", "DMIC2", "DMIC2"},
+       {"ADC 24 Mux", "DMIC3", "DMIC3"},
+       {"ADC 24 Mux", "DMIC4", "DMIC4"},
+       {"ADC 25 Mux", "MIC1", "MIC1"},
+       {"ADC 25 Mux", "DMIC1", "DMIC1"},
+       {"ADC 25 Mux", "DMIC2", "DMIC2"},
+       {"ADC 25 Mux", "DMIC3", "DMIC3"},
+       {"ADC 25 Mux", "DMIC4", "DMIC4"},
+};
+
+static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = {
+       .controls = rt715_snd_controls_sdca,
+       .num_controls = ARRAY_SIZE(rt715_snd_controls_sdca),
+       .dapm_widgets = rt715_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets),
+       .dapm_routes = rt715_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(rt715_audio_map),
+};
+
+static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+                               int direction)
+{
+       struct rt715_sdw_stream_data *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+
+       stream->sdw_stream = sdw_stream;
+
+       /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               dai->playback_dma_data = stream;
+       else
+               dai->capture_dma_data = stream;
+
+       return 0;
+}
+
+static void rt715_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+
+{
+       struct rt715_sdw_stream_data *stream;
+
+       stream = snd_soc_dai_get_dma_data(dai, substream);
+       if (!stream)
+               return;
+
+       snd_soc_dai_set_dma_data(dai, substream, NULL);
+       kfree(stream);
+}
+
+static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+       struct sdw_stream_config stream_config;
+       struct sdw_port_config port_config;
+       enum sdw_data_direction direction;
+       struct rt715_sdw_stream_data *stream;
+       int retval, port, num_channels;
+       unsigned int val;
+
+       stream = snd_soc_dai_get_dma_data(dai, substream);
+
+       if (!stream)
+               return -EINVAL;
+
+       if (!rt715->slave)
+               return -EINVAL;
+
+       switch (dai->id) {
+       case RT715_AIF1:
+               direction = SDW_DATA_DIR_TX;
+               port = 6;
+               rt715_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
+                       0xa500);
+               break;
+       case RT715_AIF2:
+               direction = SDW_DATA_DIR_TX;
+               port = 4;
+               rt715_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
+                       0xaf00);
+               break;
+       default:
+               dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
+               return -EINVAL;
+       }
+
+       stream_config.frame_rate =  params_rate(params);
+       stream_config.ch_count = params_channels(params);
+       stream_config.bps = snd_pcm_format_width(params_format(params));
+       stream_config.direction = direction;
+
+       num_channels = params_channels(params);
+       port_config.ch_mask = GENMASK(num_channels - 1, 0);
+       port_config.num = port;
+
+       retval = sdw_stream_add_slave(rt715->slave, &stream_config,
+                                       &port_config, 1, stream->sdw_stream);
+       if (retval) {
+               dev_err(component->dev, "Unable to configure port, retval:%d\n",
+                       retval);
+               return retval;
+       }
+
+       switch (params_rate(params)) {
+       case 8000:
+               val = 0x1;
+               break;
+       case 11025:
+               val = 0x2;
+               break;
+       case 12000:
+               val = 0x3;
+               break;
+       case 16000:
+               val = 0x4;
+               break;
+       case 22050:
+               val = 0x5;
+               break;
+       case 24000:
+               val = 0x6;
+               break;
+       case 32000:
+               val = 0x7;
+               break;
+       case 44100:
+               val = 0x8;
+               break;
+       case 48000:
+               val = 0x9;
+               break;
+       case 88200:
+               val = 0xa;
+               break;
+       case 96000:
+               val = 0xb;
+               break;
+       case 176400:
+               val = 0xc;
+               break;
+       case 192000:
+               val = 0xd;
+               break;
+       case 384000:
+               val = 0xe;
+               break;
+       case 768000:
+               val = 0xf;
+               break;
+       default:
+               dev_err(component->dev, "Unsupported sample rate %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       regmap_write(rt715->regmap,
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CS_FREQ_IND_EN,
+                       RT715_SDCA_FREQ_IND_CTRL, CH_00), val);
+
+       return 0;
+}
+
+static int rt715_pcm_hw_free(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+       struct rt715_sdw_stream_data *stream =
+               snd_soc_dai_get_dma_data(dai, substream);
+
+       if (!rt715->slave)
+               return -EINVAL;
+
+       sdw_stream_remove_slave(rt715->slave, stream->sdw_stream);
+       return 0;
+}
+
+#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static struct snd_soc_dai_ops rt715_ops = {
+       .hw_params      = rt715_pcm_hw_params,
+       .hw_free        = rt715_pcm_hw_free,
+       .set_sdw_stream = rt715_set_sdw_stream,
+       .shutdown       = rt715_shutdown,
+};
+
+static struct snd_soc_dai_driver rt715_dai[] = {
+       {
+               .name = "rt715-aif1",
+               .id = RT715_AIF1,
+               .capture = {
+                       .stream_name = "DP6 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT715_STEREO_RATES,
+                       .formats = RT715_FORMATS,
+               },
+               .ops = &rt715_ops,
+       },
+       {
+               .name = "rt715-aif2",
+               .id = RT715_AIF2,
+               .capture = {
+                       .stream_name = "DP4 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT715_STEREO_RATES,
+                       .formats = RT715_FORMATS,
+               },
+               .ops = &rt715_ops,
+       },
+};
+
+/* Bus clock frequency */
+#define RT715_CLK_FREQ_9600000HZ 9600000
+#define RT715_CLK_FREQ_12000000HZ 12000000
+#define RT715_CLK_FREQ_6000000HZ 6000000
+#define RT715_CLK_FREQ_4800000HZ 4800000
+#define RT715_CLK_FREQ_2400000HZ 2400000
+#define RT715_CLK_FREQ_12288000HZ 12288000
+
+int rt715_init(struct device *dev, struct regmap *mbq_regmap,
+       struct regmap *regmap, struct sdw_slave *slave)
+{
+       struct rt715_sdca_priv *rt715;
+       int ret;
+
+       rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL);
+       if (!rt715)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, rt715);
+       rt715->slave = slave;
+       rt715->regmap = regmap;
+       rt715->mbq_regmap = mbq_regmap;
+       rt715->hw_sdw_ver = slave->id.sdw_version;
+       /*
+        * Mark hw_init to false
+        * HW init will be performed when device reports present
+        */
+       rt715->hw_init = false;
+       rt715->first_init = false;
+
+       ret = devm_snd_soc_register_component(dev,
+                       &soc_codec_dev_rt715_sdca,
+                       rt715_dai,
+                       ARRAY_SIZE(rt715_dai));
+
+       return ret;
+}
+
+int rt715_io_init(struct device *dev, struct sdw_slave *slave)
+{
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+       unsigned int hw_ver;
+
+       if (rt715->hw_init)
+               return 0;
+
+       /*
+        * PM runtime is only enabled when a Slave reports as Attached
+        */
+       if (!rt715->first_init) {
+               /* set autosuspend parameters */
+               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+               pm_runtime_use_autosuspend(&slave->dev);
+
+               /* update count of parent 'active' children */
+               pm_runtime_set_active(&slave->dev);
+
+               /* make sure the device does not suspend immediately */
+               pm_runtime_mark_last_busy(&slave->dev);
+
+               pm_runtime_enable(&slave->dev);
+
+               rt715->first_init = true;
+       }
+
+       pm_runtime_get_noresume(&slave->dev);
+
+       rt715_index_read(rt715, RT715_VENDOR_REG,
+               RT715_PRODUCT_NUM, &hw_ver);
+       hw_ver = hw_ver & 0x000f;
+
+       /* set clock selector = external */
+       regmap_write(rt715->regmap,
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+                       RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1);
+       /* set GPIO_4/5/6 to be 3rd/4th DMIC usage */
+       if (hw_ver == 0x0)
+               rt715_index_update_bits(rt715, RT715_VENDOR_REG,
+                       RT715_AD_FUNC_EN, 0x54, 0x54);
+       else if (hw_ver == 0x1) {
+               rt715_index_update_bits(rt715, RT715_VENDOR_REG,
+                       RT715_AD_FUNC_EN, 0x55, 0x55);
+               rt715_index_update_bits(rt715, RT715_VENDOR_REG,
+                       RT715_REV_1, 0x40, 0x40);
+       }
+       /* trigger mode = VAD enable */
+       regmap_write(rt715->regmap,
+               SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+                       RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x2);
+       /* SMPU-1 interrupt enable mask */
+       regmap_update_bits(rt715->regmap, RT715_INT_MASK, 0x1, 0x1);
+
+       /* Mark Slave initialization complete */
+       rt715->hw_init = true;
+
+       pm_runtime_mark_last_busy(&slave->dev);
+       pm_runtime_put_autosuspend(&slave->dev);
+
+       return 0;
+}
+
+MODULE_DESCRIPTION("ASoC rt715 driver SDW SDCA");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h
new file mode 100644 (file)
index 0000000..6326cd8
--- /dev/null
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt715-sdca.h -- RT715 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2020 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT715_SDCA_H__
+#define __RT715_SDCA_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+
+struct rt715_sdca_priv {
+       struct regmap *regmap;
+       struct regmap *mbq_regmap;
+       struct snd_soc_codec *codec;
+       struct sdw_slave *slave;
+       struct delayed_work adc_mute_work;
+       int dbg_nid;
+       int dbg_vid;
+       int dbg_payload;
+       enum sdw_slave_status status;
+       struct sdw_bus_params params;
+       bool hw_init;
+       bool first_init;
+       int l_is_unmute;
+       int r_is_unmute;
+       int hw_sdw_ver;
+};
+
+struct rt715_sdw_stream_data {
+       struct sdw_stream_runtime *sdw_stream;
+};
+
+/* MIPI Register */
+#define RT715_INT_CTRL                                 0x005a
+#define RT715_INT_MASK                                 0x005e
+
+/* NID */
+#define RT715_AUDIO_FUNCTION_GROUP                     0x01
+#define RT715_MIC_ADC                                  0x07
+#define RT715_LINE_ADC                                 0x08
+#define RT715_MIX_ADC                                  0x09
+#define RT715_DMIC1                                    0x12
+#define RT715_DMIC2                                    0x13
+#define RT715_MIC1                                     0x18
+#define RT715_MIC2                                     0x19
+#define RT715_LINE1                                    0x1a
+#define RT715_LINE2                                    0x1b
+#define RT715_DMIC3                                    0x1d
+#define RT715_DMIC4                                    0x29
+#define RT715_VENDOR_REG                               0x20
+#define RT715_MUX_IN1                                  0x22
+#define RT715_MUX_IN2                                  0x23
+#define RT715_MUX_IN3                                  0x24
+#define RT715_MUX_IN4                                  0x25
+#define RT715_MIX_ADC2                                 0x27
+#define RT715_INLINE_CMD                               0x55
+#define RT715_VENDOR_HDA_CTL                           0x61
+
+/* Index (NID:20h) */
+#define RT715_PRODUCT_NUM                              0x0
+#define RT715_IRQ_CTRL                                 0x2b
+#define RT715_AD_FUNC_EN                               0x36
+#define RT715_REV_1                                    0x37
+#define RT715_SDW_INPUT_SEL                            0x39
+#define RT715_EXT_DMIC_CLK_CTRL2                       0x54
+
+/* Index (NID:61h) */
+#define RT715_HDA_LEGACY_MUX_CTL1                      0x00
+
+/* SDCA (Function) */
+#define FUN_JACK_CODEC                         0x01
+#define FUN_MIC_ARRAY                          0x02
+#define FUN_HID                                                0x03
+/* SDCA (Entity) */
+#define RT715_SDCA_ST_EN                                                       0x00
+#define RT715_SDCA_CS_FREQ_IND_EN                                      0x01
+#define RT715_SDCA_FU_ADC8_9_VOL                                       0x02
+#define RT715_SDCA_SMPU_TRIG_ST_EN                                     0x05
+#define RT715_SDCA_FU_ADC10_11_VOL                                     0x06
+#define RT715_SDCA_FU_ADC7_27_VOL                                      0x0a
+#define RT715_SDCA_FU_AMIC_GAIN_EN                                     0x0c
+#define RT715_SDCA_FU_DMIC_GAIN_EN                                     0x0e
+#define RT715_SDCA_CX_CLK_SEL_EN                                       0x10
+#define RT715_SDCA_CREQ_POW_EN                                         0x18
+/* SDCA (Control) */
+#define RT715_SDCA_ST_CTRL                                                     0x00
+#define RT715_SDCA_CX_CLK_SEL_CTRL                                     0x01
+#define RT715_SDCA_REQ_POW_CTRL                                        0x01
+#define RT715_SDCA_FU_MUTE_CTRL                                        0x01
+#define RT715_SDCA_FU_VOL_CTRL                                         0x02
+#define RT715_SDCA_FU_DMIC_GAIN_CTRL                           0x0b
+#define RT715_SDCA_FREQ_IND_CTRL                                       0x10
+#define RT715_SDCA_SMPU_TRIG_EN_CTRL                           0x10
+#define RT715_SDCA_SMPU_TRIG_ST_CTRL                           0x11
+/* SDCA (Channel) */
+#define CH_00                                          0x00
+#define CH_01                                          0x01
+#define CH_02                                          0x02
+#define CH_03                                          0x03
+#define CH_04                                          0x04
+#define CH_05                                          0x05
+#define CH_06                                          0x06
+#define CH_07                                          0x07
+#define CH_08                                          0x08
+
+#define RT715_SDCA_DB_STEP                     375
+
+enum {
+       RT715_AIF1,
+       RT715_AIF2,
+};
+
+int rt715_io_init(struct device *dev, struct sdw_slave *slave);
+int rt715_init(struct device *dev, struct regmap *mbq_regmap,
+       struct regmap *regmap, struct sdw_slave *slave);
+
+#endif /* __RT715_SDCA_H__ */
index 532c530..9a7d393 100644 (file)
@@ -537,7 +537,7 @@ static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
        if (!stream)
                return -ENOMEM;
 
-       stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+       stream->sdw_stream = sdw_stream;
 
        /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
index d0d0fd2..009a826 100644 (file)
@@ -207,7 +207,6 @@ struct sdw_stream_data {
 enum {
        RT715_AIF1,
        RT715_AIF2,
-       RT715_AIFS,
 };
 
 #define RT715_POWER_UP_DELAY_MS 400
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
new file mode 100644 (file)
index 0000000..e0a09da
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Bootlin SA
+ * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+
+struct simple_mux {
+       struct gpio_desc *gpiod_mux;
+       unsigned int mux;
+};
+
+static const char * const simple_mux_texts[] = {
+       "Input 1", "Input 2"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(simple_mux_enum, simple_mux_texts);
+
+static int simple_mux_control_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
+       struct simple_mux *priv = snd_soc_component_get_drvdata(c);
+
+       ucontrol->value.enumerated.item[0] = priv->mux;
+
+       return 0;
+}
+
+static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
+       struct simple_mux *priv = snd_soc_component_get_drvdata(c);
+
+       if (ucontrol->value.enumerated.item[0] > e->items)
+               return -EINVAL;
+
+       if (priv->mux == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       priv->mux = ucontrol->value.enumerated.item[0];
+
+       gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux);
+
+       return snd_soc_dapm_mux_update_power(dapm, kcontrol,
+                                            ucontrol->value.enumerated.item[0],
+                                            e, NULL);
+}
+
+static const struct snd_kcontrol_new simple_mux_mux =
+       SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
+
+static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("IN1"),
+       SND_SOC_DAPM_INPUT("IN2"),
+       SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux),
+       SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = {
+       { "OUT", NULL, "MUX" },
+       { "MUX", "Input 1", "IN1" },
+       { "MUX", "Input 2", "IN2" },
+};
+
+static const struct snd_soc_component_driver simple_mux_component_driver = {
+       .dapm_widgets           = simple_mux_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(simple_mux_dapm_widgets),
+       .dapm_routes            = simple_mux_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(simple_mux_dapm_routes),
+};
+
+static int simple_mux_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct simple_mux *priv;
+       int err;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, priv);
+
+       priv->gpiod_mux = devm_gpiod_get(dev, "mux", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->gpiod_mux)) {
+               err = PTR_ERR(priv->gpiod_mux);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get 'mux' gpio: %d", err);
+               return err;
+       }
+
+       return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id simple_mux_ids[] = {
+       { .compatible = "simple-audio-mux", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, simple_mux_ids);
+#endif
+
+static struct platform_driver simple_mux_driver = {
+       .driver = {
+               .name = "simple-mux",
+               .of_match_table = of_match_ptr(simple_mux_ids),
+       },
+       .probe = simple_mux_probe,
+};
+
+module_platform_driver(simple_mux_driver);
+
+MODULE_DESCRIPTION("ASoC Simple Audio Mux driver");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
+MODULE_LICENSE("GPL");
index f1ff204..19965fa 100644 (file)
@@ -802,6 +802,7 @@ static const struct i2c_device_id tas2562_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tas2562_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id tas2562_of_match[] = {
        { .compatible = "ti,tas2562", },
        { .compatible = "ti,tas2563", },
@@ -810,6 +811,7 @@ static const struct of_device_id tas2562_of_match[] = {
        { },
 };
 MODULE_DEVICE_TABLE(of, tas2562_of_match);
+#endif
 
 static struct i2c_driver tas2562_i2c_driver = {
        .driver = {
index 835a723..a3e6823 100644 (file)
@@ -773,7 +773,7 @@ static struct snd_soc_dai_driver tas571x_dai = {
        .ops = &tas571x_dai_ops,
 };
 
-static const struct of_device_id tas571x_of_match[];
+static const struct of_device_id tas571x_of_match[] __maybe_unused;
 
 static int tas571x_i2c_probe(struct i2c_client *client,
                             const struct i2c_device_id *id)
@@ -889,7 +889,7 @@ static int tas571x_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct of_device_id tas571x_of_match[] = {
+static const struct of_device_id tas571x_of_match[] __maybe_unused = {
        { .compatible = "ti,tas5707", .data = &tas5707_chip, },
        { .compatible = "ti,tas5711", .data = &tas5711_chip, },
        { .compatible = "ti,tas5717", .data = &tas5717_chip, },
index 53a8024..3f027c8 100644 (file)
@@ -1073,6 +1073,7 @@ static struct snd_soc_dai_driver adcx140_dai_driver[] = {
        }
 };
 
+#ifdef CONFIG_OF
 static const struct of_device_id tlv320adcx140_of_match[] = {
        { .compatible = "ti,tlv320adc3140" },
        { .compatible = "ti,tlv320adc5140" },
@@ -1080,6 +1081,7 @@ static const struct of_device_id tlv320adcx140_of_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match);
+#endif
 
 static int adcx140_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
index 5025e5c..dbb8f96 100644 (file)
@@ -35,11 +35,13 @@ static const struct i2c_device_id tlv320aic23_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id tlv320aic23_of_match[] = {
        { .compatible = "ti,tlv320aic23", },
        { }
 };
 MODULE_DEVICE_TABLE(of, tlv320aic23_of_match);
+#endif
 
 static struct i2c_driver tlv320aic23_i2c_driver = {
        .driver = {
index 3ed3b45..962f5d4 100644 (file)
@@ -366,11 +366,13 @@ static const struct i2c_device_id ts3a227e_i2c_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids);
 
+#ifdef CONFIG_OF
 static const struct of_device_id ts3a227e_of_match[] = {
        { .compatible = "ti,ts3a227e", },
        { }
 };
 MODULE_DEVICE_TABLE(of, ts3a227e_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static struct acpi_device_id ts3a227e_acpi_match[] = {
index 3265d3e..6200fab 100644 (file)
@@ -66,7 +66,7 @@ static bool tscs42xx_volatile(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tscs42xx_precious(struct device *dev, unsigned int reg)
@@ -81,7 +81,7 @@ static bool tscs42xx_precious(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static const struct regmap_config tscs42xx_regmap = {
@@ -1294,7 +1294,7 @@ static int part_is_valid(struct tscs42xx *tscs42xx)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static int set_sysclk(struct snd_soc_component *component)
index d0af16b..cd1f1a5 100644 (file)
@@ -177,7 +177,7 @@ static bool tscs454_volatile(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tscs454_writable(struct device *dev, unsigned int reg)
@@ -197,7 +197,7 @@ static bool tscs454_writable(struct device *dev, unsigned int reg)
                return false;
        default:
                return true;
-       };
+       }
 }
 
 static bool tscs454_readable(struct device *dev, unsigned int reg)
@@ -217,7 +217,7 @@ static bool tscs454_readable(struct device *dev, unsigned int reg)
                return false;
        default:
                return true;
-       };
+       }
 }
 
 static bool tscs454_precious(struct device *dev, unsigned int reg)
@@ -246,7 +246,7 @@ static bool tscs454_precious(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static const struct regmap_range_cfg tscs454_regmap_range_cfg = {
index 4d2b1ec..9ddfed7 100644 (file)
@@ -3979,7 +3979,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
        }
 
        for_each_set_bit(j, &status, 32) {
-               tx = (j >= 16 ? true : false);
+               tx = (j >= 16);
                port_id = (tx ? j - 16 : j);
                regmap_read(wcd->if_regmap,
                                WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val);
index 2ed3fa6..70d353b 100644 (file)
@@ -682,9 +682,7 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 
        mutex_lock(&arizona->dac_comp_lock);
-       memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
-              sizeof(arizona->dac_comp_coeff));
-       arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff);
+       arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
        mutex_unlock(&arizona->dac_comp_lock);
 
        return 0;
index a6aa212..15d42ce 100644 (file)
@@ -218,7 +218,8 @@ static void wm8350_pga_work(struct work_struct *work)
 
        /* PGA volumes have 6 bits of resolution to ramp */
        for (i = 0; i <= 63; i++) {
-               out1_complete = 1, out2_complete = 1;
+               out1_complete = 1;
+               out2_complete = 1;
                if (out1->ramp != WM8350_RAMP_NONE)
                        out1_complete = wm8350_out1_ramp_step(wm8350_data);
                if (out2->ramp != WM8350_RAMP_NONE)
index 0bd3bbc..3af4560 100644 (file)
@@ -3203,6 +3203,7 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
        case SND_BELL:
                if (hz)
                        hz = 1000;
+               fallthrough;
        case SND_TONE:
                break;
        default:
index fc9ea19..f578841 100644 (file)
@@ -4645,8 +4645,12 @@ static int wm8994_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
-       return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994,
+       ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994,
                        wm8994_dai, ARRAY_SIZE(wm8994_dai));
+       if (ret < 0)
+               pm_runtime_disable(&pdev->dev);
+
+       return ret;
 }
 
 static int wm8994_remove(struct platform_device *pdev)
index 37e4bb3..229f298 100644 (file)
@@ -1177,6 +1177,8 @@ static int wm8997_probe(struct platform_device *pdev)
                goto err_spk_irqs;
        }
 
+       return ret;
+
 err_spk_irqs:
        arizona_free_spk_irqs(arizona);
 
index f6c5cc8..5413254 100644 (file)
@@ -1375,7 +1375,7 @@ static int wm8998_probe(struct platform_device *pdev)
 
        ret = arizona_init_spk_irqs(arizona);
        if (ret < 0)
-               return ret;
+               goto err_pm_disable;
 
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &soc_component_dev_wm8998,
@@ -1390,6 +1390,8 @@ static int wm8998_probe(struct platform_device *pdev)
 
 err_spk_irqs:
        arizona_free_spk_irqs(arizona);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
 
        return ret;
 }
index e61d004..dec8716 100644 (file)
@@ -1519,7 +1519,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
        ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
        if (!ctl_work) {
                ret = -ENOMEM;
-               goto err_ctl_cache;
+               goto err_list_del;
        }
 
        ctl_work->dsp = dsp;
@@ -1529,7 +1529,8 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
 
        return 0;
 
-err_ctl_cache:
+err_list_del:
+       list_del(&ctl->list);
        kfree(ctl->cache);
 err_ctl_subname:
        kfree(ctl->subname);
index 3f76ff7..84db0b7 100644 (file)
@@ -95,6 +95,22 @@ config SND_SOC_FSL_EASRC
          destination sample rate. It is a new design module compare with the
          old ASRC.
 
+config SND_SOC_FSL_XCVR
+       tristate "NXP Audio Transceiver (XCVR) module support"
+       select REGMAP_MMIO
+       select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y if you want to add Audio Transceiver (XCVR) support for NXP
+         iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC,
+         HDMI1.4 ARC and SPDIF.
+
+config SND_SOC_FSL_AUD2HTX
+       tristate "AUDIO TO HDMI TX module support"
+       depends on ARCH_MXC || COMPILE_TEST
+       help
+         Say Y if you want to add AUDIO TO HDMI TX support for NXP.
+
 config SND_SOC_FSL_UTILS
        tristate
 
@@ -213,57 +229,18 @@ endif # SND_POWERPC_SOC
 
 config SND_SOC_IMX_PCM_FIQ
        tristate
-       default y if SND_SOC_IMX_SSI=y && (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
+       default y if (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
        select FIQ
 
 if SND_IMX_SOC
 
-config SND_SOC_IMX_SSI
-       tristate
-       select SND_SOC_FSL_UTILS
-
 comment "SoC Audio support for Freescale i.MX boards:"
 
-config SND_MXC_SOC_WM1133_EV1
-       tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
-       depends on MACH_MX31ADS_WM1133_EV1
-       select SND_SOC_WM8350
-       select SND_SOC_IMX_PCM_FIQ
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Enable support for audio on the i.MX31ADS with the WM1133-EV1
-         PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
-       tristate "SoC audio support for Visstrim M10 boards"
-       depends on MACH_IMX27_VISSTRIM_M10 && I2C
-       select SND_SOC_TLV320AIC32X4
-       select SND_SOC_IMX_PCM_DMA
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Say Y if you want to add support for SoC audio on Visstrim SM10
-         board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
-       tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
-       depends on MACH_PCM043 || MACH_PCA100
-       select SND_SOC_AC97_BUS
-       select SND_SOC_WM9712
-       select SND_SOC_IMX_PCM_FIQ
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Say Y if you want to add support for SoC audio on Phytec phyCORE
-         and phyCARD boards in AC97 mode
-
 config SND_SOC_EUKREA_TLV320
        tristate "Eukrea TLV320"
        depends on ARCH_MXC && !ARM64 && I2C
        select SND_SOC_TLV320AIC23_I2C
        select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
        select SND_SOC_FSL_SSI
        select SND_SOC_IMX_PCM_DMA
        help
@@ -302,14 +279,6 @@ config SND_SOC_IMX_SPDIF
          Say Y if you want to add support for SoC audio on an i.MX board with
          a S/DPDIF.
 
-config SND_SOC_IMX_MC13783
-       tristate "SoC Audio support for I.MX boards with mc13783"
-       depends on MFD_MC13XXX && ARM
-       select SND_SOC_IMX_SSI
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_MC13783
-       select SND_SOC_IMX_PCM_DMA
-
 config SND_SOC_FSL_ASOC_CARD
        tristate "Generic ASoC Sound Card with ASRC support"
        depends on OF && I2C
@@ -336,6 +305,18 @@ config SND_SOC_IMX_AUDMIX
          Say Y if you want to add support for SoC audio on an i.MX board with
          an Audio Mixer.
 
+config SND_SOC_IMX_HDMI
+       tristate "SoC Audio support for i.MX boards with HDMI port"
+       select SND_SOC_FSL_SAI
+       select SND_SOC_FSL_AUD2HTX
+       select SND_SOC_HDMI_CODEC
+       help
+         ALSA SoC Audio support with HDMI feature for Freescale SoCs that have
+         SAI/AUD2HTX and connect with internal HDMI IP or external module
+         SII902X.
+         Say Y if you want to add support for SoC audio on an i.MX board with
+         IMX HDMI.
+
 endif # SND_IMX_SOC
 
 endmenu
index b835eeb..8c5fa8a 100644 (file)
@@ -25,6 +25,8 @@ snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 snd-soc-fsl-mqs-objs := fsl_mqs.o
 snd-soc-fsl-easrc-objs := fsl_easrc.o
+snd-soc-fsl-xcvr-objs := fsl_xcvr.o
+snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
 obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
+obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -49,9 +53,7 @@ obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
 obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
 # i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
 snd-soc-imx-audmux-objs := imx-audmux.o
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
 
 obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
@@ -59,21 +61,15 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
 snd-soc-imx-es8328-objs := imx-es8328.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-spdif-objs := imx-spdif.o
-snd-soc-imx-mc13783-objs := imx-mc13783.o
 snd-soc-imx-audmix-objs := imx-audmix.o
+snd-soc-imx-hdmi-objs := imx-hdmi.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
 obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
-obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
+obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
index a2dd3b6..f62f81c 100644 (file)
@@ -131,6 +131,13 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
        {"CPU-Playback",  NULL, "ASRC-Playback"},
 };
 
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+       /* 1st half -- Normal DAPM routes */
+       {"CPU-Capture",  NULL, "Capture"},
+       /* 2nd half -- ASRC DAPM routes */
+       {"ASRC-Capture",  NULL, "CPU-Capture"},
+};
+
 /* Add all possible widgets into here without being redundant */
 static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
        SND_SOC_DAPM_LINE("Line Out Jack", NULL),
@@ -653,6 +660,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                priv->cpu_priv.slot_width = 32;
                priv->card.dapm_routes = audio_map_tx;
                priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
+       } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
+               codec_dai_name = "si476x-codec";
+               priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+               priv->card.dapm_routes = audio_map_rx;
+               priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
        } else {
                dev_err(&pdev->dev, "unknown Device Tree compatible\n");
                ret = -EINVAL;
@@ -869,6 +881,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
        { .compatible = "fsl,imx-audio-wm8960", },
        { .compatible = "fsl,imx-audio-mqs", },
        { .compatible = "fsl,imx-audio-wm8524", },
+       { .compatible = "fsl,imx-audio-si476x", },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c
new file mode 100644 (file)
index 0000000..d70d5e7
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2020 NXP
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/pm_qos.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/dma-mapping.h>
+
+#include "fsl_aud2htx.h"
+#include "imx-pcm.h"
+
+static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct fsl_aud2htx *aud2htx = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+                                  AUD2HTX_CTRL_EN, AUD2HTX_CTRL_EN);
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                                  AUD2HTX_CTRE_DE, AUD2HTX_CTRE_DE);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                                  AUD2HTX_CTRE_DE, 0);
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+                                  AUD2HTX_CTRL_EN, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+       .trigger        = fsl_aud2htx_trigger,
+};
+
+static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
+
+       /* DMA request when number of entries < WTMK_LOW */
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                          AUD2HTX_CTRE_DT_MASK, 0);
+
+       /* Disable interrupts*/
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_IRQ_MASK,
+                          AUD2HTX_WM_HIGH_IRQ_MASK |
+                          AUD2HTX_WM_LOW_IRQ_MASK |
+                          AUD2HTX_OVF_MASK,
+                          AUD2HTX_WM_HIGH_IRQ_MASK |
+                          AUD2HTX_WM_LOW_IRQ_MASK |
+                          AUD2HTX_OVF_MASK);
+
+       /* Configure watermark */
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                          AUD2HTX_CTRE_WL_MASK,
+                          AUD2HTX_WTMK_LOW << AUD2HTX_CTRE_WL_SHIFT);
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                          AUD2HTX_CTRE_WH_MASK,
+                          AUD2HTX_WTMK_HIGH << AUD2HTX_CTRE_WH_SHIFT);
+
+       snd_soc_dai_init_dma_data(cpu_dai, &aud2htx->dma_params_tx,
+                                 &aud2htx->dma_params_rx);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver fsl_aud2htx_dai = {
+       .probe = fsl_aud2htx_dai_probe,
+       .playback = {
+               .stream_name = "CPU-Playback",
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_32000 |
+                        SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_88200 |
+                        SNDRV_PCM_RATE_96000 |
+                        SNDRV_PCM_RATE_176400 |
+                        SNDRV_PCM_RATE_192000,
+               .formats = FSL_AUD2HTX_FORMATS,
+       },
+       .ops = &fsl_aud2htx_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_aud2htx_component = {
+       .name   = "fsl-aud2htx",
+};
+
+static const struct reg_default fsl_aud2htx_reg_defaults[] = {
+       {AUD2HTX_CTRL,          0x00000000},
+       {AUD2HTX_CTRL_EXT,      0x00000000},
+       {AUD2HTX_WR,            0x00000000},
+       {AUD2HTX_STATUS,        0x00000000},
+       {AUD2HTX_IRQ_NOMASK,    0x00000000},
+       {AUD2HTX_IRQ_MASKED,    0x00000000},
+       {AUD2HTX_IRQ_MASK,      0x00000000},
+};
+
+static bool fsl_aud2htx_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AUD2HTX_CTRL:
+       case AUD2HTX_CTRL_EXT:
+       case AUD2HTX_STATUS:
+       case AUD2HTX_IRQ_NOMASK:
+       case AUD2HTX_IRQ_MASKED:
+       case AUD2HTX_IRQ_MASK:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_aud2htx_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AUD2HTX_CTRL:
+       case AUD2HTX_CTRL_EXT:
+       case AUD2HTX_WR:
+       case AUD2HTX_IRQ_NOMASK:
+       case AUD2HTX_IRQ_MASKED:
+       case AUD2HTX_IRQ_MASK:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_aud2htx_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AUD2HTX_STATUS:
+       case AUD2HTX_IRQ_NOMASK:
+       case AUD2HTX_IRQ_MASKED:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config fsl_aud2htx_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+
+       .max_register = AUD2HTX_IRQ_MASK,
+       .reg_defaults = fsl_aud2htx_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_aud2htx_reg_defaults),
+       .readable_reg = fsl_aud2htx_readable_reg,
+       .volatile_reg = fsl_aud2htx_volatile_reg,
+       .writeable_reg = fsl_aud2htx_writeable_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct of_device_id fsl_aud2htx_dt_ids[] = {
+       { .compatible = "fsl,imx8mp-aud2htx",},
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_aud2htx_dt_ids);
+
+static irqreturn_t fsl_aud2htx_isr(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+static int fsl_aud2htx_probe(struct platform_device *pdev)
+{
+       struct fsl_aud2htx *aud2htx;
+       struct resource *res;
+       void __iomem *regs;
+       int ret, irq;
+
+       aud2htx = devm_kzalloc(&pdev->dev, sizeof(*aud2htx), GFP_KERNEL);
+       if (!aud2htx)
+               return -ENOMEM;
+
+       aud2htx->pdev = pdev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(regs)) {
+               dev_err(&pdev->dev, "failed ioremap\n");
+               return PTR_ERR(regs);
+       }
+
+       aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                               &fsl_aud2htx_regmap_config);
+       if (IS_ERR(aud2htx->regmap)) {
+               dev_err(&pdev->dev, "failed to init regmap");
+               return PTR_ERR(aud2htx->regmap);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0,
+                              dev_name(&pdev->dev), aud2htx);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
+               return ret;
+       }
+
+       aud2htx->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       if (IS_ERR(aud2htx->bus_clk)) {
+               dev_err(&pdev->dev, "failed to get mem clock\n");
+               return PTR_ERR(aud2htx->bus_clk);
+       }
+
+       aud2htx->dma_params_tx.chan_name = "tx";
+       aud2htx->dma_params_tx.maxburst = AUD2HTX_MAXBURST;
+       aud2htx->dma_params_tx.addr = res->start + AUD2HTX_WR;
+
+       platform_set_drvdata(pdev, aud2htx);
+       pm_runtime_enable(&pdev->dev);
+
+       regcache_cache_only(aud2htx->regmap, true);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &fsl_aud2htx_component,
+                                             &fsl_aud2htx_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register ASoC DAI\n");
+               return ret;
+       }
+
+       ret = imx_pcm_dma_init(pdev, IMX_DEFAULT_DMABUF_SIZE);
+       if (ret)
+               dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+       return ret;
+}
+
+static int fsl_aud2htx_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
+{
+       struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+
+       regcache_cache_only(aud2htx->regmap, true);
+       clk_disable_unprepare(aud2htx->bus_clk);
+
+       return 0;
+}
+
+static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
+{
+       struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(aud2htx->bus_clk);
+       if (ret)
+               return ret;
+
+       regcache_cache_only(aud2htx->regmap, false);
+       regcache_mark_dirty(aud2htx->regmap);
+       regcache_sync(aud2htx->regmap);
+
+       return 0;
+}
+
+static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
+       SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend,
+                          fsl_aud2htx_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_aud2htx_driver = {
+       .probe = fsl_aud2htx_probe,
+       .remove = fsl_aud2htx_remove,
+       .driver = {
+               .name = "fsl-aud2htx",
+               .pm = &fsl_aud2htx_pm_ops,
+               .of_match_table = fsl_aud2htx_dt_ids,
+       },
+};
+module_platform_driver(fsl_aud2htx_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
+MODULE_DESCRIPTION("NXP AUD2HTX driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_aud2htx.h b/sound/soc/fsl/fsl_aud2htx.h
new file mode 100644 (file)
index 0000000..ad70d6a
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef _FSL_AUD2HTX_H
+#define _FSL_AUD2HTX_H
+
+#define FSL_AUD2HTX_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
+                            SNDRV_PCM_FMTBIT_S32_LE)
+
+/* AUD2HTX Register Map */
+#define AUD2HTX_CTRL          0x0   /* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EXT      0x4   /* AUD2HTX Control Extended Register */
+#define AUD2HTX_WR            0x8   /* AUD2HTX Write Register */
+#define AUD2HTX_STATUS        0xC   /* AUD2HTX Status Register */
+#define AUD2HTX_IRQ_NOMASK    0x10  /* AUD2HTX Nonmasked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASKED    0x14  /* AUD2HTX Masked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASK      0x18  /* AUD2HTX IRQ Masks Register */
+
+/* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EN          BIT(0)
+
+/* AUD2HTX Control Extended Register */
+#define AUD2HTX_CTRE_DE          BIT(0)
+#define AUD2HTX_CTRE_DT_SHIFT    0x1
+#define AUD2HTX_CTRE_DT_WIDTH    0x2
+#define AUD2HTX_CTRE_DT_MASK     ((BIT(AUD2HTX_CTRE_DT_WIDTH) - 1) \
+                                << AUD2HTX_CTRE_DT_SHIFT)
+#define AUD2HTX_CTRE_WL_SHIFT    16
+#define AUD2HTX_CTRE_WL_WIDTH    5
+#define AUD2HTX_CTRE_WL_MASK     ((BIT(AUD2HTX_CTRE_WL_WIDTH) - 1) \
+                                << AUD2HTX_CTRE_WL_SHIFT)
+#define AUD2HTX_CTRE_WH_SHIFT    24
+#define AUD2HTX_CTRE_WH_WIDTH    5
+#define AUD2HTX_CTRE_WH_MASK     ((BIT(AUD2HTX_CTRE_WH_WIDTH) - 1) \
+                                << AUD2HTX_CTRE_WH_SHIFT)
+
+/* AUD2HTX IRQ Masks Register */
+#define AUD2HTX_WM_HIGH_IRQ_MASK BIT(2)
+#define AUD2HTX_WM_LOW_IRQ_MASK  BIT(1)
+#define AUD2HTX_OVF_MASK         BIT(0)
+
+#define AUD2HTX_FIFO_DEPTH       0x20
+#define AUD2HTX_WTMK_LOW         0x10
+#define AUD2HTX_WTMK_HIGH        0x10
+#define AUD2HTX_MAXBURST         0x10
+
+/**
+ * fsl_aud2htx: AUD2HTX private data
+ *
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @bus_clk: clock source to access register
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ */
+struct fsl_aud2htx {
+       struct platform_device *pdev;
+       struct regmap *regmap;
+       struct clk *bus_clk;
+
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+};
+
+#endif /* _FSL_AUD2HTX_H */
index 7ad5925..8dc44de 100644 (file)
@@ -455,7 +455,6 @@ static const struct regmap_config fsl_audmix_regmap_config = {
 static const struct of_device_id fsl_audmix_ids[] = {
        {
                .compatible = "fsl,imx8qm-audmix",
-               .data = "imx-audmix",
        },
        { /* sentinel */ }
 };
@@ -465,17 +464,9 @@ static int fsl_audmix_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fsl_audmix *priv;
-       const char *mdrv;
-       const struct of_device_id *of_id;
        void __iomem *regs;
        int ret;
 
-       of_id = of_match_device(fsl_audmix_ids, dev);
-       if (!of_id || !of_id->data)
-               return -EINVAL;
-
-       mdrv = of_id->data;
-
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
@@ -510,10 +501,10 @@ static int fsl_audmix_probe(struct platform_device *pdev)
                goto err_disable_pm;
        }
 
-       priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0);
+       priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
        if (IS_ERR(priv->pdev)) {
                ret = PTR_ERR(priv->pdev);
-               dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret);
+               dev_err(dev, "failed to register platform: %d\n", ret);
                goto err_disable_pm;
        }
 
index 3e5c1ea..f3d3d20 100644 (file)
@@ -359,7 +359,14 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
        if (sai->is_slave_mode)
                return 0;
 
-       for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+       /*
+        * There is no point in polling MCLK0 if it is identical to MCLK1.
+        * And given that MQS use case has to use MCLK1 though two clocks
+        * are the same, we simply skip MCLK0 and start to find from MCLK1.
+        */
+       id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0;
+
+       for (; id < FSL_SAI_MCLK_MAX; id++) {
                clk_rate = clk_get_rate(sai->mclk_clk[id]);
                if (!clk_rate)
                        continue;
@@ -1040,7 +1047,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
                sai->bus_clk = NULL;
        }
 
-       sai->mclk_clk[0] = sai->bus_clk;
        for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
                sprintf(tmp, "mclk%d", i);
                sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
@@ -1051,6 +1057,11 @@ static int fsl_sai_probe(struct platform_device *pdev)
                }
        }
 
+       if (sai->soc_data->mclk0_is_mclk1)
+               sai->mclk_clk[0] = sai->mclk_clk[1];
+       else
+               sai->mclk_clk[0] = sai->bus_clk;
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
@@ -1165,6 +1176,7 @@ static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
        .use_edma = false,
        .fifo_depth = 32,
        .reg_offset = 0,
+       .mclk0_is_mclk1 = false,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
@@ -1172,6 +1184,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
        .use_edma = false,
        .fifo_depth = 32,
        .reg_offset = 0,
+       .mclk0_is_mclk1 = true,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
@@ -1179,6 +1192,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
        .use_edma = false,
        .fifo_depth = 16,
        .reg_offset = 8,
+       .mclk0_is_mclk1 = false,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
@@ -1186,6 +1200,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
        .use_edma = false,
        .fifo_depth = 128,
        .reg_offset = 8,
+       .mclk0_is_mclk1 = false,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
@@ -1193,6 +1208,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
        .use_edma = true,
        .fifo_depth = 64,
        .reg_offset = 0,
+       .mclk0_is_mclk1 = false,
 };
 
 static const struct of_device_id fsl_sai_ids[] = {
index 4bbcd0d..ff2619f 100644 (file)
 struct fsl_sai_soc_data {
        bool use_imx_pcm;
        bool use_edma;
+       bool mclk0_is_mclk1;
        unsigned int fifo_depth;
        unsigned int reg_offset;
 };
index b0f643f..5fa178f 100644 (file)
@@ -49,10 +49,18 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
  * @imx: for imx platform
  * @shared_root_clock: flag of sharing a clock source with others;
  *                     so the driver shouldn't set root clock rate
+ * @interrupts: interrupt number
+ * @tx_burst: tx maxburst size
+ * @rx_burst: rx maxburst size
+ * @tx_formats: tx supported data format
  */
 struct fsl_spdif_soc_data {
        bool imx;
        bool shared_root_clock;
+       u32 interrupts;
+       u32 tx_burst;
+       u32 rx_burst;
+       u64 tx_formats;
 };
 
 /*
@@ -128,16 +136,38 @@ struct fsl_spdif_priv {
 static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
        .imx = false,
        .shared_root_clock = false,
+       .interrupts = 1,
+       .tx_burst = FSL_SPDIF_TXFIFO_WML,
+       .rx_burst = FSL_SPDIF_RXFIFO_WML,
+       .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
 };
 
 static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
        .imx = true,
        .shared_root_clock = false,
+       .interrupts = 1,
+       .tx_burst = FSL_SPDIF_TXFIFO_WML,
+       .rx_burst = FSL_SPDIF_RXFIFO_WML,
+       .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
 };
 
 static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
        .imx = true,
        .shared_root_clock = true,
+       .interrupts = 1,
+       .tx_burst = FSL_SPDIF_TXFIFO_WML,
+       .rx_burst = FSL_SPDIF_RXFIFO_WML,
+       .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+
+};
+
+static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
+       .imx = true,
+       .shared_root_clock = true,
+       .interrupts = 2,
+       .tx_burst = 2,          /* Applied for EDMA */
+       .rx_burst = 2,          /* Applied for EDMA */
+       .tx_formats = SNDRV_PCM_FMTBIT_S24_LE,  /* Applied for EDMA */
 };
 
 /* Check if clk is a root clock that does not share clock source with others */
@@ -429,10 +459,18 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
                rate = SPDIF_TXRATE_48000;
                csfs = IEC958_AES3_CON_FS_48000;
                break;
+       case 88200:
+               rate = SPDIF_TXRATE_88200;
+               csfs = IEC958_AES3_CON_FS_88200;
+               break;
        case 96000:
                rate = SPDIF_TXRATE_96000;
                csfs = IEC958_AES3_CON_FS_96000;
                break;
+       case 176400:
+               rate = SPDIF_TXRATE_176400;
+               csfs = IEC958_AES3_CON_FS_176400;
+               break;
        case 192000:
                rate = SPDIF_TXRATE_192000;
                csfs = IEC958_AES3_CON_FS_192000;
@@ -827,7 +865,7 @@ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
        uinfo->value.integer.min = 16000;
-       uinfo->value.integer.max = 96000;
+       uinfo->value.integer.max = 192000;
 
        return 0;
 }
@@ -1145,7 +1183,8 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
                                struct clk *clk, u64 savesub,
                                enum spdif_txrate index, bool round)
 {
-       static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+       static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+                                   192000, };
        bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
        u64 rate_ideal, rate_actual, sub;
        u32 arate;
@@ -1205,7 +1244,8 @@ out:
 static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
                                enum spdif_txrate index)
 {
-       static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+       static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+                                   192000, };
        struct platform_device *pdev = spdif_priv->pdev;
        struct device *dev = &pdev->dev;
        u64 savesub = 100000, ret;
@@ -1273,6 +1313,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        /* Initialize this copy of the CPU DAI driver structure */
        memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
        spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
+       spdif_priv->cpu_dai_drv.playback.formats =
+                               spdif_priv->soc->tx_formats;
 
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1287,15 +1329,19 @@ static int fsl_spdif_probe(struct platform_device *pdev)
                return PTR_ERR(spdif_priv->regmap);
        }
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
+       for (i = 0; i < spdif_priv->soc->interrupts; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0) {
+                       dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+                       return irq;
+               }
 
-       ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
-                              dev_name(&pdev->dev), spdif_priv);
-       if (ret) {
-               dev_err(&pdev->dev, "could not claim irq %u\n", irq);
-               return ret;
+               ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+                                      dev_name(&pdev->dev), spdif_priv);
+               if (ret) {
+                       dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+                       return ret;
+               }
        }
 
        /* Get system clock for rx clock rate calculation */
@@ -1344,8 +1390,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 
        spdif_priv->dpll_locked = false;
 
-       spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
-       spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+       spdif_priv->dma_params_tx.maxburst = spdif_priv->soc->tx_burst;
+       spdif_priv->dma_params_rx.maxburst = spdif_priv->soc->rx_burst;
        spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
        spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
 
@@ -1458,6 +1504,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = {
        { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, },
        { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
        { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, },
+       { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
index e6c61e0..d5f1dfd 100644 (file)
@@ -163,7 +163,9 @@ enum spdif_txrate {
        SPDIF_TXRATE_32000 = 0,
        SPDIF_TXRATE_44100,
        SPDIF_TXRATE_48000,
+       SPDIF_TXRATE_88200,
        SPDIF_TXRATE_96000,
+       SPDIF_TXRATE_176400,
        SPDIF_TXRATE_192000,
 };
 #define SPDIF_TXRATE_MAX               (SPDIF_TXRATE_192000 + 1)
@@ -177,15 +179,20 @@ enum spdif_txrate {
 #define FSL_SPDIF_RATES_PLAYBACK       (SNDRV_PCM_RATE_32000 | \
                                         SNDRV_PCM_RATE_44100 | \
                                         SNDRV_PCM_RATE_48000 | \
+                                        SNDRV_PCM_RATE_88200 | \
                                         SNDRV_PCM_RATE_96000 | \
+                                        SNDRV_PCM_RATE_176400 | \
                                         SNDRV_PCM_RATE_192000)
 
 #define FSL_SPDIF_RATES_CAPTURE                (SNDRV_PCM_RATE_16000 | \
                                         SNDRV_PCM_RATE_32000 | \
                                         SNDRV_PCM_RATE_44100 | \
                                         SNDRV_PCM_RATE_48000 | \
+                                        SNDRV_PCM_RATE_88200 | \
                                         SNDRV_PCM_RATE_64000 | \
-                                        SNDRV_PCM_RATE_96000)
+                                        SNDRV_PCM_RATE_96000 | \
+                                        SNDRV_PCM_RATE_176400 | \
+                                        SNDRV_PCM_RATE_192000)
 
 #define FSL_SPDIF_FORMATS_PLAYBACK     (SNDRV_PCM_FMTBIT_S16_LE | \
                                         SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
new file mode 100644 (file)
index 0000000..3d58c88
--- /dev/null
@@ -0,0 +1,1360 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/bitrev.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_iec958.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_xcvr.h"
+#include "imx-pcm.h"
+
+#define FSL_XCVR_CAPDS_SIZE    256
+
+struct fsl_xcvr_soc_data {
+       const char *fw_name;
+};
+
+struct fsl_xcvr {
+       const struct fsl_xcvr_soc_data *soc_data;
+       struct platform_device *pdev;
+       struct regmap *regmap;
+       struct clk *ipg_clk;
+       struct clk *pll_ipg_clk;
+       struct clk *phy_clk;
+       struct clk *spba_clk;
+       struct reset_control *reset;
+       u8 streams;
+       u32 mode;
+       u32 arc_mode;
+       void __iomem *ram_addr;
+       struct snd_dmaengine_dai_dma_data dma_prms_rx;
+       struct snd_dmaengine_dai_dma_data dma_prms_tx;
+       struct snd_aes_iec958 rx_iec958;
+       struct snd_aes_iec958 tx_iec958;
+       u8 cap_ds[FSL_XCVR_CAPDS_SIZE];
+};
+
+static const struct fsl_xcvr_pll_conf {
+       u8 mfi;   /* min=0x18, max=0x38 */
+       u32 mfn;  /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */
+       u32 mfd;  /* unsigned int */
+       u32 fout; /* Fout = Fref*(MFI + MFN/MFD), Fref is 24MHz */
+} fsl_xcvr_pll_cfg[] = {
+       { .mfi = 54, .mfn = 1,  .mfd = 6,   .fout = 1300000000, }, /* 1.3 GHz */
+       { .mfi = 32, .mfn = 96, .mfd = 125, .fout = 786432000, },  /* 8000 Hz */
+       { .mfi = 30, .mfn = 66, .mfd = 625, .fout = 722534400, },  /* 11025 Hz */
+       { .mfi = 29, .mfn = 1,  .mfd = 6,   .fout = 700000000, },  /* 700 MHz */
+};
+
+/*
+ * HDMI2.1 spec defines 6- and 12-channels layout for one bit audio
+ * stream. Todo: to check how this case can be considered below
+ */
+static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = {
+       .count = ARRAY_SIZE(fsl_xcvr_earc_channels),
+       .list = fsl_xcvr_earc_channels,
+};
+
+static const u32 fsl_xcvr_earc_rates[] = {
+       32000, 44100, 48000, 64000, 88200, 96000,
+       128000, 176400, 192000, 256000, 352800, 384000,
+       512000, 705600, 768000, 1024000, 1411200, 1536000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_rates_constr = {
+       .count = ARRAY_SIZE(fsl_xcvr_earc_rates),
+       .list = fsl_xcvr_earc_rates,
+};
+
+static const u32 fsl_xcvr_spdif_channels[] = { 2, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_channels_constr = {
+       .count = ARRAY_SIZE(fsl_xcvr_spdif_channels),
+       .list = fsl_xcvr_spdif_channels,
+};
+
+static const u32 fsl_xcvr_spdif_rates[] = {
+       32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_rates_constr = {
+       .count = ARRAY_SIZE(fsl_xcvr_spdif_rates),
+       .list = fsl_xcvr_spdif_rates,
+};
+
+static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int *item = ucontrol->value.enumerated.item;
+
+       xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]);
+
+       return 0;
+}
+
+static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       ucontrol->value.enumerated.item[0] = xcvr->arc_mode;
+
+       return 0;
+}
+
+static const u32 fsl_xcvr_phy_arc_cfg[] = {
+       FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN, FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN,
+};
+
+static const char * const fsl_xcvr_arc_mode[] = { "Single Ended", "Common", };
+static const struct soc_enum fsl_xcvr_arc_mode_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode);
+static struct snd_kcontrol_new fsl_xcvr_arc_mode_kctl =
+       SOC_ENUM_EXT("ARC Mode", fsl_xcvr_arc_mode_enum,
+                    fsl_xcvr_arc_mode_get, fsl_xcvr_arc_mode_put);
+
+/* Capabilities data structure, bytes */
+static int fsl_xcvr_type_capds_bytes_info(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = FSL_XCVR_CAPDS_SIZE;
+
+       return 0;
+}
+
+static int fsl_xcvr_capds_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       memcpy(ucontrol->value.bytes.data, xcvr->cap_ds, FSL_XCVR_CAPDS_SIZE);
+
+       return 0;
+}
+
+static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       memcpy(xcvr->cap_ds, ucontrol->value.bytes.data, FSL_XCVR_CAPDS_SIZE);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name = "Capabilities Data Structure",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = fsl_xcvr_type_capds_bytes_info,
+       .get = fsl_xcvr_capds_get,
+       .put = fsl_xcvr_capds_put,
+};
+
+static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name,
+                                bool active)
+{
+       struct snd_soc_card *card = dai->component->card;
+       struct snd_kcontrol *kctl;
+       bool enabled;
+
+       kctl = snd_soc_card_get_kcontrol(card, name);
+       if (kctl == NULL)
+               return -ENOENT;
+
+       enabled = ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_WRITE) != 0);
+       if (active == enabled)
+               return 0; /* nothing to do */
+
+       if (active)
+               kctl->vd[0].access |=  SNDRV_CTL_ELEM_ACCESS_WRITE;
+       else
+               kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
+
+       snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
+
+       return 1;
+}
+
+static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int *item = ucontrol->value.enumerated.item;
+       struct snd_soc_card *card = dai->component->card;
+       struct snd_soc_pcm_runtime *rtd;
+
+       xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
+
+       fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+                             (xcvr->mode == FSL_XCVR_MODE_ARC));
+       fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+                             (xcvr->mode == FSL_XCVR_MODE_EARC));
+       /* Allow playback for SPDIF only */
+       rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
+       rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
+               (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0);
+       return 0;
+}
+
+static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       ucontrol->value.enumerated.item[0] = xcvr->mode;
+
+       return 0;
+}
+
+static const char * const fsl_xcvr_mode[] = { "SPDIF", "ARC RX", "eARC", };
+static const struct soc_enum fsl_xcvr_mode_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_mode), fsl_xcvr_mode);
+static struct snd_kcontrol_new fsl_xcvr_mode_kctl =
+       SOC_ENUM_EXT("XCVR Mode", fsl_xcvr_mode_enum,
+                    fsl_xcvr_mode_get, fsl_xcvr_mode_put);
+
+/** phy: true => phy, false => pll */
+static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
+{
+       struct device *dev = &xcvr->pdev->dev;
+       u32 val, idx, tidx;
+       int ret;
+
+       idx  = BIT(phy ? 26 : 24);
+       tidx = BIT(phy ? 27 : 25);
+
+       regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF);
+       regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg);
+       regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data);
+       regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);
+
+       ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
+                                      (val & idx) == ((val & tidx) >> 1),
+                                      10, 10000);
+       if (ret)
+               dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n",
+                       phy ? "PHY" : "PLL", reg, data);
+       return ret;
+}
+
+static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
+{
+       struct device *dev = &xcvr->pdev->dev;
+       u32 i, div = 0, log2;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
+               if (fsl_xcvr_pll_cfg[i].fout % freq == 0) {
+                       div = fsl_xcvr_pll_cfg[i].fout / freq;
+                       break;
+               }
+       }
+
+       if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg))
+               return -EINVAL;
+
+       log2 = ilog2(div);
+
+       /* Release AI interface from reset */
+       ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+                          FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+       if (ret < 0) {
+               dev_err(dev, "Error while setting IER0: %d\n", ret);
+               return ret;
+       }
+
+       /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
+       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
+                         FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
+
+       /* PLL: CTRL0: DIV_INTEGER */
+       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0);
+       /* PLL: NUMERATOR: MFN */
+       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0);
+       /* PLL: DENOMINATOR: MFD */
+       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0);
+       /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
+       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+                         FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0);
+       udelay(25);
+       /* PLL: CTRL0: Clear Hold Ring Off */
+       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR,
+                         FSL_XCVR_PLL_CTRL0_HROFF, 0);
+       udelay(100);
+       if (tx) { /* TX is enabled for SPDIF only */
+               /* PLL: POSTDIV: PDIV0 */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+                                 FSL_XCVR_PLL_PDIVx(log2, 0), 0);
+               /* PLL: CTRL_SET: CLKMUX0_EN */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+                                 FSL_XCVR_PLL_CTRL0_CM0_EN, 0);
+       } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */
+               /* PLL: POSTDIV: PDIV1 */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+                                 FSL_XCVR_PLL_PDIVx(log2, 1), 0);
+               /* PLL: CTRL_SET: CLKMUX1_EN */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+                                 FSL_XCVR_PLL_CTRL0_CM1_EN, 0);
+       } else { /* SPDIF / ARC RX */
+               /* PLL: POSTDIV: PDIV2 */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+                                 FSL_XCVR_PLL_PDIVx(log2, 2), 0);
+               /* PLL: CTRL_SET: CLKMUX2_EN */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+                                 FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
+       }
+
+       if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+               /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+                                 FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+                                 FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+               /* PHY: CTRL2_SET: EARC_TX_MODE */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+                                 FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+       } else if (!tx) { /* SPDIF / ARC RX mode */
+               if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+                       /* PHY: CTRL_SET: SPDIF_EN */
+                       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+                                         FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+               else    /* PHY: CTRL_SET: ARC RX setup */
+                       fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+                                         FSL_XCVR_PHY_CTRL_PHY_EN |
+                                         FSL_XCVR_PHY_CTRL_RX_CM_EN |
+                                         fsl_xcvr_phy_arc_cfg[xcvr->arc_mode], 1);
+       }
+
+       dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n",
+               freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi,
+               fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2);
+       return 0;
+}
+
+static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
+{
+       struct device *dev = &xcvr->pdev->dev;
+       int ret;
+
+       clk_disable_unprepare(xcvr->phy_clk);
+       ret = clk_set_rate(xcvr->phy_clk, freq);
+       if (ret < 0) {
+               dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(xcvr->phy_clk);
+       if (ret) {
+               dev_err(dev, "failed to start PHY clock: %d\n", ret);
+               return ret;
+       }
+
+       /* Release AI interface from reset */
+       ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+                          FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+       if (ret < 0) {
+               dev_err(dev, "Error while setting IER0: %d\n", ret);
+               return ret;
+       }
+
+       if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+               /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+                                 FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+                                 FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+               /* PHY: CTRL2_SET: EARC_TX_MODE */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+                                 FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+       } else { /* SPDIF mode */
+               /* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */
+               fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+                                 FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
+                                 FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+       }
+
+       dev_dbg(dev, "PLL Fexp: %u\n", freq);
+
+       return 0;
+}
+
+#define FSL_XCVR_SPDIF_RX_FREQ 175000000
+static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *dai)
+{
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u32 m_ctl = 0, v_ctl = 0;
+       u32 r = substream->runtime->rate, ch = substream->runtime->channels;
+       u32 fout = 32 * r * ch * 10 * 2;
+       int ret = 0;
+
+       switch (xcvr->mode) {
+       case FSL_XCVR_MODE_SPDIF:
+       case FSL_XCVR_MODE_ARC:
+               if (tx) {
+                       ret = fsl_xcvr_en_aud_pll(xcvr, fout);
+                       if (ret < 0) {
+                               dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
+                                       fout, ret);
+                               return ret;
+                       }
+
+                       ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
+                                          FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
+                       if (ret < 0) {
+                               dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret);
+                               return ret;
+                       }
+
+                       /**
+                        * set SPDIF MODE - this flag is used to gate
+                        * SPDIF output, useless for SPDIF RX
+                        */
+                       m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+                       v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+               } else {
+                       /**
+                        * Clear RX FIFO, flip RX FIFO bits,
+                        * disable eARC related HW mode detects
+                        */
+                       ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+                                          FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+                                          FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
+                                          FSL_XCVR_RX_DPTH_CTRL_COMP |
+                                          FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+                       if (ret < 0) {
+                               dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+                               return ret;
+                       }
+
+                       ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx);
+                       if (ret < 0) {
+                               dev_err(dai->dev, "Failed to set RX freq %u: %d\n",
+                                       FSL_XCVR_SPDIF_RX_FREQ, ret);
+                               return ret;
+                       }
+               }
+               break;
+       case FSL_XCVR_MODE_EARC:
+               if (!tx) {
+                       /** Clear RX FIFO, flip RX FIFO bits */
+                       ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+                                          FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+                                          FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
+                       if (ret < 0) {
+                               dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+                               return ret;
+                       }
+
+                       /** Enable eARC related HW mode detects */
+                       ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_CLR,
+                                          FSL_XCVR_RX_DPTH_CTRL_COMP |
+                                          FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+                       if (ret < 0) {
+                               dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret);
+                               return ret;
+                       }
+               }
+
+               /* clear CMDC RESET */
+               m_ctl |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+               /* set TX_RX_MODE */
+               m_ctl |= FSL_XCVR_EXT_CTRL_TX_RX_MODE;
+               v_ctl |= (tx ? FSL_XCVR_EXT_CTRL_TX_RX_MODE : 0);
+               break;
+       }
+
+       ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+                                FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
+       if (ret < 0) {
+               dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
+               return ret;
+       }
+
+       /* clear DPATH RESET */
+       m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+       ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl);
+       if (ret < 0) {
+               dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int fsl_xcvr_constr(const struct snd_pcm_substream *substream,
+                          const struct snd_pcm_hw_constraint_list *channels,
+                          const struct snd_pcm_hw_constraint_list *rates)
+{
+       struct snd_pcm_runtime *rt = substream->runtime;
+       int ret;
+
+       ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                        channels);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                        rates);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *dai)
+{
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret = 0;
+
+       if (xcvr->streams & BIT(substream->stream)) {
+               dev_err(dai->dev, "%sX busy\n", tx ? "T" : "R");
+               return -EBUSY;
+       }
+
+       switch (xcvr->mode) {
+       case FSL_XCVR_MODE_SPDIF:
+       case FSL_XCVR_MODE_ARC:
+               ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
+                                     &fsl_xcvr_spdif_rates_constr);
+               break;
+       case FSL_XCVR_MODE_EARC:
+               ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
+                                     &fsl_xcvr_earc_rates_constr);
+               break;
+       }
+       if (ret < 0)
+               return ret;
+
+       xcvr->streams |= BIT(substream->stream);
+
+       /* Disable XCVR controls if there is stream started */
+       fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
+       fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
+       fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
+
+       return 0;
+}
+
+static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u32 mask = 0, val = 0;
+       int ret;
+
+       xcvr->streams &= ~BIT(substream->stream);
+
+       /* Enable XCVR controls if there is no stream started */
+       if (!xcvr->streams) {
+               fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
+               fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+                                     (xcvr->mode == FSL_XCVR_MODE_ARC));
+               fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+                                     (xcvr->mode == FSL_XCVR_MODE_EARC));
+
+               ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+                                        FSL_XCVR_IRQ_EARC_ALL, 0);
+               if (ret < 0) {
+                       dev_err(dai->dev, "Failed to set IER0: %d\n", ret);
+                       return;
+               }
+
+               /* clear SPDIF MODE */
+               if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+                       mask |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+       }
+
+       if (xcvr->mode == FSL_XCVR_MODE_EARC) {
+               /* set CMDC RESET */
+               mask |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+               val  |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+       }
+
+       /* set DPATH RESET */
+       mask |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+       val  |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+
+       ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+       if (ret < 0) {
+               dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret);
+               return;
+       }
+}
+
+static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *dai)
+{
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int ret;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (tx) {
+                       switch (xcvr->mode) {
+                       case FSL_XCVR_MODE_EARC:
+                               /* set isr_cmdc_tx_en, w1c */
+                               ret = regmap_write(xcvr->regmap,
+                                                  FSL_XCVR_ISR_SET,
+                                                  FSL_XCVR_ISR_CMDC_TX_EN);
+                               if (ret < 0) {
+                                       dev_err(dai->dev, "err updating isr %d\n", ret);
+                                       return ret;
+                               }
+                               fallthrough;
+                       case FSL_XCVR_MODE_SPDIF:
+                               ret = regmap_write(xcvr->regmap,
+                                        FSL_XCVR_TX_DPTH_CTRL_SET,
+                                        FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+                               if (ret < 0) {
+                                       dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
+                                       return ret;
+                               }
+                               break;
+                       }
+               }
+
+               /* enable DMA RD/WR */
+               ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+                                        FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
+               if (ret < 0) {
+                       dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
+                       return ret;
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               /* disable DMA RD/WR */
+               ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+                                        FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
+                                        FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
+               if (ret < 0) {
+                       dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
+                       return ret;
+               }
+
+               if (tx) {
+                       switch (xcvr->mode) {
+                       case FSL_XCVR_MODE_SPDIF:
+                               ret = regmap_write(xcvr->regmap,
+                                        FSL_XCVR_TX_DPTH_CTRL_CLR,
+                                        FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+                               if (ret < 0) {
+                                       dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
+                                       return ret;
+                               }
+                               fallthrough;
+                       case FSL_XCVR_MODE_EARC:
+                               /* clear ISR_CMDC_TX_EN, W1C */
+                               ret = regmap_write(xcvr->regmap,
+                                                  FSL_XCVR_ISR_CLR,
+                                                  FSL_XCVR_ISR_CMDC_TX_EN);
+                               if (ret < 0) {
+                                       dev_err(dai->dev,
+                                               "Err updating ISR %d\n", ret);
+                                       return ret;
+                               }
+                               break;
+                       }
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
+{
+       struct device *dev = &xcvr->pdev->dev;
+       const struct firmware *fw;
+       int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET;
+       u32 mask, val;
+
+       ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev);
+       if (ret) {
+               dev_err(dev, "failed to request firmware.\n");
+               return ret;
+       }
+
+       rem = fw->size;
+
+       /* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */
+       if (rem > 16384) {
+               dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
+               release_firmware(fw);
+               return -ENOMEM;
+       }
+
+       for (page = 0; page < 10; page++) {
+               ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+                                        FSL_XCVR_EXT_CTRL_PAGE_MASK,
+                                        FSL_XCVR_EXT_CTRL_PAGE(page));
+               if (ret < 0) {
+                       dev_err(dev, "FW: failed to set page %d, err=%d\n",
+                               page, ret);
+                       goto err_firmware;
+               }
+
+               off = page * size;
+               out = min(rem, size);
+               /* IPG clock is assumed to be running, otherwise it will hang */
+               if (out > 0) {
+                       /* write firmware into code memory */
+                       memcpy_toio(xcvr->ram_addr, fw->data + off, out);
+                       rem -= out;
+                       if (rem == 0) {
+                               /* last part of firmware written */
+                               /* clean remaining part of code memory page */
+                               memset_io(xcvr->ram_addr + out, 0, size - out);
+                       }
+               } else {
+                       /* clean current page, including data memory */
+                       memset_io(xcvr->ram_addr, 0, size);
+               }
+       };
+
+err_firmware:
+       release_firmware(fw);
+       if (ret < 0)
+               return ret;
+
+       /* configure watermarks */
+       mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
+       val  = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
+       val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX);
+       /* disable DMA RD/WR */
+       mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+       val  |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+       /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+       mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
+       val  |= FSL_XCVR_EXT_CTRL_PAGE(8);
+
+       ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+       if (ret < 0) {
+               dev_err(dev, "Failed to set watermarks: %d\n", ret);
+               return ret;
+       }
+
+       /* Store Capabilities Data Structure into Data RAM */
+       memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
+                   FSL_XCVR_CAPDS_SIZE);
+       return 0;
+}
+
+static int fsl_xcvr_type_iec958_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int fsl_xcvr_type_iec958_bytes_info(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = sizeof_field(struct snd_aes_iec958, status);
+
+       return 0;
+}
+
+static int fsl_xcvr_rx_cs_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       memcpy(ucontrol->value.iec958.status, xcvr->rx_iec958.status, 24);
+
+       return 0;
+}
+
+static int fsl_xcvr_tx_cs_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       memcpy(ucontrol->value.iec958.status, xcvr->tx_iec958.status, 24);
+
+       return 0;
+}
+
+static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = {
+       /* Channel status controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .info = fsl_xcvr_type_iec958_info,
+               .get = fsl_xcvr_rx_cs_get,
+       },
+       /* Capture channel status, bytes */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "Capture Channel Status",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .info = fsl_xcvr_type_iec958_bytes_info,
+               .get = fsl_xcvr_rx_cs_get,
+       },
+};
+
+static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
+       /* Channel status controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = fsl_xcvr_type_iec958_info,
+               .get = fsl_xcvr_tx_cs_get,
+               .put = fsl_xcvr_tx_cs_put,
+       },
+       /* Playback channel status, bytes */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "Playback Channel Status",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = fsl_xcvr_type_iec958_bytes_info,
+               .get = fsl_xcvr_tx_cs_get,
+               .put = fsl_xcvr_tx_cs_put,
+       },
+};
+
+static struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+       .prepare = fsl_xcvr_prepare,
+       .startup = fsl_xcvr_startup,
+       .shutdown = fsl_xcvr_shutdown,
+       .trigger = fsl_xcvr_trigger,
+};
+
+static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
+{
+       struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx, &xcvr->dma_prms_rx);
+       snd_soc_dai_set_drvdata(dai, xcvr);
+
+       snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1);
+       snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1);
+       snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl, 1);
+       snd_soc_add_dai_controls(dai, fsl_xcvr_tx_ctls,
+                                ARRAY_SIZE(fsl_xcvr_tx_ctls));
+       snd_soc_add_dai_controls(dai, fsl_xcvr_rx_ctls,
+                                ARRAY_SIZE(fsl_xcvr_rx_ctls));
+       return 0;
+}
+
+static struct snd_soc_dai_driver fsl_xcvr_dai = {
+       .probe  = fsl_xcvr_dai_probe,
+       .ops = &fsl_xcvr_dai_ops,
+       .playback = {
+               .stream_name = "CPU-Playback",
+               .channels_min = 1,
+               .channels_max = 32,
+               .rate_min = 32000,
+               .rate_max = 1536000,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+       },
+       .capture = {
+               .stream_name = "CPU-Capture",
+               .channels_min = 1,
+               .channels_max = 32,
+               .rate_min = 32000,
+               .rate_max = 1536000,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+       },
+};
+
+static const struct snd_soc_component_driver fsl_xcvr_comp = {
+       .name = "fsl-xcvr-dai",
+};
+
+static const struct reg_default fsl_xcvr_reg_defaults[] = {
+       { FSL_XCVR_VERSION,     0x00000000 },
+       { FSL_XCVR_EXT_CTRL,    0xF8204040 },
+       { FSL_XCVR_EXT_STATUS,  0x00000000 },
+       { FSL_XCVR_EXT_IER0,    0x00000000 },
+       { FSL_XCVR_EXT_IER1,    0x00000000 },
+       { FSL_XCVR_EXT_ISR,     0x00000000 },
+       { FSL_XCVR_EXT_ISR_SET, 0x00000000 },
+       { FSL_XCVR_EXT_ISR_CLR, 0x00000000 },
+       { FSL_XCVR_EXT_ISR_TOG, 0x00000000 },
+       { FSL_XCVR_IER,         0x00000000 },
+       { FSL_XCVR_ISR,         0x00000000 },
+       { FSL_XCVR_ISR_SET,     0x00000000 },
+       { FSL_XCVR_ISR_CLR,     0x00000000 },
+       { FSL_XCVR_ISR_TOG,     0x00000000 },
+       { FSL_XCVR_RX_DPTH_CTRL,        0x00002C89 },
+       { FSL_XCVR_RX_DPTH_CTRL_SET,    0x00002C89 },
+       { FSL_XCVR_RX_DPTH_CTRL_CLR,    0x00002C89 },
+       { FSL_XCVR_RX_DPTH_CTRL_TOG,    0x00002C89 },
+       { FSL_XCVR_TX_DPTH_CTRL,        0x00000000 },
+       { FSL_XCVR_TX_DPTH_CTRL_SET,    0x00000000 },
+       { FSL_XCVR_TX_DPTH_CTRL_CLR,    0x00000000 },
+       { FSL_XCVR_TX_DPTH_CTRL_TOG,    0x00000000 },
+       { FSL_XCVR_TX_CS_DATA_0,        0x00000000 },
+       { FSL_XCVR_TX_CS_DATA_1,        0x00000000 },
+       { FSL_XCVR_TX_CS_DATA_2,        0x00000000 },
+       { FSL_XCVR_TX_CS_DATA_3,        0x00000000 },
+       { FSL_XCVR_TX_CS_DATA_4,        0x00000000 },
+       { FSL_XCVR_TX_CS_DATA_5,        0x00000000 },
+       { FSL_XCVR_DEBUG_REG_0,         0x00000000 },
+       { FSL_XCVR_DEBUG_REG_1,         0x00000000 },
+};
+
+static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case FSL_XCVR_VERSION:
+       case FSL_XCVR_EXT_CTRL:
+       case FSL_XCVR_EXT_STATUS:
+       case FSL_XCVR_EXT_IER0:
+       case FSL_XCVR_EXT_IER1:
+       case FSL_XCVR_EXT_ISR:
+       case FSL_XCVR_EXT_ISR_SET:
+       case FSL_XCVR_EXT_ISR_CLR:
+       case FSL_XCVR_EXT_ISR_TOG:
+       case FSL_XCVR_IER:
+       case FSL_XCVR_ISR:
+       case FSL_XCVR_ISR_SET:
+       case FSL_XCVR_ISR_CLR:
+       case FSL_XCVR_ISR_TOG:
+       case FSL_XCVR_PHY_AI_CTRL:
+       case FSL_XCVR_PHY_AI_CTRL_SET:
+       case FSL_XCVR_PHY_AI_CTRL_CLR:
+       case FSL_XCVR_PHY_AI_CTRL_TOG:
+       case FSL_XCVR_PHY_AI_RDATA:
+       case FSL_XCVR_CLK_CTRL:
+       case FSL_XCVR_RX_DPTH_CTRL:
+       case FSL_XCVR_RX_DPTH_CTRL_SET:
+       case FSL_XCVR_RX_DPTH_CTRL_CLR:
+       case FSL_XCVR_RX_DPTH_CTRL_TOG:
+       case FSL_XCVR_TX_DPTH_CTRL:
+       case FSL_XCVR_TX_DPTH_CTRL_SET:
+       case FSL_XCVR_TX_DPTH_CTRL_CLR:
+       case FSL_XCVR_TX_DPTH_CTRL_TOG:
+       case FSL_XCVR_TX_CS_DATA_0:
+       case FSL_XCVR_TX_CS_DATA_1:
+       case FSL_XCVR_TX_CS_DATA_2:
+       case FSL_XCVR_TX_CS_DATA_3:
+       case FSL_XCVR_TX_CS_DATA_4:
+       case FSL_XCVR_TX_CS_DATA_5:
+       case FSL_XCVR_DEBUG_REG_0:
+       case FSL_XCVR_DEBUG_REG_1:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case FSL_XCVR_EXT_CTRL:
+       case FSL_XCVR_EXT_IER0:
+       case FSL_XCVR_EXT_IER1:
+       case FSL_XCVR_EXT_ISR:
+       case FSL_XCVR_EXT_ISR_SET:
+       case FSL_XCVR_EXT_ISR_CLR:
+       case FSL_XCVR_EXT_ISR_TOG:
+       case FSL_XCVR_IER:
+       case FSL_XCVR_ISR_SET:
+       case FSL_XCVR_ISR_CLR:
+       case FSL_XCVR_ISR_TOG:
+       case FSL_XCVR_PHY_AI_CTRL:
+       case FSL_XCVR_PHY_AI_CTRL_SET:
+       case FSL_XCVR_PHY_AI_CTRL_CLR:
+       case FSL_XCVR_PHY_AI_CTRL_TOG:
+       case FSL_XCVR_PHY_AI_WDATA:
+       case FSL_XCVR_CLK_CTRL:
+       case FSL_XCVR_RX_DPTH_CTRL:
+       case FSL_XCVR_RX_DPTH_CTRL_SET:
+       case FSL_XCVR_RX_DPTH_CTRL_CLR:
+       case FSL_XCVR_RX_DPTH_CTRL_TOG:
+       case FSL_XCVR_TX_DPTH_CTRL_SET:
+       case FSL_XCVR_TX_DPTH_CTRL_CLR:
+       case FSL_XCVR_TX_DPTH_CTRL_TOG:
+       case FSL_XCVR_TX_CS_DATA_0:
+       case FSL_XCVR_TX_CS_DATA_1:
+       case FSL_XCVR_TX_CS_DATA_2:
+       case FSL_XCVR_TX_CS_DATA_3:
+       case FSL_XCVR_TX_CS_DATA_4:
+       case FSL_XCVR_TX_CS_DATA_5:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_xcvr_volatile_reg(struct device *dev, unsigned int reg)
+{
+       return fsl_xcvr_readable_reg(dev, reg);
+}
+
+static const struct regmap_config fsl_xcvr_regmap_cfg = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = FSL_XCVR_MAX_REG,
+       .reg_defaults = fsl_xcvr_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_xcvr_reg_defaults),
+       .readable_reg = fsl_xcvr_readable_reg,
+       .volatile_reg = fsl_xcvr_volatile_reg,
+       .writeable_reg = fsl_xcvr_writeable_reg,
+       .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t irq0_isr(int irq, void *devid)
+{
+       struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
+       struct device *dev = &xcvr->pdev->dev;
+       struct regmap *regmap = xcvr->regmap;
+       void __iomem *reg_ctrl, *reg_buff;
+       u32 isr, isr_clr = 0, val, i;
+
+       regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr);
+
+       if (isr & FSL_XCVR_IRQ_NEW_CS) {
+               dev_dbg(dev, "Received new CS block\n");
+               isr_clr |= FSL_XCVR_IRQ_NEW_CS;
+               /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+               regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+                                  FSL_XCVR_EXT_CTRL_PAGE_MASK,
+                                  FSL_XCVR_EXT_CTRL_PAGE(8));
+
+               /* Find updated CS buffer */
+               reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
+               reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0;
+               memcpy_fromio(&val, reg_ctrl, sizeof(val));
+               if (!val) {
+                       reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1;
+                       reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1;
+                       memcpy_fromio(&val, reg_ctrl, sizeof(val));
+               }
+
+               if (val) {
+                       /* copy CS buffer */
+                       memcpy_fromio(&xcvr->rx_iec958.status, reg_buff,
+                                     sizeof(xcvr->rx_iec958.status));
+                       for (i = 0; i < 6; i++) {
+                               val = *(u32 *)(xcvr->rx_iec958.status + i*4);
+                               *(u32 *)(xcvr->rx_iec958.status + i*4) =
+                                       bitrev32(val);
+                       }
+                       /* clear CS control register */
+                       memset_io(reg_ctrl, 0, sizeof(val));
+               }
+       }
+       if (isr & FSL_XCVR_IRQ_NEW_UD) {
+               dev_dbg(dev, "Received new UD block\n");
+               isr_clr |= FSL_XCVR_IRQ_NEW_UD;
+       }
+       if (isr & FSL_XCVR_IRQ_MUTE) {
+               dev_dbg(dev, "HW mute bit detected\n");
+               isr_clr |= FSL_XCVR_IRQ_MUTE;
+       }
+       if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR) {
+               dev_dbg(dev, "RX/TX FIFO full/empty\n");
+               isr_clr |= FSL_XCVR_IRQ_FIFO_UOFL_ERR;
+       }
+       if (isr & FSL_XCVR_IRQ_ARC_MODE) {
+               dev_dbg(dev, "CMDC SM falls out of eARC mode\n");
+               isr_clr |= FSL_XCVR_IRQ_ARC_MODE;
+       }
+       if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) {
+               dev_dbg(dev, "DMA read request\n");
+               isr_clr |= FSL_XCVR_IRQ_DMA_RD_REQ;
+       }
+       if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) {
+               dev_dbg(dev, "DMA write request\n");
+               isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ;
+       }
+
+       if (isr_clr) {
+               regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
+       .fw_name = "imx/xcvr/xcvr-imx8mp.bin",
+};
+
+static const struct of_device_id fsl_xcvr_dt_ids[] = {
+       { .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
+
+static int fsl_xcvr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const struct of_device_id *of_id;
+       struct fsl_xcvr *xcvr;
+       struct resource *ram_res, *regs_res, *rx_res, *tx_res;
+       void __iomem *regs;
+       int ret, irq;
+
+       of_id = of_match_device(fsl_xcvr_dt_ids, dev);
+       if (!of_id)
+               return -EINVAL;
+
+       xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL);
+       if (!xcvr)
+               return -ENOMEM;
+
+       xcvr->pdev = pdev;
+       xcvr->soc_data = of_device_get_match_data(&pdev->dev);
+
+       xcvr->ipg_clk = devm_clk_get(dev, "ipg");
+       if (IS_ERR(xcvr->ipg_clk)) {
+               dev_err(dev, "failed to get ipg clock\n");
+               return PTR_ERR(xcvr->ipg_clk);
+       }
+
+       xcvr->phy_clk = devm_clk_get(dev, "phy");
+       if (IS_ERR(xcvr->phy_clk)) {
+               dev_err(dev, "failed to get phy clock\n");
+               return PTR_ERR(xcvr->phy_clk);
+       }
+
+       xcvr->spba_clk = devm_clk_get(dev, "spba");
+       if (IS_ERR(xcvr->spba_clk)) {
+               dev_err(dev, "failed to get spba clock\n");
+               return PTR_ERR(xcvr->spba_clk);
+       }
+
+       xcvr->pll_ipg_clk = devm_clk_get(dev, "pll_ipg");
+       if (IS_ERR(xcvr->pll_ipg_clk)) {
+               dev_err(dev, "failed to get pll_ipg clock\n");
+               return PTR_ERR(xcvr->pll_ipg_clk);
+       }
+
+       ram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ram");
+       xcvr->ram_addr = devm_ioremap_resource(dev, ram_res);
+       if (IS_ERR(xcvr->ram_addr))
+               return PTR_ERR(xcvr->ram_addr);
+
+       regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+       regs = devm_ioremap_resource(dev, regs_res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       xcvr->regmap = devm_regmap_init_mmio_clk(dev, NULL, regs,
+                                                &fsl_xcvr_regmap_cfg);
+       if (IS_ERR(xcvr->regmap)) {
+               dev_err(dev, "failed to init XCVR regmap: %ld\n",
+                       PTR_ERR(xcvr->regmap));
+               return PTR_ERR(xcvr->regmap);
+       }
+
+       xcvr->reset = devm_reset_control_get_exclusive(dev, NULL);
+       if (IS_ERR(xcvr->reset)) {
+               dev_err(dev, "failed to get XCVR reset control\n");
+               return PTR_ERR(xcvr->reset);
+       }
+
+       /* get IRQs */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "no irq[0]: %d\n", irq);
+               return irq;
+       }
+
+       ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr);
+       if (ret) {
+               dev_err(dev, "failed to claim IRQ0: %i\n", ret);
+               return ret;
+       }
+
+       rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo");
+       tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo");
+       xcvr->dma_prms_rx.chan_name = "rx";
+       xcvr->dma_prms_tx.chan_name = "tx";
+       xcvr->dma_prms_rx.addr = rx_res->start;
+       xcvr->dma_prms_tx.addr = tx_res->start;
+       xcvr->dma_prms_rx.maxburst = FSL_XCVR_MAXBURST_RX;
+       xcvr->dma_prms_tx.maxburst = FSL_XCVR_MAXBURST_TX;
+
+       platform_set_drvdata(pdev, xcvr);
+       pm_runtime_enable(dev);
+       regcache_cache_only(xcvr->regmap, true);
+
+       ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
+                                             &fsl_xcvr_dai, 1);
+       if (ret) {
+               dev_err(dev, "failed to register component %s\n",
+                       fsl_xcvr_comp.name);
+               return ret;
+       }
+
+       ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
+       if (ret)
+               dev_err(dev, "failed to pcm register\n");
+
+       return ret;
+}
+
+static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
+{
+       struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+       int ret;
+
+       /* Assert M0+ reset */
+       ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+                                FSL_XCVR_EXT_CTRL_CORE_RESET,
+                                FSL_XCVR_EXT_CTRL_CORE_RESET);
+       if (ret < 0)
+               dev_err(dev, "Failed to assert M0+ core: %d\n", ret);
+
+       ret = reset_control_assert(xcvr->reset);
+       if (ret < 0)
+               dev_err(dev, "Failed to assert M0+ reset: %d\n", ret);
+
+       regcache_cache_only(xcvr->regmap, true);
+
+       clk_disable_unprepare(xcvr->spba_clk);
+       clk_disable_unprepare(xcvr->phy_clk);
+       clk_disable_unprepare(xcvr->pll_ipg_clk);
+       clk_disable_unprepare(xcvr->ipg_clk);
+
+       return 0;
+}
+
+static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev)
+{
+       struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(xcvr->ipg_clk);
+       if (ret) {
+               dev_err(dev, "failed to start IPG clock.\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(xcvr->pll_ipg_clk);
+       if (ret) {
+               dev_err(dev, "failed to start PLL IPG clock.\n");
+               goto stop_ipg_clk;
+       }
+
+       ret = clk_prepare_enable(xcvr->phy_clk);
+       if (ret) {
+               dev_err(dev, "failed to start PHY clock: %d\n", ret);
+               goto stop_pll_ipg_clk;
+       }
+
+       ret = clk_prepare_enable(xcvr->spba_clk);
+       if (ret) {
+               dev_err(dev, "failed to start SPBA clock.\n");
+               goto stop_phy_clk;
+       }
+
+       regcache_cache_only(xcvr->regmap, false);
+       regcache_mark_dirty(xcvr->regmap);
+       ret = regcache_sync(xcvr->regmap);
+
+       if (ret) {
+               dev_err(dev, "failed to sync regcache.\n");
+               goto stop_spba_clk;
+       }
+
+       ret = reset_control_deassert(xcvr->reset);
+       if (ret) {
+               dev_err(dev, "failed to deassert M0+ reset.\n");
+               goto stop_spba_clk;
+       }
+
+       ret = fsl_xcvr_load_firmware(xcvr);
+       if (ret) {
+               dev_err(dev, "failed to load firmware.\n");
+               goto stop_spba_clk;
+       }
+
+       /* Release M0+ reset */
+       ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+                                FSL_XCVR_EXT_CTRL_CORE_RESET, 0);
+       if (ret < 0) {
+               dev_err(dev, "M0+ core release failed: %d\n", ret);
+               goto stop_spba_clk;
+       }
+
+       /* Let M0+ core complete firmware initialization */
+       msleep(50);
+
+       return 0;
+
+stop_spba_clk:
+       clk_disable_unprepare(xcvr->spba_clk);
+stop_phy_clk:
+       clk_disable_unprepare(xcvr->phy_clk);
+stop_pll_ipg_clk:
+       clk_disable_unprepare(xcvr->pll_ipg_clk);
+stop_ipg_clk:
+       clk_disable_unprepare(xcvr->ipg_clk);
+
+       return ret;
+}
+
+static const struct dev_pm_ops fsl_xcvr_pm_ops = {
+       SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend,
+                          fsl_xcvr_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_xcvr_driver = {
+       .probe = fsl_xcvr_probe,
+       .driver = {
+               .name = "fsl,imx8mp-audio-xcvr",
+               .pm = &fsl_xcvr_pm_ops,
+               .of_match_table = fsl_xcvr_dt_ids,
+       },
+};
+module_platform_driver(fsl_xcvr_driver);
+
+MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
+MODULE_DESCRIPTION("NXP Audio Transceiver (XCVR) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
new file mode 100644 (file)
index 0000000..7f2853c
--- /dev/null
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NXP XCVR ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright 2019 NXP
+ */
+
+#ifndef __FSL_XCVR_H
+#define __FSL_XCVR_H
+
+#define FSL_XCVR_MODE_SPDIF    0
+#define FSL_XCVR_MODE_ARC      1
+#define FSL_XCVR_MODE_EARC     2
+
+/* XCVR Registers */
+#define FSL_XCVR_REG_OFFSET            0x800 /* regs offset */
+#define FSL_XCVR_FIFO_SIZE             0x80  /* 128 */
+#define FSL_XCVR_FIFO_WMK_RX           (FSL_XCVR_FIFO_SIZE >> 1)   /* 64 */
+#define FSL_XCVR_FIFO_WMK_TX           (FSL_XCVR_FIFO_SIZE >> 1)   /* 64 */
+#define FSL_XCVR_MAXBURST_RX           (FSL_XCVR_FIFO_WMK_RX >> 2) /* 16 */
+#define FSL_XCVR_MAXBURST_TX           (FSL_XCVR_FIFO_WMK_TX >> 2) /* 16 */
+
+#define FSL_XCVR_RX_FIFO_ADDR          0x0C00
+#define FSL_XCVR_TX_FIFO_ADDR          0x0E00
+
+#define FSL_XCVR_VERSION               0x00  /* Version */
+#define FSL_XCVR_EXT_CTRL              0x10  /* Control */
+#define FSL_XCVR_EXT_STATUS            0x20  /* Status */
+#define FSL_XCVR_EXT_IER0              0x30  /* Interrupt en 0 */
+#define FSL_XCVR_EXT_IER1              0x40  /* Interrupt en 1 */
+#define FSL_XCVR_EXT_ISR               0x50  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_SET           0x54  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_CLR           0x58  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_TOG           0x5C  /* Interrupt status */
+#define FSL_XCVR_IER                   0x70  /* Interrupt en for M0+ */
+#define FSL_XCVR_ISR                   0x80  /* Interrupt status */
+#define FSL_XCVR_ISR_SET               0x84  /* Interrupt status set */
+#define FSL_XCVR_ISR_CLR               0x88  /* Interrupt status clear */
+#define FSL_XCVR_ISR_TOG               0x8C  /* Interrupt status toggle */
+#define FSL_XCVR_PHY_AI_CTRL           0x90
+#define FSL_XCVR_PHY_AI_CTRL_SET       0x94
+#define FSL_XCVR_PHY_AI_CTRL_CLR       0x98
+#define FSL_XCVR_PHY_AI_CTRL_TOG       0x9C
+#define FSL_XCVR_PHY_AI_WDATA          0xA0
+#define FSL_XCVR_PHY_AI_RDATA          0xA4
+#define FSL_XCVR_CLK_CTRL              0xB0
+#define FSL_XCVR_RX_DPTH_CTRL          0x180 /* RX datapath ctrl reg */
+#define FSL_XCVR_RX_DPTH_CTRL_SET      0x184
+#define FSL_XCVR_RX_DPTH_CTRL_CLR      0x188
+#define FSL_XCVR_RX_DPTH_CTRL_TOG      0x18c
+
+#define FSL_XCVR_TX_DPTH_CTRL          0x220 /* TX datapath ctrl reg */
+#define FSL_XCVR_TX_DPTH_CTRL_SET      0x224
+#define FSL_XCVR_TX_DPTH_CTRL_CLR      0x228
+#define FSL_XCVR_TX_DPTH_CTRL_TOG      0x22C
+#define FSL_XCVR_TX_CS_DATA_0          0x230 /* TX channel status bits regs */
+#define FSL_XCVR_TX_CS_DATA_1          0x234
+#define FSL_XCVR_TX_CS_DATA_2          0x238
+#define FSL_XCVR_TX_CS_DATA_3          0x23C
+#define FSL_XCVR_TX_CS_DATA_4          0x240
+#define FSL_XCVR_TX_CS_DATA_5          0x244
+#define FSL_XCVR_DEBUG_REG_0           0x2E0
+#define FSL_XCVR_DEBUG_REG_1           0x2F0
+
+#define FSL_XCVR_MAX_REG               FSL_XCVR_DEBUG_REG_1
+
+#define FSL_XCVR_EXT_CTRL_CORE_RESET   BIT(31)
+
+#define FSL_XCVR_EXT_CTRL_RX_CMDC_RESET        BIT(30)
+#define FSL_XCVR_EXT_CTRL_TX_CMDC_RESET        BIT(29)
+#define FSL_XCVR_EXT_CTRL_CMDC_RESET(t) (t ? BIT(29) : BIT(30))
+
+#define FSL_XCVR_EXT_CTRL_RX_DPTH_RESET        BIT(28)
+#define FSL_XCVR_EXT_CTRL_TX_DPTH_RESET        BIT(27)
+#define FSL_XCVR_EXT_CTRL_DPTH_RESET(t) (t ? BIT(27) : BIT(28))
+
+#define FSL_XCVR_EXT_CTRL_TX_RX_MODE   BIT(26)
+#define FSL_XCVR_EXT_CTRL_DMA_RD_DIS   BIT(25)
+#define FSL_XCVR_EXT_CTRL_DMA_WR_DIS   BIT(24)
+#define FSL_XCVR_EXT_CTRL_DMA_DIS(t)   (t ? BIT(24) : BIT(25))
+#define FSL_XCVR_EXT_CTRL_SPDIF_MODE   BIT(23)
+#define FSL_XCVR_EXT_CTRL_SLEEP_MODE   BIT(21)
+
+#define FSL_XCVR_EXT_CTRL_TX_FWM_SHFT  0
+#define FSL_XCVR_EXT_CTRL_TX_FWM_MASK  GENMASK(6, 0)
+#define FSL_XCVR_EXT_CTRL_TX_FWM(i)    (((i) << FSL_XCVR_EXT_CTRL_TX_FWM_SHFT) \
+                                         & FSL_XCVR_EXT_CTRL_TX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_RX_FWM_SHFT  8
+#define FSL_XCVR_EXT_CTRL_RX_FWM_MASK  GENMASK(14, 8)
+#define FSL_XCVR_EXT_CTRL_RX_FWM(i)    (((i) << FSL_XCVR_EXT_CTRL_RX_FWM_SHFT) \
+                                         & FSL_XCVR_EXT_CTRL_RX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_PAGE_SHFT    16
+#define FSL_XCVR_EXT_CTRL_PAGE_MASK    GENMASK(19, 16)
+#define FSL_XCVR_EXT_CTRL_PAGE(i)      (((i) << FSL_XCVR_EXT_CTRL_PAGE_SHFT) \
+                                         & FSL_XCVR_EXT_CTRL_PAGE_MASK)
+
+#define FSL_XCVR_EXT_STUS_NT_FIFO_ENTR GENMASK(7, 0)
+#define FSL_XCVR_EXT_STUS_NR_FIFO_ENTR GENMASK(15, 8)
+#define FSL_XCVR_EXT_STUS_CM0_SLEEPING BIT(16)
+#define FSL_XCVR_EXT_STUS_CM0_DEEP_SLP BIT(17)
+#define FSL_XCVR_EXT_STUS_CM0_SLP_HACK BIT(18)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_RSTO BIT(23)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_RSTO BIT(24)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_COTO BIT(25)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_COTO BIT(26)
+#define FSL_XCVR_EXT_STUS_HB_STATUS    BIT(27)
+#define FSL_XCVR_EXT_STUS_NEW_UD4_REC  BIT(28)
+#define FSL_XCVR_EXT_STUS_NEW_UD5_REC  BIT(29)
+#define FSL_XCVR_EXT_STUS_NEW_UD6_REC  BIT(30)
+#define FSL_XCVR_EXT_STUS_HPD_INPUT    BIT(31)
+
+#define FSL_XCVR_IRQ_NEW_CS            BIT(0)
+#define FSL_XCVR_IRQ_NEW_UD            BIT(1)
+#define FSL_XCVR_IRQ_MUTE              BIT(2)
+#define FSL_XCVR_IRQ_CMDC_RESP_TO      BIT(3)
+#define FSL_XCVR_IRQ_ECC_ERR           BIT(4)
+#define FSL_XCVR_IRQ_PREAMBLE_MISMATCH BIT(5)
+#define FSL_XCVR_IRQ_FIFO_UOFL_ERR     BIT(6)
+#define FSL_XCVR_IRQ_HOST_WAKEUP       BIT(7)
+#define FSL_XCVR_IRQ_HOST_OHPD         BIT(8)
+#define FSL_XCVR_IRQ_DMAC_NO_DATA_REC  BIT(9)
+#define FSL_XCVR_IRQ_DMAC_FMT_CHG_DET  BIT(10)
+#define FSL_XCVR_IRQ_HB_STATE_CHG      BIT(11)
+#define FSL_XCVR_IRQ_CMDC_STATUS_UPD   BIT(12)
+#define FSL_XCVR_IRQ_TEMP_UPD          BIT(13)
+#define FSL_XCVR_IRQ_DMA_RD_REQ                BIT(14)
+#define FSL_XCVR_IRQ_DMA_WR_REQ                BIT(15)
+#define FSL_XCVR_IRQ_DMAC_BME_BIT_ERR  BIT(16)
+#define FSL_XCVR_IRQ_PREAMBLE_MATCH    BIT(17)
+#define FSL_XCVR_IRQ_M_W_PRE_MISMATCH  BIT(18)
+#define FSL_XCVR_IRQ_B_PRE_MISMATCH    BIT(19)
+#define FSL_XCVR_IRQ_UNEXP_PRE_REC     BIT(20)
+#define FSL_XCVR_IRQ_ARC_MODE          BIT(21)
+#define FSL_XCVR_IRQ_CH_UD_OFLOW       BIT(22)
+#define FSL_XCVR_IRQ_EARC_ALL          (FSL_XCVR_IRQ_NEW_CS | \
+                                        FSL_XCVR_IRQ_NEW_UD | \
+                                        FSL_XCVR_IRQ_MUTE | \
+                                        FSL_XCVR_IRQ_FIFO_UOFL_ERR | \
+                                        FSL_XCVR_IRQ_HOST_WAKEUP | \
+                                        FSL_XCVR_IRQ_ARC_MODE)
+
+#define FSL_XCVR_ISR_CMDC_TX_EN                BIT(3)
+#define FSL_XCVR_ISR_HPD_TGL           BIT(15)
+#define FSL_XCVR_ISR_DMAC_SPARE_INT    BIT(19)
+#define FSL_XCVR_ISR_SET_SPDIF_RX_INT  BIT(20)
+#define FSL_XCVR_ISR_SET_SPDIF_TX_INT  BIT(21)
+#define FSL_XCVR_ISR_SET_SPDIF_MODE(t) (t ? BIT(21) : BIT(20))
+#define FSL_XCVR_ISR_SET_ARC_CM_INT    BIT(22)
+#define FSL_XCVR_ISR_SET_ARC_SE_INT    BIT(23)
+
+#define FSL_XCVR_PHY_AI_ADDR_MASK      GENMASK(7, 0)
+#define FSL_XCVR_PHY_AI_RESETN         BIT(15)
+#define FSL_XCVR_PHY_AI_TOG_PLL                BIT(24)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PLL   BIT(25)
+#define FSL_XCVR_PHY_AI_TOG_PHY                BIT(26)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PHY   BIT(27)
+#define FSL_XCVR_PHY_AI_RW_MASK                BIT(31)
+
+#define FSL_XCVR_RX_DPTH_CTRL_PAPB_FIFO_STATUS BIT(0)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_PRE_ERR_CHK  BIT(1)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_NOD_REC_CHK  BIT(2)
+#define FSL_XCVR_RX_DPTH_CTRL_ECC_VUC_BIT_CHK  BIT(3)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_CMP_PAR_CALC  BIT(4)
+#define FSL_XCVR_RX_DPTH_CTRL_RST_PKT_CNT_FIFO BIT(5)
+#define FSL_XCVR_RX_DPTH_CTRL_STORE_FMT                BIT(6)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_PAR_CALC      BIT(7)
+#define FSL_XCVR_RX_DPTH_CTRL_UDR              BIT(8)
+#define FSL_XCVR_RX_DPTH_CTRL_CSR              BIT(9)
+#define FSL_XCVR_RX_DPTH_CTRL_UDA              BIT(10)
+#define FSL_XCVR_RX_DPTH_CTRL_CSA              BIT(11)
+#define FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO      BIT(12)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_B_PRE_ERR_CHK        BIT(13)
+#define FSL_XCVR_RX_DPTH_CTRL_PABS             BIT(19)
+#define FSL_XCVR_RX_DPTH_CTRL_DTS_CDS          BIT(20)
+#define FSL_XCVR_RX_DPTH_CTRL_BLKC             BIT(21)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_CTRL                BIT(22)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_MODE                BIT(23)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_CTRL     BIT(24)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_MODE     BIT(25)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL                BIT(26)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_MODE                BIT(27)
+#define FSL_XCVR_RX_DPTH_CTRL_PRC              BIT(28)
+#define FSL_XCVR_RX_DPTH_CTRL_COMP             BIT(29)
+#define FSL_XCVR_RX_DPTH_CTRL_FSM              GENMASK(31, 30)
+
+#define FSL_XCVR_TX_DPTH_CTRL_CS_ACK           BIT(0)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_ACK           BIT(1)
+#define FSL_XCVR_TX_DPTH_CTRL_CS_MOD           BIT(2)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_MOD           BIT(3)
+#define FSL_XCVR_TX_DPTH_CTRL_VLD_MOD          BIT(4)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_VLD          BIT(5)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PARITY                BIT(6)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PREAMBLE      BIT(7)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_ECC_INTER     BIT(8)
+#define FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM       BIT(10)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_FMT          BIT(11)
+#define FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX     BIT(14)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_STR        BIT(15)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_END        BIT(16)
+#define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO                BIT(29)
+#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME    GENMASK(31, 30)
+
+#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN         BIT(15)
+
+#define FSL_XCVR_PLL_CTRL0                     0x00
+#define FSL_XCVR_PLL_CTRL0_SET                 0x04
+#define FSL_XCVR_PLL_CTRL0_CLR                 0x08
+#define FSL_XCVR_PLL_NUM                       0x20
+#define FSL_XCVR_PLL_DEN                       0x30
+#define FSL_XCVR_PLL_PDIV                      0x40
+#define FSL_XCVR_PLL_BANDGAP_SET               0x54
+#define FSL_XCVR_PHY_CTRL                      0x00
+#define FSL_XCVR_PHY_CTRL_SET                  0x04
+#define FSL_XCVR_PHY_CTRL_CLR                  0x08
+#define FSL_XCVR_PHY_CTRL2                     0x70
+#define FSL_XCVR_PHY_CTRL2_SET                 0x74
+#define FSL_XCVR_PHY_CTRL2_CLR                 0x78
+
+#define FSL_XCVR_PLL_BANDGAP_EN_VBG            BIT(0)
+#define FSL_XCVR_PLL_CTRL0_HROFF               BIT(13)
+#define FSL_XCVR_PLL_CTRL0_PWP                 BIT(14)
+#define FSL_XCVR_PLL_CTRL0_CM0_EN              BIT(24)
+#define FSL_XCVR_PLL_CTRL0_CM1_EN              BIT(25)
+#define FSL_XCVR_PLL_CTRL0_CM2_EN              BIT(26)
+#define FSL_XCVR_PLL_PDIVx(v, i)               ((v & 0x7) << (4 * i))
+
+#define FSL_XCVR_PHY_CTRL_PHY_EN               BIT(0)
+#define FSL_XCVR_PHY_CTRL_RX_CM_EN             BIT(1)
+#define FSL_XCVR_PHY_CTRL_TSDIFF_OE            BIT(5)
+#define FSL_XCVR_PHY_CTRL_SPDIF_EN             BIT(8)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN       BIT(9)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN       BIT(10)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_MASK          GENMASK(26, 25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_HDMI_SS       BIT(25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS                BIT(26)
+#define FSL_XCVR_PHY_CTRL2_EARC_TXMS           BIT(14)
+
+#define FSL_XCVR_CS_DATA_0_FS_MASK             GENMASK(31, 24)
+#define FSL_XCVR_CS_DATA_0_FS_32000            0x3000000
+#define FSL_XCVR_CS_DATA_0_FS_44100            0x0000000
+#define FSL_XCVR_CS_DATA_0_FS_48000            0x2000000
+#define FSL_XCVR_CS_DATA_0_FS_64000            0xB000000
+#define FSL_XCVR_CS_DATA_0_FS_88200            0x8000000
+#define FSL_XCVR_CS_DATA_0_FS_96000            0xA000000
+#define FSL_XCVR_CS_DATA_0_FS_176400           0xC000000
+#define FSL_XCVR_CS_DATA_0_FS_192000           0xE000000
+
+#define FSL_XCVR_CS_DATA_0_CH_MASK             0x3A
+#define FSL_XCVR_CS_DATA_0_CH_U2LPCM           0x00
+#define FSL_XCVR_CS_DATA_0_CH_UMLPCM           0x20
+#define FSL_XCVR_CS_DATA_0_CH_U1BAUD           0x30
+
+#define FSL_XCVR_CS_DATA_1_CH_MASK             0xF000
+#define FSL_XCVR_CS_DATA_1_CH_2                        0x0000
+#define FSL_XCVR_CS_DATA_1_CH_8                        0x7000
+#define FSL_XCVR_CS_DATA_1_CH_16               0xB000
+#define FSL_XCVR_CS_DATA_1_CH_32               0x3000
+
+/* Data memory structures */
+#define FSL_XCVR_RX_CS_CTRL_0          0x20 /* First  RX CS control register */
+#define FSL_XCVR_RX_CS_CTRL_1          0x24 /* Second RX CS control register */
+#define FSL_XCVR_RX_CS_BUFF_0          0x80 /* First  RX CS buffer */
+#define FSL_XCVR_RX_CS_BUFF_1          0xA0 /* Second RX CS buffer */
+#define FSL_XCVR_CAP_DATA_STR          0x300 /* Capabilities data structure */
+
+#endif /* __FSL_XCVR_H */
index 25c18b9..dfa05d4 100644 (file)
@@ -170,22 +170,9 @@ static enum imx_audmux_type {
        IMX31_AUDMUX,
 } audmux_type;
 
-static const struct platform_device_id imx_audmux_ids[] = {
-       {
-               .name = "imx21-audmux",
-               .driver_data = IMX21_AUDMUX,
-       }, {
-               .name = "imx31-audmux",
-               .driver_data = IMX31_AUDMUX,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(platform, imx_audmux_ids);
-
 static const struct of_device_id imx_audmux_dt_ids[] = {
-       { .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], },
-       { .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], },
+       { .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, },
+       { .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids);
@@ -300,9 +287,6 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
 
 static int imx_audmux_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *of_id =
-                       of_match_device(imx_audmux_dt_ids, &pdev->dev);
-
        audmux_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(audmux_base))
                return PTR_ERR(audmux_base);
@@ -314,9 +298,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
                audmux_clk = NULL;
        }
 
-       if (of_id)
-               pdev->id_entry = of_id->data;
-       audmux_type = pdev->id_entry->driver_data;
+       audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev);
 
        switch (audmux_type) {
        case IMX31_AUDMUX:
@@ -335,8 +317,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
        if (!regcache)
                return -ENOMEM;
 
-       if (of_id)
-               imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
+       imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
 
        return 0;
 }
@@ -386,7 +367,6 @@ static const struct dev_pm_ops imx_audmux_pm = {
 static struct platform_driver imx_audmux_driver = {
        .probe          = imx_audmux_probe,
        .remove         = imx_audmux_remove,
-       .id_table       = imx_audmux_ids,
        .driver = {
                .name   = DRIVER_NAME,
                .pm = &imx_audmux_pm,
diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c
new file mode 100644 (file)
index 0000000..2c2a76a
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2017-2020 NXP
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/hdmi-codec.h>
+#include "fsl_sai.h"
+
+/**
+ * struct cpu_priv - CPU private data
+ * @sysclk_freq: SYSCLK rates for set_sysclk()
+ * @sysclk_dir: SYSCLK directions for set_sysclk()
+ * @sysclk_id: SYSCLK ids for set_sysclk()
+ * @slot_width: Slot width of each frame
+ *
+ * Note: [1] for tx and [0] for rx
+ */
+struct cpu_priv {
+       unsigned long sysclk_freq[2];
+       u32 sysclk_dir[2];
+       u32 sysclk_id[2];
+       u32 slot_width;
+};
+
+struct imx_hdmi_data {
+       struct snd_soc_dai_link dai;
+       struct snd_soc_card card;
+       struct snd_soc_jack hdmi_jack;
+       struct snd_soc_jack_pin hdmi_jack_pin;
+       struct cpu_priv cpu_priv;
+       u32 dai_fmt;
+};
+
+static int imx_hdmi_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct imx_hdmi_data *data = snd_soc_card_get_drvdata(rtd->card);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_card *card = rtd->card;
+       struct device *dev = card->dev;
+       u32 slot_width = data->cpu_priv.slot_width;
+       int ret;
+
+       /* MCLK always is (256 or 192) * rate. */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, data->cpu_priv.sysclk_id[tx],
+                                    8 * slot_width * params_rate(params),
+                                    tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN);
+       if (ret && ret != -ENOTSUPP) {
+               dev_err(dev, "failed to set cpu sysclk: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0, 2, slot_width);
+       if (ret && ret != -ENOTSUPP) {
+               dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops imx_hdmi_ops = {
+       .hw_params = imx_hdmi_hw_params,
+};
+
+static const struct snd_soc_dapm_widget imx_hdmi_widgets[] = {
+       SND_SOC_DAPM_LINE("HDMI Jack", NULL),
+};
+
+static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       struct imx_hdmi_data *data = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       data->hdmi_jack_pin.pin = "HDMI Jack";
+       data->hdmi_jack_pin.mask = SND_JACK_LINEOUT;
+       /* enable jack detection */
+       ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
+                                   &data->hdmi_jack, &data->hdmi_jack_pin, 1);
+       if (ret) {
+               dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_component_set_jack(component, &data->hdmi_jack, NULL);
+       if (ret && ret != -EOPNOTSUPP) {
+               dev_err(card->dev, "Can't set HDMI Jack %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+};
+
+static int imx_hdmi_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       bool hdmi_out = of_property_read_bool(np, "hdmi-out");
+       bool hdmi_in = of_property_read_bool(np, "hdmi-in");
+       struct snd_soc_dai_link_component *dlc;
+       struct platform_device *cpu_pdev;
+       struct device_node *cpu_np;
+       struct imx_hdmi_data *data;
+       int ret;
+
+       dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL);
+       if (!dlc)
+               return -ENOMEM;
+
+       cpu_np = of_parse_phandle(np, "audio-cpu", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       cpu_pdev = of_find_device_by_node(cpu_np);
+       if (!cpu_pdev) {
+               dev_err(&pdev->dev, "failed to find SAI platform device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       data->dai.cpus = &dlc[0];
+       data->dai.num_cpus = 1;
+       data->dai.platforms = &dlc[1];
+       data->dai.num_platforms = 1;
+       data->dai.codecs = &dlc[2];
+       data->dai.num_codecs = 1;
+
+       data->dai.name = "i.MX HDMI";
+       data->dai.stream_name = "i.MX HDMI";
+       data->dai.cpus->dai_name = dev_name(&cpu_pdev->dev);
+       data->dai.platforms->of_node = cpu_np;
+       data->dai.ops = &imx_hdmi_ops;
+       data->dai.playback_only = true;
+       data->dai.capture_only = false;
+       data->dai.init = imx_hdmi_init;
+
+       if (of_node_name_eq(cpu_np, "sai")) {
+               data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
+               data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
+       }
+
+       if (of_device_is_compatible(np, "fsl,imx-audio-sii902x")) {
+               data->dai_fmt = SND_SOC_DAIFMT_LEFT_J;
+               data->cpu_priv.slot_width = 24;
+       } else {
+               data->dai_fmt = SND_SOC_DAIFMT_I2S;
+               data->cpu_priv.slot_width = 32;
+       }
+
+       if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) {
+               dev_err(&pdev->dev, "Invalid HDMI DAI link\n");
+               goto fail;
+       }
+
+       if (hdmi_out) {
+               data->dai.playback_only = true;
+               data->dai.capture_only = false;
+               data->dai.codecs->dai_name = "i2s-hifi";
+               data->dai.codecs->name = "hdmi-audio-codec.1";
+               data->dai.dai_fmt = data->dai_fmt |
+                                   SND_SOC_DAIFMT_NB_NF |
+                                   SND_SOC_DAIFMT_CBS_CFS;
+       }
+
+       if (hdmi_in) {
+               data->dai.playback_only = false;
+               data->dai.capture_only = true;
+               data->dai.codecs->dai_name = "i2s-hifi";
+               data->dai.codecs->name = "hdmi-audio-codec.2";
+               data->dai.dai_fmt = data->dai_fmt |
+                                   SND_SOC_DAIFMT_NB_NF |
+                                   SND_SOC_DAIFMT_CBM_CFM;
+       }
+
+       data->card.dapm_widgets = imx_hdmi_widgets;
+       data->card.num_dapm_widgets = ARRAY_SIZE(imx_hdmi_widgets);
+       data->card.dev = &pdev->dev;
+       data->card.owner = THIS_MODULE;
+       ret = snd_soc_of_parse_card_name(&data->card, "model");
+       if (ret)
+               goto fail;
+
+       data->card.num_links = 1;
+       data->card.dai_link = &data->dai;
+
+       snd_soc_card_set_drvdata(&data->card, data);
+       ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               goto fail;
+       }
+
+fail:
+       if (cpu_np)
+               of_node_put(cpu_np);
+
+       return ret;
+}
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-hdmi", },
+       { .compatible = "fsl,imx-audio-sii902x", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static struct platform_driver imx_hdmi_driver = {
+       .driver = {
+               .name = "imx-hdmi",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = imx_hdmi_dt_ids,
+       },
+       .probe = imx_hdmi_probe,
+};
+module_platform_driver(imx_hdmi_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX hdmi audio ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-hdmi");
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
deleted file mode 100644 (file)
index d9dca7b..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// imx-mc13783.c  --  SoC audio for imx based boards with mc13783 codec
-//
-// Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
-//
-// Heavly based on phycore-mc13783:
-// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/mc13783.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
-               SND_SOC_DAIFMT_CBM_CFM)
-
-static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       int ret;
-
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
-       if (ret)
-               return ret;
-
-       return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
-}
-
-static const struct snd_soc_ops imx_mc13783_hifi_ops = {
-       .hw_params = imx_mc13783_hifi_hw_params,
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
-       DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-       DAILINK_COMP_ARRAY(COMP_CODEC("mc13783-codec", "mc13783-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
-       {
-               .name = "MC13783",
-               .stream_name     = "Sound",
-               .ops             = &imx_mc13783_hifi_ops,
-               .symmetric_rates = 1,
-               .dai_fmt         = FMT_SSI,
-               SND_SOC_DAILINK_REG(hifi),
-       },
-};
-
-static const struct snd_soc_dapm_widget imx_mc13783_widget[] = {
-       SND_SOC_DAPM_MIC("Mic", NULL),
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
-       {"Speaker", NULL, "LSP"},
-       {"Headphone", NULL, "HSL"},
-       {"Headphone", NULL, "HSR"},
-
-       {"MC1LIN", NULL, "MC1 Bias"},
-       {"MC2IN", NULL, "MC2 Bias"},
-       {"MC1 Bias", NULL, "Mic"},
-       {"MC2 Bias", NULL, "Mic"},
-};
-
-static struct snd_soc_card imx_mc13783 = {
-       .name           = "imx_mc13783",
-       .owner          = THIS_MODULE,
-       .dai_link       = imx_mc13783_dai_mc13783,
-       .num_links      = ARRAY_SIZE(imx_mc13783_dai_mc13783),
-       .dapm_widgets   = imx_mc13783_widget,
-       .num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget),
-       .dapm_routes    = imx_mc13783_routes,
-       .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
-};
-
-static int imx_mc13783_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       imx_mc13783.dev = &pdev->dev;
-
-       ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
-
-       if (machine_is_mx31_3ds() || machine_is_mx31moboard()) {
-               imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
-                       IMX_AUDMUX_V2_PTCR_SYN,
-                       IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
-                       IMX_AUDMUX_V2_PDCR_MODE(1) |
-                       IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
-               imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
-                       IMX_AUDMUX_V2_PTCR_SYN |
-                       IMX_AUDMUX_V2_PTCR_TFSDIR |
-                       IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
-                       IMX_AUDMUX_V2_PTCR_TCLKDIR |
-                       IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
-                       IMX_AUDMUX_V2_PTCR_RFSDIR |
-                       IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
-                       IMX_AUDMUX_V2_PTCR_RCLKDIR |
-                       IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
-                       IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
-       } else if (machine_is_mx27_3ds()) {
-               imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-                       IMX_AUDMUX_V1_PCR_SYN |
-                       IMX_AUDMUX_V1_PCR_TFSDIR |
-                       IMX_AUDMUX_V1_PCR_TCLKDIR |
-                       IMX_AUDMUX_V1_PCR_RFSDIR |
-                       IMX_AUDMUX_V1_PCR_RCLKDIR |
-                       IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-                       IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-                       IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
-               );
-               imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
-                       IMX_AUDMUX_V1_PCR_SYN |
-                       IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
-               );
-       }
-
-       return ret;
-}
-
-static struct platform_driver imx_mc13783_audio_driver = {
-       .driver = {
-               .name = "imx_mc13783",
-       },
-       .probe = imx_mc13783_probe,
-};
-
-module_platform_driver(imx_mc13783_audio_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch");
-MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx_mc13783");
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
deleted file mode 100644 (file)
index f8488e8..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// imx-ssi.c  --  ALSA Soc Audio Layer
-//
-// Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
-//
-// This code is based on code copyrighted by Freescale,
-// Liam Girdwood, Javier Martin and probably others.
-//
-// The i.MX SSI core has some nasty limitations in AC97 mode. While most
-// sane processor vendors have a FIFO per AC97 slot, the i.MX has only
-// one FIFO which combines all valid receive slots. We cannot even select
-// which slots we want to receive. The WM9712 with which this driver
-// was developed with always sends GPIO status data in slot 12 which
-// we receive in our (PCM-) data stream. The only chance we have is to
-// manually skip this data in the FIQ handler. With sampling rates different
-// from 48000Hz not every frame has valid receive data, so the ratio
-// between pcm data and GPIO status data changes. Our FIQ handler is not
-// able to handle this, hence this driver only works with 48000Hz sampling
-// rate.
-// Reading and writing AC97 registers is another challenge. The core
-// provides us status bits when the read register is updated with *another*
-// value. When we read the same register two times (and the register still
-// contains the same value) these status bits are not set. We work
-// around this by not polling these bits but only wait a fixed delay.
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <linux/platform_data/asoc-imx-ssi.h>
-
-#include "imx-ssi.h"
-#include "fsl_utils.h"
-
-#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
-
-/*
- * SSI Network Mode or TDM slots configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
-       unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
-{
-       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 sccr;
-
-       sccr = readl(ssi->base + SSI_STCCR);
-       sccr &= ~SSI_STCCR_DC_MASK;
-       sccr |= SSI_STCCR_DC(slots - 1);
-       writel(sccr, ssi->base + SSI_STCCR);
-
-       sccr = readl(ssi->base + SSI_SRCCR);
-       sccr &= ~SSI_STCCR_DC_MASK;
-       sccr |= SSI_STCCR_DC(slots - 1);
-       writel(sccr, ssi->base + SSI_SRCCR);
-
-       writel(~tx_mask, ssi->base + SSI_STMSK);
-       writel(~rx_mask, ssi->base + SSI_SRMSK);
-
-       return 0;
-}
-
-/*
- * SSI DAI format configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 strcr = 0, scr;
-
-       scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
-
-       /* DAI mode */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               /* data on rising edge of bclk, frame low 1clk before data */
-               strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
-                       SSI_STCR_TEFS;
-               scr |= SSI_SCR_NET;
-               if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
-                       scr &= ~SSI_I2S_MODE_MASK;
-                       scr |= SSI_SCR_I2S_MODE_SLAVE;
-               }
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               /* data on rising edge of bclk, frame high with data */
-               strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               /* data on rising edge of bclk, frame high with data */
-               strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL;
-               break;
-       case SND_SOC_DAIFMT_DSP_A:
-               /* data on rising edge of bclk, frame high 1clk before data */
-               strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL |
-                       SSI_STCR_TEFS;
-               break;
-       }
-
-       /* DAI clock inversion */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_IB_IF:
-               strcr ^= SSI_STCR_TSCKP | SSI_STCR_TFSI;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               strcr ^= SSI_STCR_TSCKP;
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               strcr ^= SSI_STCR_TFSI;
-               break;
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       }
-
-       /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               break;
-       default:
-               /* Master mode not implemented, needs handling of clocks. */
-               return -EINVAL;
-       }
-
-       strcr |= SSI_STCR_TFEN0;
-
-       if (ssi->flags & IMX_SSI_NET)
-               scr |= SSI_SCR_NET;
-       if (ssi->flags & IMX_SSI_SYN)
-               scr |= SSI_SCR_SYN;
-
-       writel(strcr, ssi->base + SSI_STCR);
-       writel(strcr, ssi->base + SSI_SRCR);
-       writel(scr, ssi->base + SSI_SCR);
-
-       return 0;
-}
-
-/*
- * SSI system clock configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-                                 int clk_id, unsigned int freq, int dir)
-{
-       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 scr;
-
-       scr = readl(ssi->base + SSI_SCR);
-
-       switch (clk_id) {
-       case IMX_SSP_SYS_CLK:
-               if (dir == SND_SOC_CLOCK_OUT)
-                       scr |= SSI_SCR_SYS_CLK_EN;
-               else
-                       scr &= ~SSI_SCR_SYS_CLK_EN;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       writel(scr, ssi->base + SSI_SCR);
-
-       return 0;
-}
-
-/*
- * SSI Clock dividers
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-                                 int div_id, int div)
-{
-       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 stccr, srccr;
-
-       stccr = readl(ssi->base + SSI_STCCR);
-       srccr = readl(ssi->base + SSI_SRCCR);
-
-       switch (div_id) {
-       case IMX_SSI_TX_DIV_2:
-               stccr &= ~SSI_STCCR_DIV2;
-               stccr |= div;
-               break;
-       case IMX_SSI_TX_DIV_PSR:
-               stccr &= ~SSI_STCCR_PSR;
-               stccr |= div;
-               break;
-       case IMX_SSI_TX_DIV_PM:
-               stccr &= ~0xff;
-               stccr |= SSI_STCCR_PM(div);
-               break;
-       case IMX_SSI_RX_DIV_2:
-               stccr &= ~SSI_STCCR_DIV2;
-               stccr |= div;
-               break;
-       case IMX_SSI_RX_DIV_PSR:
-               stccr &= ~SSI_STCCR_PSR;
-               stccr |= div;
-               break;
-       case IMX_SSI_RX_DIV_PM:
-               stccr &= ~0xff;
-               stccr |= SSI_STCCR_PM(div);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       writel(stccr, ssi->base + SSI_STCCR);
-       writel(srccr, ssi->base + SSI_SRCCR);
-
-       return 0;
-}
-
-/*
- * Should only be called when port is inactive (i.e. SSIEN = 0),
- * although can be called multiple times by upper layers.
- */
-static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *params,
-                            struct snd_soc_dai *cpu_dai)
-{
-       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 reg, sccr;
-
-       /* Tx/Rx config */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               reg = SSI_STCCR;
-       else
-               reg = SSI_SRCCR;
-
-       if (ssi->flags & IMX_SSI_SYN)
-               reg = SSI_STCCR;
-
-       sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
-
-       /* DAI data (word) size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               sccr |= SSI_SRCCR_WL(16);
-               break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
-               sccr |= SSI_SRCCR_WL(20);
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               sccr |= SSI_SRCCR_WL(24);
-               break;
-       }
-
-       writel(sccr, ssi->base + reg);
-
-       return 0;
-}
-
-static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
-               struct snd_soc_dai *dai)
-{
-       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
-       unsigned int sier_bits, sier;
-       unsigned int scr;
-
-       scr = readl(ssi->base + SSI_SCR);
-       sier = readl(ssi->base + SSI_SIER);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (ssi->flags & IMX_SSI_DMA)
-                       sier_bits = SSI_SIER_TDMAE;
-               else
-                       sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
-       } else {
-               if (ssi->flags & IMX_SSI_DMA)
-                       sier_bits = SSI_SIER_RDMAE;
-               else
-                       sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
-       }
-
-       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)
-                       scr |= SSI_SCR_TE;
-               else
-                       scr |= SSI_SCR_RE;
-               sier |= sier_bits;
-
-               scr |= SSI_SCR_SSIEN;
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       scr &= ~SSI_SCR_TE;
-               else
-                       scr &= ~SSI_SCR_RE;
-               sier &= ~sier_bits;
-
-               if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
-                       scr &= ~SSI_SCR_SSIEN;
-
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (!(ssi->flags & IMX_SSI_USE_AC97))
-               /* rx/tx are always enabled to access ac97 registers */
-               writel(scr, ssi->base + SSI_SCR);
-
-       writel(sier, ssi->base + SSI_SIER);
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
-       .hw_params      = imx_ssi_hw_params,
-       .set_fmt        = imx_ssi_set_dai_fmt,
-       .set_clkdiv     = imx_ssi_set_dai_clkdiv,
-       .set_sysclk     = imx_ssi_set_dai_sysclk,
-       .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
-       .trigger        = imx_ssi_trigger,
-};
-
-static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
-{
-       struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
-       uint32_t val;
-
-       snd_soc_dai_set_drvdata(dai, ssi);
-
-       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
-               SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
-       writel(val, ssi->base + SSI_SFCSR);
-
-       /* Tx/Rx config */
-       dai->playback_dma_data = &ssi->dma_params_tx;
-       dai->capture_dma_data = &ssi->dma_params_rx;
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver imx_ssi_dai = {
-       .probe = imx_ssi_dai_probe,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &imx_ssi_pcm_dai_ops,
-};
-
-static struct snd_soc_dai_driver imx_ac97_dai = {
-       .probe = imx_ssi_dai_probe,
-       .playback = {
-               .stream_name = "AC97 Playback",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .stream_name = "AC97 Capture",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &imx_ssi_pcm_dai_ops,
-};
-
-static const struct snd_soc_component_driver imx_component = {
-       .name           = DRV_NAME,
-};
-
-static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
-{
-       void __iomem *base = imx_ssi->base;
-
-       writel(0x0, base + SSI_SCR);
-       writel(0x0, base + SSI_STCR);
-       writel(0x0, base + SSI_SRCR);
-
-       writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
-
-       writel(SSI_SFCSR_RFWM0(8) |
-               SSI_SFCSR_TFWM0(8) |
-               SSI_SFCSR_RFWM1(8) |
-               SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
-
-       writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
-       writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
-
-       writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
-       writel(SSI_SOR_WAIT(3), base + SSI_SOR);
-
-       writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
-                       SSI_SCR_TE | SSI_SCR_RE,
-                       base + SSI_SCR);
-
-       writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
-       writel(0xff, base + SSI_SACCDIS);
-       writel(0x300, base + SSI_SACCEN);
-}
-
-static struct imx_ssi *ac97_ssi;
-
-static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-               unsigned short val)
-{
-       struct imx_ssi *imx_ssi = ac97_ssi;
-       void __iomem *base = imx_ssi->base;
-       unsigned int lreg;
-       unsigned int lval;
-
-       if (reg > 0x7f)
-               return;
-
-       pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
-       lreg = reg <<  12;
-       writel(lreg, base + SSI_SACADD);
-
-       lval = val << 4;
-       writel(lval , base + SSI_SACDAT);
-
-       writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
-       udelay(100);
-}
-
-static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
-               unsigned short reg)
-{
-       struct imx_ssi *imx_ssi = ac97_ssi;
-       void __iomem *base = imx_ssi->base;
-
-       unsigned short val = -1;
-       unsigned int lreg;
-
-       lreg = (reg & 0x7f) <<  12 ;
-       writel(lreg, base + SSI_SACADD);
-       writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
-
-       udelay(100);
-
-       val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
-
-       pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
-       return val;
-}
-
-static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
-{
-       struct imx_ssi *imx_ssi = ac97_ssi;
-
-       if (imx_ssi->ac97_reset)
-               imx_ssi->ac97_reset(ac97);
-       /* First read sometimes fails, do a dummy read */
-       imx_ssi_ac97_read(ac97, 0);
-}
-
-static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
-{
-       struct imx_ssi *imx_ssi = ac97_ssi;
-
-       if (imx_ssi->ac97_warm_reset)
-               imx_ssi->ac97_warm_reset(ac97);
-
-       /* First read sometimes fails, do a dummy read */
-       imx_ssi_ac97_read(ac97, 0);
-}
-
-static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
-       .read           = imx_ssi_ac97_read,
-       .write          = imx_ssi_ac97_write,
-       .reset          = imx_ssi_ac97_reset,
-       .warm_reset     = imx_ssi_ac97_warm_reset
-};
-
-static int imx_ssi_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct imx_ssi *ssi;
-       struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
-       int ret = 0;
-       struct snd_soc_dai_driver *dai;
-
-       ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
-       if (!ssi)
-               return -ENOMEM;
-       dev_set_drvdata(&pdev->dev, ssi);
-
-       if (pdata) {
-               ssi->ac97_reset = pdata->ac97_reset;
-               ssi->ac97_warm_reset = pdata->ac97_warm_reset;
-               ssi->flags = pdata->flags;
-       }
-
-       ssi->irq = platform_get_irq(pdev, 0);
-       if (ssi->irq < 0)
-               return ssi->irq;
-
-       ssi->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(ssi->clk)) {
-               ret = PTR_ERR(ssi->clk);
-               dev_err(&pdev->dev, "Cannot get the clock: %d\n",
-                       ret);
-               goto failed_clk;
-       }
-       ret = clk_prepare_enable(ssi->clk);
-       if (ret)
-               goto failed_clk;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ssi->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(ssi->base)) {
-               ret = PTR_ERR(ssi->base);
-               goto failed_register;
-       }
-
-       if (ssi->flags & IMX_SSI_USE_AC97) {
-               if (ac97_ssi) {
-                       dev_err(&pdev->dev, "AC'97 SSI already registered\n");
-                       ret = -EBUSY;
-                       goto failed_register;
-               }
-               ac97_ssi = ssi;
-               setup_channel_to_ac97(ssi);
-               dai = &imx_ac97_dai;
-       } else
-               dai = &imx_ssi_dai;
-
-       writel(0x0, ssi->base + SSI_SIER);
-
-       ssi->dma_params_rx.addr = res->start + SSI_SRX0;
-       ssi->dma_params_tx.addr = res->start + SSI_STX0;
-
-       ssi->dma_params_tx.maxburst = 6;
-       ssi->dma_params_rx.maxburst = 4;
-
-       ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
-       ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
-       if (res) {
-               imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
-                       IMX_DMATYPE_SSI);
-       }
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
-       if (res) {
-               imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
-                       IMX_DMATYPE_SSI);
-       }
-
-       platform_set_drvdata(pdev, ssi);
-
-       ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
-               goto failed_register;
-       }
-
-       ret = snd_soc_register_component(&pdev->dev, &imx_component,
-                                        dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "register DAI failed\n");
-               goto failed_register;
-       }
-
-       ssi->fiq_params.irq = ssi->irq;
-       ssi->fiq_params.base = ssi->base;
-       ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
-       ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
-
-       ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
-       ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
-
-       if (ssi->fiq_init && ssi->dma_init) {
-               ret = ssi->fiq_init;
-               goto failed_pcm;
-       }
-
-       return 0;
-
-failed_pcm:
-       snd_soc_unregister_component(&pdev->dev);
-failed_register:
-       clk_disable_unprepare(ssi->clk);
-failed_clk:
-       snd_soc_set_ac97_ops(NULL);
-
-       return ret;
-}
-
-static int imx_ssi_remove(struct platform_device *pdev)
-{
-       struct imx_ssi *ssi = platform_get_drvdata(pdev);
-
-       if (!ssi->fiq_init)
-               imx_pcm_fiq_exit(pdev);
-
-       snd_soc_unregister_component(&pdev->dev);
-
-       if (ssi->flags & IMX_SSI_USE_AC97)
-               ac97_ssi = NULL;
-
-       clk_disable_unprepare(ssi->clk);
-       snd_soc_set_ac97_ops(NULL);
-
-       return 0;
-}
-
-static struct platform_driver imx_ssi_driver = {
-       .probe = imx_ssi_probe,
-       .remove = imx_ssi_remove,
-
-       .driver = {
-               .name = "imx-ssi",
-       },
-};
-
-module_platform_driver(imx_ssi_driver);
-
-/* Module information */
-MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ssi");
diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
deleted file mode 100644 (file)
index 8d3b189..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// mx27vis-aic32x4.c
-//
-// Copyright 2011 Vista Silicon S.L.
-//
-// Author: Javier Martin <javier.martin@vista-silicon.com>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/asoc-mx27vis.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/tlv320aic32x4.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define MX27VIS_AMP_GAIN       0
-#define MX27VIS_AMP_MUTE       1
-
-static int mx27vis_amp_gain;
-static int mx27vis_amp_mute;
-static int mx27vis_amp_gain0_gpio;
-static int mx27vis_amp_gain1_gpio;
-static int mx27vis_amp_mutel_gpio;
-static int mx27vis_amp_muter_gpio;
-
-static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-                                    25000000, SND_SOC_CLOCK_OUT);
-       if (ret) {
-               pr_err("%s: failed setting codec sysclk\n", __func__);
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
-                               SND_SOC_CLOCK_IN);
-       if (ret) {
-               pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_ops mx27vis_aic32x4_snd_ops = {
-       .hw_params      = mx27vis_aic32x4_hw_params,
-};
-
-static int mx27vis_amp_set(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int value = ucontrol->value.integer.value[0];
-       unsigned int reg = mc->reg;
-       int max = mc->max;
-
-       if (value > max)
-               return -EINVAL;
-
-       switch (reg) {
-       case MX27VIS_AMP_GAIN:
-               gpio_set_value(mx27vis_amp_gain0_gpio, value & 1);
-               gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1);
-               mx27vis_amp_gain = value;
-               break;
-       case MX27VIS_AMP_MUTE:
-               gpio_set_value(mx27vis_amp_mutel_gpio, value & 1);
-               gpio_set_value(mx27vis_amp_muter_gpio, value >> 1);
-               mx27vis_amp_mute = value;
-               break;
-       }
-       return 0;
-}
-
-static int mx27vis_amp_get(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
-
-       switch (reg) {
-       case MX27VIS_AMP_GAIN:
-               ucontrol->value.integer.value[0] = mx27vis_amp_gain;
-               break;
-       case MX27VIS_AMP_MUTE:
-               ucontrol->value.integer.value[0] = mx27vis_amp_mute;
-               break;
-       }
-       return 0;
-}
-
-/* From 6dB to 24dB in steps of 6dB */
-static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0);
-
-static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = {
-       SOC_DAPM_PIN_SWITCH("External Mic"),
-       SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0,
-                      mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv),
-       SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0,
-                      mx27vis_amp_get, mx27vis_amp_set),
-};
-
-static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
-       SND_SOC_DAPM_MIC("External Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
-       {"Mic Bias", NULL, "External Mic"},
-       {"IN1_R", NULL, "Mic Bias"},
-       {"IN2_R", NULL, "Mic Bias"},
-       {"IN3_R", NULL, "Mic Bias"},
-       {"IN1_L", NULL, "Mic Bias"},
-       {"IN2_L", NULL, "Mic Bias"},
-       {"IN3_L", NULL, "Mic Bias"},
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
-       DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-       DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic32x4.0-0018",
-                                     "tlv320aic32x4-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
-       .name           = "tlv320aic32x4",
-       .stream_name    = "TLV320AIC32X4",
-       .dai_fmt        = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
-                         SND_SOC_DAIFMT_CBM_CFM,
-       .ops            = &mx27vis_aic32x4_snd_ops,
-       SND_SOC_DAILINK_REG(hifi),
-};
-
-static struct snd_soc_card mx27vis_aic32x4 = {
-       .name           = "visstrim_m10-audio",
-       .owner          = THIS_MODULE,
-       .dai_link       = &mx27vis_aic32x4_dai,
-       .num_links      = 1,
-       .controls       = mx27vis_aic32x4_controls,
-       .num_controls   = ARRAY_SIZE(mx27vis_aic32x4_controls),
-       .dapm_widgets   = aic32x4_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
-       .dapm_routes    = aic32x4_dapm_routes,
-       .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
-};
-
-static int mx27vis_aic32x4_probe(struct platform_device *pdev)
-{
-       struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data;
-       int ret;
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
-       mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio;
-       mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio;
-       mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio;
-       mx27vis_amp_muter_gpio = pdata->amp_muter_gpio;
-
-       mx27vis_aic32x4.dev = &pdev->dev;
-       ret = devm_snd_soc_register_card(&pdev->dev, &mx27vis_aic32x4);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
-
-       /* Connect SSI0 as clock slave to SSI1 external pins */
-       imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-                       IMX_AUDMUX_V1_PCR_SYN |
-                       IMX_AUDMUX_V1_PCR_TFSDIR |
-                       IMX_AUDMUX_V1_PCR_TCLKDIR |
-                       IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
-                       IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
-       );
-       imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
-                       IMX_AUDMUX_V1_PCR_SYN |
-                       IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
-       );
-
-       return ret;
-}
-
-static struct platform_driver mx27vis_aic32x4_audio_driver = {
-       .driver = {
-               .name = "mx27vis",
-       },
-       .probe = mx27vis_aic32x4_probe,
-};
-
-module_platform_driver(mx27vis_aic32x4_audio_driver);
-
-MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
-MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mx27vis");
diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
deleted file mode 100644 (file)
index e561f7f..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// phycore-ac97.c  --  SoC audio for imx_phycore in AC97 mode
-//
-// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-
-#include "imx-audmux.h"
-
-static struct snd_soc_card imx_phycore;
-
-static const struct snd_soc_ops imx_phycore_hifi_ops = {
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
-       DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-       DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
-       {
-               .name           = "HiFi",
-               .stream_name    = "HiFi",
-               .ops            = &imx_phycore_hifi_ops,
-               SND_SOC_DAILINK_REG(hifi),
-       },
-};
-
-static struct snd_soc_card imx_phycore = {
-       .name           = "PhyCORE-ac97-audio",
-       .owner          = THIS_MODULE,
-       .dai_link       = imx_phycore_dai_ac97,
-       .num_links      = ARRAY_SIZE(imx_phycore_dai_ac97),
-};
-
-static struct platform_device *imx_phycore_snd_ac97_device;
-static struct platform_device *imx_phycore_snd_device;
-
-static int __init imx_phycore_init(void)
-{
-       int ret;
-
-       if (machine_is_pca100()) {
-               imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-                       IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
-                       IMX_AUDMUX_V1_PCR_TFCSEL(3) |
-                       IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
-                       IMX_AUDMUX_V1_PCR_RXDSEL(3));
-               imx_audmux_v1_configure_port(3,
-                       IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
-                       IMX_AUDMUX_V1_PCR_TFCSEL(0) |
-                       IMX_AUDMUX_V1_PCR_TFSDIR |
-                       IMX_AUDMUX_V1_PCR_RXDSEL(0));
-       } else if (machine_is_pcm043()) {
-               imx_audmux_v2_configure_port(3,
-                       IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
-                       IMX_AUDMUX_V2_PTCR_TFSEL(0) |
-                       IMX_AUDMUX_V2_PTCR_TFSDIR,
-                       IMX_AUDMUX_V2_PDCR_RXDSEL(0));
-               imx_audmux_v2_configure_port(0,
-                       IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
-                       IMX_AUDMUX_V2_PTCR_TCSEL(3) |
-                       IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
-                       IMX_AUDMUX_V2_PDCR_RXDSEL(3));
-       } else {
-               /* return happy. We might run on a totally different machine */
-               return 0;
-       }
-
-       imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1);
-       if (!imx_phycore_snd_ac97_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(imx_phycore_snd_ac97_device, &imx_phycore);
-       ret = platform_device_add(imx_phycore_snd_ac97_device);
-       if (ret)
-               goto fail1;
-
-       imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
-       if (!imx_phycore_snd_device) {
-               ret = -ENOMEM;
-               goto fail2;
-       }
-       ret = platform_device_add(imx_phycore_snd_device);
-
-       if (ret) {
-               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-               goto fail3;
-       }
-
-       return 0;
-
-fail3:
-       platform_device_put(imx_phycore_snd_device);
-fail2:
-       platform_device_del(imx_phycore_snd_ac97_device);
-fail1:
-       platform_device_put(imx_phycore_snd_ac97_device);
-       return ret;
-}
-
-static void __exit imx_phycore_exit(void)
-{
-       platform_device_unregister(imx_phycore_snd_device);
-       platform_device_unregister(imx_phycore_snd_ac97_device);
-}
-
-late_initcall(imx_phycore_init);
-module_exit(imx_phycore_exit);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
deleted file mode 100644 (file)
index 99611a0..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-//  wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS
-//
-//  Copyright (c) 2010 Wolfson Microelectronics plc
-//  Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
-//
-//  Based on an earlier driver for the same hardware by Liam Girdwood.
-
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "imx-ssi.h"
-#include "../codecs/wm8350.h"
-#include "imx-audmux.h"
-
-/* There is a silicon mic on the board optionally connected via a solder pad
- * SP1.  Define this to enable it.
- */
-#undef USE_SIMIC
-
-struct _wm8350_audio {
-       unsigned int channels;
-       snd_pcm_format_t format;
-       unsigned int rate;
-       unsigned int sysclk;
-       unsigned int bclkdiv;
-       unsigned int clkdiv;
-       unsigned int lr_rate;
-};
-
-/* in order of power consumption per rate (lowest first) */
-static const struct _wm8350_audio wm8350_audio[] = {
-       /* 16bit mono modes */
-       {1, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000 >> 1,
-        WM8350_BCLK_DIV_48, WM8350_DACDIV_3, 16,},
-
-       /* 16 bit stereo modes */
-       {2, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000,
-        WM8350_BCLK_DIV_48, WM8350_DACDIV_6, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 16000, 12288000,
-        WM8350_BCLK_DIV_24, WM8350_DACDIV_3, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 32000, 12288000,
-        WM8350_BCLK_DIV_12, WM8350_DACDIV_1_5, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 48000, 12288000,
-        WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 96000, 24576000,
-        WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 11025, 11289600,
-        WM8350_BCLK_DIV_32, WM8350_DACDIV_4, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 22050, 11289600,
-        WM8350_BCLK_DIV_16, WM8350_DACDIV_2, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 44100, 11289600,
-        WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-       {2, SNDRV_PCM_FORMAT_S16_LE, 88200, 22579200,
-        WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-
-       /* 24bit stereo modes */
-       {2, SNDRV_PCM_FORMAT_S24_LE, 48000, 12288000,
-        WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-       {2, SNDRV_PCM_FORMAT_S24_LE, 96000, 24576000,
-        WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-       {2, SNDRV_PCM_FORMAT_S24_LE, 44100, 11289600,
-        WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-       {2, SNDRV_PCM_FORMAT_S24_LE, 88200, 22579200,
-        WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-};
-
-static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int i, found = 0;
-       snd_pcm_format_t format = params_format(params);
-       unsigned int rate = params_rate(params);
-       unsigned int channels = params_channels(params);
-
-       /* find the correct audio parameters */
-       for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) {
-               if (rate == wm8350_audio[i].rate &&
-                   format == wm8350_audio[i].format &&
-                   channels == wm8350_audio[i].channels) {
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found)
-               return -EINVAL;
-
-       /* codec FLL input is 14.75 MHz from MCLK */
-       snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk);
-
-       /* TODO: The SSI driver should figure this out for us */
-       switch (channels) {
-       case 2:
-               snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
-               break;
-       case 1:
-               snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* set MCLK as the codec system clock for DAC and ADC */
-       snd_soc_dai_set_sysclk(codec_dai, WM8350_MCLK_SEL_PLL_MCLK,
-                              wm8350_audio[i].sysclk, SND_SOC_CLOCK_IN);
-
-       /* set codec BCLK division for sample rate */
-       snd_soc_dai_set_clkdiv(codec_dai, WM8350_BCLK_CLKDIV,
-                              wm8350_audio[i].bclkdiv);
-
-       /* DAI is synchronous and clocked with DAC LRCLK & ADC LRC */
-       snd_soc_dai_set_clkdiv(codec_dai,
-                              WM8350_DACLR_CLKDIV, wm8350_audio[i].lr_rate);
-       snd_soc_dai_set_clkdiv(codec_dai,
-                              WM8350_ADCLR_CLKDIV, wm8350_audio[i].lr_rate);
-
-       /* now configure DAC and ADC clocks */
-       snd_soc_dai_set_clkdiv(codec_dai,
-                              WM8350_DAC_CLKDIV, wm8350_audio[i].clkdiv);
-
-       snd_soc_dai_set_clkdiv(codec_dai,
-                              WM8350_ADC_CLKDIV, wm8350_audio[i].clkdiv);
-
-       return 0;
-}
-
-static const struct snd_soc_ops wm1133_ev1_ops = {
-       .hw_params = wm1133_ev1_hw_params,
-};
-
-static const struct snd_soc_dapm_widget wm1133_ev1_widgets[] = {
-#ifdef USE_SIMIC
-       SND_SOC_DAPM_MIC("SiMIC", NULL),
-#endif
-       SND_SOC_DAPM_MIC("Mic1 Jack", NULL),
-       SND_SOC_DAPM_MIC("Mic2 Jack", NULL),
-       SND_SOC_DAPM_LINE("Line In Jack", NULL),
-       SND_SOC_DAPM_LINE("Line Out Jack", NULL),
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-};
-
-/* imx32ads soc_card audio map */
-static const struct snd_soc_dapm_route wm1133_ev1_map[] = {
-
-#ifdef USE_SIMIC
-       /* SiMIC --> IN1LN (with automatic bias) via SP1 */
-       { "IN1LN", NULL, "Mic Bias" },
-       { "Mic Bias", NULL, "SiMIC" },
-#endif
-
-       /* Mic 1 Jack --> IN1LN and IN1LP (with automatic bias) */
-       { "IN1LN", NULL, "Mic Bias" },
-       { "IN1LP", NULL, "Mic1 Jack" },
-       { "Mic Bias", NULL, "Mic1 Jack" },
-
-       /* Mic 2 Jack --> IN1RN and IN1RP (with automatic bias) */
-       { "IN1RN", NULL, "Mic Bias" },
-       { "IN1RP", NULL, "Mic2 Jack" },
-       { "Mic Bias", NULL, "Mic2 Jack" },
-
-       /* Line in Jack --> AUX (L+R) */
-       { "IN3R", NULL, "Line In Jack" },
-       { "IN3L", NULL, "Line In Jack" },
-
-       /* Out1 --> Headphone Jack */
-       { "Headphone Jack", NULL, "OUT1R" },
-       { "Headphone Jack", NULL, "OUT1L" },
-
-       /* Out1 --> Line Out Jack */
-       { "Line Out Jack", NULL, "OUT2R" },
-       { "Line Out Jack", NULL, "OUT2L" },
-};
-
-static struct snd_soc_jack hp_jack;
-
-static struct snd_soc_jack_pin hp_jack_pins[] = {
-       { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE },
-};
-
-static struct snd_soc_jack mic_jack;
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
-       { .pin = "Mic1 Jack", .mask = SND_JACK_MICROPHONE },
-       { .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
-};
-
-static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
-       /* Headphone jack detection */
-       snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
-                             &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
-       wm8350_hp_jack_detect(component, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
-
-       /* Microphone jack detection */
-       snd_soc_card_jack_new(rtd->card, "Microphone",
-                             SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
-                             mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
-       wm8350_mic_jack_detect(component, &mic_jack, SND_JACK_MICROPHONE,
-                              SND_JACK_BTN_0);
-
-       snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
-
-       return 0;
-}
-
-
-SND_SOC_DAILINK_DEFS(ev1,
-       DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-       DAILINK_COMP_ARRAY(COMP_CODEC("wm8350-codec.0-0x1a", "wm8350-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link wm1133_ev1_dai = {
-       .name = "WM1133-EV1",
-       .stream_name = "Audio",
-       .init = wm1133_ev1_init,
-       .ops = &wm1133_ev1_ops,
-       .symmetric_rates = 1,
-       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       SND_SOC_DAILINK_REG(ev1),
-};
-
-static struct snd_soc_card wm1133_ev1 = {
-       .name = "WM1133-EV1",
-       .owner = THIS_MODULE,
-       .dai_link = &wm1133_ev1_dai,
-       .num_links = 1,
-
-       .dapm_widgets = wm1133_ev1_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets),
-       .dapm_routes = wm1133_ev1_map,
-       .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map),
-};
-
-static struct platform_device *wm1133_ev1_snd_device;
-
-static int __init wm1133_ev1_audio_init(void)
-{
-       int ret;
-       unsigned int ptcr, pdcr;
-
-       /* SSI0 mastered by port 5 */
-       ptcr = IMX_AUDMUX_V2_PTCR_SYN |
-               IMX_AUDMUX_V2_PTCR_TFSDIR |
-               IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
-               IMX_AUDMUX_V2_PTCR_TCLKDIR |
-               IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
-       pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
-       imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr);
-
-       ptcr = IMX_AUDMUX_V2_PTCR_SYN;
-       pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0);
-       imx_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr);
-
-       wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!wm1133_ev1_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
-       ret = platform_device_add(wm1133_ev1_snd_device);
-
-       if (ret)
-               platform_device_put(wm1133_ev1_snd_device);
-
-       return ret;
-}
-module_init(wm1133_ev1_audio_init);
-
-static void __exit wm1133_ev1_audio_exit(void)
-{
-       platform_device_unregister(wm1133_ev1_snd_device);
-}
-module_exit(wm1133_ev1_audio_exit);
-
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_DESCRIPTION("Audio for WM1133-EV1 on i.MX31ADS");
-MODULE_LICENSE("GPL");
index a90c3b2..4cafcf0 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SND_SIMPLE_CARD_UTILS
-       tristate
+       tristate
 
 config SND_SIMPLE_CARD
        tristate "ASoC Simple sound card support"
index 97b4f54..16a04a6 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
-#include <sound/simple_card_utils.h>
+#include <sound/graph_card.h>
 
 #define DPCM_SELECTABLE 1
 
@@ -111,6 +111,17 @@ static int graph_get_dai_id(struct device_node *ep)
        return id;
 }
 
+static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
+{
+       struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
+
+       if (dai && (dai->component->driver->pcm_construct ||
+                   dai->driver->pcm_new))
+               return true;
+
+       return false;
+}
+
 static int asoc_simple_parse_dai(struct device_node *ep,
                                 struct snd_soc_dai_link_component *dlc,
                                 int *is_single_link)
@@ -205,6 +216,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
                                  int dup_codec)
 {
        struct device *dev = simple_priv_to_dev(priv);
+       struct snd_soc_card *card = simple_priv_to_card(priv);
        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
        struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
        struct device_node *top = dev->of_node;
@@ -217,6 +229,14 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
        struct snd_soc_dai_link_component *codecs = dai_link->codecs;
        int ret;
 
+       /*
+        * Codec endpoint can be NULL for pluggable audio HW.
+        * Platform DT can populate the Codec endpoint depending on the
+        * plugged HW.
+        */
+       if (!li->cpu && !codec_ep)
+               return 0;
+
        /* Do it all CPU endpoint, and 1st Codec endpoint */
        if (!li->cpu && dup_codec)
                return 0;
@@ -253,11 +273,25 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
                        goto out_put_node;
 
                ret = asoc_simple_set_dailink_name(dev, dai_link,
-                                                  "fe.%s",
+                                                  "fe.%pOFP.%s",
+                                                  cpus->of_node,
                                                   cpus->dai_name);
                if (ret < 0)
                        goto out_put_node;
 
+               /*
+                * In BE<->BE connections it is not required to create
+                * PCM devices at CPU end of the dai link and thus 'no_pcm'
+                * flag needs to be set. It is useful when there are many
+                * BE components and some of these have to be connected to
+                * form a valid audio path.
+                *
+                * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where
+                * there are 'n' BE components in the path.
+                */
+               if (card->component_chaining && !soc_component_is_pcm(cpus))
+                       dai_link->no_pcm = 1;
+
                /* card->num_links includes Codec */
                asoc_simple_canonicalize_cpu(dai_link, is_single_links);
        } else {
@@ -287,7 +321,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
                        goto out_put_node;
 
                ret = asoc_simple_set_dailink_name(dev, dai_link,
-                                                  "be.%s",
+                                                  "be.%pOFP.%s",
+                                                  codecs->of_node,
                                                   codecs->dai_name);
                if (ret < 0)
                        goto out_put_node;
@@ -320,6 +355,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
        snd_soc_dai_link_set_capabilities(dai_link);
 
        dai_link->ops                   = &graph_ops;
+
+       /* Use custom snd_soc_ops callbacks if available */
+       if (priv->ops)
+               dai_link->ops = priv->ops;
+
        dai_link->init                  = asoc_simple_dai_init;
 
 out_put_node:
@@ -404,6 +444,28 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv,
        return 0;
 }
 
+static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv,
+                                     struct device_node *codec_port,
+                                     struct asoc_simple_data *adata)
+{
+       if (priv->force_dpcm)
+               return true;
+
+       if (!priv->dpcm_selectable)
+               return false;
+
+       /*
+        * It is DPCM
+        * if Codec port has many endpoints,
+        * or has convert-xxx property
+        */
+       if ((of_get_child_count(codec_port) > 1) ||
+           (adata->convert_rate || adata->convert_channels))
+               return true;
+
+       return false;
+}
+
 static int graph_for_each_link(struct asoc_simple_priv *priv,
                        struct link_info *li,
                        int (*func_noml)(struct asoc_simple_priv *priv,
@@ -424,7 +486,6 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
        struct device_node *codec_port;
        struct device_node *codec_port_old = NULL;
        struct asoc_simple_data adata;
-       uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
        int rc, ret;
 
        /* loop for all listed CPU port */
@@ -447,14 +508,8 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
                        graph_parse_convert(dev, codec_ep, &adata);
                        graph_parse_convert(dev, cpu_ep,   &adata);
 
-                       /*
-                        * It is DPCM
-                        * if Codec port has many endpoints,
-                        * or has convert-xxx property
-                        */
-                       if (dpcm_selectable &&
-                           ((of_get_child_count(codec_port) > 1) ||
-                            adata.convert_rate || adata.convert_channels))
+                       /* check if link requires DPCM parsing */
+                       if (parse_as_dpcm_link(priv, codec_port, &adata))
                                ret = func_dpcm(priv, cpu_ep, codec_ep, li,
                                                (codec_port_old == codec_port));
                        /* else normal sound */
@@ -474,12 +529,34 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
        return 0;
 }
 
-static int graph_parse_of(struct asoc_simple_priv *priv)
+static void graph_get_dais_count(struct asoc_simple_priv *priv,
+                                struct link_info *li);
+
+int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 {
        struct snd_soc_card *card = simple_priv_to_card(priv);
        struct link_info li;
        int ret;
 
+       card->owner = THIS_MODULE;
+       card->dev = dev;
+
+       memset(&li, 0, sizeof(li));
+       graph_get_dais_count(priv, &li);
+       if (!li.link || !li.dais)
+               return -EINVAL;
+
+       ret = asoc_simple_init_priv(priv, &li);
+       if (ret < 0)
+               return ret;
+
+       priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->pa_gpio)) {
+               ret = PTR_ERR(priv->pa_gpio);
+               dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
+               return ret;
+       }
+
        ret = asoc_simple_parse_widgets(card, NULL);
        if (ret < 0)
                return ret;
@@ -506,11 +583,32 @@ static int graph_parse_of(struct asoc_simple_priv *priv)
                                          graph_dai_link_of,
                                          graph_dai_link_of_dpcm);
                if (ret < 0)
-                       return ret;
+                       goto err;
        }
 
-       return asoc_simple_parse_card_name(card, NULL);
+       ret = asoc_simple_parse_card_name(card, NULL);
+       if (ret < 0)
+               goto err;
+
+       snd_soc_card_set_drvdata(card, priv);
+
+       asoc_simple_debug_info(priv);
+
+       ret = devm_snd_soc_register_card(dev, card);
+       if (ret < 0)
+               goto err;
+
+       return 0;
+
+err:
+       asoc_simple_clean_reference(card);
+
+       if (ret != -EPROBE_DEFER)
+               dev_err(dev, "parse error %d\n", ret);
+
+       return ret;
 }
+EXPORT_SYMBOL_GPL(graph_parse_of);
 
 static int graph_count_noml(struct asoc_simple_priv *priv,
                            struct device_node *cpu_ep,
@@ -538,7 +636,7 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
        li->link++; /* 1xCPU-dummy */
        li->dais++; /* 1xCPU */
 
-       if (!dup_codec) {
+       if (!dup_codec && codec_ep) {
                li->link++; /* 1xdummy-Codec */
                li->conf++; /* 1xdummy-Codec */
                li->dais++; /* 1xCodec */
@@ -607,7 +705,7 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv,
                li->link, li->dais, li->conf);
 }
 
-static int graph_card_probe(struct snd_soc_card *card)
+int graph_card_probe(struct snd_soc_card *card)
 {
        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
        int ret;
@@ -622,14 +720,13 @@ static int graph_card_probe(struct snd_soc_card *card)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(graph_card_probe);
 
 static int graph_probe(struct platform_device *pdev)
 {
        struct asoc_simple_priv *priv;
        struct device *dev = &pdev->dev;
        struct snd_soc_card *card;
-       struct link_info li;
-       int ret;
 
        /* Allocate the private data and the DAI link array */
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -637,48 +734,14 @@ static int graph_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        card = simple_priv_to_card(priv);
-       card->owner             = THIS_MODULE;
-       card->dev               = dev;
        card->dapm_widgets      = graph_dapm_widgets;
        card->num_dapm_widgets  = ARRAY_SIZE(graph_dapm_widgets);
        card->probe             = graph_card_probe;
 
-       memset(&li, 0, sizeof(li));
-       graph_get_dais_count(priv, &li);
-       if (!li.link || !li.dais)
-               return -EINVAL;
-
-       ret = asoc_simple_init_priv(priv, &li);
-       if (ret < 0)
-               return ret;
+       if (of_device_get_match_data(dev))
+               priv->dpcm_selectable = 1;
 
-       priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
-       if (IS_ERR(priv->pa_gpio)) {
-               ret = PTR_ERR(priv->pa_gpio);
-               dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
-               return ret;
-       }
-
-       ret = graph_parse_of(priv);
-       if (ret < 0) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "parse error %d\n", ret);
-               goto err;
-       }
-
-       snd_soc_card_set_drvdata(card, priv);
-
-       asoc_simple_debug_info(priv);
-
-       ret = devm_snd_soc_register_card(dev, card);
-       if (ret < 0)
-               goto err;
-
-       return 0;
-err:
-       asoc_simple_clean_reference(card);
-
-       return ret;
+       return graph_parse_of(priv, dev);
 }
 
 static int graph_remove(struct platform_device *pdev)
index a5b446d..0c6404f 100644 (file)
@@ -24,6 +24,8 @@ config SND_SOC_INTEL_CATPT
        depends on DMADEVICES && SND_DMA_SGBUF
        select DW_DMAC_CORE
        select SND_SOC_ACPI_INTEL_MATCH
+       select WANT_DEV_COREDUMP
+       select SND_INTEL_DSP_CONFIG
        help
          Enable support for Intel(R) Haswell and Broadwell platforms
          with I2S codec present. This is a recommended option.
@@ -55,6 +57,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
        depends on X86 && ACPI && PCI
        select SND_SST_ATOM_HIFI2_PLATFORM
        select SND_SOC_ACPI_INTEL_MATCH
+       select SND_INTEL_DSP_CONFIG
        select IOSF_MBI
        help
          If you have a Intel Baytrail or Cherrytrail platform with an I2S
@@ -198,7 +201,7 @@ endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
 
 config SND_SOC_INTEL_KEEMBAY
        tristate "Keembay Platforms"
-       depends on ARM64 || COMPILE_TEST
+       depends on ARCH_KEEMBAY || COMPILE_TEST
        depends on COMMON_CLK
        help
          If you have a Intel Keembay platform then enable this option
index 6b5a34a..335c327 100644 (file)
@@ -827,14 +827,14 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
 {
        int format;
 
-       format = (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+       format = (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
        dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
 
        switch (format) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               return SSP_MODE_MASTER;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               return SSP_MODE_SLAVE;
+       case SND_SOC_DAIFMT_CBC_CFC:
+               return SSP_MODE_PROVIDER;
+       case SND_SOC_DAIFMT_CBP_CFP:
+               return SSP_MODE_CONSUMER;
        default:
                dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
        }
@@ -905,7 +905,7 @@ static const struct sst_ssp_config sst_ssp_configs = {
        .ssp_id = SSP_CODEC,
        .bits_per_slot = 24,
        .slots = 4,
-       .ssp_mode = SSP_MODE_MASTER,
+       .ssp_mode = SSP_MODE_PROVIDER,
        .pcm_mode = SSP_PCM_MODE_NETWORK,
        .duplex = SSP_DUPLEX,
        .ssp_protocol = SSP_MODE_PCM,
index 620b48d..23bf375 100644 (file)
@@ -439,8 +439,8 @@ struct sst_cmd_tone_stop {
 } __packed;
 
 enum sst_ssp_mode {
-       SSP_MODE_MASTER = 0,
-       SSP_MODE_SLAVE = 1,
+       SSP_MODE_PROVIDER = 0,
+       SSP_MODE_CONSUMER = 1,
 };
 
 enum sst_ssp_pcm_mode {
index e905905..e21e11d 100644 (file)
@@ -186,7 +186,7 @@ int sst_driver_ops(struct intel_sst_drv *sst)
                        "SST Driver capabilities missing for dev_id: %x",
                        sst->dev_id);
                return -EINVAL;
-       };
+       }
 }
 
 void sst_process_pending_msg(struct work_struct *work)
index f943a08..2c1b8a2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/acpi.h>
 #include <asm/platform_sst_audio.h>
 #include <sound/core.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc.h>
 #include <sound/compress_driver.h>
 #include <acpi/acbuffer.h>
@@ -246,6 +247,13 @@ static int sst_acpi_probe(struct platform_device *pdev)
        id = acpi_match_device(dev->driver->acpi_match_table, dev);
        if (!id)
                return -ENODEV;
+
+       ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+       if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) {
+               dev_dbg(dev, "SST ACPI driver not selected, aborting probe\n");
+               return -ENODEV;
+       }
+
        dev_dbg(dev, "for %s\n", id->id);
 
        mach = (struct snd_soc_acpi_mach *)id->driver_data;
index c10c378..b58b9b6 100644 (file)
@@ -443,6 +443,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
                    (MFD_INTEL_LPSS || COMPILE_TEST)) ||\
                   (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST))
        select SND_SOC_MAX98373_I2C
+       select SND_SOC_RT1011
        select SND_SOC_RT1015
        select SND_SOC_RT5682_I2C
        select SND_SOC_DMIC
@@ -552,7 +553,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
        select SND_SOC_RT715_SDCA_SDW
        select SND_SOC_RT5682_SDW
        select SND_SOC_DMIC
-        help
+       help
          Add support for Intel SoundWire-based platforms connected to
          MAX98373, RT700, RT711, RT1308 and RT715
          If unsure select "N".
index a58e4d2..5f03e48 100644 (file)
@@ -18,7 +18,7 @@ snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o
 snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
 snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
 snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
-snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o
+snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o sof_realtek_common.o
 snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o
 snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
 snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
index aa420b2..c5122d3 100644 (file)
@@ -262,14 +262,12 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bdw-rt5650"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* ASoC machine driver for Broadwell DSP + RT5650 */
 static struct snd_soc_card bdw_rt5650_card = {
@@ -309,6 +307,15 @@ static int bdw_rt5650_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       /* set card and driver name */
+       if (snd_soc_acpi_sof_parent(&pdev->dev)) {
+               bdw_rt5650_card.name = SOF_CARD_NAME;
+               bdw_rt5650_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               bdw_rt5650_card.name = CARD_NAME;
+               bdw_rt5650_card.driver_name = DRIVER_NAME;
+       }
+
        snd_soc_card_set_drvdata(&bdw_rt5650_card, bdw_rt5650);
 
        return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5650_card);
index 7a3e773..021bc59 100644 (file)
@@ -387,14 +387,12 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bdw-rt5677"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* ASoC machine driver for Broadwell DSP + RT5677 */
 static struct snd_soc_card bdw_rt5677_card = {
@@ -437,6 +435,15 @@ static int bdw_rt5677_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       /* set card and driver name */
+       if (snd_soc_acpi_sof_parent(&pdev->dev)) {
+               bdw_rt5677_card.name = SOF_CARD_NAME;
+               bdw_rt5677_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               bdw_rt5677_card.name = CARD_NAME;
+               bdw_rt5677_card.driver_name = DRIVER_NAME;
+       }
+
        snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677);
 
        return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card);
@@ -446,6 +453,7 @@ static struct platform_driver bdw_rt5677_audio = {
        .probe = bdw_rt5677_probe,
        .driver = {
                .name = "bdw-rt5677",
+               .pm = &snd_soc_pm_ops
        },
 };
 
index 77c85f1..3c3aff9 100644 (file)
@@ -262,19 +262,15 @@ static int broadwell_resume(struct snd_soc_card *card){
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "broadwell-rt286"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* broadwell audio machine driver for WPT + RT286S */
 static struct snd_soc_card broadwell_rt286 = {
-       .name = CARD_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = broadwell_rt286_dais,
        .num_links = ARRAY_SIZE(broadwell_rt286_dais),
@@ -303,6 +299,15 @@ static int broadwell_audio_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       /* set card and driver name */
+       if (snd_soc_acpi_sof_parent(&pdev->dev)) {
+               broadwell_rt286.name = SOF_CARD_NAME;
+               broadwell_rt286.driver_name = SOF_DRIVER_NAME;
+       } else {
+               broadwell_rt286.name = CARD_NAME;
+               broadwell_rt286.driver_name = DRIVER_NAME;
+       }
+
        return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
 }
 
@@ -318,6 +323,7 @@ static struct platform_driver broadwell_audio = {
        .remove = broadwell_audio_remove,
        .driver = {
                .name = "broadwell-audio",
+               .pm = &snd_soc_pm_ops
        },
 };
 
index 0b50b36..2bfe3e4 100644 (file)
@@ -205,14 +205,12 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcht-cx2072x"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card byt_cht_cx2072x_card = {
@@ -236,6 +234,7 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
        struct snd_soc_acpi_mach *mach;
        struct acpi_device *adev;
        int dai_index = 0;
+       bool sof_parent;
        int i, ret;
 
        byt_cht_cx2072x_card.dev = &pdev->dev;
@@ -265,15 +264,27 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               byt_cht_cx2072x_card.name = SOF_CARD_NAME;
+               byt_cht_cx2072x_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               byt_cht_cx2072x_card.name = CARD_NAME;
+               byt_cht_cx2072x_card.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               pdev->dev.driver->pm = &snd_soc_pm_ops;
+
        return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card);
 }
 
 static struct platform_driver snd_byt_cht_cx2072x_driver = {
        .driver = {
                .name = "bytcht_cx2072x",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_byt_cht_cx2072x_probe,
 };
index e1e46b4..cfeba27 100644 (file)
@@ -205,14 +205,12 @@ static struct snd_soc_dai_link dailink[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcht-da7213"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card bytcht_da7213_card = {
@@ -237,6 +235,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
        struct snd_soc_acpi_mach *mach;
        const char *platform_name;
        struct acpi_device *adev;
+       bool sof_parent;
        int dai_index = 0;
        int ret_val = 0;
        int i;
@@ -269,6 +268,21 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
        if (ret_val)
                return ret_val;
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               bytcht_da7213_card.name = SOF_CARD_NAME;
+               bytcht_da7213_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               bytcht_da7213_card.name = CARD_NAME;
+               bytcht_da7213_card.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               pdev->dev.driver->pm = &snd_soc_pm_ops;
+
        ret_val = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret_val) {
                dev_err(&pdev->dev,
@@ -282,9 +296,6 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
 static struct platform_driver bytcht_da7213_driver = {
        .driver = {
                .name = "bytcht_da7213",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = bytcht_da7213_probe,
 };
index 7ed869b..892cf68 100644 (file)
@@ -406,18 +406,14 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcht-es8316"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 static struct snd_soc_card byt_cht_es8316_card = {
-       .name = CARD_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = byt_cht_es8316_dais,
        .num_links = ARRAY_SIZE(byt_cht_es8316_dais),
@@ -472,6 +468,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
        const char *platform_name;
        struct acpi_device *adev;
        struct device *codec_dev;
+       bool sof_parent;
        unsigned int cnt = 0;
        int dai_index = 0;
        int i;
@@ -590,6 +587,21 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
        byt_cht_es8316_card.long_name = long_name;
 #endif
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               byt_cht_es8316_card.name = SOF_CARD_NAME;
+               byt_cht_es8316_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               byt_cht_es8316_card.name = CARD_NAME;
+               byt_cht_es8316_card.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               dev->driver->pm = &snd_soc_pm_ops;
+
        /* register the soc card */
        snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
 
@@ -615,9 +627,6 @@ static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev)
 static struct platform_driver snd_byt_cht_es8316_mc_driver = {
        .driver = {
                .name = "bytcht_es8316",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_byt_cht_es8316_mc_probe,
        .remove = snd_byt_cht_es8316_mc_remove,
index f790514..5520d7c 100644 (file)
@@ -421,6 +421,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -1147,18 +1159,14 @@ static int byt_rt5640_resume(struct snd_soc_card *card)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcr-rt5640"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 static struct snd_soc_card byt_rt5640_card = {
-       .name = CARD_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = byt_rt5640_dais,
        .num_links = ARRAY_SIZE(byt_rt5640_dais),
@@ -1178,12 +1186,14 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" };
        const struct dmi_system_id *dmi_id;
        struct byt_rt5640_private *priv;
        struct snd_soc_acpi_mach *mach;
        const char *platform_name;
        struct acpi_device *adev;
+       bool sof_parent;
        int ret_val = 0;
        int dai_index = 0;
        int i;
@@ -1347,6 +1357,21 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
        if (ret_val)
                return ret_val;
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               byt_rt5640_card.name = SOF_CARD_NAME;
+               byt_rt5640_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               byt_rt5640_card.name = CARD_NAME;
+               byt_rt5640_card.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               dev->driver->pm = &snd_soc_pm_ops;
+
        ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
 
        if (ret_val) {
@@ -1361,9 +1386,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_byt_rt5640_mc_driver = {
        .driver = {
                .name = "bytcr_rt5640",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_byt_rt5640_mc_probe,
 };
index 688b5e0..f289ec8 100644 (file)
@@ -143,7 +143,7 @@ static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
 
        /* Configure the PLL before selecting it */
        if (!(byt_rt5651_quirk & BYT_RT5651_MCLK_EN)) {
-               clk_id = RT5651_PLL1_S_BCLK1,
+               clk_id = RT5651_PLL1_S_BCLK1;
                clk_freq = rate * bclk_ratio;
        } else {
                clk_id = RT5651_PLL1_S_MCLK;
@@ -827,14 +827,12 @@ static int byt_rt5651_resume(struct snd_soc_card *card)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcr-rt5651"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 static struct snd_soc_card byt_rt5651_card = {
        .name = CARD_NAME,
@@ -876,6 +874,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
        const char *platform_name;
        struct acpi_device *adev;
        struct device *codec_dev;
+       bool sof_parent;
        bool is_bytcr = false;
        int ret_val = 0;
        int dai_index = 0;
@@ -1093,6 +1092,21 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
        if (ret_val)
                return ret_val;
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               byt_rt5651_card.name = SOF_CARD_NAME;
+               byt_rt5651_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               byt_rt5651_card.name = CARD_NAME;
+               byt_rt5651_card.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               pdev->dev.driver->pm = &snd_soc_pm_ops;
+
        ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
 
        if (ret_val) {
@@ -1107,9 +1121,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_byt_rt5651_mc_driver = {
        .driver = {
                .name = "bytcr_rt5651",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_byt_rt5651_mc_probe,
 };
index 835e9bd..1318823 100644 (file)
@@ -382,19 +382,15 @@ static struct snd_soc_dai_link cht_dailink[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "chtmax98090"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_cht = {
-       .name = CARD_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = cht_dailink,
        .num_links = ARRAY_SIZE(cht_dailink),
@@ -540,6 +536,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        const char *mclk_name;
        struct snd_soc_acpi_mach *mach;
        const char *platform_name;
+       bool sof_parent;
 
        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
        if (!drv)
@@ -602,6 +599,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
                }
        }
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               snd_soc_card_cht.name = SOF_CARD_NAME;
+               snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
+       } else {
+               snd_soc_card_cht.name = CARD_NAME;
+               snd_soc_card_cht.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               dev->driver->pm = &snd_soc_pm_ops;
+
        ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
        if (ret_val) {
                dev_err(&pdev->dev,
@@ -626,9 +638,6 @@ static int snd_cht_mc_remove(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
                .name = "cht-bsw-max98090",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_cht_mc_probe,
        .remove = snd_cht_mc_remove,
index 3e12bff..fd5e25c 100644 (file)
@@ -176,9 +176,6 @@ SND_SOC_DAILINK_DEF(media,
 SND_SOC_DAILINK_DEF(deepbuffer,
        DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
 
-SND_SOC_DAILINK_DEF(compress,
-       DAILINK_COMP_ARRAY(COMP_CPU("compress-cpu-dai")));
-
 SND_SOC_DAILINK_DEF(ssp2_port,
        DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
 SND_SOC_DAILINK_DEF(ssp2_codec,
@@ -209,16 +206,11 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .ops = &cht_aif1_ops,
                SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
        },
-       [MERR_DPCM_COMPR] = {
-               .name = "Compressed Port",
-               .stream_name = "Compress",
-               SND_SOC_DAILINK_REG(compress, dummy, platform),
-       },
        /* Back End DAI links */
        {
                /* SSP2 - Codec */
                .name = "SSP2-Codec",
-               .id = 1,
+               .id = 0,
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
                        | SND_SOC_DAIFMT_CBS_CFS,
@@ -231,19 +223,15 @@ static struct snd_soc_dai_link cht_dailink[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "chtnau8824"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_cht = {
-       .name = CARD_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = cht_dailink,
        .num_links = ARRAY_SIZE(cht_dailink),
@@ -260,6 +248,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        struct cht_mc_private *drv;
        struct snd_soc_acpi_mach *mach;
        const char *platform_name;
+       bool sof_parent;
        int ret_val;
 
        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -277,6 +266,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        if (ret_val)
                return ret_val;
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               snd_soc_card_cht.name = SOF_CARD_NAME;
+               snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
+       } else {
+               snd_soc_card_cht.name = CARD_NAME;
+               snd_soc_card_cht.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               pdev->dev.driver->pm = &snd_soc_pm_ops;
+
        /* register the soc card */
        ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
        if (ret_val) {
@@ -292,9 +296,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
                .name = "cht-bsw-nau8824",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_cht_mc_probe,
 };
index b53c024..6fea554 100644 (file)
@@ -479,21 +479,17 @@ static struct snd_soc_dai_link cht_dailink[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */
-#define CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */
+#define SOF_CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_RT5645_NAME "chtrt5645"
 #define CARD_RT5650_NAME "chtrt5650"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_chtrt5645 = {
-       .name = CARD_RT5645_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = cht_dailink,
        .num_links = ARRAY_SIZE(cht_dailink),
@@ -506,8 +502,6 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = {
 };
 
 static struct snd_soc_card snd_soc_card_chtrt5650 = {
-       .name = CARD_RT5650_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = cht_dailink,
        .num_links = ARRAY_SIZE(cht_dailink),
@@ -541,6 +535,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        const char *platform_name;
        struct cht_mc_private *drv;
        struct acpi_device *adev;
+       bool sof_parent;
        bool found = false;
        bool is_bytcr = false;
        int dai_index = 0;
@@ -680,6 +675,26 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        }
 
        snd_soc_card_set_drvdata(card, drv);
+
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               snd_soc_card_chtrt5645.name = SOF_CARD_RT5645_NAME;
+               snd_soc_card_chtrt5645.driver_name = SOF_DRIVER_NAME;
+               snd_soc_card_chtrt5650.name = SOF_CARD_RT5650_NAME;
+               snd_soc_card_chtrt5650.driver_name = SOF_DRIVER_NAME;
+       } else {
+               snd_soc_card_chtrt5645.name = CARD_RT5645_NAME;
+               snd_soc_card_chtrt5645.driver_name = DRIVER_NAME;
+               snd_soc_card_chtrt5650.name = CARD_RT5650_NAME;
+               snd_soc_card_chtrt5650.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               pdev->dev.driver->pm = &snd_soc_pm_ops;
+
        ret_val = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret_val) {
                dev_err(&pdev->dev,
@@ -693,9 +708,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
                .name = "cht-bsw-rt5645",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_cht_mc_probe,
 };
index 8442be9..10c88ef 100644 (file)
@@ -382,19 +382,15 @@ static int cht_resume_post(struct snd_soc_card *card)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "cht-bsw-rt5672"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_cht = {
-       .name = CARD_NAME,
-       .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = cht_dailink,
        .num_links = ARRAY_SIZE(cht_dailink),
@@ -417,6 +413,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
        const char *platform_name;
        struct acpi_device *adev;
+       bool sof_parent;
        int i;
 
        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -458,6 +455,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        }
        snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
 
+       sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+       /* set card and driver name */
+       if (sof_parent) {
+               snd_soc_card_cht.name = SOF_CARD_NAME;
+               snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
+       } else {
+               snd_soc_card_cht.name = CARD_NAME;
+               snd_soc_card_cht.driver_name = DRIVER_NAME;
+       }
+
+       /* set pm ops */
+       if (sof_parent)
+               pdev->dev.driver->pm = &snd_soc_pm_ops;
+
        /* register the soc card */
        ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
        if (ret_val) {
@@ -472,9 +484,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
                .name = "cht-bsw-rt5672",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-               .pm = &snd_soc_pm_ops,
-#endif
        },
        .probe = snd_cht_mc_probe,
 };
index b6e63ea..c2a9757 100644 (file)
@@ -49,11 +49,11 @@ static int max98373_hw_params(struct snd_pcm_substream *substream,
        for_each_rtd_codec_dais(rtd, j, codec_dai) {
                if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
                        /* DEV0 tdm slot configuration */
-                       snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 24);
+                       snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
                }
                if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
                        /* DEV1 tdm slot configuration */
-                       snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 24);
+                       snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
                }
        }
        return 0;
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
new file mode 100644 (file)
index 0000000..f3cf73c
--- /dev/null
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <uapi/sound/asound.h>
+#include "../../codecs/rt1011.h"
+#include "sof_realtek_common.h"
+
+/*
+ * Current only 2-amp configuration is supported for rt1011
+ */
+static const struct snd_soc_dapm_route rt1011_dapm_routes[] = {
+       /* speaker */
+       { "Left Spk", NULL, "Left SPO" },
+       { "Right Spk", NULL, "Right SPO" },
+};
+
+/*
+ * Make sure device's Unique ID follows this configuration:
+ *
+ * Two speakers:
+ *         0: left, 1: right
+ * Four speakers:
+ *         0: Woofer left, 1: Woofer right
+ *         2: Tweeter left, 3: Tweeter right
+ */
+static struct snd_soc_codec_conf rt1011_codec_confs[] = {
+       {
+               .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),
+               .name_prefix = "Left",
+       },
+       {
+               .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),
+               .name_prefix = "Right",
+       },
+};
+
+static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {
+       {
+               .name = RT1011_DEV0_NAME,
+               .dai_name = RT1011_CODEC_DAI,
+       },
+       {
+               .name = RT1011_DEV1_NAME,
+               .dai_name = RT1011_CODEC_DAI,
+       },
+};
+
+static const struct {
+       unsigned int tx;
+       unsigned int rx;
+} rt1011_tdm_mask[] = {
+       {.tx = 0x4, .rx = 0x1},
+       {.tx = 0x8, .rx = 0x2},
+};
+
+static int rt1011_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai;
+       int srate, i, ret = 0;
+
+       srate = params_rate(params);
+
+       for_each_rtd_codec_dais(rtd, i, codec_dai) {
+               /* 100 Fs to drive 24 bit data */
+               ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,
+                                         100 * srate, 256 * srate);
+               if (ret < 0) {
+                       dev_err(codec_dai->dev, "fail to set pll, ret %d\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,
+                                            256 * srate, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",
+                               ret);
+                       return ret;
+               }
+
+               if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {
+                       dev_err(codec_dai->dev, "invalid codec index %d\n",
+                               i);
+                       return -ENODEV;
+               }
+
+               ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,
+                                              rt1011_tdm_mask[i].rx, 4,
+                                              params_width(params));
+               if (ret < 0) {
+                       dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops rt1011_ops = {
+       .hw_params = rt1011_hw_params,
+};
+
+static int rt1011_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       int ret;
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_dapm_routes,
+                                     ARRAY_SIZE(rt1011_dapm_routes));
+       if (ret)
+               dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
+       return ret;
+}
+
+void sof_rt1011_dai_link(struct snd_soc_dai_link *link)
+{
+       link->codecs = rt1011_dai_link_components;
+       link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components);
+       link->init = rt1011_init;
+       link->ops = &rt1011_ops;
+}
+
+void sof_rt1011_codec_conf(struct snd_soc_card *card)
+{
+       card->codec_conf = rt1011_codec_confs;
+       card->num_configs = ARRAY_SIZE(rt1011_codec_confs);
+}
diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h
new file mode 100644 (file)
index 0000000..87cb381
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation.
+ */
+
+/*
+ * This file defines data structures used in Machine Driver for Intel
+ * platforms with Realtek Codecs.
+ */
+#ifndef __SOF_REALTEK_COMMON_H
+#define __SOF_REALTEK_COMMON_H
+
+#include <sound/soc.h>
+
+#define RT1011_CODEC_DAI       "rt1011-aif"
+#define RT1011_DEV0_NAME       "i2c-10EC1011:00"
+#define RT1011_DEV1_NAME       "i2c-10EC1011:01"
+#define RT1011_DEV2_NAME       "i2c-10EC1011:02"
+#define RT1011_DEV3_NAME       "i2c-10EC1011:03"
+
+void sof_rt1011_dai_link(struct snd_soc_dai_link *link);
+void sof_rt1011_codec_conf(struct snd_soc_card *card);
+
+#endif /* __SOF_REALTEK_COMMON_H */
index ddbb9fe..8b1ca2d 100644 (file)
@@ -24,6 +24,7 @@
 #include "../common/soc-intel-quirks.h"
 #include "hda_dsp_common.h"
 #include "sof_maxim_common.h"
+#include "sof_realtek_common.h"
 
 #define NAME_SIZE 32
 
 #define SOF_RT5682_NUM_HDMIDEV_MASK            (GENMASK(12, 10))
 #define SOF_RT5682_NUM_HDMIDEV(quirk)  \
        ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK)
-#define SOF_RT1015_SPEAKER_AMP_PRESENT         BIT(13)
-#define SOF_MAX98373_SPEAKER_AMP_PRESENT       BIT(14)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT      BIT(15)
+#define SOF_RT1011_SPEAKER_AMP_PRESENT         BIT(13)
+#define SOF_RT1015_SPEAKER_AMP_PRESENT         BIT(14)
+#define SOF_RT1015_SPEAKER_AMP_100FS           BIT(15)
+#define SOF_MAX98373_SPEAKER_AMP_PRESENT       BIT(16)
+#define SOF_MAX98360A_SPEAKER_AMP_PRESENT      BIT(17)
 
 /* Default: MCLK on, MCLK 19.2M, SSP0  */
 static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
@@ -99,6 +102,24 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
                                        SOF_RT5682_MCLK_24MHZ |
                                        SOF_RT5682_SSP_CODEC(1)),
        },
+       {
+               /*
+                * Dooly is hatch family but using rt1015 amp so it
+                * requires a quirk before "Google_Hatch".
+                */
+               .callback = sof_rt5682_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Dooly"),
+               },
+               .driver_data = (void *)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_MCLK_24MHZ |
+                                       SOF_RT5682_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT1015_SPEAKER_AMP_PRESENT |
+                                       SOF_RT1015_SPEAKER_AMP_100FS |
+                                       SOF_RT5682_SSP_AMP(1)),
+       },
        {
                .callback = sof_rt5682_quirk_cb,
                .matches = {
@@ -291,21 +312,26 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct snd_soc_dai *codec_dai;
-       int i, ret;
+       int i, fs, ret;
 
        if (!snd_soc_card_get_codec_dai(card, "rt1015-aif"))
                return 0;
 
+       if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS)
+               fs = 100;
+       else
+               fs = 64;
+
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
                /* Set tdm/i2s1 master bclk ratio */
-               ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
+               ret = snd_soc_dai_set_bclk_ratio(codec_dai, fs);
                if (ret < 0) {
                        dev_err(card->dev, "failed to set bclk ratio\n");
                        return ret;
                }
 
                ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
-                                         params_rate(params) * 64,
+                                         params_rate(params) * fs,
                                          params_rate(params) * 256);
                if (ret < 0) {
                        dev_err(card->dev, "failed to set pll\n");
@@ -319,6 +345,26 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream,
                        dev_err(card->dev, "failed to set sysclk\n");
                        return ret;
                }
+
+               if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS) {
+                       if (!strcmp(codec_dai->component->name, "i2c-10EC1015:00")) {
+                               ret = snd_soc_dai_set_tdm_slot(codec_dai,
+                                                              0x0, 0x1, 4, 24);
+                               if (ret < 0) {
+                                       dev_err(card->dev, "failed to set tdm slot\n");
+                                       return ret;
+                               }
+                       }
+
+                       if (!strcmp(codec_dai->component->name, "i2c-10EC1015:01")) {
+                               ret = snd_soc_dai_set_tdm_slot(codec_dai,
+                                                              0x0, 0x2, 4, 24);
+                               if (ret < 0) {
+                                       dev_err(card->dev, "failed to set tdm slot\n");
+                                       return ret;
+                               }
+                       }
+               }
        }
 
        return 0;
@@ -690,11 +736,16 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                        links[id].num_codecs = ARRAY_SIZE(max_98373_components);
                        links[id].init = max98373_spk_codec_init;
                        links[id].ops = &max_98373_ops;
+                       /* feedback stream */
+                       links[id].dpcm_capture = 1;
                } else if (sof_rt5682_quirk &
                                SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
                        links[id].codecs = max98360a_component;
                        links[id].num_codecs = ARRAY_SIZE(max98360a_component);
                        links[id].init = speaker_codec_init;
+               } else if (sof_rt5682_quirk &
+                               SOF_RT1011_SPEAKER_AMP_PRESENT) {
+                       sof_rt1011_dai_link(&links[id]);
                } else {
                        links[id].codecs = max98357a_component;
                        links[id].num_codecs = ARRAY_SIZE(max98357a_component);
@@ -805,6 +856,8 @@ static int sof_audio_probe(struct platform_device *pdev)
 
        if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
                sof_max98373_codec_conf(&sof_audio_card_rt5682);
+       else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT)
+               sof_rt1011_codec_conf(&sof_audio_card_rt5682);
 
        dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
                                              dmic_be_num, hdmi_num);
@@ -875,6 +928,25 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_MAX98360A_SPEAKER_AMP_PRESENT |
                                        SOF_RT5682_SSP_AMP(1)),
        },
+       {
+               .name = "cml_rt1015_rt5682",
+               .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_MCLK_24MHZ |
+                                       SOF_RT5682_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT1015_SPEAKER_AMP_PRESENT |
+                                       SOF_RT1015_SPEAKER_AMP_100FS |
+                                       SOF_RT5682_SSP_AMP(1)),
+       },
+       {
+               .name = "tgl_rt1011_rt5682",
+               .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT1011_SPEAKER_AMP_PRESENT |
+                                       SOF_RT5682_SSP_AMP(1) |
+                                       SOF_RT5682_NUM_HDMIDEV(4)),
+       },
        { }
 };
 
@@ -892,9 +964,12 @@ module_platform_driver(sof_audio)
 MODULE_DESCRIPTION("SOF Audio Machine driver");
 MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>");
 MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:sof_rt5682");
 MODULE_ALIAS("platform:tgl_max98357a_rt5682");
 MODULE_ALIAS("platform:jsl_rt5682_rt1015");
 MODULE_ALIAS("platform:tgl_max98373_rt5682");
 MODULE_ALIAS("platform:jsl_rt5682_max98360a");
+MODULE_ALIAS("platform:cml_rt1015_rt5682");
+MODULE_ALIAS("platform:tgl_rt1011_rt5682");
index b29946e..ca96890 100644 (file)
@@ -48,6 +48,16 @@ static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
 }
 
 static const struct dmi_system_id sof_sdw_quirk_table[] = {
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
+               },
+               .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX |
+                                       SOF_SDW_FOUR_SPK),
+       },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
index 88dc3fb..0f53a0d 100644 (file)
@@ -80,9 +80,9 @@ struct catpt_spec {
        u32 host_ssp_offset[CATPT_SSP_COUNT];
        u32 dram_mask;
        u32 iram_mask;
+       u32 d3srampgd_bit;
+       u32 d3pgd_bit;
        void (*pll_shutdown)(struct catpt_dev *cdev, bool enable);
-       int (*power_up)(struct catpt_dev *cdev);
-       int (*power_down)(struct catpt_dev *cdev);
 };
 
 struct catpt_dev {
@@ -126,10 +126,8 @@ int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
 
 void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable);
 void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable);
-int lpt_dsp_power_up(struct catpt_dev *cdev);
-int lpt_dsp_power_down(struct catpt_dev *cdev);
-int wpt_dsp_power_up(struct catpt_dev *cdev);
-int wpt_dsp_power_down(struct catpt_dev *cdev);
+int catpt_dsp_power_up(struct catpt_dev *cdev);
+int catpt_dsp_power_down(struct catpt_dev *cdev);
 int catpt_dsp_stall(struct catpt_dev *cdev, bool stall);
 void catpt_dsp_update_srampge(struct catpt_dev *cdev, struct resource *sram,
                              unsigned long mask);
index a701799..85a34e3 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
@@ -69,7 +70,7 @@ release_dma_chan:
        dma_release_channel(chan);
        if (ret)
                return ret;
-       return cdev->spec->power_down(cdev);
+       return catpt_dsp_power_down(cdev);
 }
 
 static int __maybe_unused catpt_resume(struct device *dev)
@@ -77,7 +78,7 @@ static int __maybe_unused catpt_resume(struct device *dev)
        struct catpt_dev *cdev = dev_get_drvdata(dev);
        int ret, i;
 
-       ret = cdev->spec->power_up(cdev);
+       ret = catpt_dsp_power_up(cdev);
        if (ret)
                return ret;
 
@@ -162,7 +163,7 @@ static int catpt_probe_components(struct catpt_dev *cdev)
 {
        int ret;
 
-       ret = cdev->spec->power_up(cdev);
+       ret = catpt_dsp_power_up(cdev);
        if (ret)
                return ret;
 
@@ -204,7 +205,7 @@ err_reg_board:
 err_boot_fw:
        catpt_dmac_remove(cdev);
 err_dmac_probe:
-       cdev->spec->power_down(cdev);
+       catpt_dsp_power_down(cdev);
 
        return ret;
 }
@@ -239,9 +240,20 @@ static int catpt_acpi_probe(struct platform_device *pdev)
        const struct catpt_spec *spec;
        struct catpt_dev *cdev;
        struct device *dev = &pdev->dev;
+       const struct acpi_device_id *id;
        struct resource *res;
        int ret;
 
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!id)
+               return -ENODEV;
+
+       ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+       if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) {
+               dev_dbg(dev, "CATPT ACPI driver not selected, aborting probe\n");
+               return -ENODEV;
+       }
+
        spec = device_get_match_data(dev);
        if (!spec)
                return -ENODEV;
@@ -293,7 +305,7 @@ static int catpt_acpi_remove(struct platform_device *pdev)
 
        snd_soc_unregister_component(cdev->dev);
        catpt_dmac_remove(cdev);
-       cdev->spec->power_down(cdev);
+       catpt_dsp_power_down(cdev);
 
        catpt_sram_free(&cdev->iram);
        catpt_sram_free(&cdev->dram);
@@ -311,9 +323,9 @@ static struct catpt_spec lpt_desc = {
        .host_ssp_offset = { 0x0E8000, 0x0E9000 },
        .dram_mask = LPT_VDRTCTL0_DSRAMPGE_MASK,
        .iram_mask = LPT_VDRTCTL0_ISRAMPGE_MASK,
+       .d3srampgd_bit = LPT_VDRTCTL0_D3SRAMPGD,
+       .d3pgd_bit = LPT_VDRTCTL0_D3PGD,
        .pll_shutdown = lpt_dsp_pll_shutdown,
-       .power_up = lpt_dsp_power_up,
-       .power_down = lpt_dsp_power_down,
 };
 
 static struct catpt_spec wpt_desc = {
@@ -326,9 +338,9 @@ static struct catpt_spec wpt_desc = {
        .host_ssp_offset = { 0x0FC000, 0x0FD000 },
        .dram_mask = WPT_VDRTCTL0_DSRAMPGE_MASK,
        .iram_mask = WPT_VDRTCTL0_ISRAMPGE_MASK,
+       .d3srampgd_bit = WPT_VDRTCTL0_D3SRAMPGD,
+       .d3pgd_bit = WPT_VDRTCTL0_D3PGD,
        .pll_shutdown = wpt_dsp_pll_shutdown,
-       .power_up = wpt_dsp_power_up,
-       .power_down = wpt_dsp_power_down,
 };
 
 static const struct acpi_device_id catpt_ids[] = {
index 9e807b9..9c5fd18 100644 (file)
@@ -344,53 +344,7 @@ static void catpt_dsp_set_regs_defaults(struct catpt_dev *cdev)
        }
 }
 
-int lpt_dsp_power_down(struct catpt_dev *cdev)
-{
-       catpt_dsp_reset(cdev, true);
-
-       /* set 24Mhz clock for both SSPs */
-       catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
-                          CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
-       catpt_dsp_select_lpclock(cdev, true, false);
-
-       /* DRAM power gating all */
-       catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask,
-                             cdev->spec->dram_mask);
-       catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
-                             cdev->spec->iram_mask);
-
-       catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot);
-       /* give hw time to drop off */
-       udelay(50);
-
-       return 0;
-}
-
-int lpt_dsp_power_up(struct catpt_dev *cdev)
-{
-       /* SRAM power gating none */
-       catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
-       catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
-
-       catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0);
-       /* give hw time to wake up */
-       udelay(100);
-
-       catpt_dsp_select_lpclock(cdev, false, false);
-       catpt_updatel_shim(cdev, CS1,
-                          CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
-                          CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
-       /* stagger DSP reset after clock selection */
-       udelay(50);
-
-       catpt_dsp_reset(cdev, false);
-       /* generate int deassert msg to fix inversed int logic */
-       catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB | CATPT_IMC_IPCCD, 0);
-
-       return 0;
-}
-
-int wpt_dsp_power_down(struct catpt_dev *cdev)
+int catpt_dsp_power_down(struct catpt_dev *cdev)
 {
        u32 mask, val;
 
@@ -420,8 +374,8 @@ int wpt_dsp_power_down(struct catpt_dev *cdev)
                              cdev->spec->dram_mask);
        catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
                              cdev->spec->iram_mask);
-       mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD;
-       catpt_updatel_pci(cdev, VDRTCTL0, mask, WPT_VDRTCTL0_D3PGD);
+       mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
+       catpt_updatel_pci(cdev, VDRTCTL0, mask, cdev->spec->d3pgd_bit);
 
        catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot);
        /* give hw time to drop off */
@@ -435,7 +389,7 @@ int wpt_dsp_power_down(struct catpt_dev *cdev)
        return 0;
 }
 
-int wpt_dsp_power_up(struct catpt_dev *cdev)
+int catpt_dsp_power_up(struct catpt_dev *cdev)
 {
        u32 mask, val;
 
@@ -450,7 +404,7 @@ int wpt_dsp_power_up(struct catpt_dev *cdev)
        catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0);
 
        /* SRAM power gating none */
-       mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD;
+       mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
        catpt_updatel_pci(cdev, VDRTCTL0, mask, mask);
        catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
        catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
index 8a5f20a..40c22e4 100644 (file)
@@ -304,7 +304,7 @@ static int catpt_load_block(struct catpt_dev *cdev,
        default:
                sram = &cdev->dram;
                break;
-       };
+       }
 
        dst_addr = sram->start + blk->ram_offset;
        if (alloc) {
index 408e64e..e5d54bb 100644 (file)
@@ -92,7 +92,7 @@ catpt_get_stream_template(struct snd_pcm_substream *substream)
                break;
        default:
                break;
-       };
+       }
 
        return catpt_topology[type];
 }
@@ -324,6 +324,54 @@ static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
        snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
+static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
+
+static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
+                                    struct catpt_stream_runtime *stream)
+{
+       struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+       struct snd_soc_component *component = dai->component;
+       struct snd_kcontrol *pos, *kctl = NULL;
+       const char *name;
+       int ret;
+       u32 id = stream->info.stream_hw_id;
+
+       /* only selected streams have individual controls */
+       switch (id) {
+       case CATPT_PIN_ID_OFFLOAD1:
+               name = "Media0 Playback Volume";
+               break;
+       case CATPT_PIN_ID_OFFLOAD2:
+               name = "Media1 Playback Volume";
+               break;
+       case CATPT_PIN_ID_CAPTURE1:
+               name = "Mic Capture Volume";
+               break;
+       case CATPT_PIN_ID_REFERENCE:
+               name = "Loopback Mute";
+               break;
+       default:
+               return 0;
+       };
+
+       list_for_each_entry(pos, &component->card->snd_card->controls, list) {
+               if (pos->private_data == component &&
+                   !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
+                       kctl = pos;
+                       break;
+               }
+       }
+       if (!kctl)
+               return -ENOENT;
+
+       if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
+               return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
+       ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
+       if (ret)
+               return CATPT_IPC_ERROR(ret);
+       return 0;
+}
+
 static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
                               struct snd_pcm_hw_params *params,
                               struct snd_soc_dai *dai)
@@ -370,6 +418,10 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return CATPT_IPC_ERROR(ret);
 
+       ret = catpt_dai_apply_usettings(dai, stream);
+       if (ret)
+               return ret;
+
        stream->allocated = true;
        return 0;
 }
@@ -391,54 +443,6 @@ static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
-
-static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
-                                    struct catpt_stream_runtime *stream)
-{
-       struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
-       struct snd_soc_component *component = dai->component;
-       struct snd_kcontrol *pos, *kctl = NULL;
-       const char *name;
-       int ret;
-       u32 id = stream->info.stream_hw_id;
-
-       /* only selected streams have individual controls */
-       switch (id) {
-       case CATPT_PIN_ID_OFFLOAD1:
-               name = "Media0 Playback Volume";
-               break;
-       case CATPT_PIN_ID_OFFLOAD2:
-               name = "Media1 Playback Volume";
-               break;
-       case CATPT_PIN_ID_CAPTURE1:
-               name = "Mic Capture Volume";
-               break;
-       case CATPT_PIN_ID_REFERENCE:
-               name = "Loopback Mute";
-               break;
-       default:
-               return 0;
-       };
-
-       list_for_each_entry(pos, &component->card->snd_card->controls, list) {
-               if (pos->private_data == component &&
-                   !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
-                       kctl = pos;
-                       break;
-               }
-       }
-       if (!kctl)
-               return -ENOENT;
-
-       if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
-               return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
-       ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
-       if (ret)
-               return CATPT_IPC_ERROR(ret);
-       return 0;
-}
-
 static int catpt_dai_prepare(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
@@ -458,10 +462,6 @@ static int catpt_dai_prepare(struct snd_pcm_substream *substream,
        if (ret)
                return CATPT_IPC_ERROR(ret);
 
-       ret = catpt_dai_apply_usettings(dai, stream);
-       if (ret)
-               return ret;
-
        stream->prepared = true;
        return 0;
 }
index 64468fe..12a205c 100644 (file)
@@ -8,7 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
        soc-acpi-intel-cnl-match.o soc-acpi-intel-cfl-match.o \
        soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \
        soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \
-       soc-acpi-intel-jsl-match.o \
+       soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \
        soc-acpi-intel-hda-match.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
new file mode 100644 (file)
index 0000000..06b233d
--- /dev/null
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-apci-intel-adl-match.c - tables and support for ADL ACPI enumeration.
+ *
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static const struct snd_soc_acpi_endpoint single_endpoint = {
+       .num = 0,
+       .aggregated = 0,
+       .group_position = 0,
+       .group_id = 0,
+};
+
+static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
+       {
+               .adr = 0x000020025D071100,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt711"
+       }
+};
+
+static const struct snd_soc_acpi_link_adr adl_rvp[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_0_adr),
+               .adr_d = rt711_0_adr,
+       },
+       {}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
+       {
+               .link_mask = 0x1, /* link0 required */
+               .links = adl_rvp,
+               .drv_name = "sof_sdw",
+               .sof_fw_filename = "sof-adl.ri",
+               .sof_tplg_filename = "sof-adl-rt711.tplg",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines);
index 26dde88..adddc91 100644 (file)
@@ -14,6 +14,11 @@ static struct snd_soc_acpi_codecs rt1011_spk_codecs = {
        .codecs = {"10EC1011"}
 };
 
+static struct snd_soc_acpi_codecs rt1015_spk_codecs = {
+       .num_codecs = 1,
+       .codecs = {"10EC1015"}
+};
+
 static struct snd_soc_acpi_codecs max98357a_spk_codecs = {
        .num_codecs = 1,
        .codecs = {"MX98357A"}
@@ -38,6 +43,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
                .sof_fw_filename = "sof-cml.ri",
                .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
        },
+       {
+               .id = "10EC5682",
+               .drv_name = "cml_rt1015_rt5682",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &rt1015_spk_codecs,
+               .sof_fw_filename = "sof-cml.ri",
+               .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
+       },
        {
                .id = "10EC5682",
                .drv_name = "sof_rt5682",
index 9f243e6..98196e9 100644 (file)
@@ -9,7 +9,7 @@
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 
-static struct snd_soc_acpi_codecs tgl_codecs = {
+static const struct snd_soc_acpi_codecs tgl_codecs = {
        .num_codecs = 1,
        .codecs = {"MX98357A"}
 };
@@ -305,11 +305,16 @@ static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca[] = {
        {}
 };
 
-static struct snd_soc_acpi_codecs tgl_max98373_amp = {
+static const struct snd_soc_acpi_codecs tgl_max98373_amp = {
        .num_codecs = 1,
        .codecs = {"MX98373"}
 };
 
+static const struct snd_soc_acpi_codecs tgl_rt1011_amp = {
+       .num_codecs = 1,
+       .codecs = {"10EC1011"}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
        {
                .id = "10EC1308",
@@ -335,6 +340,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
                .sof_fw_filename = "sof-tgl.ri",
                .sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg",
        },
+       {
+               .id = "10EC5682",
+               .drv_name = "tgl_rt1011_rt5682",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &tgl_rt1011_amp,
+               .sof_fw_filename = "sof-tgl.ri",
+               .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg",
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines);
index 291a686..1c3748f 100644 (file)
@@ -358,7 +358,7 @@ static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
 
        kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true);
 
-       if (kmb_i2s->master)
+       if (kmb_i2s->clock_provider)
                writel(1, kmb_i2s->i2s_base + CER);
        else
                writel(0, kmb_i2s->i2s_base + CER);
@@ -393,13 +393,13 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
        int ret;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               kmb_i2s->master = false;
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
+               kmb_i2s->clock_provider = false;
                ret = 0;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               writel(MASTER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
+       case SND_SOC_DAIFMT_CBC_CFC:
+               writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
 
                ret = clk_prepare_enable(kmb_i2s->clk_i2s);
                if (ret < 0)
@@ -410,7 +410,7 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
                if (ret)
                        return ret;
 
-               kmb_i2s->master = true;
+               kmb_i2s->clock_provider = true;
                break;
        default:
                return -EINVAL;
@@ -510,7 +510,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
                 * Platform is not capable of providing clocks for
                 * multi channel audio
                 */
-               if (kmb_i2s->master)
+               if (kmb_i2s->clock_provider)
                        return -EINVAL;
 
                write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
@@ -524,12 +524,12 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
                 * Platform is only capable of providing clocks need for
                 * 2 channel master mode
                 */
-               if (!(kmb_i2s->master))
+               if (!(kmb_i2s->clock_provider))
                        return -EINVAL;
 
                write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
                                (config->data_width << DATA_WIDTH_CONFIG_BIT) |
-                               MASTER_MODE | I2S_OPERATION;
+                               CLOCK_PROVIDER_MODE | I2S_OPERATION;
 
                writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
                break;
@@ -544,7 +544,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
 
        config->sample_rate = params_rate(hw_params);
 
-       if (kmb_i2s->master) {
+       if (kmb_i2s->clock_provider) {
                /* Only 2 ch supported in Master mode */
                u32 bitclk = config->sample_rate * config->data_width * 2;
 
index 9756b13..0c393e5 100644 (file)
@@ -58,7 +58,7 @@
 #define PSS_CPR_CLK_CLR                0x000
 #define PSS_CPR_AUX_RST_EN     0x070
 
-#define MASTER_MODE            BIT(13)
+#define CLOCK_PROVIDER_MODE    BIT(13)
 
 /* Interrupt Flag */
 #define TX_INT_FLAG            GENMASK(5, 4)
@@ -99,8 +99,8 @@
 
 #define DWC_I2S_PLAY   BIT(0)
 #define DWC_I2S_RECORD BIT(1)
-#define DW_I2S_SLAVE   BIT(2)
-#define DW_I2S_MASTER  BIT(3)
+#define DW_I2S_CONSUMER        BIT(2)
+#define DW_I2S_PROVIDER        BIT(3)
 
 #define I2S_RXDMA      0x01C0
 #define I2S_TXDMA      0x01C8
@@ -130,7 +130,7 @@ struct kmb_i2s_info {
        u32 ccr;
        u32 xfer_resolution;
        u32 fifo_th;
-       bool master;
+       bool clock_provider;
 
        struct i2s_clk_config_data config;
        int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
index 40bee10..ae466cd 100644 (file)
@@ -3742,12 +3742,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
        }
 
 component_load:
-
-       /*
-        * The complete tplg for SKL is loaded as index 0, we don't use
-        * any other index
-        */
-       ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0);
+       ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw);
        if (ret < 0) {
                dev_err(bus->dev, "tplg component load failed%d\n", ret);
                goto err;
@@ -3777,5 +3772,5 @@ void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
                list_del(&ppl->node);
 
        /* clean up topology */
-       snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+       snd_soc_tplg_component_remove(component);
 }
index c7bd201..0a68f4c 100644 (file)
@@ -26,9 +26,6 @@
 
 #include "jz4740-i2s.h"
 
-#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
-#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
-
 #define JZ_REG_AIC_CONF                0x00
 #define JZ_REG_AIC_CTRL                0x04
 #define JZ_REG_AIC_I2S_FMT     0x10
@@ -312,10 +309,14 @@ static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        switch (clk_id) {
        case JZ4740_I2S_CLKSRC_EXT:
                parent = clk_get(NULL, "ext");
+               if (IS_ERR(parent))
+                       return PTR_ERR(parent);
                clk_set_parent(i2s->clk_i2s, parent);
                break;
        case JZ4740_I2S_CLKSRC_PLL:
                parent = clk_get(NULL, "pll half");
+               if (IS_ERR(parent))
+                       return PTR_ERR(parent);
                clk_set_parent(i2s->clk_i2s, parent);
                ret = clk_set_rate(i2s->clk_i2s, freq);
                break;
@@ -377,13 +378,11 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
        /* Playback */
        dma_data = &i2s->playback_dma_data;
        dma_data->maxburst = 16;
-       dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT;
        dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 
        /* Capture */
        dma_data = &i2s->capture_dma_data;
        dma_data->maxburst = 16;
-       dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE;
        dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 }
 
index 8e44ae3..8132642 100644 (file)
@@ -134,7 +134,7 @@ static int a370db_probe(struct platform_device *pdev)
        return devm_snd_soc_register_card(card->dev, card);
 }
 
-static const struct of_device_id a370db_dt_ids[] = {
+static const struct of_device_id a370db_dt_ids[] __maybe_unused = {
        { .compatible = "marvell,a370db-audio" },
        { },
 };
index 76e055d..8d3dcfb 100644 (file)
@@ -158,3 +158,28 @@ config SND_SOC_MTK_BTCVSD
          BT encoded data to/from BT firmware.
          Select Y if you have such device.
          If unsure select "N".
+
+config SND_SOC_MT8192
+       tristate "ASoC support for Mediatek MT8192 chip"
+       depends on ARCH_MEDIATEK
+       select SND_SOC_MEDIATEK
+       help
+         This adds ASoC platform driver support for Mediatek MT8192 chip
+         that can be used with other codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
+config SND_SOC_MT8192_MT6359_RT1015_RT5682
+       tristate "ASoC Audio driver for MT8192 with MT6359 RT1015 RT5682 codec"
+       depends on I2C
+       depends on SND_SOC_MT8192
+       select SND_SOC_MT6359
+       select SND_SOC_RT1015
+       select SND_SOC_RT1015P
+       select SND_SOC_RT5682_I2C
+       select SND_SOC_DMIC
+       help
+         This adds ASoC driver for Mediatek MT8192 boards
+         with the MT6359 RT1015 RT5682 audio codec.
+         Select Y if you have such device.
+         If unsure select "N".
index 76032ca..f6cb6b8 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
 obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
+obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
index 882cdf8..3cb2adf 100644 (file)
@@ -542,8 +542,13 @@ int mtk_memif_set_format(struct mtk_base_afe *afe,
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
        case SNDRV_PCM_FORMAT_U32_LE:
-               hd_audio = 1;
-               hd_align = 1;
+               if (afe->memif_32bit_supported) {
+                       hd_audio = 2;
+                       hd_align = 0;
+               } else {
+                       hd_audio = 1;
+                       hd_align = 1;
+               }
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
        case SNDRV_PCM_FORMAT_U24_LE:
@@ -556,10 +561,10 @@ int mtk_memif_set_format(struct mtk_base_afe *afe,
        }
 
        mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
-                              1, hd_audio, memif->data->hd_shift);
+                              0x3, hd_audio, memif->data->hd_shift);
 
        mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
-                              1, hd_align, memif->data->hd_align_mshift);
+                              0x1, hd_align, memif->data->hd_align_mshift);
 
        return 0;
 }
index a8cf44d..a6f68c6 100644 (file)
@@ -91,6 +91,7 @@ struct mtk_base_afe {
        int memif_size;
        struct mtk_base_afe_irq *irqs;
        int irqs_size;
+       int memif_32bit_supported;
 
        struct list_head sub_dais;
        struct snd_soc_dai_driver *dai_drivers;
index 668fef3..a554c57 100644 (file)
@@ -808,7 +808,7 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt,
                spin_unlock_irqrestore(&bt->tx_lock, flags);
 
                if (!avail) {
-                       int ret = wait_for_bt_irq(bt, bt->rx);
+                       int ret = wait_for_bt_irq(bt, bt->tx);
 
                        if (ret)
                                return written_size;
index 48e81c5..cc4f8f4 100644 (file)
@@ -584,7 +584,6 @@ int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
                        __func__, aud_clks[div_clk_id],
                        rate, ret);
                goto ERR_SET_MCLK_RATE;
-               return ret;
        }
 
        return 0;
index 26e7d9a..078e58f 100644 (file)
@@ -811,6 +811,7 @@ static struct platform_driver mt8183_da7219_max98357_driver = {
 #ifdef CONFIG_OF
                .of_match_table = mt8183_da7219_max98357_dt_match,
 #endif
+               .pm = &snd_soc_pm_ops,
        },
        .probe = mt8183_da7219_max98357_dev_probe,
 };
index 327dfad..8c83408 100644 (file)
@@ -744,6 +744,7 @@ static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = {
 #ifdef CONFIG_OF
                .of_match_table = mt8183_mt6358_ts3a227_max98357_dt_match,
 #endif
+               .pm = &snd_soc_pm_ops,
        },
        .probe = mt8183_mt6358_ts3a227_max98357_dev_probe,
 };
diff --git a/sound/soc/mediatek/mt8192/Makefile b/sound/soc/mediatek/mt8192/Makefile
new file mode 100644 (file)
index 0000000..8b27d82
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt8192-afe-objs := \
+       mt8192-afe-pcm.o \
+       mt8192-afe-clk.o \
+       mt8192-afe-gpio.o \
+       mt8192-dai-adda.o \
+       mt8192-afe-control.o \
+       mt8192-dai-i2s.o \
+       mt8192-dai-pcm.o \
+       mt8192-dai-tdm.o
+
+obj-$(CONFIG_SND_SOC_MT8192) += snd-soc-mt8192-afe.o
+obj-$(CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682) += \
+       mt8192-mt6359-rt1015-rt5682.o
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-clk.c b/sound/soc/mediatek/mt8192/mt8192-afe-clk.c
new file mode 100644 (file)
index 0000000..bba5f30
--- /dev/null
@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8192-afe-clk.c  --  Mediatek 8192 afe clock ctrl
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+
+static const char *aud_clks[CLK_NUM] = {
+       [CLK_AFE] = "aud_afe_clk",
+       [CLK_TML] = "aud_tml_clk",
+       [CLK_APLL22M] = "aud_apll22m_clk",
+       [CLK_APLL24M] = "aud_apll24m_clk",
+       [CLK_APLL1_TUNER] = "aud_apll1_tuner_clk",
+       [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk",
+       [CLK_NLE] = "aud_nle",
+       [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk",
+       [CLK_INFRA_AUDIO_26M] = "aud_infra_26m_clk",
+       [CLK_MUX_AUDIO] = "top_mux_audio",
+       [CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int",
+       [CLK_TOP_MAINPLL_D4_D4] = "top_mainpll_d4_d4",
+       [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1",
+       [CLK_TOP_APLL1_CK] = "top_apll1_ck",
+       [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2",
+       [CLK_TOP_APLL2_CK] = "top_apll2_ck",
+       [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1",
+       [CLK_TOP_APLL1_D4] = "top_apll1_d4",
+       [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2",
+       [CLK_TOP_APLL2_D4] = "top_apll2_d4",
+       [CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h",
+       [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel",
+       [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel",
+       [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel",
+       [CLK_TOP_I2S3_M_SEL] = "top_i2s3_m_sel",
+       [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel",
+       [CLK_TOP_I2S5_M_SEL] = "top_i2s5_m_sel",
+       [CLK_TOP_I2S6_M_SEL] = "top_i2s6_m_sel",
+       [CLK_TOP_I2S7_M_SEL] = "top_i2s7_m_sel",
+       [CLK_TOP_I2S8_M_SEL] = "top_i2s8_m_sel",
+       [CLK_TOP_I2S9_M_SEL] = "top_i2s9_m_sel",
+       [CLK_TOP_APLL12_DIV0] = "top_apll12_div0",
+       [CLK_TOP_APLL12_DIV1] = "top_apll12_div1",
+       [CLK_TOP_APLL12_DIV2] = "top_apll12_div2",
+       [CLK_TOP_APLL12_DIV3] = "top_apll12_div3",
+       [CLK_TOP_APLL12_DIV4] = "top_apll12_div4",
+       [CLK_TOP_APLL12_DIVB] = "top_apll12_divb",
+       [CLK_TOP_APLL12_DIV5] = "top_apll12_div5",
+       [CLK_TOP_APLL12_DIV6] = "top_apll12_div6",
+       [CLK_TOP_APLL12_DIV7] = "top_apll12_div7",
+       [CLK_TOP_APLL12_DIV8] = "top_apll12_div8",
+       [CLK_TOP_APLL12_DIV9] = "top_apll12_div9",
+       [CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8192_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+                                   int clk_id)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS],
+                            afe_priv->clk[clk_id]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+                       aud_clks[clk_id], ret);
+       }
+
+       return ret;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       if (enable) {
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret);
+                       goto EXIT;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+                                    afe_priv->clk[CLK_TOP_APLL1_CK]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+                               aud_clks[CLK_TOP_APLL1_CK], ret);
+                       goto EXIT;
+               }
+
+               /* 180.6336 / 4 = 45.1584MHz */
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret);
+                       goto EXIT;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+                                    afe_priv->clk[CLK_TOP_APLL1_D4]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+                               aud_clks[CLK_TOP_APLL1_D4], ret);
+                       goto EXIT;
+               }
+       } else {
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+                               aud_clks[CLK_CLK26M], ret);
+                       goto EXIT;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+                               aud_clks[CLK_CLK26M], ret);
+                       goto EXIT;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+       }
+
+EXIT:
+       return ret;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       if (enable) {
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret);
+                       goto EXIT;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+                                    afe_priv->clk[CLK_TOP_APLL2_CK]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+                               aud_clks[CLK_TOP_APLL2_CK], ret);
+                       goto EXIT;
+               }
+
+               /* 196.608 / 4 = 49.152MHz */
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret);
+                       goto EXIT;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+                                    afe_priv->clk[CLK_TOP_APLL2_D4]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+                               aud_clks[CLK_TOP_APLL2_D4], ret);
+                       goto EXIT;
+               }
+       } else {
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+                               aud_clks[CLK_CLK26M], ret);
+                       goto EXIT;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+                               aud_clks[CLK_CLK26M], ret);
+                       goto EXIT;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+       }
+
+EXIT:
+       return ret;
+}
+
+int mt8192_afe_enable_clock(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret);
+               goto EXIT;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_INFRA_AUDIO_26M], ret);
+               goto EXIT;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIO], ret);
+               goto EXIT;
+       }
+       ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO],
+                            afe_priv->clk[CLK_CLK26M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIO],
+                       aud_clks[CLK_CLK26M], ret);
+               goto EXIT;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+               goto EXIT;
+       }
+
+       ret = mt8192_set_audio_int_bus_parent(afe, CLK_CLK26M);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+                       aud_clks[CLK_CLK26M], ret);
+               goto EXIT;
+       }
+
+       ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H],
+                            afe_priv->clk[CLK_TOP_APLL2_CK]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_TOP_MUX_AUDIO_H],
+                       aud_clks[CLK_TOP_APLL2_CK], ret);
+               goto EXIT;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_AFE], ret);
+               goto EXIT;
+       }
+
+EXIT:
+       return ret;
+}
+
+void mt8192_afe_disable_clock(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+       mt8192_set_audio_int_bus_parent(afe, CLK_CLK26M);
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+       clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+       clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+}
+
+int mt8192_apll1_enable(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       /* setting for APLL */
+       apll1_mux_setting(afe, true);
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL22M], ret);
+               goto EXIT;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL1_TUNER], ret);
+               goto EXIT;
+       }
+
+       regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+                          0x0000FFF7, 0x00000832);
+       regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_22M_ON_MASK_SFT,
+                          0x1 << AFE_22M_ON_SFT);
+
+EXIT:
+       return ret;
+}
+
+void mt8192_apll1_disable(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_22M_ON_MASK_SFT,
+                          0x0 << AFE_22M_ON_SFT);
+
+       regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0);
+
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+
+       apll1_mux_setting(afe, false);
+}
+
+int mt8192_apll2_enable(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       /* setting for APLL */
+       apll2_mux_setting(afe, true);
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL24M], ret);
+               goto EXIT;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL2_TUNER], ret);
+               goto EXIT;
+       }
+
+       regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+                          0x0000FFF7, 0x00000634);
+       regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_24M_ON_MASK_SFT,
+                          0x1 << AFE_24M_ON_SFT);
+
+EXIT:
+       return ret;
+}
+
+void mt8192_apll2_disable(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_24M_ON_MASK_SFT,
+                          0x0 << AFE_24M_ON_SFT);
+
+       regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0);
+
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+
+       apll2_mux_setting(afe, false);
+}
+
+int mt8192_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+       return (apll == MT8192_APLL1) ? 180633600 : 196608000;
+}
+
+int mt8192_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+       return ((rate % 8000) == 0) ? MT8192_APLL2 : MT8192_APLL1;
+}
+
+int mt8192_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+       if (strcmp(name, APLL1_W_NAME) == 0)
+               return MT8192_APLL1;
+       else
+               return MT8192_APLL2;
+}
+
+/* mck */
+struct mt8192_mck_div {
+       int m_sel_id;
+       int div_clk_id;
+       /* below will be deprecated */
+       int div_pdn_reg;
+       int div_pdn_mask_sft;
+       int div_reg;
+       int div_mask_sft;
+       int div_mask;
+       int div_sft;
+       int div_apll_sel_reg;
+       int div_apll_sel_mask_sft;
+       int div_apll_sel_sft;
+};
+
+static const struct mt8192_mck_div mck_div[MT8192_MCK_NUM] = {
+       [MT8192_I2S0_MCK] = {
+               .m_sel_id = CLK_TOP_I2S0_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV0,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV0_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_2,
+               .div_mask_sft = APLL12_CK_DIV0_MASK_SFT,
+               .div_mask = APLL12_CK_DIV0_MASK,
+               .div_sft = APLL12_CK_DIV0_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S0_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S0_MCK_SEL_SFT,
+       },
+       [MT8192_I2S1_MCK] = {
+               .m_sel_id = CLK_TOP_I2S1_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV1,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV1_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_2,
+               .div_mask_sft = APLL12_CK_DIV1_MASK_SFT,
+               .div_mask = APLL12_CK_DIV1_MASK,
+               .div_sft = APLL12_CK_DIV1_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S1_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S1_MCK_SEL_SFT,
+       },
+       [MT8192_I2S2_MCK] = {
+               .m_sel_id = CLK_TOP_I2S2_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV2,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV2_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_2,
+               .div_mask_sft = APLL12_CK_DIV2_MASK_SFT,
+               .div_mask = APLL12_CK_DIV2_MASK,
+               .div_sft = APLL12_CK_DIV2_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S2_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S2_MCK_SEL_SFT,
+       },
+       [MT8192_I2S3_MCK] = {
+               .m_sel_id = CLK_TOP_I2S3_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV3,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV3_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_2,
+               .div_mask_sft = APLL12_CK_DIV3_MASK_SFT,
+               .div_mask = APLL12_CK_DIV3_MASK,
+               .div_sft = APLL12_CK_DIV3_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S3_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S3_MCK_SEL_SFT,
+       },
+       [MT8192_I2S4_MCK] = {
+               .m_sel_id = CLK_TOP_I2S4_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV4,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV4_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_3,
+               .div_mask_sft = APLL12_CK_DIV4_MASK_SFT,
+               .div_mask = APLL12_CK_DIV4_MASK,
+               .div_sft = APLL12_CK_DIV4_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S4_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S4_MCK_SEL_SFT,
+       },
+       [MT8192_I2S4_BCK] = {
+               .m_sel_id = -1,
+               .div_clk_id = CLK_TOP_APLL12_DIVB,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIVB_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_2,
+               .div_mask_sft = APLL12_CK_DIVB_MASK_SFT,
+               .div_mask = APLL12_CK_DIVB_MASK,
+               .div_sft = APLL12_CK_DIVB_SFT,
+       },
+       [MT8192_I2S5_MCK] = {
+               .m_sel_id = CLK_TOP_I2S5_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV5,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV5_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_3,
+               .div_mask_sft = APLL12_CK_DIV5_MASK_SFT,
+               .div_mask = APLL12_CK_DIV5_MASK,
+               .div_sft = APLL12_CK_DIV5_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S5_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S5_MCK_SEL_SFT,
+       },
+       [MT8192_I2S6_MCK] = {
+               .m_sel_id = CLK_TOP_I2S6_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV6,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV6_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_3,
+               .div_mask_sft = APLL12_CK_DIV6_MASK_SFT,
+               .div_mask = APLL12_CK_DIV6_MASK,
+               .div_sft = APLL12_CK_DIV6_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S6_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S6_MCK_SEL_SFT,
+       },
+       [MT8192_I2S7_MCK] = {
+               .m_sel_id = CLK_TOP_I2S7_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV7,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV7_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_4,
+               .div_mask_sft = APLL12_CK_DIV7_MASK_SFT,
+               .div_mask = APLL12_CK_DIV7_MASK,
+               .div_sft = APLL12_CK_DIV7_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S7_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S7_MCK_SEL_SFT,
+       },
+       [MT8192_I2S8_MCK] = {
+               .m_sel_id = CLK_TOP_I2S8_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV8,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV8_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_4,
+               .div_mask_sft = APLL12_CK_DIV8_MASK_SFT,
+               .div_mask = APLL12_CK_DIV8_MASK,
+               .div_sft = APLL12_CK_DIV8_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S8_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S8_MCK_SEL_SFT,
+       },
+       [MT8192_I2S9_MCK] = {
+               .m_sel_id = CLK_TOP_I2S9_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV9,
+               .div_pdn_reg = CLK_AUDDIV_0,
+               .div_pdn_mask_sft = APLL12_DIV9_PDN_MASK_SFT,
+               .div_reg = CLK_AUDDIV_4,
+               .div_mask_sft = APLL12_CK_DIV9_MASK_SFT,
+               .div_mask = APLL12_CK_DIV9_MASK,
+               .div_sft = APLL12_CK_DIV9_SFT,
+               .div_apll_sel_reg = CLK_AUDDIV_0,
+               .div_apll_sel_mask_sft = APLL_I2S9_MCK_SEL_MASK_SFT,
+               .div_apll_sel_sft = APLL_I2S9_MCK_SEL_SFT,
+       },
+};
+
+int mt8192_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int apll = mt8192_get_apll_by_rate(afe, rate);
+       int apll_clk_id = apll == MT8192_APLL1 ?
+                         CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2;
+       int m_sel_id = mck_div[mck_id].m_sel_id;
+       int div_clk_id = mck_div[mck_id].div_clk_id;
+       int ret;
+
+       /* select apll */
+       if (m_sel_id >= 0) {
+               ret = clk_prepare_enable(afe_priv->clk[m_sel_id]);
+               if (ret) {
+                       dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[m_sel_id], ret);
+                       return ret;
+               }
+               ret = clk_set_parent(afe_priv->clk[m_sel_id],
+                                    afe_priv->clk[apll_clk_id]);
+               if (ret) {
+                       dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[m_sel_id],
+                               aud_clks[apll_clk_id], ret);
+                       return ret;
+               }
+       }
+
+       /* enable div, set rate */
+       ret = clk_prepare_enable(afe_priv->clk[div_clk_id]);
+       if (ret) {
+               dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[div_clk_id], ret);
+               return ret;
+       }
+       ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
+       if (ret) {
+               dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
+                       __func__, aud_clks[div_clk_id],
+                       rate, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void mt8192_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int m_sel_id = mck_div[mck_id].m_sel_id;
+       int div_clk_id = mck_div[mck_id].div_clk_id;
+
+       clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+       if (m_sel_id >= 0)
+               clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+}
+
+int mt8192_init_clock(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       struct device_node *of_node = afe->dev->of_node;
+       int i = 0;
+
+       afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+                                    GFP_KERNEL);
+       if (!afe_priv->clk)
+               return -ENOMEM;
+
+       for (i = 0; i < CLK_NUM; i++) {
+               afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+               if (IS_ERR(afe_priv->clk[i])) {
+                       dev_warn(afe->dev, "%s devm_clk_get %s fail, ret %ld\n",
+                                __func__,
+                                aud_clks[i], PTR_ERR(afe_priv->clk[i]));
+                       afe_priv->clk[i] = NULL;
+               }
+       }
+
+       afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node,
+                                                              "mediatek,apmixedsys");
+       if (IS_ERR(afe_priv->apmixedsys)) {
+               dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n",
+                       __func__, PTR_ERR(afe_priv->apmixedsys));
+               return PTR_ERR(afe_priv->apmixedsys);
+       }
+
+       afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node,
+                                                            "mediatek,topckgen");
+       if (IS_ERR(afe_priv->topckgen)) {
+               dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n",
+                       __func__, PTR_ERR(afe_priv->topckgen));
+               return PTR_ERR(afe_priv->topckgen);
+       }
+
+       afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node,
+                                                            "mediatek,infracfg");
+       if (IS_ERR(afe_priv->infracfg)) {
+               dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n",
+                       __func__, PTR_ERR(afe_priv->infracfg));
+               return PTR_ERR(afe_priv->infracfg);
+       }
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-clk.h b/sound/soc/mediatek/mt8192/mt8192-afe-clk.h
new file mode 100644 (file)
index 0000000..3adaf02
--- /dev/null
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-afe-clk.h  --  Mediatek 8192 afe clock ctrl definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_AFE_CLOCK_CTRL_H_
+#define _MT8192_AFE_CLOCK_CTRL_H_
+
+#define AP_PLL_CON3 0x0014
+#define APLL1_CON0 0x0318
+#define APLL1_CON1 0x031c
+#define APLL1_CON2 0x0320
+#define APLL1_CON4 0x0328
+#define APLL1_TUNER_CON0 0x0040
+
+#define APLL2_CON0 0x032c
+#define APLL2_CON1 0x0330
+#define APLL2_CON2 0x0334
+#define APLL2_CON4 0x033c
+#define APLL2_TUNER_CON0 0x0044
+
+#define CLK_CFG_7 0x0080
+#define CLK_CFG_8 0x0090
+#define CLK_CFG_11 0x00c0
+#define CLK_CFG_12 0x00d0
+#define CLK_CFG_13 0x00e0
+#define CLK_CFG_15 0x0100
+
+#define CLK_AUDDIV_0 0x0320
+#define CLK_AUDDIV_2 0x0328
+#define CLK_AUDDIV_3 0x0334
+#define CLK_AUDDIV_4 0x0338
+#define CKSYS_AUD_TOP_CFG 0x032c
+#define CKSYS_AUD_TOP_MON 0x0330
+
+#define PERI_BUS_DCM_CTRL 0x0074
+#define MODULE_SW_CG_1_STA 0x0094
+#define MODULE_SW_CG_2_STA 0x00ac
+
+/* CLK_AUDDIV_0 */
+#define APLL12_DIV0_PDN_SFT                0
+#define APLL12_DIV0_PDN_MASK               0x1
+#define APLL12_DIV0_PDN_MASK_SFT           (0x1 << 0)
+#define APLL12_DIV1_PDN_SFT                1
+#define APLL12_DIV1_PDN_MASK               0x1
+#define APLL12_DIV1_PDN_MASK_SFT           (0x1 << 1)
+#define APLL12_DIV2_PDN_SFT                2
+#define APLL12_DIV2_PDN_MASK               0x1
+#define APLL12_DIV2_PDN_MASK_SFT           (0x1 << 2)
+#define APLL12_DIV3_PDN_SFT                3
+#define APLL12_DIV3_PDN_MASK               0x1
+#define APLL12_DIV3_PDN_MASK_SFT           (0x1 << 3)
+#define APLL12_DIV4_PDN_SFT                4
+#define APLL12_DIV4_PDN_MASK               0x1
+#define APLL12_DIV4_PDN_MASK_SFT           (0x1 << 4)
+#define APLL12_DIVB_PDN_SFT                5
+#define APLL12_DIVB_PDN_MASK               0x1
+#define APLL12_DIVB_PDN_MASK_SFT           (0x1 << 5)
+#define APLL12_DIV5_PDN_SFT                6
+#define APLL12_DIV5_PDN_MASK               0x1
+#define APLL12_DIV5_PDN_MASK_SFT           (0x1 << 6)
+#define APLL12_DIV6_PDN_SFT                7
+#define APLL12_DIV6_PDN_MASK               0x1
+#define APLL12_DIV6_PDN_MASK_SFT           (0x1 << 7)
+#define APLL12_DIV7_PDN_SFT                8
+#define APLL12_DIV7_PDN_MASK               0x1
+#define APLL12_DIV7_PDN_MASK_SFT           (0x1 << 8)
+#define APLL12_DIV8_PDN_SFT                9
+#define APLL12_DIV8_PDN_MASK               0x1
+#define APLL12_DIV8_PDN_MASK_SFT           (0x1 << 9)
+#define APLL12_DIV9_PDN_SFT                10
+#define APLL12_DIV9_PDN_MASK               0x1
+#define APLL12_DIV9_PDN_MASK_SFT           (0x1 << 10)
+#define APLL_I2S0_MCK_SEL_SFT              16
+#define APLL_I2S0_MCK_SEL_MASK             0x1
+#define APLL_I2S0_MCK_SEL_MASK_SFT         (0x1 << 16)
+#define APLL_I2S1_MCK_SEL_SFT              17
+#define APLL_I2S1_MCK_SEL_MASK             0x1
+#define APLL_I2S1_MCK_SEL_MASK_SFT         (0x1 << 17)
+#define APLL_I2S2_MCK_SEL_SFT              18
+#define APLL_I2S2_MCK_SEL_MASK             0x1
+#define APLL_I2S2_MCK_SEL_MASK_SFT         (0x1 << 18)
+#define APLL_I2S3_MCK_SEL_SFT              19
+#define APLL_I2S3_MCK_SEL_MASK             0x1
+#define APLL_I2S3_MCK_SEL_MASK_SFT         (0x1 << 19)
+#define APLL_I2S4_MCK_SEL_SFT              20
+#define APLL_I2S4_MCK_SEL_MASK             0x1
+#define APLL_I2S4_MCK_SEL_MASK_SFT         (0x1 << 20)
+#define APLL_I2S5_MCK_SEL_SFT              21
+#define APLL_I2S5_MCK_SEL_MASK             0x1
+#define APLL_I2S5_MCK_SEL_MASK_SFT         (0x1 << 21)
+#define APLL_I2S6_MCK_SEL_SFT              22
+#define APLL_I2S6_MCK_SEL_MASK             0x1
+#define APLL_I2S6_MCK_SEL_MASK_SFT         (0x1 << 22)
+#define APLL_I2S7_MCK_SEL_SFT              23
+#define APLL_I2S7_MCK_SEL_MASK             0x1
+#define APLL_I2S7_MCK_SEL_MASK_SFT         (0x1 << 23)
+#define APLL_I2S8_MCK_SEL_SFT              24
+#define APLL_I2S8_MCK_SEL_MASK             0x1
+#define APLL_I2S8_MCK_SEL_MASK_SFT         (0x1 << 24)
+#define APLL_I2S9_MCK_SEL_SFT              25
+#define APLL_I2S9_MCK_SEL_MASK             0x1
+#define APLL_I2S9_MCK_SEL_MASK_SFT         (0x1 << 25)
+
+/* CLK_AUDDIV_2 */
+#define APLL12_CK_DIV0_SFT                 0
+#define APLL12_CK_DIV0_MASK                0xff
+#define APLL12_CK_DIV0_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIV1_SFT                 8
+#define APLL12_CK_DIV1_MASK                0xff
+#define APLL12_CK_DIV1_MASK_SFT            (0xff << 8)
+#define APLL12_CK_DIV2_SFT                 16
+#define APLL12_CK_DIV2_MASK                0xff
+#define APLL12_CK_DIV2_MASK_SFT            (0xff << 16)
+#define APLL12_CK_DIV3_SFT                 24
+#define APLL12_CK_DIV3_MASK                0xff
+#define APLL12_CK_DIV3_MASK_SFT            (0xff << 24)
+
+/* CLK_AUDDIV_3 */
+#define APLL12_CK_DIV4_SFT                 0
+#define APLL12_CK_DIV4_MASK                0xff
+#define APLL12_CK_DIV4_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIVB_SFT                 8
+#define APLL12_CK_DIVB_MASK                0xff
+#define APLL12_CK_DIVB_MASK_SFT            (0xff << 8)
+#define APLL12_CK_DIV5_SFT                 16
+#define APLL12_CK_DIV5_MASK                0xff
+#define APLL12_CK_DIV5_MASK_SFT            (0xff << 16)
+#define APLL12_CK_DIV6_SFT                 24
+#define APLL12_CK_DIV6_MASK                0xff
+#define APLL12_CK_DIV6_MASK_SFT            (0xff << 24)
+
+/* CLK_AUDDIV_4 */
+#define APLL12_CK_DIV7_SFT                 0
+#define APLL12_CK_DIV7_MASK                0xff
+#define APLL12_CK_DIV7_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIV8_SFT                 8
+#define APLL12_CK_DIV8_MASK                0xff
+#define APLL12_CK_DIV8_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIV9_SFT                 16
+#define APLL12_CK_DIV9_MASK                0xff
+#define APLL12_CK_DIV9_MASK_SFT            (0xff << 0)
+
+/* AUD_TOP_CFG */
+#define AUD_TOP_CFG_SFT                    0
+#define AUD_TOP_CFG_MASK                   0xffffffff
+#define AUD_TOP_CFG_MASK_SFT               (0xffffffff << 0)
+
+/* AUD_TOP_MON */
+#define AUD_TOP_MON_SFT                    0
+#define AUD_TOP_MON_MASK                   0xffffffff
+#define AUD_TOP_MON_MASK_SFT               (0xffffffff << 0)
+
+/* CLK_AUDDIV_3 */
+#define APLL12_CK_DIV5_MSB_SFT             0
+#define APLL12_CK_DIV5_MSB_MASK            0xf
+#define APLL12_CK_DIV5_MSB_MASK_SFT        (0xf << 0)
+#define RESERVED0_SFT                      4
+#define RESERVED0_MASK                     0xfffffff
+#define RESERVED0_MASK_SFT                 (0xfffffff << 4)
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+enum {
+       MT8192_APLL1 = 0,
+       MT8192_APLL2,
+};
+
+enum {
+       CLK_AFE = 0,
+       CLK_TML,
+       CLK_APLL22M,
+       CLK_APLL24M,
+       CLK_APLL1_TUNER,
+       CLK_APLL2_TUNER,
+       CLK_NLE,
+       CLK_INFRA_SYS_AUDIO,
+       CLK_INFRA_AUDIO_26M,
+       CLK_MUX_AUDIO,
+       CLK_MUX_AUDIOINTBUS,
+       CLK_TOP_MAINPLL_D4_D4,
+       /* apll related mux */
+       CLK_TOP_MUX_AUD_1,
+       CLK_TOP_APLL1_CK,
+       CLK_TOP_MUX_AUD_2,
+       CLK_TOP_APLL2_CK,
+       CLK_TOP_MUX_AUD_ENG1,
+       CLK_TOP_APLL1_D4,
+       CLK_TOP_MUX_AUD_ENG2,
+       CLK_TOP_APLL2_D4,
+       CLK_TOP_MUX_AUDIO_H,
+       CLK_TOP_I2S0_M_SEL,
+       CLK_TOP_I2S1_M_SEL,
+       CLK_TOP_I2S2_M_SEL,
+       CLK_TOP_I2S3_M_SEL,
+       CLK_TOP_I2S4_M_SEL,
+       CLK_TOP_I2S5_M_SEL,
+       CLK_TOP_I2S6_M_SEL,
+       CLK_TOP_I2S7_M_SEL,
+       CLK_TOP_I2S8_M_SEL,
+       CLK_TOP_I2S9_M_SEL,
+       CLK_TOP_APLL12_DIV0,
+       CLK_TOP_APLL12_DIV1,
+       CLK_TOP_APLL12_DIV2,
+       CLK_TOP_APLL12_DIV3,
+       CLK_TOP_APLL12_DIV4,
+       CLK_TOP_APLL12_DIVB,
+       CLK_TOP_APLL12_DIV5,
+       CLK_TOP_APLL12_DIV6,
+       CLK_TOP_APLL12_DIV7,
+       CLK_TOP_APLL12_DIV8,
+       CLK_TOP_APLL12_DIV9,
+       CLK_CLK26M,
+       CLK_NUM
+};
+
+struct mtk_base_afe;
+
+int mt8192_init_clock(struct mtk_base_afe *afe);
+int mt8192_afe_enable_clock(struct mtk_base_afe *afe);
+void mt8192_afe_disable_clock(struct mtk_base_afe *afe);
+
+int mt8192_apll1_enable(struct mtk_base_afe *afe);
+void mt8192_apll1_disable(struct mtk_base_afe *afe);
+
+int mt8192_apll2_enable(struct mtk_base_afe *afe);
+void mt8192_apll2_disable(struct mtk_base_afe *afe);
+
+int mt8192_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8192_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8192_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+
+/* these will be replaced by using CCF */
+int mt8192_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+void mt8192_mck_disable(struct mtk_base_afe *afe, int mck_id);
+
+int mt8192_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+                                   int clk_id);
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-common.h b/sound/soc/mediatek/mt8192/mt8192-afe-common.h
new file mode 100644 (file)
index 0000000..d55eff4
--- /dev/null
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-afe-common.h  --  Mediatek 8192 audio driver definitions
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT_8192_AFE_COMMON_H_
+#define _MT_8192_AFE_COMMON_H_
+
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "../common/mtk-base-afe.h"
+#include "mt8192-reg.h"
+
+enum {
+       MT8192_MEMIF_DL1,
+       MT8192_MEMIF_DL12,
+       MT8192_MEMIF_DL2,
+       MT8192_MEMIF_DL3,
+       MT8192_MEMIF_DL4,
+       MT8192_MEMIF_DL5,
+       MT8192_MEMIF_DL6,
+       MT8192_MEMIF_DL7,
+       MT8192_MEMIF_DL8,
+       MT8192_MEMIF_DL9,
+       MT8192_MEMIF_DAI,
+       MT8192_MEMIF_DAI2,
+       MT8192_MEMIF_MOD_DAI,
+       MT8192_MEMIF_VUL12,
+       MT8192_MEMIF_VUL2,
+       MT8192_MEMIF_VUL3,
+       MT8192_MEMIF_VUL4,
+       MT8192_MEMIF_VUL5,
+       MT8192_MEMIF_VUL6,
+       MT8192_MEMIF_AWB,
+       MT8192_MEMIF_AWB2,
+       MT8192_MEMIF_HDMI,
+       MT8192_MEMIF_NUM,
+       MT8192_DAI_ADDA = MT8192_MEMIF_NUM,
+       MT8192_DAI_ADDA_CH34,
+       MT8192_DAI_AP_DMIC,
+       MT8192_DAI_AP_DMIC_CH34,
+       MT8192_DAI_VOW,
+       MT8192_DAI_CONNSYS_I2S,
+       MT8192_DAI_I2S_0,
+       MT8192_DAI_I2S_1,
+       MT8192_DAI_I2S_2,
+       MT8192_DAI_I2S_3,
+       MT8192_DAI_I2S_5,
+       MT8192_DAI_I2S_6,
+       MT8192_DAI_I2S_7,
+       MT8192_DAI_I2S_8,
+       MT8192_DAI_I2S_9,
+       MT8192_DAI_HW_GAIN_1,
+       MT8192_DAI_HW_GAIN_2,
+       MT8192_DAI_SRC_1,
+       MT8192_DAI_SRC_2,
+       MT8192_DAI_PCM_1,
+       MT8192_DAI_PCM_2,
+       MT8192_DAI_TDM,
+       MT8192_DAI_NUM,
+};
+
+enum {
+       MT8192_IRQ_0,
+       MT8192_IRQ_1,
+       MT8192_IRQ_2,
+       MT8192_IRQ_3,
+       MT8192_IRQ_4,
+       MT8192_IRQ_5,
+       MT8192_IRQ_6,
+       MT8192_IRQ_7,
+       MT8192_IRQ_8,
+       MT8192_IRQ_9,
+       MT8192_IRQ_10,
+       MT8192_IRQ_11,
+       MT8192_IRQ_12,
+       MT8192_IRQ_13,
+       MT8192_IRQ_14,
+       MT8192_IRQ_15,
+       MT8192_IRQ_16,
+       MT8192_IRQ_17,
+       MT8192_IRQ_18,
+       MT8192_IRQ_19,
+       MT8192_IRQ_20,
+       MT8192_IRQ_21,
+       MT8192_IRQ_22,
+       MT8192_IRQ_23,
+       MT8192_IRQ_24,
+       MT8192_IRQ_25,
+       MT8192_IRQ_26,
+       MT8192_IRQ_31,  /* used only for TDM */
+       MT8192_IRQ_NUM,
+};
+
+enum {
+       MTKAIF_PROTOCOL_1 = 0,
+       MTKAIF_PROTOCOL_2,
+       MTKAIF_PROTOCOL_2_CLK_P2,
+};
+
+enum {
+       MTK_AFE_ADDA_DL_GAIN_MUTE = 0,
+       MTK_AFE_ADDA_DL_GAIN_NORMAL = 0xf74f,
+       /* SA suggest apply -0.3db to audio/speech path */
+};
+
+/* MCLK */
+enum {
+       MT8192_I2S0_MCK = 0,
+       MT8192_I2S1_MCK,
+       MT8192_I2S2_MCK,
+       MT8192_I2S3_MCK,
+       MT8192_I2S4_MCK,
+       MT8192_I2S4_BCK,
+       MT8192_I2S5_MCK,
+       MT8192_I2S6_MCK,
+       MT8192_I2S7_MCK,
+       MT8192_I2S8_MCK,
+       MT8192_I2S9_MCK,
+       MT8192_MCK_NUM,
+};
+
+struct clk;
+
+struct mt8192_afe_private {
+       struct clk **clk;
+       struct regmap *topckgen;
+       struct regmap *apmixedsys;
+       struct regmap *infracfg;
+       int stf_positive_gain_db;
+       int pm_runtime_bypass_reg_ctl;
+
+       /* dai */
+       bool dai_on[MT8192_DAI_NUM];
+       void *dai_priv[MT8192_DAI_NUM];
+
+       /* adda */
+       int mtkaif_protocol;
+       int mtkaif_chosen_phase[4];
+       int mtkaif_phase_cycle[4];
+       int mtkaif_calibration_num_phase;
+       int mtkaif_dmic;
+       int mtkaif_dmic_ch34;
+       int mtkaif_adda6_only;
+
+       /* mck */
+       int mck_rate[MT8192_MCK_NUM];
+};
+
+int mt8192_dai_adda_register(struct mtk_base_afe *afe);
+int mt8192_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8192_dai_hw_gain_register(struct mtk_base_afe *afe);
+int mt8192_dai_src_register(struct mtk_base_afe *afe);
+int mt8192_dai_pcm_register(struct mtk_base_afe *afe);
+int mt8192_dai_tdm_register(struct mtk_base_afe *afe);
+
+unsigned int mt8192_general_rate_transform(struct device *dev,
+                                          unsigned int rate);
+unsigned int mt8192_rate_transform(struct device *dev,
+                                  unsigned int rate, int aud_blk);
+
+int mt8192_dai_set_priv(struct mtk_base_afe *afe, int id,
+                       int priv_size, const void *priv_data);
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-control.c b/sound/soc/mediatek/mt8192/mt8192-afe-control.c
new file mode 100644 (file)
index 0000000..9163e05
--- /dev/null
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/pm_runtime.h>
+
+#include "mt8192-afe-common.h"
+
+enum {
+       MTK_AFE_RATE_8K = 0,
+       MTK_AFE_RATE_11K = 1,
+       MTK_AFE_RATE_12K = 2,
+       MTK_AFE_RATE_384K = 3,
+       MTK_AFE_RATE_16K = 4,
+       MTK_AFE_RATE_22K = 5,
+       MTK_AFE_RATE_24K = 6,
+       MTK_AFE_RATE_352K = 7,
+       MTK_AFE_RATE_32K = 8,
+       MTK_AFE_RATE_44K = 9,
+       MTK_AFE_RATE_48K = 10,
+       MTK_AFE_RATE_88K = 11,
+       MTK_AFE_RATE_96K = 12,
+       MTK_AFE_RATE_176K = 13,
+       MTK_AFE_RATE_192K = 14,
+       MTK_AFE_RATE_260K = 15,
+};
+
+enum {
+       MTK_AFE_DAI_MEMIF_RATE_8K = 0,
+       MTK_AFE_DAI_MEMIF_RATE_16K = 1,
+       MTK_AFE_DAI_MEMIF_RATE_32K = 2,
+       MTK_AFE_DAI_MEMIF_RATE_48K = 3,
+};
+
+enum {
+       MTK_AFE_PCM_RATE_8K = 0,
+       MTK_AFE_PCM_RATE_16K = 1,
+       MTK_AFE_PCM_RATE_32K = 2,
+       MTK_AFE_PCM_RATE_48K = 3,
+};
+
+unsigned int mt8192_general_rate_transform(struct device *dev,
+                                          unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_RATE_8K;
+       case 11025:
+               return MTK_AFE_RATE_11K;
+       case 12000:
+               return MTK_AFE_RATE_12K;
+       case 16000:
+               return MTK_AFE_RATE_16K;
+       case 22050:
+               return MTK_AFE_RATE_22K;
+       case 24000:
+               return MTK_AFE_RATE_24K;
+       case 32000:
+               return MTK_AFE_RATE_32K;
+       case 44100:
+               return MTK_AFE_RATE_44K;
+       case 48000:
+               return MTK_AFE_RATE_48K;
+       case 88200:
+               return MTK_AFE_RATE_88K;
+       case 96000:
+               return MTK_AFE_RATE_96K;
+       case 176400:
+               return MTK_AFE_RATE_176K;
+       case 192000:
+               return MTK_AFE_RATE_192K;
+       case 260000:
+               return MTK_AFE_RATE_260K;
+       case 352800:
+               return MTK_AFE_RATE_352K;
+       case 384000:
+               return MTK_AFE_RATE_384K;
+       default:
+               dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+                        __func__,
+                        rate, MTK_AFE_RATE_48K);
+               return MTK_AFE_RATE_48K;
+       }
+}
+
+static unsigned int dai_memif_rate_transform(struct device *dev,
+                                            unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_DAI_MEMIF_RATE_8K;
+       case 16000:
+               return MTK_AFE_DAI_MEMIF_RATE_16K;
+       case 32000:
+               return MTK_AFE_DAI_MEMIF_RATE_32K;
+       case 48000:
+               return MTK_AFE_DAI_MEMIF_RATE_48K;
+       default:
+               dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+                        __func__,
+                        rate, MTK_AFE_DAI_MEMIF_RATE_16K);
+               return MTK_AFE_DAI_MEMIF_RATE_16K;
+       }
+}
+
+static unsigned int pcm_rate_transform(struct device *dev,
+                                      unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_PCM_RATE_8K;
+       case 16000:
+               return MTK_AFE_PCM_RATE_16K;
+       case 32000:
+               return MTK_AFE_PCM_RATE_32K;
+       case 48000:
+               return MTK_AFE_PCM_RATE_48K;
+       default:
+               dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+                        __func__,
+                        rate, MTK_AFE_PCM_RATE_32K);
+               return MTK_AFE_PCM_RATE_32K;
+       }
+}
+
+unsigned int mt8192_rate_transform(struct device *dev,
+                                  unsigned int rate, int aud_blk)
+{
+       switch (aud_blk) {
+       case MT8192_MEMIF_DAI:
+       case MT8192_MEMIF_MOD_DAI:
+               return dai_memif_rate_transform(dev, rate);
+       case MT8192_DAI_PCM_1:
+       case MT8192_DAI_PCM_2:
+               return pcm_rate_transform(dev, rate);
+       default:
+               return mt8192_general_rate_transform(dev, rate);
+       }
+}
+
+int mt8192_dai_set_priv(struct mtk_base_afe *afe, int id,
+                       int priv_size, const void *priv_data)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       void *temp_data;
+
+       temp_data = devm_kzalloc(afe->dev,
+                                priv_size,
+                                GFP_KERNEL);
+       if (!temp_data)
+               return -ENOMEM;
+
+       if (priv_data)
+               memcpy(temp_data, priv_data, priv_size);
+
+       afe_priv->dai_priv[id] = temp_data;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c
new file mode 100644 (file)
index 0000000..165663a
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8192-afe-gpio.c  --  Mediatek 8192 afe gpio ctrl
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+
+static struct pinctrl *aud_pinctrl;
+
+enum mt8192_afe_gpio {
+       MT8192_AFE_GPIO_DAT_MISO_OFF,
+       MT8192_AFE_GPIO_DAT_MISO_ON,
+       MT8192_AFE_GPIO_DAT_MOSI_OFF,
+       MT8192_AFE_GPIO_DAT_MOSI_ON,
+       MT8192_AFE_GPIO_DAT_MISO_CH34_OFF,
+       MT8192_AFE_GPIO_DAT_MISO_CH34_ON,
+       MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF,
+       MT8192_AFE_GPIO_DAT_MOSI_CH34_ON,
+       MT8192_AFE_GPIO_I2S0_OFF,
+       MT8192_AFE_GPIO_I2S0_ON,
+       MT8192_AFE_GPIO_I2S1_OFF,
+       MT8192_AFE_GPIO_I2S1_ON,
+       MT8192_AFE_GPIO_I2S2_OFF,
+       MT8192_AFE_GPIO_I2S2_ON,
+       MT8192_AFE_GPIO_I2S3_OFF,
+       MT8192_AFE_GPIO_I2S3_ON,
+       MT8192_AFE_GPIO_I2S5_OFF,
+       MT8192_AFE_GPIO_I2S5_ON,
+       MT8192_AFE_GPIO_I2S6_OFF,
+       MT8192_AFE_GPIO_I2S6_ON,
+       MT8192_AFE_GPIO_I2S7_OFF,
+       MT8192_AFE_GPIO_I2S7_ON,
+       MT8192_AFE_GPIO_I2S8_OFF,
+       MT8192_AFE_GPIO_I2S8_ON,
+       MT8192_AFE_GPIO_I2S9_OFF,
+       MT8192_AFE_GPIO_I2S9_ON,
+       MT8192_AFE_GPIO_VOW_DAT_OFF,
+       MT8192_AFE_GPIO_VOW_DAT_ON,
+       MT8192_AFE_GPIO_VOW_CLK_OFF,
+       MT8192_AFE_GPIO_VOW_CLK_ON,
+       MT8192_AFE_GPIO_CLK_MOSI_OFF,
+       MT8192_AFE_GPIO_CLK_MOSI_ON,
+       MT8192_AFE_GPIO_TDM_OFF,
+       MT8192_AFE_GPIO_TDM_ON,
+       MT8192_AFE_GPIO_GPIO_NUM
+};
+
+struct audio_gpio_attr {
+       const char *name;
+       bool gpio_prepare;
+       struct pinctrl_state *gpioctrl;
+};
+
+static struct audio_gpio_attr aud_gpios[MT8192_AFE_GPIO_GPIO_NUM] = {
+       [MT8192_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL},
+       [MT8192_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL},
+       [MT8192_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL},
+       [MT8192_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S5_OFF] = {"aud_gpio_i2s5_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S5_ON] = {"aud_gpio_i2s5_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S6_OFF] = {"aud_gpio_i2s6_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S6_ON] = {"aud_gpio_i2s6_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S7_OFF] = {"aud_gpio_i2s7_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S7_ON] = {"aud_gpio_i2s7_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S8_OFF] = {"aud_gpio_i2s8_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S8_ON] = {"aud_gpio_i2s8_on", false, NULL},
+       [MT8192_AFE_GPIO_I2S9_OFF] = {"aud_gpio_i2s9_off", false, NULL},
+       [MT8192_AFE_GPIO_I2S9_ON] = {"aud_gpio_i2s9_on", false, NULL},
+       [MT8192_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL},
+       [MT8192_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL},
+       [MT8192_AFE_GPIO_VOW_DAT_OFF] = {"vow_dat_miso_off", false, NULL},
+       [MT8192_AFE_GPIO_VOW_DAT_ON] = {"vow_dat_miso_on", false, NULL},
+       [MT8192_AFE_GPIO_VOW_CLK_OFF] = {"vow_clk_miso_off", false, NULL},
+       [MT8192_AFE_GPIO_VOW_CLK_ON] = {"vow_clk_miso_on", false, NULL},
+       [MT8192_AFE_GPIO_DAT_MISO_CH34_OFF] = {"aud_dat_miso_ch34_off",
+                                              false, NULL},
+       [MT8192_AFE_GPIO_DAT_MISO_CH34_ON] = {"aud_dat_miso_ch34_on",
+                                             false, NULL},
+       [MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF] = {"aud_dat_mosi_ch34_off",
+                                              false, NULL},
+       [MT8192_AFE_GPIO_DAT_MOSI_CH34_ON] = {"aud_dat_mosi_ch34_on",
+                                             false, NULL},
+       [MT8192_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL},
+       [MT8192_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL},
+};
+
+static DEFINE_MUTEX(gpio_request_mutex);
+
+static int mt8192_afe_gpio_select(struct device *dev,
+                                 enum mt8192_afe_gpio type)
+{
+       int ret;
+
+       if (type < 0 || type >= MT8192_AFE_GPIO_GPIO_NUM) {
+               dev_err(dev, "%s(), error, invalid gpio type %d\n",
+                       __func__, type);
+               return -EINVAL;
+       }
+
+       if (!aud_gpios[type].gpio_prepare) {
+               dev_warn(dev, "%s(), error, gpio type %d not prepared\n",
+                        __func__, type);
+               return -EIO;
+       }
+
+       ret = pinctrl_select_state(aud_pinctrl,
+                                  aud_gpios[type].gpioctrl);
+       if (ret) {
+               dev_dbg(dev, "%s(), error, can not set gpio type %d\n",
+                       __func__, type);
+       }
+
+       return ret;
+}
+
+int mt8192_afe_gpio_init(struct device *dev)
+{
+       int i, ret;
+
+       aud_pinctrl = devm_pinctrl_get(dev);
+       if (IS_ERR(aud_pinctrl)) {
+               ret = PTR_ERR(aud_pinctrl);
+               dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
+               aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
+                                                            aud_gpios[i].name);
+               if (IS_ERR(aud_gpios[i].gpioctrl)) {
+                       ret = PTR_ERR(aud_gpios[i].gpioctrl);
+                       dev_dbg(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
+                               __func__, aud_gpios[i].name, ret);
+               } else {
+                       aud_gpios[i].gpio_prepare = true;
+               }
+       }
+
+       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_CLK_MOSI_ON);
+
+       /* gpio status init */
+       mt8192_afe_gpio_request(dev, false, MT8192_DAI_ADDA, 0);
+       mt8192_afe_gpio_request(dev, false, MT8192_DAI_ADDA, 1);
+
+       return 0;
+}
+EXPORT_SYMBOL(mt8192_afe_gpio_init);
+
+static int mt8192_afe_gpio_adda_dl(struct device *dev, bool enable)
+{
+       if (enable) {
+               return mt8192_afe_gpio_select(dev,
+                                             MT8192_AFE_GPIO_DAT_MOSI_ON);
+       } else {
+               return mt8192_afe_gpio_select(dev,
+                                             MT8192_AFE_GPIO_DAT_MOSI_OFF);
+       }
+}
+
+static int mt8192_afe_gpio_adda_ul(struct device *dev, bool enable)
+{
+       if (enable) {
+               return mt8192_afe_gpio_select(dev,
+                                             MT8192_AFE_GPIO_DAT_MISO_ON);
+       } else {
+               return mt8192_afe_gpio_select(dev,
+                                             MT8192_AFE_GPIO_DAT_MISO_OFF);
+       }
+}
+
+static int mt8192_afe_gpio_adda_ch34_dl(struct device *dev, bool enable)
+{
+       if (enable) {
+               return mt8192_afe_gpio_select(dev,
+                       MT8192_AFE_GPIO_DAT_MOSI_CH34_ON);
+       } else {
+               return mt8192_afe_gpio_select(dev,
+                       MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF);
+       }
+}
+
+static int mt8192_afe_gpio_adda_ch34_ul(struct device *dev, bool enable)
+{
+       if (enable) {
+               return mt8192_afe_gpio_select(dev,
+                       MT8192_AFE_GPIO_DAT_MISO_CH34_ON);
+       } else {
+               return mt8192_afe_gpio_select(dev,
+                       MT8192_AFE_GPIO_DAT_MISO_CH34_OFF);
+       }
+}
+
+int mt8192_afe_gpio_request(struct device *dev, bool enable,
+                           int dai, int uplink)
+{
+       mutex_lock(&gpio_request_mutex);
+       switch (dai) {
+       case MT8192_DAI_ADDA:
+               if (uplink)
+                       mt8192_afe_gpio_adda_ul(dev, enable);
+               else
+                       mt8192_afe_gpio_adda_dl(dev, enable);
+               break;
+       case MT8192_DAI_ADDA_CH34:
+               if (uplink)
+                       mt8192_afe_gpio_adda_ch34_ul(dev, enable);
+               else
+                       mt8192_afe_gpio_adda_ch34_dl(dev, enable);
+               break;
+       case MT8192_DAI_I2S_0:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S0_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S0_OFF);
+               break;
+       case MT8192_DAI_I2S_1:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S1_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S1_OFF);
+               break;
+       case MT8192_DAI_I2S_2:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S2_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S2_OFF);
+               break;
+       case MT8192_DAI_I2S_3:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S3_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S3_OFF);
+               break;
+       case MT8192_DAI_I2S_5:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S5_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S5_OFF);
+               break;
+       case MT8192_DAI_I2S_6:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S6_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S6_OFF);
+               break;
+       case MT8192_DAI_I2S_7:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S7_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S7_OFF);
+               break;
+       case MT8192_DAI_I2S_8:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S8_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S8_OFF);
+               break;
+       case MT8192_DAI_I2S_9:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S9_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S9_OFF);
+               break;
+       case MT8192_DAI_TDM:
+               if (enable)
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_TDM_ON);
+               else
+                       mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_TDM_OFF);
+               break;
+       case MT8192_DAI_VOW:
+               if (enable) {
+                       mt8192_afe_gpio_select(dev,
+                                              MT8192_AFE_GPIO_VOW_CLK_ON);
+                       mt8192_afe_gpio_select(dev,
+                                              MT8192_AFE_GPIO_VOW_DAT_ON);
+               } else {
+                       mt8192_afe_gpio_select(dev,
+                                              MT8192_AFE_GPIO_VOW_CLK_OFF);
+                       mt8192_afe_gpio_select(dev,
+                                              MT8192_AFE_GPIO_VOW_DAT_OFF);
+               }
+               break;
+       default:
+               mutex_unlock(&gpio_request_mutex);
+               dev_warn(dev, "%s(), invalid dai %d\n", __func__, dai);
+               return -EINVAL;
+       }
+       mutex_unlock(&gpio_request_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(mt8192_afe_gpio_request);
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h
new file mode 100644 (file)
index 0000000..5d29469
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-afe-gpio.h  --  Mediatek 8192 afe gpio ctrl definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_AFE_GPIO_H_
+#define _MT8192_AFE_GPIO_H_
+
+struct device;
+
+int mt8192_afe_gpio_init(struct device *dev);
+
+int mt8192_afe_gpio_request(struct device *dev, bool enable,
+                           int dai, int uplink);
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
new file mode 100644 (file)
index 0000000..e7fec2d
--- /dev/null
@@ -0,0 +1,2389 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 8192
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <sound/soc.h>
+
+#include "../common/mtk-afe-fe-dai.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+static const struct snd_pcm_hardware mt8192_afe_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+                   SNDRV_PCM_FMTBIT_S24_LE |
+                   SNDRV_PCM_FMTBIT_S32_LE),
+       .period_bytes_min = 96,
+       .period_bytes_max = 4 * 48 * 1024,
+       .periods_min = 2,
+       .periods_max = 256,
+       .buffer_bytes_max = 4 * 48 * 1024,
+       .fifo_size = 0,
+};
+
+static int mt8192_memif_fs(struct snd_pcm_substream *substream,
+                          unsigned int rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+
+       return mt8192_rate_transform(afe->dev, rate, id);
+}
+
+static int mt8192_get_dai_fs(struct mtk_base_afe *afe,
+                            int dai_id, unsigned int rate)
+{
+       return mt8192_rate_transform(afe->dev, rate, dai_id);
+}
+
+static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+       return mt8192_general_rate_transform(afe->dev, rate);
+}
+
+static int mt8192_get_memif_pbuf_size(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if ((runtime->period_size * 1000) / runtime->rate > 10)
+               return MT8192_MEMIF_PBUF_SIZE_256_BYTES;
+       else
+               return MT8192_MEMIF_PBUF_SIZE_32_BYTES;
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\
+                          SNDRV_PCM_RATE_16000 |\
+                          SNDRV_PCM_RATE_32000 |\
+                          SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt8192_memif_dai_driver[] = {
+       /* FE DAIs: memory intefaces to CPU */
+       {
+               .name = "DL1",
+               .id = MT8192_MEMIF_DL1,
+               .playback = {
+                       .stream_name = "DL1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL12",
+               .id = MT8192_MEMIF_DL12,
+               .playback = {
+                       .stream_name = "DL12",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL2",
+               .id = MT8192_MEMIF_DL2,
+               .playback = {
+                       .stream_name = "DL2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL3",
+               .id = MT8192_MEMIF_DL3,
+               .playback = {
+                       .stream_name = "DL3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL4",
+               .id = MT8192_MEMIF_DL4,
+               .playback = {
+                       .stream_name = "DL4",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL5",
+               .id = MT8192_MEMIF_DL5,
+               .playback = {
+                       .stream_name = "DL5",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL6",
+               .id = MT8192_MEMIF_DL6,
+               .playback = {
+                       .stream_name = "DL6",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL7",
+               .id = MT8192_MEMIF_DL7,
+               .playback = {
+                       .stream_name = "DL7",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL8",
+               .id = MT8192_MEMIF_DL8,
+               .playback = {
+                       .stream_name = "DL8",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "DL9",
+               .id = MT8192_MEMIF_DL9,
+               .playback = {
+                       .stream_name = "DL9",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL1",
+               .id = MT8192_MEMIF_VUL12,
+               .capture = {
+                       .stream_name = "UL1",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL2",
+               .id = MT8192_MEMIF_AWB,
+               .capture = {
+                       .stream_name = "UL2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL3",
+               .id = MT8192_MEMIF_VUL2,
+               .capture = {
+                       .stream_name = "UL3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL4",
+               .id = MT8192_MEMIF_AWB2,
+               .capture = {
+                       .stream_name = "UL4",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL5",
+               .id = MT8192_MEMIF_VUL3,
+               .capture = {
+                       .stream_name = "UL5",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL6",
+               .id = MT8192_MEMIF_VUL4,
+               .capture = {
+                       .stream_name = "UL6",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL7",
+               .id = MT8192_MEMIF_VUL5,
+               .capture = {
+                       .stream_name = "UL7",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL8",
+               .id = MT8192_MEMIF_VUL6,
+               .capture = {
+                       .stream_name = "UL8",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL_MONO_1",
+               .id = MT8192_MEMIF_MOD_DAI,
+               .capture = {
+                       .stream_name = "UL_MONO_1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_DAI_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL_MONO_2",
+               .id = MT8192_MEMIF_DAI,
+               .capture = {
+                       .stream_name = "UL_MONO_2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_DAI_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL_MONO_3",
+               .id = MT8192_MEMIF_DAI2,
+               .capture = {
+                       .stream_name = "UL_MONO_3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_DAI_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "HDMI",
+               .id = MT8192_MEMIF_HDMI,
+               .playback = {
+                       .stream_name = "HDMI",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+};
+
+static int ul_tinyconn_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int reg_shift;
+       unsigned int reg_mask_shift;
+
+       dev_info(afe->dev, "%s(), event 0x%x\n", __func__, event);
+
+       if (strstr(w->name, "UL1")) {
+               reg_shift = VUL1_USE_TINY_SFT;
+               reg_mask_shift = VUL1_USE_TINY_MASK_SFT;
+       } else if (strstr(w->name, "UL2")) {
+               reg_shift = VUL2_USE_TINY_SFT;
+               reg_mask_shift = VUL2_USE_TINY_MASK_SFT;
+       } else if (strstr(w->name, "UL3")) {
+               reg_shift = VUL12_USE_TINY_SFT;
+               reg_mask_shift = VUL12_USE_TINY_MASK_SFT;
+       } else if (strstr(w->name, "UL4")) {
+               reg_shift = AWB2_USE_TINY_SFT;
+               reg_mask_shift = AWB2_USE_TINY_MASK_SFT;
+       } else {
+               reg_shift = AWB2_USE_TINY_SFT;
+               reg_mask_shift = AWB2_USE_TINY_MASK_SFT;
+               dev_warn(afe->dev, "%s(), err widget name %s, default use UL4",
+                        __func__, w->name);
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               regmap_update_bits(afe->regmap, AFE_MEMIF_CONN, reg_mask_shift,
+                                  0x1 << reg_shift);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_update_bits(afe->regmap, AFE_MEMIF_CONN, reg_mask_shift,
+                                  0x0 << reg_shift);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/* dma widget & routes*/
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN21,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN21,
+                                   I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN22,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN22,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN22,
+                                   I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch3_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN9,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN9,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN9,
+                                   I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch4_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN10,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN10,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN10,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN10,
+                                   I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN5,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN5,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN5_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN5_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN5_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN5,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN5,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN5,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S6_CH1", AFE_CONN5_1,
+                                   I_I2S6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S8_CH1", AFE_CONN5_1,
+                                   I_I2S8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN5_1,
+                                   I_CONNSYS_I2S_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1", AFE_CONN5_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN6,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN6,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN6_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN6_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN6_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN6,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN6,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN6,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S6_CH2", AFE_CONN6_1,
+                                   I_I2S6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S8_CH2", AFE_CONN6_1,
+                                   I_I2S8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN6_1,
+                                   I_CONNSYS_I2S_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2", AFE_CONN6_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN32_1,
+                                   I_CONNSYS_I2S_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN32,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN32,
+                                   I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN33_1,
+                                   I_CONNSYS_I2S_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN38,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN38,
+                                   I_I2S0_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN39,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN39,
+                                   I_I2S0_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN44,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN45,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN46,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN46,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN46,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN46_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN46,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN46,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN46_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN46,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN46,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN47,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN47,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN47,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN47_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN47,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN47,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN47_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN47,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN47,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN48,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN49,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN50,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN51,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN12,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN12,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN11,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_3_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN35,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+/* TINYCONN MUX */
+enum {
+       TINYCONN_CH1_MUX_I2S0 = 0x14,
+       TINYCONN_CH2_MUX_I2S0 = 0x15,
+       TINYCONN_CH1_MUX_I2S6 = 0x1a,
+       TINYCONN_CH2_MUX_I2S6 = 0x1b,
+       TINYCONN_CH1_MUX_I2S8 = 0x1c,
+       TINYCONN_CH2_MUX_I2S8 = 0x1d,
+       TINYCONN_MUX_NONE = 0x1f,
+};
+
+static const char * const tinyconn_mux_map[] = {
+       "NONE",
+       "I2S0_CH1",
+       "I2S0_CH2",
+       "I2S6_CH1",
+       "I2S6_CH2",
+       "I2S8_CH1",
+       "I2S8_CH2",
+};
+
+static int tinyconn_mux_map_value[] = {
+       TINYCONN_MUX_NONE,
+       TINYCONN_CH1_MUX_I2S0,
+       TINYCONN_CH2_MUX_I2S0,
+       TINYCONN_CH1_MUX_I2S6,
+       TINYCONN_CH2_MUX_I2S6,
+       TINYCONN_CH1_MUX_I2S8,
+       TINYCONN_CH2_MUX_I2S8,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_tinyconn_ch1_mux_map_enum,
+                                 AFE_TINY_CONN0,
+                                 O_2_CFG_SFT,
+                                 O_2_CFG_MASK,
+                                 tinyconn_mux_map,
+                                 tinyconn_mux_map_value);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_tinyconn_ch2_mux_map_enum,
+                                 AFE_TINY_CONN0,
+                                 O_3_CFG_SFT,
+                                 O_3_CFG_MASK,
+                                 tinyconn_mux_map,
+                                 tinyconn_mux_map_value);
+
+static const struct snd_kcontrol_new ul4_tinyconn_ch1_mux_control =
+       SOC_DAPM_ENUM("UL4_TINYCONN_CH1_MUX", ul4_tinyconn_ch1_mux_map_enum);
+static const struct snd_kcontrol_new ul4_tinyconn_ch2_mux_control =
+       SOC_DAPM_ENUM("UL4_TINYCONN_CH2_MUX", ul4_tinyconn_ch2_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mt8192_memif_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+       SND_SOC_DAPM_MIXER("UL1_CH3", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch3_mix, ARRAY_SIZE(memif_ul1_ch3_mix)),
+       SND_SOC_DAPM_MIXER("UL1_CH4", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch4_mix, ARRAY_SIZE(memif_ul1_ch4_mix)),
+
+       SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)),
+       SND_SOC_DAPM_MUX_E("UL4_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0,
+                          &ul4_tinyconn_ch1_mux_control,
+                          ul_tinyconn_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MUX_E("UL4_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0,
+                          &ul4_tinyconn_ch2_mux_control,
+                          ul_tinyconn_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul_mono_1_mix,
+                          ARRAY_SIZE(memif_ul_mono_1_mix)),
+
+       SND_SOC_DAPM_MIXER("UL_MONO_2_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul_mono_2_mix,
+                          ARRAY_SIZE(memif_ul_mono_2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL_MONO_3_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul_mono_3_mix,
+                          ARRAY_SIZE(memif_ul_mono_3_mix)),
+
+       SND_SOC_DAPM_INPUT("UL1_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL6_VIRTUAL_INPUT"),
+};
+
+static const struct snd_soc_dapm_route mt8192_memif_routes[] = {
+       {"UL1", NULL, "UL1_CH1"},
+       {"UL1", NULL, "UL1_CH2"},
+       {"UL1", NULL, "UL1_CH3"},
+       {"UL1", NULL, "UL1_CH4"},
+       {"UL1_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL1_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+       {"UL1_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+       {"UL1_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL1_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+       {"UL1_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+       {"UL1_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+       {"UL1_CH3", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL1_CH3", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+       {"UL1_CH3", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+       {"UL1_CH4", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL1_CH4", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+       {"UL1_CH4", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+       {"UL1_CH4", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+       {"UL2", NULL, "UL2_CH1"},
+       {"UL2", NULL, "UL2_CH2"},
+       {"UL2_CH1", "I2S0_CH1", "I2S0"},
+       {"UL2_CH2", "I2S0_CH2", "I2S0"},
+       {"UL2_CH1", "I2S2_CH1", "I2S2"},
+       {"UL2_CH2", "I2S2_CH2", "I2S2"},
+       {"UL2_CH1", "I2S6_CH1", "I2S6"},
+       {"UL2_CH2", "I2S6_CH2", "I2S6"},
+       {"UL2_CH1", "I2S8_CH1", "I2S8"},
+       {"UL2_CH2", "I2S8_CH2", "I2S8"},
+
+       {"UL2_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+       {"UL2_CH2", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+       {"UL2_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+       {"UL2_CH2", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+
+       {"UL_MONO_1", NULL, "UL_MONO_1_CH1"},
+       {"UL_MONO_1_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+       {"UL_MONO_1_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+
+       {"UL_MONO_2", NULL, "UL_MONO_2_CH1"},
+       {"UL_MONO_2_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+
+       {"UL_MONO_3", NULL, "UL_MONO_3_CH1"},
+       {"UL_MONO_3_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+
+       {"UL2_CH1", "CONNSYS_I2S_CH1", "Connsys I2S"},
+       {"UL2_CH2", "CONNSYS_I2S_CH2", "Connsys I2S"},
+
+       {"UL3", NULL, "UL3_CH1"},
+       {"UL3", NULL, "UL3_CH2"},
+       {"UL3_CH1", "CONNSYS_I2S_CH1", "Connsys I2S"},
+       {"UL3_CH2", "CONNSYS_I2S_CH2", "Connsys I2S"},
+
+       {"UL4", NULL, "UL4_CH1"},
+       {"UL4", NULL, "UL4_CH2"},
+       {"UL4", NULL, "UL4_TINYCONN_CH1_MUX"},
+       {"UL4", NULL, "UL4_TINYCONN_CH2_MUX"},
+       {"UL4_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL4_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+       {"UL4_CH1", "I2S0_CH1", "I2S0"},
+       {"UL4_CH2", "I2S0_CH2", "I2S0"},
+       {"UL4_TINYCONN_CH1_MUX", "I2S0_CH1", "I2S0"},
+       {"UL4_TINYCONN_CH2_MUX", "I2S0_CH2", "I2S0"},
+
+       {"UL5", NULL, "UL5_CH1"},
+       {"UL5", NULL, "UL5_CH2"},
+       {"UL5_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL5_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+       {"UL6", NULL, "UL6_CH1"},
+       {"UL6", NULL, "UL6_CH2"},
+
+       {"UL6_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL6_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+       {"UL6_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+       {"UL6_CH2", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+       {"UL6_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+       {"UL6_CH2", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+
+       {"UL7", NULL, "UL7_CH1"},
+       {"UL7", NULL, "UL7_CH2"},
+       {"UL7_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL7_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+       {"UL8", NULL, "UL8_CH1"},
+       {"UL8", NULL, "UL8_CH2"},
+       {"UL8_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+       {"UL8_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+};
+
+static const struct mtk_base_memif_data memif_data[MT8192_MEMIF_NUM] = {
+       [MT8192_MEMIF_DL1] = {
+               .name = "DL1",
+               .id = MT8192_MEMIF_DL1,
+               .reg_ofs_base = AFE_DL1_BASE,
+               .reg_ofs_cur = AFE_DL1_CUR,
+               .reg_ofs_end = AFE_DL1_END,
+               .reg_ofs_base_msb = AFE_DL1_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL1_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL1_END_MSB,
+               .fs_reg = AFE_DL1_CON0,
+               .fs_shift = DL1_MODE_SFT,
+               .fs_maskbit = DL1_MODE_MASK,
+               .mono_reg = AFE_DL1_CON0,
+               .mono_shift = DL1_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL1_ON_SFT,
+               .hd_reg = AFE_DL1_CON0,
+               .hd_shift = DL1_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL1_CON0,
+               .hd_align_mshift = DL1_HALIGN_SFT,
+               .pbuf_reg = AFE_DL1_CON0,
+               .pbuf_shift = DL1_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL1_CON0,
+               .minlen_shift = DL1_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL12] = {
+               .name = "DL12",
+               .id = MT8192_MEMIF_DL12,
+               .reg_ofs_base = AFE_DL12_BASE,
+               .reg_ofs_cur = AFE_DL12_CUR,
+               .reg_ofs_end = AFE_DL12_END,
+               .reg_ofs_base_msb = AFE_DL12_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL12_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL12_END_MSB,
+               .fs_reg = AFE_DL12_CON0,
+               .fs_shift = DL12_MODE_SFT,
+               .fs_maskbit = DL12_MODE_MASK,
+               .mono_reg = AFE_DL12_CON0,
+               .mono_shift = DL12_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL12_ON_SFT,
+               .hd_reg = AFE_DL12_CON0,
+               .hd_shift = DL12_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL12_CON0,
+               .hd_align_mshift = DL12_HALIGN_SFT,
+               .pbuf_reg = AFE_DL12_CON0,
+               .pbuf_shift = DL12_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL12_CON0,
+               .minlen_shift = DL12_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL2] = {
+               .name = "DL2",
+               .id = MT8192_MEMIF_DL2,
+               .reg_ofs_base = AFE_DL2_BASE,
+               .reg_ofs_cur = AFE_DL2_CUR,
+               .reg_ofs_end = AFE_DL2_END,
+               .reg_ofs_base_msb = AFE_DL2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL2_END_MSB,
+               .fs_reg = AFE_DL2_CON0,
+               .fs_shift = DL2_MODE_SFT,
+               .fs_maskbit = DL2_MODE_MASK,
+               .mono_reg = AFE_DL2_CON0,
+               .mono_shift = DL2_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL2_ON_SFT,
+               .hd_reg = AFE_DL2_CON0,
+               .hd_shift = DL2_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL2_CON0,
+               .hd_align_mshift = DL2_HALIGN_SFT,
+               .pbuf_reg = AFE_DL2_CON0,
+               .pbuf_shift = DL2_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL2_CON0,
+               .minlen_shift = DL2_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL3] = {
+               .name = "DL3",
+               .id = MT8192_MEMIF_DL3,
+               .reg_ofs_base = AFE_DL3_BASE,
+               .reg_ofs_cur = AFE_DL3_CUR,
+               .reg_ofs_end = AFE_DL3_END,
+               .reg_ofs_base_msb = AFE_DL3_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL3_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL3_END_MSB,
+               .fs_reg = AFE_DL3_CON0,
+               .fs_shift = DL3_MODE_SFT,
+               .fs_maskbit = DL3_MODE_MASK,
+               .mono_reg = AFE_DL3_CON0,
+               .mono_shift = DL3_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL3_ON_SFT,
+               .hd_reg = AFE_DL3_CON0,
+               .hd_shift = DL3_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL3_CON0,
+               .hd_align_mshift = DL3_HALIGN_SFT,
+               .pbuf_reg = AFE_DL3_CON0,
+               .pbuf_shift = DL3_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL3_CON0,
+               .minlen_shift = DL3_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL4] = {
+               .name = "DL4",
+               .id = MT8192_MEMIF_DL4,
+               .reg_ofs_base = AFE_DL4_BASE,
+               .reg_ofs_cur = AFE_DL4_CUR,
+               .reg_ofs_end = AFE_DL4_END,
+               .reg_ofs_base_msb = AFE_DL4_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL4_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL4_END_MSB,
+               .fs_reg = AFE_DL4_CON0,
+               .fs_shift = DL4_MODE_SFT,
+               .fs_maskbit = DL4_MODE_MASK,
+               .mono_reg = AFE_DL4_CON0,
+               .mono_shift = DL4_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL4_ON_SFT,
+               .hd_reg = AFE_DL4_CON0,
+               .hd_shift = DL4_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL4_CON0,
+               .hd_align_mshift = DL4_HALIGN_SFT,
+               .pbuf_reg = AFE_DL4_CON0,
+               .pbuf_shift = DL4_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL4_CON0,
+               .minlen_shift = DL4_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL5] = {
+               .name = "DL5",
+               .id = MT8192_MEMIF_DL5,
+               .reg_ofs_base = AFE_DL5_BASE,
+               .reg_ofs_cur = AFE_DL5_CUR,
+               .reg_ofs_end = AFE_DL5_END,
+               .reg_ofs_base_msb = AFE_DL5_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL5_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL5_END_MSB,
+               .fs_reg = AFE_DL5_CON0,
+               .fs_shift = DL5_MODE_SFT,
+               .fs_maskbit = DL5_MODE_MASK,
+               .mono_reg = AFE_DL5_CON0,
+               .mono_shift = DL5_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL5_ON_SFT,
+               .hd_reg = AFE_DL5_CON0,
+               .hd_shift = DL5_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL5_CON0,
+               .hd_align_mshift = DL5_HALIGN_SFT,
+               .pbuf_reg = AFE_DL5_CON0,
+               .pbuf_shift = DL5_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL5_CON0,
+               .minlen_shift = DL5_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL6] = {
+               .name = "DL6",
+               .id = MT8192_MEMIF_DL6,
+               .reg_ofs_base = AFE_DL6_BASE,
+               .reg_ofs_cur = AFE_DL6_CUR,
+               .reg_ofs_end = AFE_DL6_END,
+               .reg_ofs_base_msb = AFE_DL6_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL6_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL6_END_MSB,
+               .fs_reg = AFE_DL6_CON0,
+               .fs_shift = DL6_MODE_SFT,
+               .fs_maskbit = DL6_MODE_MASK,
+               .mono_reg = AFE_DL6_CON0,
+               .mono_shift = DL6_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL6_ON_SFT,
+               .hd_reg = AFE_DL6_CON0,
+               .hd_shift = DL6_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL6_CON0,
+               .hd_align_mshift = DL6_HALIGN_SFT,
+               .pbuf_reg = AFE_DL6_CON0,
+               .pbuf_shift = DL6_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL6_CON0,
+               .minlen_shift = DL6_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL7] = {
+               .name = "DL7",
+               .id = MT8192_MEMIF_DL7,
+               .reg_ofs_base = AFE_DL7_BASE,
+               .reg_ofs_cur = AFE_DL7_CUR,
+               .reg_ofs_end = AFE_DL7_END,
+               .reg_ofs_base_msb = AFE_DL7_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL7_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL7_END_MSB,
+               .fs_reg = AFE_DL7_CON0,
+               .fs_shift = DL7_MODE_SFT,
+               .fs_maskbit = DL7_MODE_MASK,
+               .mono_reg = AFE_DL7_CON0,
+               .mono_shift = DL7_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL7_ON_SFT,
+               .hd_reg = AFE_DL7_CON0,
+               .hd_shift = DL7_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL7_CON0,
+               .hd_align_mshift = DL7_HALIGN_SFT,
+               .pbuf_reg = AFE_DL7_CON0,
+               .pbuf_shift = DL7_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL7_CON0,
+               .minlen_shift = DL7_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL8] = {
+               .name = "DL8",
+               .id = MT8192_MEMIF_DL8,
+               .reg_ofs_base = AFE_DL8_BASE,
+               .reg_ofs_cur = AFE_DL8_CUR,
+               .reg_ofs_end = AFE_DL8_END,
+               .reg_ofs_base_msb = AFE_DL8_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL8_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL8_END_MSB,
+               .fs_reg = AFE_DL8_CON0,
+               .fs_shift = DL8_MODE_SFT,
+               .fs_maskbit = DL8_MODE_MASK,
+               .mono_reg = AFE_DL8_CON0,
+               .mono_shift = DL8_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL8_ON_SFT,
+               .hd_reg = AFE_DL8_CON0,
+               .hd_shift = DL8_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL8_CON0,
+               .hd_align_mshift = DL8_HALIGN_SFT,
+               .pbuf_reg = AFE_DL8_CON0,
+               .pbuf_shift = DL8_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL8_CON0,
+               .minlen_shift = DL8_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DL9] = {
+               .name = "DL9",
+               .id = MT8192_MEMIF_DL9,
+               .reg_ofs_base = AFE_DL9_BASE,
+               .reg_ofs_cur = AFE_DL9_CUR,
+               .reg_ofs_end = AFE_DL9_END,
+               .reg_ofs_base_msb = AFE_DL9_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL9_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL9_END_MSB,
+               .fs_reg = AFE_DL9_CON0,
+               .fs_shift = DL9_MODE_SFT,
+               .fs_maskbit = DL9_MODE_MASK,
+               .mono_reg = AFE_DL9_CON0,
+               .mono_shift = DL9_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL9_ON_SFT,
+               .hd_reg = AFE_DL9_CON0,
+               .hd_shift = DL9_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL9_CON0,
+               .hd_align_mshift = DL9_HALIGN_SFT,
+               .pbuf_reg = AFE_DL9_CON0,
+               .pbuf_shift = DL9_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL9_CON0,
+               .minlen_shift = DL9_MINLEN_SFT,
+       },
+       [MT8192_MEMIF_DAI] = {
+               .name = "DAI",
+               .id = MT8192_MEMIF_DAI,
+               .reg_ofs_base = AFE_DAI_BASE,
+               .reg_ofs_cur = AFE_DAI_CUR,
+               .reg_ofs_end = AFE_DAI_END,
+               .reg_ofs_base_msb = AFE_DAI_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DAI_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DAI_END_MSB,
+               .fs_reg = AFE_DAI_CON0,
+               .fs_shift = DAI_MODE_SFT,
+               .fs_maskbit = DAI_MODE_MASK,
+               .mono_reg = AFE_DAI_CON0,
+               .mono_shift = DAI_DUPLICATE_WR_SFT,
+               .mono_invert = 1,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DAI_ON_SFT,
+               .hd_reg = AFE_DAI_CON0,
+               .hd_shift = DAI_HD_MODE_SFT,
+               .hd_align_reg = AFE_DAI_CON0,
+               .hd_align_mshift = DAI_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_MOD_DAI] = {
+               .name = "MOD_DAI",
+               .id = MT8192_MEMIF_MOD_DAI,
+               .reg_ofs_base = AFE_MOD_DAI_BASE,
+               .reg_ofs_cur = AFE_MOD_DAI_CUR,
+               .reg_ofs_end = AFE_MOD_DAI_END,
+               .reg_ofs_base_msb = AFE_MOD_DAI_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_MOD_DAI_CUR_MSB,
+               .reg_ofs_end_msb = AFE_MOD_DAI_END_MSB,
+               .fs_reg = AFE_MOD_DAI_CON0,
+               .fs_shift = MOD_DAI_MODE_SFT,
+               .fs_maskbit = MOD_DAI_MODE_MASK,
+               .mono_reg = AFE_MOD_DAI_CON0,
+               .mono_shift = MOD_DAI_DUPLICATE_WR_SFT,
+               .mono_invert = 1,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = MOD_DAI_ON_SFT,
+               .hd_reg = AFE_MOD_DAI_CON0,
+               .hd_shift = MOD_DAI_HD_MODE_SFT,
+               .hd_align_reg = AFE_MOD_DAI_CON0,
+               .hd_align_mshift = MOD_DAI_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_DAI2] = {
+               .name = "DAI2",
+               .id = MT8192_MEMIF_DAI2,
+               .reg_ofs_base = AFE_DAI2_BASE,
+               .reg_ofs_cur = AFE_DAI2_CUR,
+               .reg_ofs_end = AFE_DAI2_END,
+               .reg_ofs_base_msb = AFE_DAI2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DAI2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DAI2_END_MSB,
+               .fs_reg = AFE_DAI2_CON0,
+               .fs_shift = DAI2_MODE_SFT,
+               .fs_maskbit = DAI2_MODE_MASK,
+               .mono_reg = AFE_DAI2_CON0,
+               .mono_shift = DAI2_DUPLICATE_WR_SFT,
+               .mono_invert = 1,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DAI2_ON_SFT,
+               .hd_reg = AFE_DAI2_CON0,
+               .hd_shift = DAI2_HD_MODE_SFT,
+               .hd_align_reg = AFE_DAI2_CON0,
+               .hd_align_mshift = DAI2_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_VUL12] = {
+               .name = "VUL12",
+               .id = MT8192_MEMIF_VUL12,
+               .reg_ofs_base = AFE_VUL12_BASE,
+               .reg_ofs_cur = AFE_VUL12_CUR,
+               .reg_ofs_end = AFE_VUL12_END,
+               .reg_ofs_base_msb = AFE_VUL12_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL12_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL12_END_MSB,
+               .fs_reg = AFE_VUL12_CON0,
+               .fs_shift = VUL12_MODE_SFT,
+               .fs_maskbit = VUL12_MODE_MASK,
+               .mono_reg = AFE_VUL12_CON0,
+               .mono_shift = VUL12_MONO_SFT,
+               .quad_ch_reg = AFE_VUL12_CON0,
+               .quad_ch_shift = VUL12_4CH_EN_SFT,
+               .quad_ch_mask = VUL12_4CH_EN_MASK,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL12_ON_SFT,
+               .hd_reg = AFE_VUL12_CON0,
+               .hd_shift = VUL12_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL12_CON0,
+               .hd_align_mshift = VUL12_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_VUL2] = {
+               .name = "VUL2",
+               .id = MT8192_MEMIF_VUL2,
+               .reg_ofs_base = AFE_VUL2_BASE,
+               .reg_ofs_cur = AFE_VUL2_CUR,
+               .reg_ofs_end = AFE_VUL2_END,
+               .reg_ofs_base_msb = AFE_VUL2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL2_END_MSB,
+               .fs_reg = AFE_VUL2_CON0,
+               .fs_shift = VUL2_MODE_SFT,
+               .fs_maskbit = VUL2_MODE_MASK,
+               .mono_reg = AFE_VUL2_CON0,
+               .mono_shift = VUL2_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL2_ON_SFT,
+               .hd_reg = AFE_VUL2_CON0,
+               .hd_shift = VUL2_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL2_CON0,
+               .hd_align_mshift = VUL2_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_AWB] = {
+               .name = "AWB",
+               .id = MT8192_MEMIF_AWB,
+               .reg_ofs_base = AFE_AWB_BASE,
+               .reg_ofs_cur = AFE_AWB_CUR,
+               .reg_ofs_end = AFE_AWB_END,
+               .reg_ofs_base_msb = AFE_AWB_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_AWB_CUR_MSB,
+               .reg_ofs_end_msb = AFE_AWB_END_MSB,
+               .fs_reg = AFE_AWB_CON0,
+               .fs_shift = AWB_MODE_SFT,
+               .fs_maskbit = AWB_MODE_MASK,
+               .mono_reg = AFE_AWB_CON0,
+               .mono_shift = AWB_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = AWB_ON_SFT,
+               .hd_reg = AFE_AWB_CON0,
+               .hd_shift = AWB_HD_MODE_SFT,
+               .hd_align_reg = AFE_AWB_CON0,
+               .hd_align_mshift = AWB_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_AWB2] = {
+               .name = "AWB2",
+               .id = MT8192_MEMIF_AWB2,
+               .reg_ofs_base = AFE_AWB2_BASE,
+               .reg_ofs_cur = AFE_AWB2_CUR,
+               .reg_ofs_end = AFE_AWB2_END,
+               .reg_ofs_base_msb = AFE_AWB2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_AWB2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_AWB2_END_MSB,
+               .fs_reg = AFE_AWB2_CON0,
+               .fs_shift = AWB2_MODE_SFT,
+               .fs_maskbit = AWB2_MODE_MASK,
+               .mono_reg = AFE_AWB2_CON0,
+               .mono_shift = AWB2_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = AWB2_ON_SFT,
+               .hd_reg = AFE_AWB2_CON0,
+               .hd_shift = AWB2_HD_MODE_SFT,
+               .hd_align_reg = AFE_AWB2_CON0,
+               .hd_align_mshift = AWB2_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_VUL3] = {
+               .name = "VUL3",
+               .id = MT8192_MEMIF_VUL3,
+               .reg_ofs_base = AFE_VUL3_BASE,
+               .reg_ofs_cur = AFE_VUL3_CUR,
+               .reg_ofs_end = AFE_VUL3_END,
+               .reg_ofs_base_msb = AFE_VUL3_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL3_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL3_END_MSB,
+               .fs_reg = AFE_VUL3_CON0,
+               .fs_shift = VUL3_MODE_SFT,
+               .fs_maskbit = VUL3_MODE_MASK,
+               .mono_reg = AFE_VUL3_CON0,
+               .mono_shift = VUL3_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL3_ON_SFT,
+               .hd_reg = AFE_VUL3_CON0,
+               .hd_shift = VUL3_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL3_CON0,
+               .hd_align_mshift = VUL3_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_VUL4] = {
+               .name = "VUL4",
+               .id = MT8192_MEMIF_VUL4,
+               .reg_ofs_base = AFE_VUL4_BASE,
+               .reg_ofs_cur = AFE_VUL4_CUR,
+               .reg_ofs_end = AFE_VUL4_END,
+               .reg_ofs_base_msb = AFE_VUL4_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL4_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL4_END_MSB,
+               .fs_reg = AFE_VUL4_CON0,
+               .fs_shift = VUL4_MODE_SFT,
+               .fs_maskbit = VUL4_MODE_MASK,
+               .mono_reg = AFE_VUL4_CON0,
+               .mono_shift = VUL4_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL4_ON_SFT,
+               .hd_reg = AFE_VUL4_CON0,
+               .hd_shift = VUL4_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL4_CON0,
+               .hd_align_mshift = VUL4_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_VUL5] = {
+               .name = "VUL5",
+               .id = MT8192_MEMIF_VUL5,
+               .reg_ofs_base = AFE_VUL5_BASE,
+               .reg_ofs_cur = AFE_VUL5_CUR,
+               .reg_ofs_end = AFE_VUL5_END,
+               .reg_ofs_base_msb = AFE_VUL5_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL5_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL5_END_MSB,
+               .fs_reg = AFE_VUL5_CON0,
+               .fs_shift = VUL5_MODE_SFT,
+               .fs_maskbit = VUL5_MODE_MASK,
+               .mono_reg = AFE_VUL5_CON0,
+               .mono_shift = VUL5_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL5_ON_SFT,
+               .hd_reg = AFE_VUL5_CON0,
+               .hd_shift = VUL5_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL5_CON0,
+               .hd_align_mshift = VUL5_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_VUL6] = {
+               .name = "VUL6",
+               .id = MT8192_MEMIF_VUL6,
+               .reg_ofs_base = AFE_VUL6_BASE,
+               .reg_ofs_cur = AFE_VUL6_CUR,
+               .reg_ofs_end = AFE_VUL6_END,
+               .reg_ofs_base_msb = AFE_VUL6_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL6_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL6_END_MSB,
+               .fs_reg = AFE_VUL6_CON0,
+               .fs_shift = VUL6_MODE_SFT,
+               .fs_maskbit = VUL6_MODE_MASK,
+               .mono_reg = AFE_VUL6_CON0,
+               .mono_shift = VUL6_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL6_ON_SFT,
+               .hd_reg = AFE_VUL6_CON0,
+               .hd_shift = VUL6_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL6_CON0,
+               .hd_align_mshift = VUL6_HALIGN_SFT,
+       },
+       [MT8192_MEMIF_HDMI] = {
+               .name = "HDMI",
+               .id = MT8192_MEMIF_HDMI,
+               .reg_ofs_base = AFE_HDMI_OUT_BASE,
+               .reg_ofs_cur = AFE_HDMI_OUT_CUR,
+               .reg_ofs_end = AFE_HDMI_OUT_END,
+               .reg_ofs_base_msb = AFE_HDMI_OUT_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_HDMI_OUT_CUR_MSB,
+               .reg_ofs_end_msb = AFE_HDMI_OUT_END_MSB,
+               .fs_reg = -1,
+               .fs_shift = -1,
+               .fs_maskbit = -1,
+               .mono_reg = -1,
+               .mono_shift = -1,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = HDMI_OUT_ON_SFT,
+               .hd_reg = AFE_HDMI_OUT_CON0,
+               .hd_shift = HDMI_OUT_HD_MODE_SFT,
+               .hd_align_reg = AFE_HDMI_OUT_CON0,
+               .hd_align_mshift = HDMI_OUT_HALIGN_SFT,
+               .pbuf_reg = AFE_HDMI_OUT_CON0,
+               .minlen_reg = AFE_HDMI_OUT_CON0,
+               .minlen_shift = HDMI_OUT_MINLEN_SFT,
+       },
+};
+
+static const struct mtk_base_irq_data irq_data[MT8192_IRQ_NUM] = {
+       [MT8192_IRQ_0] = {
+               .id = MT8192_IRQ_0,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT0,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ0_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ0_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ0_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ0_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_1] = {
+               .id = MT8192_IRQ_1,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ1_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ1_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ1_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_2] = {
+               .id = MT8192_IRQ_2,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ2_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ2_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ2_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_3] = {
+               .id = MT8192_IRQ_3,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ3_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ3_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ3_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ3_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_4] = {
+               .id = MT8192_IRQ_4,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ4_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ4_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ4_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ4_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_5] = {
+               .id = MT8192_IRQ_5,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ5_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ5_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ5_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ5_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_6] = {
+               .id = MT8192_IRQ_6,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT6,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ6_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ6_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ6_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ6_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_7] = {
+               .id = MT8192_IRQ_7,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ7_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ7_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ7_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ7_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_8] = {
+               .id = MT8192_IRQ_8,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ8_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ8_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ8_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ8_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_9] = {
+               .id = MT8192_IRQ_9,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT9,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ9_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ9_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ9_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ9_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_10] = {
+               .id = MT8192_IRQ_10,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT10,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ10_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ10_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ10_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ10_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_11] = {
+               .id = MT8192_IRQ_11,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT11,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ11_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ11_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ11_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ11_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_12] = {
+               .id = MT8192_IRQ_12,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT12,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ12_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ12_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ12_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ12_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_13] = {
+               .id = MT8192_IRQ_13,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT13,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ13_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ13_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ13_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ13_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_14] = {
+               .id = MT8192_IRQ_14,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT14,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ14_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ14_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ14_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ14_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_15] = {
+               .id = MT8192_IRQ_15,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT15,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ15_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ15_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ15_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ15_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_16] = {
+               .id = MT8192_IRQ_16,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT16,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ16_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ16_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ16_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ16_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_17] = {
+               .id = MT8192_IRQ_17,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT17,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ17_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ17_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ17_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ17_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_18] = {
+               .id = MT8192_IRQ_18,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT18,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ18_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ18_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ18_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ18_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_19] = {
+               .id = MT8192_IRQ_19,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT19,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ19_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ19_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ19_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ19_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_20] = {
+               .id = MT8192_IRQ_20,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT20,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ20_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ20_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ20_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ20_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_21] = {
+               .id = MT8192_IRQ_21,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT21,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ21_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ21_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ21_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ21_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_22] = {
+               .id = MT8192_IRQ_22,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT22,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ22_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ22_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ22_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ22_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_23] = {
+               .id = MT8192_IRQ_23,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT23,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ23_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ23_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ23_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ23_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_24] = {
+               .id = MT8192_IRQ_24,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT24,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON4,
+               .irq_fs_shift = IRQ24_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ24_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ24_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ24_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_25] = {
+               .id = MT8192_IRQ_25,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT25,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON4,
+               .irq_fs_shift = IRQ25_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ25_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ25_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ25_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_26] = {
+               .id = MT8192_IRQ_26,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT26,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON4,
+               .irq_fs_shift = IRQ26_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ26_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ26_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ26_MCU_CLR_SFT,
+       },
+       [MT8192_IRQ_31] = {
+               .id = MT8192_IRQ_31,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT31,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = -1,
+               .irq_fs_shift = -1,
+               .irq_fs_maskbit = -1,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ31_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ31_MCU_CLR_SFT,
+       },
+};
+
+static const int memif_irq_usage[MT8192_MEMIF_NUM] = {
+       [MT8192_MEMIF_DL1] = MT8192_IRQ_0,
+       [MT8192_MEMIF_DL2] = MT8192_IRQ_1,
+       [MT8192_MEMIF_DL3] = MT8192_IRQ_2,
+       [MT8192_MEMIF_DL4] = MT8192_IRQ_3,
+       [MT8192_MEMIF_DL5] = MT8192_IRQ_4,
+       [MT8192_MEMIF_DL6] = MT8192_IRQ_5,
+       [MT8192_MEMIF_DL7] = MT8192_IRQ_6,
+       [MT8192_MEMIF_DL8] = MT8192_IRQ_7,
+       [MT8192_MEMIF_DL9] = MT8192_IRQ_8,
+       [MT8192_MEMIF_DL12] = MT8192_IRQ_9,
+       [MT8192_MEMIF_DAI] = MT8192_IRQ_10,
+       [MT8192_MEMIF_MOD_DAI] = MT8192_IRQ_11,
+       [MT8192_MEMIF_DAI2] = MT8192_IRQ_12,
+       [MT8192_MEMIF_VUL12] = MT8192_IRQ_13,
+       [MT8192_MEMIF_VUL2] = MT8192_IRQ_14,
+       [MT8192_MEMIF_AWB] = MT8192_IRQ_15,
+       [MT8192_MEMIF_AWB2] = MT8192_IRQ_16,
+       [MT8192_MEMIF_VUL3] = MT8192_IRQ_17,
+       [MT8192_MEMIF_VUL4] = MT8192_IRQ_18,
+       [MT8192_MEMIF_VUL5] = MT8192_IRQ_19,
+       [MT8192_MEMIF_VUL6] = MT8192_IRQ_20,
+       [MT8192_MEMIF_HDMI] = MT8192_IRQ_31,
+};
+
+static bool mt8192_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       /* these auto-gen reg has read-only bit, so put it as volatile */
+       /* volatile reg cannot be cached, so cannot be set when power off */
+       switch (reg) {
+       case AUDIO_TOP_CON0:    /* reg bit controlled by CCF */
+       case AUDIO_TOP_CON1:    /* reg bit controlled by CCF */
+       case AUDIO_TOP_CON2:
+       case AUDIO_TOP_CON3:
+       case AFE_DL1_CUR_MSB:
+       case AFE_DL1_CUR:
+       case AFE_DL1_END:
+       case AFE_DL2_CUR_MSB:
+       case AFE_DL2_CUR:
+       case AFE_DL2_END:
+       case AFE_DL3_CUR_MSB:
+       case AFE_DL3_CUR:
+       case AFE_DL3_END:
+       case AFE_DL4_CUR_MSB:
+       case AFE_DL4_CUR:
+       case AFE_DL4_END:
+       case AFE_DL12_CUR_MSB:
+       case AFE_DL12_CUR:
+       case AFE_DL12_END:
+       case AFE_ADDA_SRC_DEBUG_MON0:
+       case AFE_ADDA_SRC_DEBUG_MON1:
+       case AFE_ADDA_UL_SRC_MON0:
+       case AFE_ADDA_UL_SRC_MON1:
+       case AFE_SECURE_CON0:
+       case AFE_SRAM_BOUND:
+       case AFE_SECURE_CON1:
+       case AFE_VUL_CUR_MSB:
+       case AFE_VUL_CUR:
+       case AFE_VUL_END:
+       case AFE_ADDA_3RD_DAC_DL_SDM_FIFO_MON:
+       case AFE_ADDA_3RD_DAC_DL_SRC_LCH_MON:
+       case AFE_ADDA_3RD_DAC_DL_SRC_RCH_MON:
+       case AFE_ADDA_3RD_DAC_DL_SDM_OUT_MON:
+       case AFE_SIDETONE_MON:
+       case AFE_SIDETONE_CON0:
+       case AFE_SIDETONE_COEFF:
+       case AFE_VUL2_CUR_MSB:
+       case AFE_VUL2_CUR:
+       case AFE_VUL2_END:
+       case AFE_VUL3_CUR_MSB:
+       case AFE_VUL3_CUR:
+       case AFE_VUL3_END:
+       case AFE_I2S_MON:
+       case AFE_DAC_MON:
+       case AFE_IRQ0_MCU_CNT_MON:
+       case AFE_IRQ6_MCU_CNT_MON:
+       case AFE_VUL4_CUR_MSB:
+       case AFE_VUL4_CUR:
+       case AFE_VUL4_END:
+       case AFE_VUL12_CUR_MSB:
+       case AFE_VUL12_CUR:
+       case AFE_VUL12_END:
+       case AFE_IRQ3_MCU_CNT_MON:
+       case AFE_IRQ4_MCU_CNT_MON:
+       case AFE_IRQ_MCU_STATUS:
+       case AFE_IRQ_MCU_CLR:
+       case AFE_IRQ_MCU_MON2:
+       case AFE_IRQ1_MCU_CNT_MON:
+       case AFE_IRQ2_MCU_CNT_MON:
+       case AFE_IRQ5_MCU_CNT_MON:
+       case AFE_IRQ7_MCU_CNT_MON:
+       case AFE_IRQ_MCU_MISS_CLR:
+       case AFE_GAIN1_CUR:
+       case AFE_GAIN2_CUR:
+       case AFE_SRAM_DELSEL_CON1:
+       case PCM_INTF_CON2:
+       case FPGA_CFG0:
+       case FPGA_CFG1:
+       case FPGA_CFG2:
+       case FPGA_CFG3:
+       case AUDIO_TOP_DBG_MON0:
+       case AUDIO_TOP_DBG_MON1:
+       case AFE_IRQ8_MCU_CNT_MON:
+       case AFE_IRQ11_MCU_CNT_MON:
+       case AFE_IRQ12_MCU_CNT_MON:
+       case AFE_IRQ9_MCU_CNT_MON:
+       case AFE_IRQ10_MCU_CNT_MON:
+       case AFE_IRQ13_MCU_CNT_MON:
+       case AFE_IRQ14_MCU_CNT_MON:
+       case AFE_IRQ15_MCU_CNT_MON:
+       case AFE_IRQ16_MCU_CNT_MON:
+       case AFE_IRQ17_MCU_CNT_MON:
+       case AFE_IRQ18_MCU_CNT_MON:
+       case AFE_IRQ19_MCU_CNT_MON:
+       case AFE_IRQ20_MCU_CNT_MON:
+       case AFE_IRQ21_MCU_CNT_MON:
+       case AFE_IRQ22_MCU_CNT_MON:
+       case AFE_IRQ23_MCU_CNT_MON:
+       case AFE_IRQ24_MCU_CNT_MON:
+       case AFE_IRQ25_MCU_CNT_MON:
+       case AFE_IRQ26_MCU_CNT_MON:
+       case AFE_IRQ31_MCU_CNT_MON:
+       case AFE_CBIP_MON0:
+       case AFE_CBIP_SLV_MUX_MON0:
+       case AFE_CBIP_SLV_DECODER_MON0:
+       case AFE_ADDA6_MTKAIF_MON0:
+       case AFE_ADDA6_MTKAIF_MON1:
+       case AFE_AWB_CUR_MSB:
+       case AFE_AWB_CUR:
+       case AFE_AWB_END:
+       case AFE_AWB2_CUR_MSB:
+       case AFE_AWB2_CUR:
+       case AFE_AWB2_END:
+       case AFE_DAI_CUR_MSB:
+       case AFE_DAI_CUR:
+       case AFE_DAI_END:
+       case AFE_DAI2_CUR_MSB:
+       case AFE_DAI2_CUR:
+       case AFE_DAI2_END:
+       case AFE_ADDA6_SRC_DEBUG_MON0:
+       case AFE_ADD6A_UL_SRC_MON0:
+       case AFE_ADDA6_UL_SRC_MON1:
+       case AFE_MOD_DAI_CUR_MSB:
+       case AFE_MOD_DAI_CUR:
+       case AFE_MOD_DAI_END:
+       case AFE_HDMI_OUT_CUR_MSB:
+       case AFE_HDMI_OUT_CUR:
+       case AFE_HDMI_OUT_END:
+       case AFE_AWB_RCH_MON:
+       case AFE_AWB_LCH_MON:
+       case AFE_VUL_RCH_MON:
+       case AFE_VUL_LCH_MON:
+       case AFE_VUL12_RCH_MON:
+       case AFE_VUL12_LCH_MON:
+       case AFE_VUL2_RCH_MON:
+       case AFE_VUL2_LCH_MON:
+       case AFE_DAI_DATA_MON:
+       case AFE_MOD_DAI_DATA_MON:
+       case AFE_DAI2_DATA_MON:
+       case AFE_AWB2_RCH_MON:
+       case AFE_AWB2_LCH_MON:
+       case AFE_VUL3_RCH_MON:
+       case AFE_VUL3_LCH_MON:
+       case AFE_VUL4_RCH_MON:
+       case AFE_VUL4_LCH_MON:
+       case AFE_VUL5_RCH_MON:
+       case AFE_VUL5_LCH_MON:
+       case AFE_VUL6_RCH_MON:
+       case AFE_VUL6_LCH_MON:
+       case AFE_DL1_RCH_MON:
+       case AFE_DL1_LCH_MON:
+       case AFE_DL2_RCH_MON:
+       case AFE_DL2_LCH_MON:
+       case AFE_DL12_RCH1_MON:
+       case AFE_DL12_LCH1_MON:
+       case AFE_DL12_RCH2_MON:
+       case AFE_DL12_LCH2_MON:
+       case AFE_DL3_RCH_MON:
+       case AFE_DL3_LCH_MON:
+       case AFE_DL4_RCH_MON:
+       case AFE_DL4_LCH_MON:
+       case AFE_DL5_RCH_MON:
+       case AFE_DL5_LCH_MON:
+       case AFE_DL6_RCH_MON:
+       case AFE_DL6_LCH_MON:
+       case AFE_DL7_RCH_MON:
+       case AFE_DL7_LCH_MON:
+       case AFE_DL8_RCH_MON:
+       case AFE_DL8_LCH_MON:
+       case AFE_VUL5_CUR_MSB:
+       case AFE_VUL5_CUR:
+       case AFE_VUL5_END:
+       case AFE_VUL6_CUR_MSB:
+       case AFE_VUL6_CUR:
+       case AFE_VUL6_END:
+       case AFE_ADDA_DL_SDM_FIFO_MON:
+       case AFE_ADDA_DL_SRC_LCH_MON:
+       case AFE_ADDA_DL_SRC_RCH_MON:
+       case AFE_ADDA_DL_SDM_OUT_MON:
+       case AFE_CONNSYS_I2S_MON:
+       case AFE_ASRC_2CH_CON0:
+       case AFE_ASRC_2CH_CON2:
+       case AFE_ASRC_2CH_CON3:
+       case AFE_ASRC_2CH_CON4:
+       case AFE_ASRC_2CH_CON5:
+       case AFE_ASRC_2CH_CON7:
+       case AFE_ASRC_2CH_CON8:
+       case AFE_ASRC_2CH_CON12:
+       case AFE_ASRC_2CH_CON13:
+       case AFE_DL9_CUR_MSB:
+       case AFE_DL9_CUR:
+       case AFE_DL9_END:
+       case AFE_ADDA_MTKAIF_MON0:
+       case AFE_ADDA_MTKAIF_MON1:
+       case AFE_DL_NLE_R_MON0:
+       case AFE_DL_NLE_R_MON1:
+       case AFE_DL_NLE_R_MON2:
+       case AFE_DL_NLE_L_MON0:
+       case AFE_DL_NLE_L_MON1:
+       case AFE_DL_NLE_L_MON2:
+       case AFE_GENERAL1_ASRC_2CH_CON0:
+       case AFE_GENERAL1_ASRC_2CH_CON2:
+       case AFE_GENERAL1_ASRC_2CH_CON3:
+       case AFE_GENERAL1_ASRC_2CH_CON4:
+       case AFE_GENERAL1_ASRC_2CH_CON5:
+       case AFE_GENERAL1_ASRC_2CH_CON7:
+       case AFE_GENERAL1_ASRC_2CH_CON8:
+       case AFE_GENERAL1_ASRC_2CH_CON12:
+       case AFE_GENERAL1_ASRC_2CH_CON13:
+       case AFE_GENERAL2_ASRC_2CH_CON0:
+       case AFE_GENERAL2_ASRC_2CH_CON2:
+       case AFE_GENERAL2_ASRC_2CH_CON3:
+       case AFE_GENERAL2_ASRC_2CH_CON4:
+       case AFE_GENERAL2_ASRC_2CH_CON5:
+       case AFE_GENERAL2_ASRC_2CH_CON7:
+       case AFE_GENERAL2_ASRC_2CH_CON8:
+       case AFE_GENERAL2_ASRC_2CH_CON12:
+       case AFE_GENERAL2_ASRC_2CH_CON13:
+       case AFE_DL9_RCH_MON:
+       case AFE_DL9_LCH_MON:
+       case AFE_DL5_CUR_MSB:
+       case AFE_DL5_CUR:
+       case AFE_DL5_END:
+       case AFE_DL6_CUR_MSB:
+       case AFE_DL6_CUR:
+       case AFE_DL6_END:
+       case AFE_DL7_CUR_MSB:
+       case AFE_DL7_CUR:
+       case AFE_DL7_END:
+       case AFE_DL8_CUR_MSB:
+       case AFE_DL8_CUR:
+       case AFE_DL8_END:
+       case AFE_PROT_SIDEBAND_MON:
+       case AFE_DOMAIN_SIDEBAND0_MON:
+       case AFE_DOMAIN_SIDEBAND1_MON:
+       case AFE_DOMAIN_SIDEBAND2_MON:
+       case AFE_DOMAIN_SIDEBAND3_MON:
+       case AFE_APLL1_TUNER_CFG:       /* [20:31] is monitor */
+       case AFE_APLL2_TUNER_CFG:       /* [20:31] is monitor */
+       case AFE_DAC_CON0:
+       case AFE_IRQ_MCU_CON0:
+       case AFE_IRQ_MCU_EN:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config mt8192_afe_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .volatile_reg = mt8192_is_volatile_reg,
+       .max_register = AFE_MAX_REGISTER,
+       .num_reg_defaults_raw = AFE_MAX_REGISTER,
+       .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8192_afe_irq_handler(int irq_id, void *dev)
+{
+       struct mtk_base_afe *afe = dev;
+       struct mtk_base_afe_irq *irq;
+       unsigned int status;
+       unsigned int status_mcu;
+       unsigned int mcu_en;
+       int ret;
+       int i;
+
+       /* get irq that is sent to MCU */
+       regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+       ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+       /* only care IRQ which is sent to MCU */
+       status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+       if (ret || status_mcu == 0) {
+               dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+                       __func__, ret, status, mcu_en);
+
+               goto err_irq;
+       }
+
+       for (i = 0; i < MT8192_MEMIF_NUM; i++) {
+               struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+               if (!memif->substream)
+                       continue;
+
+               if (memif->irq_usage < 0)
+                       continue;
+
+               irq = &afe->irqs[memif->irq_usage];
+
+               if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+                       snd_pcm_period_elapsed(memif->substream);
+       }
+
+err_irq:
+       /* clear irq */
+       regmap_write(afe->regmap,
+                    AFE_IRQ_MCU_CLR,
+                    status_mcu);
+
+       return IRQ_HANDLED;
+}
+
+static int mt8192_afe_runtime_suspend(struct device *dev)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dev);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       unsigned int value;
+       int ret;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+               goto skip_regmap;
+
+       /* disable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0);
+
+       ret = regmap_read_poll_timeout(afe->regmap,
+                                      AFE_DAC_MON,
+                                      value,
+                                      (value & AFE_ON_RETM_MASK_SFT) == 0,
+                                      20,
+                                      1 * 1000 * 1000);
+       if (ret)
+               dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret);
+
+       /* make sure all irq status are cleared */
+       regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff);
+       regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff);
+
+       /* reset sgen */
+       regmap_write(afe->regmap, AFE_SINEGEN_CON0, 0x0);
+       regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+                          INNER_LOOP_BACK_MODE_MASK_SFT,
+                          0x3f << INNER_LOOP_BACK_MODE_SFT);
+
+       /* cache only */
+       regcache_cache_only(afe->regmap, true);
+       regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+       mt8192_afe_disable_clock(afe);
+       return 0;
+}
+
+static int mt8192_afe_runtime_resume(struct device *dev)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dev);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       ret = mt8192_afe_enable_clock(afe);
+       if (ret)
+               return ret;
+
+       if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+               goto skip_regmap;
+
+       regcache_cache_only(afe->regmap, false);
+       regcache_sync(afe->regmap);
+
+       /* enable audio sys DCM for power saving */
+       regmap_update_bits(afe_priv->infracfg,
+                          PERI_BUS_DCM_CTRL, 0x1 << 29, 0x1 << 29);
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, 0x1 << 29, 0x1 << 29);
+
+       /* force cpu use 8_24 format when writing 32bit data */
+       regmap_update_bits(afe->regmap, AFE_MEMIF_CON0,
+                          CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
+
+       /* set all output port to 24bit */
+       regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff);
+       regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff);
+
+       /* enable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x1);
+
+skip_regmap:
+       return 0;
+}
+
+static int mt8192_afe_component_probe(struct snd_soc_component *component)
+{
+       return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt8192_afe_component = {
+       .name = AFE_PCM_NAME,
+       .probe = mt8192_afe_component_probe,
+       .pointer = mtk_afe_pcm_pointer,
+       .pcm_construct = mtk_afe_pcm_new,
+};
+
+static const struct snd_soc_component_driver mt8192_afe_pcm_component = {
+       .name = "mt8192-afe-pcm-dai",
+};
+
+static int mt8192_dai_memif_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mt8192_memif_dai_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mt8192_memif_dai_driver);
+
+       dai->dapm_widgets = mt8192_memif_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mt8192_memif_widgets);
+       dai->dapm_routes = mt8192_memif_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mt8192_memif_routes);
+       return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+       mt8192_dai_adda_register,
+       mt8192_dai_i2s_register,
+       mt8192_dai_pcm_register,
+       mt8192_dai_tdm_register,
+       mt8192_dai_memif_register,
+};
+
+static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct mtk_base_afe *afe;
+       struct mt8192_afe_private *afe_priv;
+       struct device *dev;
+       struct reset_control *rstc;
+       int i, ret, irq_id;
+
+       ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+       if (ret)
+               return ret;
+
+       afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+       if (!afe)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, afe);
+
+       afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+                                         GFP_KERNEL);
+       if (!afe->platform_priv)
+               return -ENOMEM;
+       afe_priv = afe->platform_priv;
+
+       afe->dev = &pdev->dev;
+       dev = afe->dev;
+
+       /* init audio related clock */
+       ret = mt8192_init_clock(afe);
+       if (ret) {
+               dev_err(dev, "init clock error\n");
+               return ret;
+       }
+
+       /* reset controller to reset audio regs before regmap cache */
+       rstc = devm_reset_control_get_exclusive(dev, "audiosys");
+       if (IS_ERR(rstc)) {
+               ret = PTR_ERR(rstc);
+               dev_err(dev, "could not get audiosys reset:%d\n", ret);
+               return ret;
+       }
+
+       ret = reset_control_reset(rstc);
+       if (ret) {
+               dev_err(dev, "failed to trigger audio reset:%d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev))
+               goto err_pm_disable;
+
+       /* regmap init */
+       afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
+       if (IS_ERR(afe->regmap)) {
+               dev_err(dev, "could not get regmap from parent\n");
+               return PTR_ERR(afe->regmap);
+       }
+       ret = regmap_attach_dev(dev, afe->regmap, &mt8192_afe_regmap_config);
+       if (ret) {
+               dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret);
+               return ret;
+       }
+
+       /* enable clock for regcache get default value from hw */
+       afe_priv->pm_runtime_bypass_reg_ctl = true;
+       pm_runtime_get_sync(&pdev->dev);
+
+       ret = regmap_reinit_cache(afe->regmap, &mt8192_afe_regmap_config);
+       if (ret) {
+               dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_put_sync(&pdev->dev);
+       afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+       regcache_cache_only(afe->regmap, true);
+       regcache_mark_dirty(afe->regmap);
+
+       /* init memif */
+       afe->memif_size = MT8192_MEMIF_NUM;
+       afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+                                 GFP_KERNEL);
+       if (!afe->memif)
+               return -ENOMEM;
+
+       for (i = 0; i < afe->memif_size; i++) {
+               afe->memif[i].data = &memif_data[i];
+               afe->memif[i].irq_usage = memif_irq_usage[i];
+               afe->memif[i].const_irq = 1;
+       }
+
+       mutex_init(&afe->irq_alloc_lock);       /* needed when dynamic irq */
+
+       /* init irq */
+       afe->irqs_size = MT8192_IRQ_NUM;
+       afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+                                GFP_KERNEL);
+       if (!afe->irqs)
+               return -ENOMEM;
+
+       for (i = 0; i < afe->irqs_size; i++)
+               afe->irqs[i].irq_data = &irq_data[i];
+
+       /* request irq */
+       irq_id = platform_get_irq(pdev, 0);
+       if (irq_id < 0)
+               return irq_id;
+
+       ret = devm_request_irq(dev, irq_id, mt8192_afe_irq_handler,
+                              IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+       if (ret) {
+               dev_err(dev, "could not request_irq for Afe_ISR_Handle\n");
+               return ret;
+       }
+
+       /* init sub_dais */
+       INIT_LIST_HEAD(&afe->sub_dais);
+
+       for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+               ret = dai_register_cbs[i](afe);
+               if (ret) {
+                       dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+                                i, ret);
+                       goto err_pm_disable;
+               }
+       }
+
+       /* init dai_driver and component_driver */
+       ret = mtk_afe_combine_sub_dai(afe);
+       if (ret) {
+               dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+                        ret);
+               goto err_pm_disable;
+       }
+
+       /* others */
+       afe->mtk_afe_hardware = &mt8192_afe_hardware;
+       afe->memif_fs = mt8192_memif_fs;
+       afe->irq_fs = mt8192_irq_fs;
+       afe->get_dai_fs = mt8192_get_dai_fs;
+       afe->get_memif_pbuf_size = mt8192_get_memif_pbuf_size;
+       afe->memif_32bit_supported = 1;
+
+       afe->runtime_resume = mt8192_afe_runtime_resume;
+       afe->runtime_suspend = mt8192_afe_runtime_suspend;
+
+       /* register platform */
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &mt8192_afe_component, NULL, 0);
+       if (ret) {
+               dev_warn(dev, "err_platform\n");
+               goto err_pm_disable;
+       }
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &mt8192_afe_pcm_component,
+                                             afe->dai_drivers,
+                                             afe->num_dai_drivers);
+       if (ret) {
+               dev_warn(dev, "err_dai_component\n");
+               goto err_pm_disable;
+       }
+
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
+static int mt8192_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               mt8192_afe_runtime_suspend(&pdev->dev);
+
+       /* disable afe clock */
+       mt8192_afe_disable_clock(afe);
+       return 0;
+}
+
+static const struct of_device_id mt8192_afe_pcm_dt_match[] = {
+       { .compatible = "mediatek,mt8192-audio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mt8192_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8192_afe_pm_ops = {
+       SET_RUNTIME_PM_OPS(mt8192_afe_runtime_suspend,
+                          mt8192_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8192_afe_pcm_driver = {
+       .driver = {
+                  .name = "mt8192-audio",
+                  .of_match_table = mt8192_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+                  .pm = &mt8192_afe_pm_ops,
+#endif
+       },
+       .probe = mt8192_afe_pcm_dev_probe,
+       .remove = mt8192_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8192_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8192");
+MODULE_AUTHOR("Shane Chien <shane.chien@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
new file mode 100644 (file)
index 0000000..f040dce
--- /dev/null
@@ -0,0 +1,1471 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/delay.h>
+#include <linux/regmap.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+enum {
+       UL_IIR_SW = 0,
+       UL_IIR_5HZ,
+       UL_IIR_10HZ,
+       UL_IIR_25HZ,
+       UL_IIR_50HZ,
+       UL_IIR_75HZ,
+};
+
+enum {
+       AUDIO_SDM_LEVEL_MUTE = 0,
+       AUDIO_SDM_LEVEL_NORMAL = 0x1d,
+       /* if you change level normal */
+       /* you need to change formula of hp impedance and dc trim too */
+};
+
+enum {
+       AUDIO_SDM_2ND = 0,
+       AUDIO_SDM_3RD,
+};
+
+enum {
+       DELAY_DATA_MISO1 = 0,
+       DELAY_DATA_MISO2,
+};
+
+enum {
+       MTK_AFE_ADDA_DL_RATE_8K = 0,
+       MTK_AFE_ADDA_DL_RATE_11K = 1,
+       MTK_AFE_ADDA_DL_RATE_12K = 2,
+       MTK_AFE_ADDA_DL_RATE_16K = 3,
+       MTK_AFE_ADDA_DL_RATE_22K = 4,
+       MTK_AFE_ADDA_DL_RATE_24K = 5,
+       MTK_AFE_ADDA_DL_RATE_32K = 6,
+       MTK_AFE_ADDA_DL_RATE_44K = 7,
+       MTK_AFE_ADDA_DL_RATE_48K = 8,
+       MTK_AFE_ADDA_DL_RATE_96K = 9,
+       MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+       MTK_AFE_ADDA_UL_RATE_8K = 0,
+       MTK_AFE_ADDA_UL_RATE_16K = 1,
+       MTK_AFE_ADDA_UL_RATE_32K = 2,
+       MTK_AFE_ADDA_UL_RATE_48K = 3,
+       MTK_AFE_ADDA_UL_RATE_96K = 4,
+       MTK_AFE_ADDA_UL_RATE_192K = 5,
+       MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+#define SDM_AUTO_RESET_THRESHOLD 0x190000
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+                                          unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_ADDA_DL_RATE_8K;
+       case 11025:
+               return MTK_AFE_ADDA_DL_RATE_11K;
+       case 12000:
+               return MTK_AFE_ADDA_DL_RATE_12K;
+       case 16000:
+               return MTK_AFE_ADDA_DL_RATE_16K;
+       case 22050:
+               return MTK_AFE_ADDA_DL_RATE_22K;
+       case 24000:
+               return MTK_AFE_ADDA_DL_RATE_24K;
+       case 32000:
+               return MTK_AFE_ADDA_DL_RATE_32K;
+       case 44100:
+               return MTK_AFE_ADDA_DL_RATE_44K;
+       case 48000:
+               return MTK_AFE_ADDA_DL_RATE_48K;
+       case 96000:
+               return MTK_AFE_ADDA_DL_RATE_96K;
+       case 192000:
+               return MTK_AFE_ADDA_DL_RATE_192K;
+       default:
+               dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+                        __func__, rate);
+               return MTK_AFE_ADDA_DL_RATE_48K;
+       }
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+                                          unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_ADDA_UL_RATE_8K;
+       case 16000:
+               return MTK_AFE_ADDA_UL_RATE_16K;
+       case 32000:
+               return MTK_AFE_ADDA_UL_RATE_32K;
+       case 48000:
+               return MTK_AFE_ADDA_UL_RATE_48K;
+       case 96000:
+               return MTK_AFE_ADDA_UL_RATE_96K;
+       case 192000:
+               return MTK_AFE_ADDA_UL_RATE_192K;
+       default:
+               dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+                        __func__, rate);
+               return MTK_AFE_ADDA_UL_RATE_48K;
+       }
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN3, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN3_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN3_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN3_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN3_1, I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN3,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN3,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1", AFE_CONN3_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1", AFE_CONN3_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN4, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN4_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN4_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN4_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN4_1, I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN4,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN4,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2", AFE_CONN4_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2", AFE_CONN4_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN52, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN52, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN52, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN52, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN52_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN52_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN52_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN52,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN52,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN52,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN52,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN52,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN52,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN53, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN53, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN53, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN53, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN53, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN53, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN53, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN53_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN53_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN53_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN53,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN53,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN53,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN53,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN53,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN53,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN53,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN53,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_stf_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN19,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_stf_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN20,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+enum {
+       SUPPLY_SEQ_ADDA_AFE_ON,
+       SUPPLY_SEQ_ADDA_DL_ON,
+       SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+       SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+       SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+       SUPPLY_SEQ_ADDA_FIFO,
+       SUPPLY_SEQ_ADDA_AP_DMIC,
+       SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+       unsigned int reg;
+
+       switch (id) {
+       case MT8192_DAI_ADDA:
+       case MT8192_DAI_AP_DMIC:
+               reg = AFE_ADDA_UL_SRC_CON0;
+               break;
+       case MT8192_DAI_ADDA_CH34:
+       case MT8192_DAI_AP_DMIC_CH34:
+               reg = AFE_ADDA6_UL_SRC_CON0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* dmic mode, 3.25M*/
+       regmap_update_bits(afe->regmap, reg,
+                          DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
+                          0x0);
+       regmap_update_bits(afe->regmap, reg,
+                          DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
+                          0x0);
+
+       /* turn on dmic, ch1, ch2 */
+       regmap_update_bits(afe->regmap, reg,
+                          UL_SDM_3_LEVEL_CTL_MASK_SFT,
+                          0x1 << UL_SDM_3_LEVEL_CTL_SFT);
+       regmap_update_bits(afe->regmap, reg,
+                          UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+                          0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
+       regmap_update_bits(afe->regmap, reg,
+                          UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+                          0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
+       return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+       dev_info(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+                __func__, w->name, event, mtkaif_dmic);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1);
+
+               /* update setting to dmic */
+               if (mtkaif_dmic) {
+                       /* mtkaif_rxif_data_mode = 1, dmic */
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+                                          0x1, 0x1);
+
+                       /* dmic mode, 3.25M*/
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+                                          MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
+                                          0x0);
+                       mtk_adda_ul_src_dmic(afe, MT8192_DAI_ADDA);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+               usleep_range(125, 135);
+               mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_ch34_ul_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol,
+                                 int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int mtkaif_dmic = afe_priv->mtkaif_dmic_ch34;
+       int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only;
+
+       dev_info(afe->dev,
+                "%s(), name %s, event 0x%x, mtkaif_dmic %d, mtkaif_adda6_only %d\n",
+                __func__, w->name, event, mtkaif_dmic, mtkaif_adda6_only);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34,
+                                       1);
+
+               /* update setting to dmic */
+               if (mtkaif_dmic) {
+                       /* mtkaif_rxif_data_mode = 1, dmic */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA6_MTKAIF_RX_CFG0,
+                                          0x1, 0x1);
+
+                       /* dmic mode, 3.25M*/
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA6_MTKAIF_RX_CFG0,
+                                          MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
+                                          0x0);
+                       mtk_adda_ul_src_dmic(afe, MT8192_DAI_ADDA_CH34);
+               }
+
+               /* when using adda6 without adda enabled,
+                * RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT need to be set or
+                * data cannot be received.
+                */
+               if (mtkaif_adda6_only) {
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_SYNCWORD_CFG,
+                                          0x1 << 23, 0x1 << 23);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+               usleep_range(125, 135);
+               mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34,
+                                       1);
+
+               /* reset dmic */
+               afe_priv->mtkaif_dmic_ch34 = 0;
+
+               if (mtkaif_adda6_only) {
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_SYNCWORD_CFG,
+                                          0x1 << 23, 0x0 << 23);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol,
+                                 int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+                       regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38);
+               else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
+                       regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30);
+               else
+                       regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
+                                    struct snd_kcontrol *kcontrol,
+                                    int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int delay_data;
+       int delay_cycle;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+                       /* set protocol 2 */
+                       regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+                                    0x00010000);
+                       regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
+                                    0x00010000);
+
+                       if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 &&
+                           (afe_priv->mtkaif_chosen_phase[0] < 0 ||
+                            afe_priv->mtkaif_chosen_phase[1] < 0)) {
+                               dev_warn(afe->dev,
+                                        "%s(), mtkaif_chosen_phase[0/1]:%d/%d\n",
+                                        __func__,
+                                        afe_priv->mtkaif_chosen_phase[0],
+                                        afe_priv->mtkaif_chosen_phase[1]);
+                               break;
+                       } else if (strcmp(w->name, "ADDA6_MTKAIF_CFG") == 0 &&
+                                  afe_priv->mtkaif_chosen_phase[2] < 0) {
+                               dev_warn(afe->dev,
+                                        "%s(), mtkaif_chosen_phase[2]:%d\n",
+                                        __func__,
+                                        afe_priv->mtkaif_chosen_phase[2]);
+                               break;
+                       }
+
+                       /* mtkaif_rxif_clkinv_adc inverse for calibration */
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+                                          MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
+                                          0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT);
+                       regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
+                                          MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
+                                          0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT);
+
+                       /* set delay for ch12 */
+                       if (afe_priv->mtkaif_phase_cycle[0] >=
+                           afe_priv->mtkaif_phase_cycle[1]) {
+                               delay_data = DELAY_DATA_MISO1;
+                               delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
+                                             afe_priv->mtkaif_phase_cycle[1];
+                       } else {
+                               delay_data = DELAY_DATA_MISO2;
+                               delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+                                             afe_priv->mtkaif_phase_cycle[0];
+                       }
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_RX_CFG2,
+                                          MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
+                                          delay_data <<
+                                          MTKAIF_RXIF_DELAY_DATA_SFT);
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_RX_CFG2,
+                                          MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
+                                          delay_cycle <<
+                                          MTKAIF_RXIF_DELAY_CYCLE_SFT);
+
+                       /* set delay between ch3 and ch2 */
+                       if (afe_priv->mtkaif_phase_cycle[2] >=
+                           afe_priv->mtkaif_phase_cycle[1]) {
+                               delay_data = DELAY_DATA_MISO1;  /* ch3 */
+                               delay_cycle = afe_priv->mtkaif_phase_cycle[2] -
+                                             afe_priv->mtkaif_phase_cycle[1];
+                       } else {
+                               delay_data = DELAY_DATA_MISO2;  /* ch2 */
+                               delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+                                             afe_priv->mtkaif_phase_cycle[2];
+                       }
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA6_MTKAIF_RX_CFG2,
+                                          MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
+                                          delay_data <<
+                                          MTKAIF_RXIF_DELAY_DATA_SFT);
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA6_MTKAIF_RX_CFG2,
+                                          MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
+                                          delay_cycle <<
+                                          MTKAIF_RXIF_DELAY_CYCLE_SFT);
+               } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+                       regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+                                    0x00010000);
+                       regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
+                                    0x00010000);
+               } else {
+                       regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0);
+                       regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0, 0x0);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
+                __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+               usleep_range(125, 135);
+               mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_ch34_dl_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol,
+                                 int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
+                __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34,
+                                       0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+               usleep_range(125, 135);
+               mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34,
+                                       0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/* stf */
+static int stf_positive_gain_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->stf_positive_gain_db;
+       return 0;
+}
+
+static int stf_positive_gain_set(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int gain_db = ucontrol->value.integer.value[0];
+
+       afe_priv->stf_positive_gain_db = gain_db;
+
+       if (gain_db >= 0 && gain_db <= 24) {
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_GAIN,
+                                  POSITIVE_GAIN_MASK_SFT,
+                                  (gain_db / 6) << POSITIVE_GAIN_SFT);
+       } else {
+               dev_warn(afe->dev, "%s(), gain_db %d invalid\n",
+                        __func__, gain_db);
+       }
+       return 0;
+}
+
+static int mt8192_adda_dmic_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+       return 0;
+}
+
+static int mt8192_adda_dmic_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int dmic_on;
+
+       dmic_on = ucontrol->value.integer.value[0];
+
+       dev_info(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+                __func__, kcontrol->id.name, dmic_on);
+
+       afe_priv->mtkaif_dmic = dmic_on;
+       afe_priv->mtkaif_dmic_ch34 = dmic_on;
+       return 0;
+}
+
+static int mt8192_adda6_only_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->mtkaif_adda6_only;
+       return 0;
+}
+
+static int mt8192_adda6_only_set(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int mtkaif_adda6_only;
+
+       mtkaif_adda6_only = ucontrol->value.integer.value[0];
+
+       dev_info(afe->dev, "%s(), kcontrol name %s, mtkaif_adda6_only %d\n",
+                __func__, kcontrol->id.name, mtkaif_adda6_only);
+
+       afe_priv->mtkaif_adda6_only = mtkaif_adda6_only;
+       return 0;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+       SOC_SINGLE("Sidetone_Gain", AFE_SIDETONE_GAIN,
+                  SIDE_TONE_GAIN_SFT, SIDE_TONE_GAIN_MASK, 0),
+       SOC_SINGLE_EXT("Sidetone_Positive_Gain_dB", SND_SOC_NOPM, 0, 100, 0,
+                      stf_positive_gain_get, stf_positive_gain_set),
+       SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
+                  DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0),
+       SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+                           mt8192_adda_dmic_get, mt8192_adda_dmic_set),
+       SOC_SINGLE_BOOL_EXT("MTKAIF_ADDA6_ONLY Switch", 0,
+                           mt8192_adda6_only_get, mt8192_adda6_only_set),
+};
+
+static const struct snd_kcontrol_new stf_ctl =
+       SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const u16 stf_coeff_table_16k[] = {
+       0x049C, 0x09E8, 0x09E0, 0x089C,
+       0xFF54, 0xF488, 0xEAFC, 0xEBAC,
+       0xfA40, 0x17AC, 0x3D1C, 0x6028,
+       0x7538
+};
+
+static const u16 stf_coeff_table_32k[] = {
+       0xFE52, 0x0042, 0x00C5, 0x0194,
+       0x029A, 0x03B7, 0x04BF, 0x057D,
+       0x05BE, 0x0555, 0x0426, 0x0230,
+       0xFF92, 0xFC89, 0xF973, 0xF6C6,
+       0xF500, 0xF49D, 0xF603, 0xF970,
+       0xFEF3, 0x065F, 0x0F4F, 0x1928,
+       0x2329, 0x2C80, 0x345E, 0x3A0D,
+       0x3D08
+};
+
+static const u16 stf_coeff_table_48k[] = {
+       0x0401, 0xFFB0, 0xFF5A, 0xFECE,
+       0xFE10, 0xFD28, 0xFC21, 0xFB08,
+       0xF9EF, 0xF8E8, 0xF80A, 0xF76C,
+       0xF724, 0xF746, 0xF7E6, 0xF90F,
+       0xFACC, 0xFD1E, 0xFFFF, 0x0364,
+       0x0737, 0x0B62, 0x0FC1, 0x1431,
+       0x188A, 0x1CA4, 0x2056, 0x237D,
+       0x25F9, 0x27B0, 0x2890
+};
+
+static int mtk_stf_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol,
+                        int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       size_t half_tap_num;
+       const u16 *stf_coeff_table;
+       unsigned int ul_rate, reg_value;
+       size_t coef_addr;
+
+       regmap_read(afe->regmap, AFE_ADDA_UL_SRC_CON0, &ul_rate);
+       ul_rate = ul_rate >> UL_VOICE_MODE_CH1_CH2_CTL_SFT;
+       ul_rate = ul_rate & UL_VOICE_MODE_CH1_CH2_CTL_MASK;
+
+       if (ul_rate == MTK_AFE_ADDA_UL_RATE_48K) {
+               half_tap_num = ARRAY_SIZE(stf_coeff_table_48k);
+               stf_coeff_table = stf_coeff_table_48k;
+       } else if (ul_rate == MTK_AFE_ADDA_UL_RATE_32K) {
+               half_tap_num = ARRAY_SIZE(stf_coeff_table_32k);
+               stf_coeff_table = stf_coeff_table_32k;
+       } else {
+               half_tap_num = ARRAY_SIZE(stf_coeff_table_16k);
+               stf_coeff_table = stf_coeff_table_16k;
+       }
+
+       regmap_read(afe->regmap, AFE_SIDETONE_CON1, &reg_value);
+
+       dev_info(afe->dev, "%s(), name %s, event 0x%x, ul_rate 0x%x, AFE_SIDETONE_CON1 0x%x\n",
+                __func__, w->name, event, ul_rate, reg_value);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* set side tone gain = 0 */
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_GAIN,
+                                  SIDE_TONE_GAIN_MASK_SFT,
+                                  0);
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_GAIN,
+                                  POSITIVE_GAIN_MASK_SFT,
+                                  0);
+               /* don't bypass stf */
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_CON1,
+                                  0x1f << 27,
+                                  0x0);
+               /* set stf half tap num */
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_CON1,
+                                  SIDE_TONE_HALF_TAP_NUM_MASK_SFT,
+                                  half_tap_num << SIDE_TONE_HALF_TAP_NUM_SFT);
+
+               /* set side tone coefficient */
+               regmap_read(afe->regmap, AFE_SIDETONE_CON0, &reg_value);
+               for (coef_addr = 0; coef_addr < half_tap_num; coef_addr++) {
+                       bool old_w_ready = (reg_value >> W_RDY_SFT) & 0x1;
+                       bool new_w_ready = 0;
+                       int try_cnt = 0;
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_SIDETONE_CON0,
+                                          0x39FFFFF,
+                                          (1 << R_W_EN_SFT) |
+                                          (1 << R_W_SEL_SFT) |
+                                          (0 << SEL_CH2_SFT) |
+                                          (coef_addr <<
+                                          SIDE_TONE_COEFFICIENT_ADDR_SFT) |
+                                          stf_coeff_table[coef_addr]);
+
+                       /* wait until flag write_ready changed */
+                       for (try_cnt = 0; try_cnt < 10; try_cnt++) {
+                               regmap_read(afe->regmap,
+                                           AFE_SIDETONE_CON0, &reg_value);
+                               new_w_ready = (reg_value >> W_RDY_SFT) & 0x1;
+
+                               /* flip => ok */
+                               if (new_w_ready == old_w_ready) {
+                                       udelay(3);
+                                       if (try_cnt == 9) {
+                                               dev_warn(afe->dev,
+                                                        "%s(), write coeff not ready",
+                                                        __func__);
+                                       }
+                               } else {
+                                       break;
+                               }
+                       }
+                       /* need write -> read -> write to write next coeff */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_SIDETONE_CON0,
+                                          R_W_SEL_MASK_SFT,
+                                          0x0);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* bypass stf */
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_CON1,
+                                  0x1f << 27,
+                                  0x1f << 27);
+
+               /* set side tone gain = 0 */
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_GAIN,
+                                  SIDE_TONE_GAIN_MASK_SFT,
+                                  0);
+               regmap_update_bits(afe->regmap,
+                                  AFE_SIDETONE_GAIN,
+                                  POSITIVE_GAIN_MASK_SFT,
+                                  0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/* stf mux */
+enum {
+       STF_SRC_ADDA_ADDA6 = 0,
+       STF_SRC_O19O20,
+};
+
+static const char *const stf_o19o20_mux_map[] = {
+       "ADDA_ADDA6",
+       "O19O20",
+};
+
+static int stf_o19o20_mux_map_value[] = {
+       STF_SRC_ADDA_ADDA6,
+       STF_SRC_O19O20,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(stf_o19o20_mux_map_enum,
+                                 AFE_SIDETONE_CON1,
+                                 STF_SOURCE_FROM_O19O20_SFT,
+                                 STF_SOURCE_FROM_O19O20_MASK,
+                                 stf_o19o20_mux_map,
+                                 stf_o19o20_mux_map_value);
+
+static const struct snd_kcontrol_new stf_o19O20_mux_control =
+       SOC_DAPM_ENUM("STF_O19O20_MUX", stf_o19o20_mux_map_enum);
+
+enum {
+       STF_SRC_ADDA = 0,
+       STF_SRC_ADDA6,
+};
+
+static const char *const stf_adda_mux_map[] = {
+       "ADDA",
+       "ADDA6",
+};
+
+static int stf_adda_mux_map_value[] = {
+       STF_SRC_ADDA,
+       STF_SRC_ADDA6,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(stf_adda_mux_map_enum,
+                                 AFE_SIDETONE_CON1,
+                                 STF_O19O20_OUT_EN_SEL_SFT,
+                                 STF_O19O20_OUT_EN_SEL_MASK,
+                                 stf_adda_mux_map,
+                                 stf_adda_mux_map_value);
+
+static const struct snd_kcontrol_new stf_adda_mux_control =
+       SOC_DAPM_ENUM("STF_ADDA_MUX", stf_adda_mux_map_enum);
+
+/* ADDA UL MUX */
+enum {
+       ADDA_UL_MUX_MTKAIF = 0,
+       ADDA_UL_MUX_AP_DMIC,
+       ADDA_UL_MUX_MASK = 0x1,
+};
+
+static const char * const adda_ul_mux_map[] = {
+       "MTKAIF", "AP_DMIC"
+};
+
+static int adda_ul_map_value[] = {
+       ADDA_UL_MUX_MTKAIF,
+       ADDA_UL_MUX_AP_DMIC,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+                                 SND_SOC_NOPM,
+                                 0,
+                                 ADDA_UL_MUX_MASK,
+                                 adda_ul_mux_map,
+                                 adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+       SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
+       SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_adda_dl_ch1_mix,
+                          ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+       SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_adda_dl_ch2_mix,
+                          ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0,
+                          mtk_adda_dl_ch3_mix,
+                          ARRAY_SIZE(mtk_adda_dl_ch3_mix)),
+       SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0,
+                          mtk_adda_dl_ch4_mix,
+                          ARRAY_SIZE(mtk_adda_dl_ch4_mix)),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+                             AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
+                             NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+                             AFE_ADDA_DL_SRC2_CON0,
+                             DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
+                             mtk_adda_dl_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Playback Enable",
+                             SUPPLY_SEQ_ADDA_DL_ON,
+                             AFE_ADDA_3RD_DAC_DL_SRC2_CON0,
+                             DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
+                             mtk_adda_ch34_dl_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+                             AFE_ADDA_UL_SRC_CON0,
+                             UL_SRC_ON_TMP_CTL_SFT, 0,
+                             mtk_adda_ul_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+                             AFE_ADDA6_UL_SRC_CON0,
+                             UL_SRC_ON_TMP_CTL_SFT, 0,
+                             mtk_adda_ch34_ul_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+                             AFE_AUD_PAD_TOP,
+                             RG_RX_FIFO_ON_SFT, 0,
+                             mtk_adda_pad_top_event,
+                             SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_adda_mtkaif_cfg_event,
+                             SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_adda_mtkaif_cfg_event,
+                             SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+                             AFE_ADDA_UL_SRC_CON0,
+                             UL_AP_DMIC_ON_SFT, 0,
+                             NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+                             AFE_ADDA6_UL_SRC_CON0,
+                             UL_AP_DMIC_ON_SFT, 0,
+                             NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+                             AFE_ADDA_UL_DL_CON0,
+                             AFE_ADDA_FIFO_AUTO_RST_SFT, 1,
+                             NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+                             AFE_ADDA_UL_DL_CON0,
+                             AFE_ADDA6_FIFO_AUTO_RST_SFT, 1,
+                             NULL, 0),
+
+       SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+                        &adda_ul_mux_control),
+       SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0,
+                        &adda_ch34_ul_mux_control),
+
+       SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+       SND_SOC_DAPM_INPUT("AP_DMIC_CH34_INPUT"),
+
+       /* stf */
+       SND_SOC_DAPM_SWITCH_E("Sidetone Filter",
+                             AFE_SIDETONE_CON1, SIDE_TONE_ON_SFT, 0,
+                             &stf_ctl,
+                             mtk_stf_event,
+                             SND_SOC_DAPM_PRE_PMU |
+                             SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("STF_O19O20_MUX", SND_SOC_NOPM, 0, 0,
+                        &stf_o19O20_mux_control),
+       SND_SOC_DAPM_MUX("STF_ADDA_MUX", SND_SOC_NOPM, 0, 0,
+                        &stf_adda_mux_control),
+       SND_SOC_DAPM_MIXER("STF_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_stf_ch1_mix,
+                          ARRAY_SIZE(mtk_stf_ch1_mix)),
+       SND_SOC_DAPM_MIXER("STF_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_stf_ch2_mix,
+                          ARRAY_SIZE(mtk_stf_ch2_mix)),
+       SND_SOC_DAPM_OUTPUT("STF_OUTPUT"),
+
+       /* clock */
+       SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"),
+
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_3rd_dac_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_3rd_dac_predis_clk"),
+
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_adda6_adc_clk"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+       /* playback */
+       {"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+       {"ADDA_DL_CH2", "DL1_CH1", "DL1"},
+       {"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+       {"ADDA_DL_CH1", "DL12_CH1", "DL12"},
+       {"ADDA_DL_CH2", "DL12_CH2", "DL12"},
+
+       {"ADDA_DL_CH1", "DL6_CH1", "DL6"},
+       {"ADDA_DL_CH2", "DL6_CH2", "DL6"},
+
+       {"ADDA_DL_CH1", "DL8_CH1", "DL8"},
+       {"ADDA_DL_CH2", "DL8_CH2", "DL8"},
+
+       {"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+       {"ADDA_DL_CH2", "DL2_CH1", "DL2"},
+       {"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+       {"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+       {"ADDA_DL_CH2", "DL3_CH1", "DL3"},
+       {"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+       {"ADDA_DL_CH1", "DL4_CH1", "DL4"},
+       {"ADDA_DL_CH2", "DL4_CH2", "DL4"},
+
+       {"ADDA_DL_CH1", "DL5_CH1", "DL5"},
+       {"ADDA_DL_CH2", "DL5_CH2", "DL5"},
+
+       {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+       {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+       {"ADDA Playback", NULL, "ADDA Enable"},
+       {"ADDA Playback", NULL, "ADDA Playback Enable"},
+
+       {"ADDA_DL_CH3", "DL1_CH1", "DL1"},
+       {"ADDA_DL_CH4", "DL1_CH1", "DL1"},
+       {"ADDA_DL_CH4", "DL1_CH2", "DL1"},
+
+       {"ADDA_DL_CH3", "DL12_CH1", "DL12"},
+       {"ADDA_DL_CH4", "DL12_CH2", "DL12"},
+
+       {"ADDA_DL_CH3", "DL6_CH1", "DL6"},
+       {"ADDA_DL_CH4", "DL6_CH2", "DL6"},
+
+       {"ADDA_DL_CH3", "DL2_CH1", "DL2"},
+       {"ADDA_DL_CH4", "DL2_CH1", "DL2"},
+       {"ADDA_DL_CH4", "DL2_CH2", "DL2"},
+
+       {"ADDA_DL_CH3", "DL3_CH1", "DL3"},
+       {"ADDA_DL_CH4", "DL3_CH1", "DL3"},
+       {"ADDA_DL_CH4", "DL3_CH2", "DL3"},
+
+       {"ADDA_DL_CH3", "DL4_CH1", "DL4"},
+       {"ADDA_DL_CH4", "DL4_CH2", "DL4"},
+
+       {"ADDA_DL_CH3", "DL5_CH1", "DL5"},
+       {"ADDA_DL_CH4", "DL5_CH2", "DL5"},
+
+       {"ADDA CH34 Playback", NULL, "ADDA_DL_CH3"},
+       {"ADDA CH34 Playback", NULL, "ADDA_DL_CH4"},
+
+       {"ADDA CH34 Playback", NULL, "ADDA Enable"},
+       {"ADDA CH34 Playback", NULL, "ADDA CH34 Playback Enable"},
+
+       /* capture */
+       {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+       {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+
+       {"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"},
+       {"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
+
+       {"ADDA Capture", NULL, "ADDA Enable"},
+       {"ADDA Capture", NULL, "ADDA Capture Enable"},
+       {"ADDA Capture", NULL, "AUD_PAD_TOP"},
+       {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+
+       {"AP DMIC Capture", NULL, "ADDA Enable"},
+       {"AP DMIC Capture", NULL, "ADDA Capture Enable"},
+       {"AP DMIC Capture", NULL, "ADDA_FIFO"},
+       {"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+
+       {"ADDA CH34 Capture", NULL, "ADDA Enable"},
+       {"ADDA CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+       {"ADDA CH34 Capture", NULL, "AUD_PAD_TOP"},
+       {"ADDA CH34 Capture", NULL, "ADDA6_MTKAIF_CFG"},
+
+       {"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
+       {"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+       {"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"},
+       {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
+
+       {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+       {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"},
+
+       /* sidetone filter */
+       {"STF_ADDA_MUX", "ADDA", "ADDA_UL_Mux"},
+       {"STF_ADDA_MUX", "ADDA6", "ADDA_CH34_UL_Mux"},
+
+       {"STF_O19O20_MUX", "ADDA_ADDA6", "STF_ADDA_MUX"},
+       {"STF_O19O20_MUX", "O19O20", "STF_CH1"},
+       {"STF_O19O20_MUX", "O19O20", "STF_CH2"},
+
+       {"Sidetone Filter", "Switch", "STF_O19O20_MUX"},
+       {"STF_OUTPUT", NULL, "Sidetone Filter"},
+       {"ADDA Playback", NULL, "Sidetone Filter"},
+       {"ADDA CH34 Playback", NULL, "Sidetone Filter"},
+
+       /* clk */
+       {"ADDA Playback", NULL, "aud_dac_clk"},
+       {"ADDA Playback", NULL, "aud_dac_predis_clk"},
+
+       {"ADDA CH34 Playback", NULL, "aud_3rd_dac_clk"},
+       {"ADDA CH34 Playback", NULL, "aud_3rd_dac_predis_clk"},
+
+       {"ADDA Capture Enable", NULL, "aud_adc_clk"},
+       {"ADDA CH34 Capture Enable", NULL, "aud_adda6_adc_clk"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       int id = dai->id;
+
+       dev_info(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+                __func__,
+                id,
+                substream->stream,
+                rate);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               unsigned int dl_src2_con0 = 0;
+               unsigned int dl_src2_con1 = 0;
+
+               /* set sampling rate */
+               dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+                              DL_2_INPUT_MODE_CTL_SFT;
+
+               /* set output mode, UP_SAMPLING_RATE_X8 */
+               dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT);
+
+               /* turn off mute function */
+               dl_src2_con0 |= (0x01 << DL_2_MUTE_CH2_OFF_CTL_PRE_SFT);
+               dl_src2_con0 |= (0x01 << DL_2_MUTE_CH1_OFF_CTL_PRE_SFT);
+
+               /* set voice input data if input sample rate is 8k or 16k */
+               if (rate == 8000 || rate == 16000)
+                       dl_src2_con0 |= 0x01 << DL_2_VOICE_MODE_CTL_PRE_SFT;
+
+               /* SA suggest apply -0.3db to audio/speech path */
+               dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+                              DL_2_GAIN_CTL_PRE_SFT;
+
+               /* turn on down-link gain */
+               dl_src2_con0 |= (0x01 << DL_2_GAIN_ON_CTL_PRE_SFT);
+
+               if (id == MT8192_DAI_ADDA) {
+                       /* clean predistortion */
+                       regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+                       regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
+
+                       /* set sdm gain */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_DCCOMP_CON,
+                                          ATTGAIN_CTL_MASK_SFT,
+                                          AUDIO_SDM_LEVEL_NORMAL <<
+                                          ATTGAIN_CTL_SFT);
+
+                       /* 2nd sdm */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_DCCOMP_CON,
+                                          USE_3RD_SDM_MASK_SFT,
+                                          AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
+
+                       /* sdm auto reset */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+                                    SDM_AUTO_RESET_THRESHOLD);
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+                                          ADDA_SDM_AUTO_RESET_ONOFF_MASK_SFT,
+                                          0x1 << ADDA_SDM_AUTO_RESET_ONOFF_SFT);
+               } else {
+                       /* clean predistortion */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_3RD_DAC_PREDIS_CON0, 0);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_3RD_DAC_PREDIS_CON1, 0);
+
+                       regmap_write(afe->regmap, AFE_ADDA_3RD_DAC_DL_SRC2_CON0,
+                                    dl_src2_con0);
+                       regmap_write(afe->regmap, AFE_ADDA_3RD_DAC_DL_SRC2_CON1,
+                                    dl_src2_con1);
+
+                       /* set sdm gain */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON,
+                                          ATTGAIN_CTL_MASK_SFT,
+                                          AUDIO_SDM_LEVEL_NORMAL <<
+                                          ATTGAIN_CTL_SFT);
+
+                       /* 2nd sdm */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON,
+                                          USE_3RD_SDM_MASK_SFT,
+                                          AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
+
+                       /* sdm auto reset */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON,
+                                    SDM_AUTO_RESET_THRESHOLD);
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON,
+                                          ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK_SFT,
+                                          0x1 << ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_SFT);
+               }
+       } else {
+               unsigned int voice_mode = 0;
+               unsigned int ul_src_con0 = 0;   /* default value */
+
+               voice_mode = adda_ul_rate_transform(afe, rate);
+
+               ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+               /* enable iir */
+               ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+                              UL_IIR_ON_TMP_CTL_MASK_SFT;
+               ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+                              UL_IIRMODE_CTL_MASK_SFT;
+
+               switch (id) {
+               case MT8192_DAI_ADDA:
+               case MT8192_DAI_AP_DMIC:
+                       /* 35Hz @ 48k */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_02_01, 0x00000000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_04_03, 0x00003FB8);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_06_05, 0x3FB80000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_08_07, 0x3FB80000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_10_09, 0x0000C048);
+
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_UL_SRC_CON0, ul_src_con0);
+
+                       /* Using Internal ADC */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_TOP_CON0,
+                                          0x1 << 0,
+                                          0x0 << 0);
+
+                       /* mtkaif_rxif_data_mode = 0, amic */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_RX_CFG0,
+                                          0x1 << 0,
+                                          0x0 << 0);
+                       break;
+               case MT8192_DAI_ADDA_CH34:
+               case MT8192_DAI_AP_DMIC_CH34:
+                       /* 35Hz @ 48k */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA6_IIR_COEF_02_01, 0x00000000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA6_IIR_COEF_04_03, 0x00003FB8);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA6_IIR_COEF_06_05, 0x3FB80000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA6_IIR_COEF_08_07, 0x3FB80000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA6_IIR_COEF_10_09, 0x0000C048);
+
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA6_UL_SRC_CON0, ul_src_con0);
+
+                       /* Using Internal ADC */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA6_TOP_CON0,
+                                          0x1 << 0,
+                                          0x0 << 0);
+
+                       /* mtkaif_rxif_data_mode = 0, amic */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA6_MTKAIF_RX_CFG0,
+                                          0x1 << 0,
+                                          0x0 << 0);
+                       break;
+               default:
+                       break;
+               }
+
+               /* ap dmic */
+               switch (id) {
+               case MT8192_DAI_AP_DMIC:
+               case MT8192_DAI_AP_DMIC_CH34:
+                       mtk_adda_ul_src_dmic(afe, id);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+       .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                                SNDRV_PCM_RATE_96000 |\
+                                SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+                               SNDRV_PCM_RATE_16000 |\
+                               SNDRV_PCM_RATE_32000 |\
+                               SNDRV_PCM_RATE_48000 |\
+                               SNDRV_PCM_RATE_96000 |\
+                               SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                         SNDRV_PCM_FMTBIT_S24_LE |\
+                         SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+       {
+               .name = "ADDA",
+               .id = MT8192_DAI_ADDA,
+               .playback = {
+                       .stream_name = "ADDA Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_PLAYBACK_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ADDA Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_CAPTURE_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .ops = &mtk_dai_adda_ops,
+       },
+       {
+               .name = "ADDA_CH34",
+               .id = MT8192_DAI_ADDA_CH34,
+               .playback = {
+                       .stream_name = "ADDA CH34 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_PLAYBACK_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ADDA CH34 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_CAPTURE_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .ops = &mtk_dai_adda_ops,
+       },
+       {
+               .name = "AP_DMIC",
+               .id = MT8192_DAI_AP_DMIC,
+               .capture = {
+                       .stream_name = "AP DMIC Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_CAPTURE_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .ops = &mtk_dai_adda_ops,
+       },
+       {
+               .name = "AP_DMIC_CH34",
+               .id = MT8192_DAI_AP_DMIC_CH34,
+               .capture = {
+                       .stream_name = "AP DMIC CH34 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_CAPTURE_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .ops = &mtk_dai_adda_ops,
+       },
+};
+
+int mt8192_dai_adda_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_adda_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+       dai->controls = mtk_adda_controls;
+       dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+       dai->dapm_widgets = mtk_dai_adda_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+       dai->dapm_routes = mtk_dai_adda_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+       /* ap dmic priv share with adda */
+       afe_priv->dai_priv[MT8192_DAI_AP_DMIC] =
+               afe_priv->dai_priv[MT8192_DAI_ADDA];
+       afe_priv->dai_priv[MT8192_DAI_AP_DMIC_CH34] =
+               afe_priv->dai_priv[MT8192_DAI_ADDA_CH34];
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c
new file mode 100644 (file)
index 0000000..5b29340
--- /dev/null
@@ -0,0 +1,2110 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+enum {
+       I2S_FMT_EIAJ = 0,
+       I2S_FMT_I2S = 1,
+};
+
+enum {
+       I2S_WLEN_16_BIT = 0,
+       I2S_WLEN_32_BIT = 1,
+};
+
+enum {
+       I2S_HD_NORMAL = 0,
+       I2S_HD_LOW_JITTER = 1,
+};
+
+enum {
+       I2S1_SEL_O28_O29 = 0,
+       I2S1_SEL_O03_O04 = 1,
+};
+
+enum {
+       I2S_IN_PAD_CONNSYS = 0,
+       I2S_IN_PAD_IO_MUX = 1,
+};
+
+struct mtk_afe_i2s_priv {
+       int id;
+       int rate; /* for determine which apll to use */
+       int low_jitter_en;
+
+       const char *share_property_name;
+       int share_i2s_id;
+
+       int mclk_id;
+       int mclk_rate;
+       int mclk_apll;
+};
+
+static unsigned int get_i2s_wlen(snd_pcm_format_t format)
+{
+       return snd_pcm_format_physical_width(format) <= 16 ?
+              I2S_WLEN_16_BIT : I2S_WLEN_32_BIT;
+}
+
+#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux"
+#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux"
+#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux"
+#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux"
+#define MTK_AFE_I2S5_KCONTROL_NAME "I2S5_HD_Mux"
+#define MTK_AFE_I2S6_KCONTROL_NAME "I2S6_HD_Mux"
+#define MTK_AFE_I2S7_KCONTROL_NAME "I2S7_HD_Mux"
+#define MTK_AFE_I2S8_KCONTROL_NAME "I2S8_HD_Mux"
+#define MTK_AFE_I2S9_KCONTROL_NAME "I2S9_HD_Mux"
+
+#define I2S0_HD_EN_W_NAME "I2S0_HD_EN"
+#define I2S1_HD_EN_W_NAME "I2S1_HD_EN"
+#define I2S2_HD_EN_W_NAME "I2S2_HD_EN"
+#define I2S3_HD_EN_W_NAME "I2S3_HD_EN"
+#define I2S5_HD_EN_W_NAME "I2S5_HD_EN"
+#define I2S6_HD_EN_W_NAME "I2S6_HD_EN"
+#define I2S7_HD_EN_W_NAME "I2S7_HD_EN"
+#define I2S8_HD_EN_W_NAME "I2S8_HD_EN"
+#define I2S9_HD_EN_W_NAME "I2S9_HD_EN"
+
+#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN"
+#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN"
+#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN"
+#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN"
+#define I2S5_MCLK_EN_W_NAME "I2S5_MCLK_EN"
+#define I2S6_MCLK_EN_W_NAME "I2S6_MCLK_EN"
+#define I2S7_MCLK_EN_W_NAME "I2S7_MCLK_EN"
+#define I2S8_MCLK_EN_W_NAME "I2S8_MCLK_EN"
+#define I2S9_MCLK_EN_W_NAME "I2S9_MCLK_EN"
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+                             const char *name)
+{
+       if (strncmp(name, "I2S0", 4) == 0)
+               return MT8192_DAI_I2S_0;
+       else if (strncmp(name, "I2S1", 4) == 0)
+               return MT8192_DAI_I2S_1;
+       else if (strncmp(name, "I2S2", 4) == 0)
+               return MT8192_DAI_I2S_2;
+       else if (strncmp(name, "I2S3", 4) == 0)
+               return MT8192_DAI_I2S_3;
+       else if (strncmp(name, "I2S5", 4) == 0)
+               return MT8192_DAI_I2S_5;
+       else if (strncmp(name, "I2S6", 4) == 0)
+               return MT8192_DAI_I2S_6;
+       else if (strncmp(name, "I2S7", 4) == 0)
+               return MT8192_DAI_I2S_7;
+       else if (strncmp(name, "I2S8", 4) == 0)
+               return MT8192_DAI_I2S_8;
+       else if (strncmp(name, "I2S9", 4) == 0)
+               return MT8192_DAI_I2S_9;
+       else
+               return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+                                                    const char *name)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_i2s_id_by_name(afe, name);
+
+       if (dai_id < 0)
+               return NULL;
+
+       return afe_priv->dai_priv[dai_id];
+}
+
+/* low jitter control */
+static const char * const mt8192_i2s_hd_str[] = {
+       "Normal", "Low_Jitter"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(mt8192_i2s_enum, mt8192_i2s_hd_str);
+
+static int mt8192_i2s_hd_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en;
+
+       return 0;
+}
+
+static int mt8192_i2s_hd_set(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int hd_en;
+
+       if (ucontrol->value.enumerated.item[0] >= e->items)
+               return -EINVAL;
+
+       hd_en = ucontrol->value.integer.value[0];
+
+       dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+               __func__, kcontrol->id.name, hd_en);
+
+       i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       i2s_priv->low_jitter_en = hd_en;
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+       SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S5_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S6_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S7_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S8_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S9_KCONTROL_NAME, mt8192_i2s_enum,
+                    mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+};
+
+/* dai component */
+/* i2s virtual mux to output widget */
+static const char * const i2s_mux_map[] = {
+       "Normal", "Dummy_Widget",
+};
+
+static int i2s_mux_map_value[] = {
+       0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum,
+                                             SND_SOC_NOPM,
+                                             0,
+                                             1,
+                                             i2s_mux_map,
+                                             i2s_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_in_mux_control =
+       SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s8_in_mux_control =
+       SOC_DAPM_ENUM("I2S8 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s1_out_mux_control =
+       SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s3_out_mux_control =
+       SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s5_out_mux_control =
+       SOC_DAPM_ENUM("I2S5 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s7_out_mux_control =
+       SOC_DAPM_ENUM("I2S7 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s9_out_mux_control =
+       SOC_DAPM_ENUM("I2S9 Out Select", i2s_mux_map_enum);
+
+/* Tinyconn Mux */
+enum {
+       TINYCONN_CH1_MUX_DL1 = 0x0,
+       TINYCONN_CH2_MUX_DL1 = 0x1,
+       TINYCONN_CH1_MUX_DL12 = 0x2,
+       TINYCONN_CH2_MUX_DL12 = 0x3,
+       TINYCONN_CH1_MUX_DL2 = 0x4,
+       TINYCONN_CH2_MUX_DL2 = 0x5,
+       TINYCONN_CH1_MUX_DL3 = 0x6,
+       TINYCONN_CH2_MUX_DL3 = 0x7,
+       TINYCONN_MUX_NONE = 0x1f,
+};
+
+static const char * const tinyconn_mux_map[] = {
+       "NONE",
+       "DL1_CH1",
+       "DL1_CH2",
+       "DL12_CH1",
+       "DL12_CH2",
+       "DL2_CH1",
+       "DL2_CH2",
+       "DL3_CH1",
+       "DL3_CH2",
+};
+
+static int tinyconn_mux_map_value[] = {
+       TINYCONN_MUX_NONE,
+       TINYCONN_CH1_MUX_DL1,
+       TINYCONN_CH2_MUX_DL1,
+       TINYCONN_CH1_MUX_DL12,
+       TINYCONN_CH2_MUX_DL12,
+       TINYCONN_CH1_MUX_DL2,
+       TINYCONN_CH2_MUX_DL2,
+       TINYCONN_CH1_MUX_DL3,
+       TINYCONN_CH2_MUX_DL3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s1_tinyconn_ch1_mux_map_enum,
+                                 AFE_TINY_CONN5,
+                                 O_20_CFG_SFT,
+                                 O_20_CFG_MASK,
+                                 tinyconn_mux_map,
+                                 tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s1_tinyconn_ch1_mux_control =
+       SOC_DAPM_ENUM("i2s1 ch1 tinyconn Select",
+                     i2s1_tinyconn_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s1_tinyconn_ch2_mux_map_enum,
+                                 AFE_TINY_CONN5,
+                                 O_21_CFG_SFT,
+                                 O_21_CFG_MASK,
+                                 tinyconn_mux_map,
+                                 tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s1_tinyconn_ch2_mux_control =
+       SOC_DAPM_ENUM("i2s1 ch2 tinyconn Select",
+                     i2s1_tinyconn_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s3_tinyconn_ch1_mux_map_enum,
+                                 AFE_TINY_CONN5,
+                                 O_22_CFG_SFT,
+                                 O_22_CFG_MASK,
+                                 tinyconn_mux_map,
+                                 tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s3_tinyconn_ch1_mux_control =
+       SOC_DAPM_ENUM("i2s3 ch1 tinyconn Select",
+                     i2s3_tinyconn_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s3_tinyconn_ch2_mux_map_enum,
+                                 AFE_TINY_CONN5,
+                                 O_23_CFG_SFT,
+                                 O_23_CFG_MASK,
+                                 tinyconn_mux_map,
+                                 tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s3_tinyconn_ch2_mux_control =
+       SOC_DAPM_ENUM("i2s3 ch2 tinyconn Select",
+                     i2s3_tinyconn_ch2_mux_map_enum);
+
+/* i2s in lpbk */
+static const char * const i2s_lpbk_mux_map[] = {
+       "Normal", "Lpbk",
+};
+
+static int i2s_lpbk_mux_map_value[] = {
+       0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum,
+                                             AFE_I2S_CON,
+                                             I2S_LOOPBACK_SFT,
+                                             1,
+                                             i2s_lpbk_mux_map,
+                                             i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_lpbk_mux_control =
+       SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum,
+                                             AFE_I2S_CON2,
+                                             I2S3_LOOPBACK_SFT,
+                                             1,
+                                             i2s_lpbk_mux_map,
+                                             i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s2_lpbk_mux_control =
+       SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum);
+
+/* interconnection */
+static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN0, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN0, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN0, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN0, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN0_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN0_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN0_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN0_1, I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN0_1, I_DL9_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN0,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN0,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN0,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN0,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN0,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN0,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN1, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN1, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN1, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN1, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN1_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN1_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN1_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN1_1, I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN1_1, I_DL9_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN1,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN1,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN1,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN1,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN1,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN1,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN1,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN1,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN28, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN28, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN28, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN28, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN28_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN28_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN28_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN28_1, I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN28_1, I_DL9_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN28,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN28,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN28,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN28,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN29, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN29, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN29, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN29, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN29_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN29_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN29_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN29_1, I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN29_1, I_DL9_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN29,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN29,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN29,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN29,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN29,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN29,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s5_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN30, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN30, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN30, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN30, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN30_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN30_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN30_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN30_1, I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN30_1, I_DL9_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN30,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN30,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN30,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN30,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s5_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN31, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN31, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN31, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN31, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN31_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN31_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN31_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN31_1, I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN31_1, I_DL9_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN31,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN31,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN31,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN31,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN31,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN31,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s7_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN54, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN54, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN54, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN54, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN54_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN54_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN54_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN54_1, I_DL9_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN54,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN54,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN54,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN54,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s7_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN55, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN55, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN55, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN55, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN55_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN55_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN55_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN55_1, I_DL9_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN55,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN55,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN55,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN55,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN55,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN55,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s9_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN56, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN56, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN56, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN56, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN56_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN56_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN56_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN56_1, I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN56_1, I_DL9_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN56,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN56,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN56,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN56,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s9_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN57, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN57, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN57, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN57, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN57_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN57_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN57_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN57_1, I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN57_1, I_DL9_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN57,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN57,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN57,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN57,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN57,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN57,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+};
+
+enum {
+       SUPPLY_SEQ_APLL,
+       SUPPLY_SEQ_I2S_MCLK_EN,
+       SUPPLY_SEQ_I2S_HD_EN,
+       SUPPLY_SEQ_I2S_EN,
+};
+
+static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_afe_gpio_request(afe->dev, true, i2s_priv->id, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               mt8192_afe_gpio_request(afe->dev, false, i2s_priv->id, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_apll_event(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (strcmp(w->name, APLL1_W_NAME) == 0)
+                       mt8192_apll1_enable(afe);
+               else
+                       mt8192_apll2_enable(afe);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (strcmp(w->name, APLL1_W_NAME) == 0)
+                       mt8192_apll1_disable(afe);
+               else
+                       mt8192_apll2_disable(afe);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int i2s_out_tinyconn_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol,
+                                 int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int reg;
+       unsigned int reg_shift;
+       unsigned int reg_mask_shift;
+
+       dev_dbg(afe->dev, "%s(), event 0x%x\n", __func__, event);
+
+       if (strstr(w->name, "I2S1")) {
+               reg = AFE_I2S_CON1;
+               reg_shift = I2S2_32BIT_EN_SFT;
+               reg_mask_shift = I2S2_32BIT_EN_MASK_SFT;
+       } else if (strstr(w->name, "I2S3")) {
+               reg = AFE_I2S_CON3;
+               reg_shift = I2S4_32BIT_EN_SFT;
+               reg_mask_shift = I2S4_32BIT_EN_MASK_SFT;
+       } else if (strstr(w->name, "I2S5")) {
+               reg = AFE_I2S_CON4;
+               reg_shift = I2S5_32BIT_EN_SFT;
+               reg_mask_shift = I2S5_32BIT_EN_MASK_SFT;
+       } else if (strstr(w->name, "I2S7")) {
+               reg = AFE_I2S_CON7;
+               reg_shift = I2S7_32BIT_EN_SFT;
+               reg_mask_shift = I2S7_32BIT_EN_MASK_SFT;
+       } else if (strstr(w->name, "I2S9")) {
+               reg = AFE_I2S_CON9;
+               reg_shift = I2S9_32BIT_EN_SFT;
+               reg_mask_shift = I2S9_32BIT_EN_MASK_SFT;
+       } else {
+               reg = AFE_I2S_CON1;
+               reg_shift = I2S2_32BIT_EN_SFT;
+               reg_mask_shift = I2S2_32BIT_EN_MASK_SFT;
+               dev_warn(afe->dev, "%s(), error widget name %s, use i2s1\n",
+                        __func__, w->name);
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               regmap_update_bits(afe->regmap, reg, reg_mask_shift,
+                                  0x1 << reg_shift);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_update_bits(afe->regmap, reg, reg_mask_shift,
+                                  0x0 << reg_shift);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               i2s_priv->mclk_rate = 0;
+               mt8192_mck_disable(afe, i2s_priv->mclk_id);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+       SND_SOC_DAPM_INPUT("CONNSYS"),
+
+       SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s1_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s1_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s1_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s1_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s3_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s3_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s3_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s3_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("I2S5_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s5_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s5_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S5_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s5_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s5_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("I2S7_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s7_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s7_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S7_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s7_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s7_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("I2S9_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s9_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s9_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S9_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s9_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s9_ch2_mix)),
+
+       SND_SOC_DAPM_MUX_E("I2S1_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0,
+                          &i2s1_tinyconn_ch1_mux_control,
+                          i2s_out_tinyconn_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MUX_E("I2S1_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0,
+                          &i2s1_tinyconn_ch2_mux_control,
+                          i2s_out_tinyconn_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MUX_E("I2S3_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0,
+                          &i2s3_tinyconn_ch1_mux_control,
+                          i2s_out_tinyconn_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_MUX_E("I2S3_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0,
+                          &i2s3_tinyconn_ch2_mux_control,
+                          i2s_out_tinyconn_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       /* i2s en*/
+       SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON1, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON2, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON3, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S5_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON4, I2S5_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S6_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON6, I2S6_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S7_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON7, I2S7_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S8_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON8, I2S8_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S9_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON9, I2S9_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       /* i2s hd en */
+       SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON, I2S1_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S5_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON4, I2S5_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S6_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON6, I2S6_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S7_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON7, I2S7_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S8_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON8, I2S8_HD_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S(I2S9_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON9, I2S9_HD_EN_SFT, 0, NULL, 0),
+
+       /* i2s mclk en */
+       SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S5_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S6_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S7_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S8_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S9_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* apll */
+       SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_apll_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_apll_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* allow i2s on without codec on */
+       SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"),
+       SND_SOC_DAPM_MUX("I2S1_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control),
+       SND_SOC_DAPM_MUX("I2S3_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control),
+       SND_SOC_DAPM_MUX("I2S5_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s5_out_mux_control),
+       SND_SOC_DAPM_MUX("I2S7_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s7_out_mux_control),
+       SND_SOC_DAPM_MUX("I2S9_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s9_out_mux_control),
+
+       SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"),
+       SND_SOC_DAPM_MUX("I2S0_In_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control),
+       SND_SOC_DAPM_MUX("I2S8_In_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s8_in_mux_control),
+
+       /* i2s in lpbk */
+       SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control),
+       SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+                                    struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return 0;
+       }
+
+       if (i2s_priv->share_i2s_id < 0)
+               return 0;
+
+       return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name);
+}
+
+static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source,
+                                 struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return 0;
+       }
+
+       if (get_i2s_id_by_name(afe, sink->name) ==
+           get_i2s_id_by_name(afe, source->name))
+               return i2s_priv->low_jitter_en;
+
+       /* check if share i2s need hd en */
+       if (i2s_priv->share_i2s_id < 0)
+               return 0;
+
+       if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+               return i2s_priv->low_jitter_en;
+
+       return 0;
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+       int cur_apll;
+       int i2s_need_apll;
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return 0;
+       }
+
+       /* which apll */
+       cur_apll = mt8192_get_apll_by_name(afe, source->name);
+
+       /* choose APLL from i2s rate */
+       i2s_need_apll = mt8192_get_apll_by_rate(afe, i2s_priv->rate);
+
+       if (i2s_need_apll == cur_apll)
+               return 1;
+
+       return 0;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return 0;
+       }
+
+       if (get_i2s_id_by_name(afe, sink->name) ==
+           get_i2s_id_by_name(afe, source->name))
+               return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+       /* check if share i2s need mclk */
+       if (i2s_priv->share_i2s_id < 0)
+               return 0;
+
+       if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+               return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+       return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+                                    struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+       int cur_apll;
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return 0;
+       }
+
+       /* which apll */
+       cur_apll = mt8192_get_apll_by_name(afe, source->name);
+
+       if (i2s_priv->mclk_apll == cur_apll)
+               return 1;
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+       {"Connsys I2S", NULL, "CONNSYS"},
+
+       /* i2s0 */
+       {"I2S0", NULL, "I2S0_EN"},
+       {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s1 */
+       {"I2S1_CH1", "DL1_CH1", "DL1"},
+       {"I2S1_CH2", "DL1_CH2", "DL1"},
+       {"I2S1_TINYCONN_CH1_MUX", "DL1_CH1", "DL1"},
+       {"I2S1_TINYCONN_CH2_MUX", "DL1_CH2", "DL1"},
+
+       {"I2S1_CH1", "DL2_CH1", "DL2"},
+       {"I2S1_CH2", "DL2_CH2", "DL2"},
+       {"I2S1_TINYCONN_CH1_MUX", "DL2_CH1", "DL2"},
+       {"I2S1_TINYCONN_CH2_MUX", "DL2_CH2", "DL2"},
+
+       {"I2S1_CH1", "DL3_CH1", "DL3"},
+       {"I2S1_CH2", "DL3_CH2", "DL3"},
+       {"I2S1_TINYCONN_CH1_MUX", "DL3_CH1", "DL3"},
+       {"I2S1_TINYCONN_CH2_MUX", "DL3_CH2", "DL3"},
+
+       {"I2S1_CH1", "DL12_CH1", "DL12"},
+       {"I2S1_CH2", "DL12_CH2", "DL12"},
+       {"I2S1_TINYCONN_CH1_MUX", "DL12_CH1", "DL12"},
+       {"I2S1_TINYCONN_CH2_MUX", "DL12_CH2", "DL12"},
+
+       {"I2S1_CH1", "DL4_CH1", "DL4"},
+       {"I2S1_CH2", "DL4_CH2", "DL4"},
+
+       {"I2S1_CH1", "DL5_CH1", "DL5"},
+       {"I2S1_CH2", "DL5_CH2", "DL5"},
+
+       {"I2S1_CH1", "DL6_CH1", "DL6"},
+       {"I2S1_CH2", "DL6_CH2", "DL6"},
+
+       {"I2S1_CH1", "DL8_CH1", "DL8"},
+       {"I2S1_CH2", "DL8_CH2", "DL8"},
+
+       {"I2S1", NULL, "I2S1_CH1"},
+       {"I2S1", NULL, "I2S1_CH2"},
+       {"I2S1", NULL, "I2S3_TINYCONN_CH1_MUX"},
+       {"I2S1", NULL, "I2S3_TINYCONN_CH2_MUX"},
+
+       {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S1_EN"},
+       {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s2 */
+       {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S2_EN"},
+       {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s3 */
+       {"I2S3_CH1", "DL1_CH1", "DL1"},
+       {"I2S3_CH2", "DL1_CH2", "DL1"},
+       {"I2S3_TINYCONN_CH1_MUX", "DL1_CH1", "DL1"},
+       {"I2S3_TINYCONN_CH2_MUX", "DL1_CH2", "DL1"},
+
+       {"I2S3_CH1", "DL2_CH1", "DL2"},
+       {"I2S3_CH2", "DL2_CH2", "DL2"},
+       {"I2S3_TINYCONN_CH1_MUX", "DL2_CH1", "DL2"},
+       {"I2S3_TINYCONN_CH2_MUX", "DL2_CH2", "DL2"},
+
+       {"I2S3_CH1", "DL3_CH1", "DL3"},
+       {"I2S3_CH2", "DL3_CH2", "DL3"},
+       {"I2S3_TINYCONN_CH1_MUX", "DL3_CH1", "DL3"},
+       {"I2S3_TINYCONN_CH2_MUX", "DL3_CH2", "DL3"},
+
+       {"I2S3_CH1", "DL12_CH1", "DL12"},
+       {"I2S3_CH2", "DL12_CH2", "DL12"},
+       {"I2S3_TINYCONN_CH1_MUX", "DL12_CH1", "DL12"},
+       {"I2S3_TINYCONN_CH2_MUX", "DL12_CH2", "DL12"},
+
+       {"I2S3_CH1", "DL4_CH1", "DL4"},
+       {"I2S3_CH2", "DL4_CH2", "DL4"},
+
+       {"I2S3_CH1", "DL5_CH1", "DL5"},
+       {"I2S3_CH2", "DL5_CH2", "DL5"},
+
+       {"I2S3_CH1", "DL6_CH1", "DL6"},
+       {"I2S3_CH2", "DL6_CH2", "DL6"},
+
+       {"I2S3_CH1", "DL8_CH1", "DL8"},
+       {"I2S3_CH2", "DL8_CH2", "DL8"},
+
+       {"I2S3", NULL, "I2S3_CH1"},
+       {"I2S3", NULL, "I2S3_CH2"},
+       {"I2S3", NULL, "I2S3_TINYCONN_CH1_MUX"},
+       {"I2S3", NULL, "I2S3_TINYCONN_CH2_MUX"},
+
+       {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S3_EN"},
+       {"I2S3", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s5 */
+       {"I2S5_CH1", "DL1_CH1", "DL1"},
+       {"I2S5_CH2", "DL1_CH2", "DL1"},
+
+       {"I2S5_CH1", "DL2_CH1", "DL2"},
+       {"I2S5_CH2", "DL2_CH2", "DL2"},
+
+       {"I2S5_CH1", "DL3_CH1", "DL3"},
+       {"I2S5_CH2", "DL3_CH2", "DL3"},
+
+       {"I2S5_CH1", "DL12_CH1", "DL12"},
+       {"I2S5_CH2", "DL12_CH2", "DL12"},
+
+       {"I2S5_CH1", "DL4_CH1", "DL4"},
+       {"I2S5_CH2", "DL4_CH2", "DL4"},
+
+       {"I2S5_CH1", "DL5_CH1", "DL5"},
+       {"I2S5_CH2", "DL5_CH2", "DL5"},
+
+       {"I2S5_CH1", "DL6_CH1", "DL6"},
+       {"I2S5_CH2", "DL6_CH2", "DL6"},
+
+       {"I2S5_CH1", "DL8_CH1", "DL8"},
+       {"I2S5_CH2", "DL8_CH2", "DL8"},
+
+       {"I2S5", NULL, "I2S5_CH1"},
+       {"I2S5", NULL, "I2S5_CH2"},
+
+       {"I2S5", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S5_EN"},
+       {"I2S5", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S5", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S5", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S5", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S5_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S5_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S5", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S5", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S5_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S5_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s6 */
+       {"I2S6", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S6_EN"},
+       {"I2S6", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S6", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S6", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S6", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S6_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S6_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S6", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S6", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S6_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S6_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s7 */
+       {"I2S7", NULL, "I2S7_CH1"},
+       {"I2S7", NULL, "I2S7_CH2"},
+
+       {"I2S7", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S7_EN"},
+       {"I2S7", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S7", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S7", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S7", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S7_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S7_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S7", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S7", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S7_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S7_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s8 */
+       {"I2S8", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S8", NULL, "I2S8_EN"},
+       {"I2S8", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S8", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S8", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S8_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S8_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S8", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S8", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S8_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S8_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s9 */
+       {"I2S9_CH1", "DL1_CH1", "DL1"},
+       {"I2S9_CH2", "DL1_CH2", "DL1"},
+
+       {"I2S9_CH1", "DL2_CH1", "DL2"},
+       {"I2S9_CH2", "DL2_CH2", "DL2"},
+
+       {"I2S9_CH1", "DL3_CH1", "DL3"},
+       {"I2S9_CH2", "DL3_CH2", "DL3"},
+
+       {"I2S9_CH1", "DL12_CH1", "DL12"},
+       {"I2S9_CH2", "DL12_CH2", "DL12"},
+
+       {"I2S9_CH1", "DL4_CH1", "DL4"},
+       {"I2S9_CH2", "DL4_CH2", "DL4"},
+
+       {"I2S9_CH1", "DL5_CH1", "DL5"},
+       {"I2S9_CH2", "DL5_CH2", "DL5"},
+
+       {"I2S9_CH1", "DL6_CH1", "DL6"},
+       {"I2S9_CH2", "DL6_CH2", "DL6"},
+
+       {"I2S9_CH1", "DL8_CH1", "DL8"},
+       {"I2S9_CH2", "DL8_CH2", "DL8"},
+
+       {"I2S9_CH1", "DL9_CH1", "DL9"},
+       {"I2S9_CH2", "DL9_CH2", "DL9"},
+
+       {"I2S9", NULL, "I2S9_CH1"},
+       {"I2S9", NULL, "I2S9_CH2"},
+
+       {"I2S9", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+       {"I2S9", NULL, "I2S9_EN"},
+
+       {"I2S9", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S9", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S9_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S9_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S9", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S9", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S9_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S9_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* allow i2s on without codec on */
+       {"I2S0", NULL, "I2S0_In_Mux"},
+       {"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+       {"I2S8", NULL, "I2S8_In_Mux"},
+       {"I2S8_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+       {"I2S1_Out_Mux", "Dummy_Widget", "I2S1"},
+       {"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"},
+
+       {"I2S3_Out_Mux", "Dummy_Widget", "I2S3"},
+       {"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"},
+
+       {"I2S5_Out_Mux", "Dummy_Widget", "I2S5"},
+       {"I2S_DUMMY_OUT", NULL, "I2S5_Out_Mux"},
+
+       {"I2S7_Out_Mux", "Dummy_Widget", "I2S7"},
+       {"I2S_DUMMY_OUT", NULL, "I2S7_Out_Mux"},
+
+       {"I2S9_Out_Mux", "Dummy_Widget", "I2S9"},
+       {"I2S_DUMMY_OUT", NULL, "I2S9_Out_Mux"},
+
+       /* i2s in lpbk */
+       {"I2S0_Lpbk_Mux", "Lpbk", "I2S3"},
+       {"I2S2_Lpbk_Mux", "Lpbk", "I2S1"},
+       {"I2S0", NULL, "I2S0_Lpbk_Mux"},
+       {"I2S2", NULL, "I2S2_Lpbk_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_connsys_i2s_hw_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *params,
+                                        struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8192_rate_transform(afe->dev,
+                                                     rate, dai->id);
+       unsigned int i2s_con = 0;
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+               __func__, dai->id, substream->stream, rate);
+
+       /* non-inverse, i2s mode, proxy mode, 16bits, from connsys */
+       i2s_con |= 0 << INV_PAD_CTRL_SFT;
+       i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+       i2s_con |= 1 << I2S_SRC_SFT;
+       i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT;
+       i2s_con |= 0 << I2SIN_PAD_SEL_SFT;
+       regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con);
+
+       /* use asrc */
+       regmap_update_bits(afe->regmap,
+                          AFE_CONNSYS_I2S_CON,
+                          I2S_BYPSRC_MASK_SFT,
+                          0x0 << I2S_BYPSRC_SFT);
+
+       /* proxy mode, set i2s for asrc */
+       regmap_update_bits(afe->regmap,
+                          AFE_CONNSYS_I2S_CON,
+                          I2S_MODE_MASK_SFT,
+                          rate_reg << I2S_MODE_SFT);
+
+       switch (rate) {
+       case 32000:
+               regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000);
+               break;
+       case 44100:
+               regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x001B9000);
+               break;
+       default:
+               regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x001E0000);
+               break;
+       }
+
+       /* Calibration setting */
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x00140000);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x00036000);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x0002FC00);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x00007EF4);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0x00FF5986);
+
+       /* 0:Stereo 1:Mono */
+       regmap_update_bits(afe->regmap,
+                          AFE_ASRC_2CH_CON2,
+                          CHSET_IS_MONO_MASK_SFT,
+                          0x0 << CHSET_IS_MONO_SFT);
+
+       return 0;
+}
+
+static int mtk_dai_connsys_i2s_trigger(struct snd_pcm_substream *substream,
+                                      int cmd, struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n",
+               __func__, cmd, substream->stream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               /* i2s enable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_CONNSYS_I2S_CON,
+                                  I2S_EN_MASK_SFT,
+                                  0x1 << I2S_EN_SFT);
+
+               /* calibrator enable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON5,
+                                  CALI_EN_MASK_SFT,
+                                  0x1 << CALI_EN_SFT);
+
+               /* asrc enable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON0,
+                                  CON0_CHSET_STR_CLR_MASK_SFT,
+                                  0x1 << CON0_CHSET_STR_CLR_SFT);
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON0,
+                                  CON0_ASM_ON_MASK_SFT,
+                                  0x1 << CON0_ASM_ON_SFT);
+
+               afe_priv->dai_on[dai->id] = true;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON0,
+                                  CON0_ASM_ON_MASK_SFT,
+                                  0 << CON0_ASM_ON_SFT);
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON5,
+                                  CALI_EN_MASK_SFT,
+                                  0 << CALI_EN_SFT);
+
+               /* i2s disable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_CONNSYS_I2S_CON,
+                                  I2S_EN_MASK_SFT,
+                                  0x0 << I2S_EN_SFT);
+
+               /* bypass asrc */
+               regmap_update_bits(afe->regmap,
+                                  AFE_CONNSYS_I2S_CON,
+                                  I2S_BYPSRC_MASK_SFT,
+                                  0x1 << I2S_BYPSRC_SFT);
+
+               afe_priv->dai_on[dai->id] = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = {
+       .hw_params = mtk_dai_connsys_i2s_hw_params,
+       .trigger = mtk_dai_connsys_i2s_trigger,
+};
+
+/* i2s */
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+                             struct snd_pcm_hw_params *params,
+                             int i2s_id)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id];
+
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8192_rate_transform(afe->dev,
+                                                     rate, i2s_id);
+       snd_pcm_format_t format = params_format(params);
+       unsigned int i2s_con = 0;
+       int ret = 0;
+
+       dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
+               __func__, i2s_id, rate, format);
+
+       if (i2s_priv)
+               i2s_priv->rate = rate;
+       else
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+
+       switch (i2s_id) {
+       case MT8192_DAI_I2S_0:
+               i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT;
+               i2s_con |= rate_reg << I2S_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_1:
+               i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT;
+               i2s_con |= rate_reg << I2S2_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_2:
+               i2s_con = 8 << I2S3_UPDATE_WORD_SFT;
+               i2s_con |= rate_reg << I2S3_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON2,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_3:
+               i2s_con = rate_reg << I2S4_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON3,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_5:
+               i2s_con = rate_reg << I2S5_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S5_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S5_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON4,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_6:
+               i2s_con = rate_reg << I2S6_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S6_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S6_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON6,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_7:
+               i2s_con = rate_reg << I2S7_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S7_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S7_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON7,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_8:
+               i2s_con = rate_reg << I2S8_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S8_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S8_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON8,
+                                  0xffffeffe, i2s_con);
+               break;
+       case MT8192_DAI_I2S_9:
+               i2s_con = rate_reg << I2S9_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S9_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S9_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON9,
+                                  0xffffeffe, i2s_con);
+               break;
+       default:
+               dev_warn(afe->dev, "%s(), id %d not support\n",
+                        __func__, i2s_id);
+               return -EINVAL;
+       }
+
+       /* set share i2s */
+       if (i2s_priv && i2s_priv->share_i2s_id >= 0)
+               ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+
+       return ret;
+}
+
+static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+       return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id];
+       int apll;
+       int apll_rate;
+
+       if (!i2s_priv) {
+               dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       if (dir != SND_SOC_CLOCK_OUT) {
+               dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+               return -EINVAL;
+       }
+
+       dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+       apll = mt8192_get_apll_by_rate(afe, freq);
+       apll_rate = mt8192_get_apll_rate(afe, apll);
+
+       if (freq > apll_rate) {
+               dev_warn(afe->dev, "%s(), freq > apll rate", __func__);
+               return -EINVAL;
+       }
+
+       if (apll_rate % freq != 0) {
+               dev_warn(afe->dev, "%s(), APLL can't gen freq Hz", __func__);
+               return -EINVAL;
+       }
+
+       i2s_priv->mclk_rate = freq;
+       i2s_priv->mclk_apll = apll;
+
+       if (i2s_priv->share_i2s_id > 0) {
+               struct mtk_afe_i2s_priv *share_i2s_priv;
+
+               share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+               if (!share_i2s_priv) {
+                       dev_warn(afe->dev, "%s(), share_i2s_priv = NULL",
+                                __func__);
+                       return -EINVAL;
+               }
+
+               share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+               share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+       .hw_params = mtk_dai_i2s_hw_params,
+       .set_sysclk = mtk_dai_i2s_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+       {
+               .name = "CONNSYS_I2S",
+               .id = MT8192_DAI_CONNSYS_I2S,
+               .capture = {
+                       .stream_name = "Connsys I2S",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_CONNSYS_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_connsys_i2s_ops,
+       },
+       {
+               .name = "I2S0",
+               .id = MT8192_DAI_I2S_0,
+               .capture = {
+                       .stream_name = "I2S0",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S1",
+               .id = MT8192_DAI_I2S_1,
+               .playback = {
+                       .stream_name = "I2S1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S2",
+               .id = MT8192_DAI_I2S_2,
+               .capture = {
+                       .stream_name = "I2S2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S3",
+               .id = MT8192_DAI_I2S_3,
+               .playback = {
+                       .stream_name = "I2S3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S5",
+               .id = MT8192_DAI_I2S_5,
+               .playback = {
+                       .stream_name = "I2S5",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S6",
+               .id = MT8192_DAI_I2S_6,
+               .capture = {
+                       .stream_name = "I2S6",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S7",
+               .id = MT8192_DAI_I2S_7,
+               .playback = {
+                       .stream_name = "I2S7",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S8",
+               .id = MT8192_DAI_I2S_8,
+               .capture = {
+                       .stream_name = "I2S8",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S9",
+               .id = MT8192_DAI_I2S_9,
+               .playback = {
+                       .stream_name = "I2S9",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       }
+};
+
+/* this enum is merely for mtk_afe_i2s_priv declare */
+enum {
+       DAI_I2S0 = 0,
+       DAI_I2S1,
+       DAI_I2S2,
+       DAI_I2S3,
+       DAI_I2S5,
+       DAI_I2S6,
+       DAI_I2S7,
+       DAI_I2S8,
+       DAI_I2S9,
+       DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8192_i2s_priv[DAI_I2S_NUM] = {
+       [DAI_I2S0] = {
+               .id = MT8192_DAI_I2S_0,
+               .mclk_id = MT8192_I2S0_MCK,
+               .share_property_name = "i2s0-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S1] = {
+               .id = MT8192_DAI_I2S_1,
+               .mclk_id = MT8192_I2S1_MCK,
+               .share_property_name = "i2s1-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S2] = {
+               .id = MT8192_DAI_I2S_2,
+               .mclk_id = MT8192_I2S2_MCK,
+               .share_property_name = "i2s2-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S3] = {
+               .id = MT8192_DAI_I2S_3,
+               .mclk_id = MT8192_I2S3_MCK,
+               .share_property_name = "i2s3-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S5] = {
+               .id = MT8192_DAI_I2S_5,
+               .mclk_id = MT8192_I2S5_MCK,
+               .share_property_name = "i2s5-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S6] = {
+               .id = MT8192_DAI_I2S_6,
+               .mclk_id = MT8192_I2S6_MCK,
+               .share_property_name = "i2s6-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S7] = {
+               .id = MT8192_DAI_I2S_7,
+               .mclk_id = MT8192_I2S7_MCK,
+               .share_property_name = "i2s7-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S8] = {
+               .id = MT8192_DAI_I2S_8,
+               .mclk_id = MT8192_I2S8_MCK,
+               .share_property_name = "i2s8-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S9] = {
+               .id = MT8192_DAI_I2S_9,
+               .mclk_id = MT8192_I2S9_MCK,
+               .share_property_name = "i2s9-share",
+               .share_i2s_id = -1,
+       },
+};
+
+static int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       const struct device_node *of_node = afe->dev->of_node;
+       const char *of_str;
+       const char *property_name;
+       struct mtk_afe_i2s_priv *i2s_priv;
+       int i;
+
+       for (i = 0; i < DAI_I2S_NUM; i++) {
+               i2s_priv = afe_priv->dai_priv[mt8192_i2s_priv[i].id];
+               property_name = mt8192_i2s_priv[i].share_property_name;
+               if (of_property_read_string(of_node, property_name, &of_str))
+                       continue;
+               i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str);
+       }
+
+       return 0;
+}
+
+static int mt8192_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < DAI_I2S_NUM; i++) {
+               ret = mt8192_dai_set_priv(afe, mt8192_i2s_priv[i].id,
+                                         sizeof(struct mtk_afe_i2s_priv),
+                                         &mt8192_i2s_priv[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int mt8192_dai_i2s_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+       int ret;
+
+       dev_dbg(afe->dev, "%s()\n", __func__);
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_i2s_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+       dai->controls = mtk_dai_i2s_controls;
+       dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+       dai->dapm_widgets = mtk_dai_i2s_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+       dai->dapm_routes = mtk_dai_i2s_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+       /* set all dai i2s private data */
+       ret = mt8192_dai_i2s_set_priv(afe);
+       if (ret)
+               return ret;
+
+       /* parse share i2s */
+       ret = mt8192_dai_i2s_get_share(afe);
+       if (ret)
+               return ret;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
new file mode 100644 (file)
index 0000000..6e94cfd
--- /dev/null
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8192-afe-common.h"
+#include "mt8192-interconnection.h"
+
+enum AUD_TX_LCH_RPT {
+       AUD_TX_LCH_RPT_NO_REPEAT = 0,
+       AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum AUD_VBT_16K_MODE {
+       AUD_VBT_16K_MODE_DISABLE = 0,
+       AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum AUD_EXT_MODEM {
+       AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+       AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum AUD_PCM_SYNC_TYPE {
+       /* bck sync length = 1 */
+       AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+       /* bck sync length = PCM_INTF_CON1[9:13] */
+       AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum AUD_BT_MODE {
+       AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+       AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum AUD_PCM_AFIFO_SRC {
+       /* slave mode & external modem uses different crystal */
+       AUD_PCM_AFIFO_ASRC = 0,
+       /* slave mode & external modem uses the same crystal */
+       AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum AUD_PCM_CLOCK_SOURCE {
+       AUD_PCM_CLOCK_MASTER_MODE = 0,
+       AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum AUD_PCM_WLEN {
+       AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+       AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum AUD_PCM_MODE {
+       AUD_PCM_MODE_PCM_MODE_8K = 0,
+       AUD_PCM_MODE_PCM_MODE_16K = 1,
+       AUD_PCM_MODE_PCM_MODE_32K = 2,
+       AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum AUD_PCM_FMT {
+       AUD_PCM_FMT_I2S = 0,
+       AUD_PCM_FMT_EIAJ = 1,
+       AUD_PCM_FMT_PCM_MODE_A = 2,
+       AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum AUD_BCLK_OUT_INV {
+       AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+       AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum AUD_PCM_EN {
+       AUD_PCM_EN_DISABLE = 0,
+       AUD_PCM_EN_ENABLE = 1
+};
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN7_1,
+                                   I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN8_1,
+                                   I_DL4_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN27,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN27,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN27,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN27,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN27_1,
+                                   I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN17,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN17,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN17_1,
+                                   I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN18,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN18,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN18_1,
+                                   I_DL4_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch3_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN23,
+                                   I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN24,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN24,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN24,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN24,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN24_1,
+                                   I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch5_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN25,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN25,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN25,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN25_1,
+                                   I_DL4_CH2, 1, 0),
+};
+
+static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
+                __func__, w->name, event);
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_1_playback_ch1_mix,
+                          ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
+       SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_1_playback_ch2_mix,
+                          ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
+       SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_1_playback_ch4_mix,
+                          ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
+       SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_2_playback_ch1_mix,
+                          ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
+       SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_2_playback_ch2_mix,
+                          ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
+       SND_SOC_DAPM_MIXER("PCM_2_PB_CH3", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_2_playback_ch3_mix,
+                          ARRAY_SIZE(mtk_pcm_2_playback_ch3_mix)),
+       SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_2_playback_ch4_mix,
+                          ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
+       SND_SOC_DAPM_MIXER("PCM_2_PB_CH5", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_2_playback_ch5_mix,
+                          ARRAY_SIZE(mtk_pcm_2_playback_ch5_mix)),
+
+       SND_SOC_DAPM_SUPPLY("PCM_1_EN",
+                           PCM_INTF_CON1, PCM_EN_SFT, 0,
+                           mtk_pcm_en_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY("PCM_2_EN",
+                           PCM2_INTF_CON, PCM2_EN_SFT, 0,
+                           mtk_pcm_en_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
+       SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
+       SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
+       SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+       {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
+       {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
+       {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
+       {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
+       {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
+       {"PCM 2 Playback", NULL, "PCM_2_PB_CH3"},
+       {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
+       {"PCM 2 Playback", NULL, "PCM_2_PB_CH5"},
+
+       {"PCM 1 Playback", NULL, "PCM_1_EN"},
+       {"PCM 2 Playback", NULL, "PCM_2_EN"},
+       {"PCM 1 Capture", NULL, "PCM_1_EN"},
+       {"PCM 2 Capture", NULL, "PCM_2_EN"},
+
+       {"AFE_TO_MD1", NULL, "PCM 2 Playback"},
+       {"AFE_TO_MD2", NULL, "PCM 1 Playback"},
+       {"PCM 2 Capture", NULL, "MD1_TO_AFE"},
+       {"PCM 1 Capture", NULL, "MD2_TO_AFE"},
+
+       {"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
+       {"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
+       {"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
+       {"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
+       {"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
+       {"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
+
+       {"PCM_1_PB_CH1", "DL4_CH1", "DL4"},
+       {"PCM_1_PB_CH2", "DL4_CH2", "DL4"},
+       {"PCM_1_PB_CH4", "DL4_CH1", "DL4"},
+       {"PCM_2_PB_CH1", "DL4_CH1", "DL4"},
+       {"PCM_2_PB_CH2", "DL4_CH2", "DL4"},
+       {"PCM_2_PB_CH4", "DL4_CH1", "DL4"},
+       {"PCM_1_PB_CH4", "I2S0_CH1", "I2S0"},
+       {"PCM_2_PB_CH4", "I2S2_CH1", "I2S2"},
+       {"PCM_2_PB_CH5", "DL1_CH2", "DL1"},
+       {"PCM_2_PB_CH5", "DL4_CH2", "DL4"},
+       {"PCM_2_PB_CH5", "I2S0_CH2", "I2S0"},
+       {"PCM_2_PB_CH5", "I2S2_CH2", "I2S2"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8192_rate_transform(afe->dev, rate, dai->id);
+       unsigned int pcm_con = 0;
+
+       dev_info(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
+                __func__,
+                dai->id,
+                substream->stream,
+                rate,
+                rate_reg,
+                dai->playback_widget->active,
+                dai->capture_widget->active);
+
+       if (dai->playback_widget->active || dai->capture_widget->active)
+               return 0;
+
+       switch (dai->id) {
+       case MT8192_DAI_PCM_1:
+               pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
+               pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
+               pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
+               pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
+               pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
+               pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
+               pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
+               pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
+               pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
+               pcm_con |= rate_reg << PCM_MODE_SFT;
+               pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
+
+               regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+                                  0xfffffffe, pcm_con);
+               break;
+       case MT8192_DAI_PCM_2:
+               pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
+               pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
+               pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
+               pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
+               pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
+               pcm_con |= rate_reg << PCM2_MODE_SFT;
+               pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
+
+               regmap_update_bits(afe->regmap, PCM2_INTF_CON,
+                                  0xfffffffe, pcm_con);
+               break;
+       default:
+               dev_warn(afe->dev, "%s(), id %d not support\n",
+                        __func__, dai->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+       .hw_params = mtk_dai_pcm_hw_params,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+                      SNDRV_PCM_RATE_16000 |\
+                      SNDRV_PCM_RATE_32000 |\
+                      SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+       {
+               .name = "PCM 1",
+               .id = MT8192_DAI_PCM_1,
+               .playback = {
+                       .stream_name = "PCM 1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "PCM 1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_dai_pcm_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+       {
+               .name = "PCM 2",
+               .id = MT8192_DAI_PCM_2,
+               .playback = {
+                       .stream_name = "PCM 2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "PCM 2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_dai_pcm_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+};
+
+int mt8192_dai_pcm_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_pcm_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+       dai->dapm_widgets = mtk_dai_pcm_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+       dai->dapm_routes = mtk_dai_pcm_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
new file mode 100644 (file)
index 0000000..8383536
--- /dev/null
@@ -0,0 +1,778 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI TDM Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+struct mtk_afe_tdm_priv {
+       int id;
+       int bck_id;
+       int bck_rate;
+       int tdm_out_mode;
+       int bck_invert;
+       int lck_invert;
+       int mclk_id;
+       int mclk_multiple; /* according to sample rate */
+       int mclk_rate;
+       int mclk_apll;
+};
+
+enum {
+       TDM_OUT_I2S = 0,
+       TDM_OUT_DSP_A = 1,
+       TDM_OUT_DSP_B = 2,
+};
+
+enum {
+       TDM_BCK_NON_INV = 0,
+       TDM_BCK_INV = 1,
+};
+
+enum {
+       TDM_LCK_NON_INV = 0,
+       TDM_LCK_INV = 1,
+};
+
+enum {
+       TDM_WLEN_16_BIT = 1,
+       TDM_WLEN_32_BIT = 2,
+};
+
+enum {
+       TDM_CHANNEL_BCK_16 = 0,
+       TDM_CHANNEL_BCK_24 = 1,
+       TDM_CHANNEL_BCK_32 = 2,
+};
+
+enum {
+       TDM_CHANNEL_NUM_2 = 0,
+       TDM_CHANNEL_NUM_4 = 1,
+       TDM_CHANNEL_NUM_8 = 2,
+};
+
+enum  {
+       TDM_CH_START_O30_O31 = 0,
+       TDM_CH_START_O32_O33,
+       TDM_CH_START_O34_O35,
+       TDM_CH_START_O36_O37,
+       TDM_CH_ZERO,
+};
+
+static unsigned int get_tdm_wlen(snd_pcm_format_t format)
+{
+       return snd_pcm_format_physical_width(format) <= 16 ?
+              TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
+}
+
+static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
+{
+       return snd_pcm_format_physical_width(format) <= 16 ?
+              TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
+}
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
+{
+       return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch(unsigned int ch)
+{
+       switch (ch) {
+       case 1:
+       case 2:
+               return TDM_CHANNEL_NUM_2;
+       case 3:
+       case 4:
+               return TDM_CHANNEL_NUM_4;
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+       default:
+               return TDM_CHANNEL_NUM_8;
+       }
+}
+
+static unsigned int get_tdm_ch_fixup(unsigned int channels)
+{
+       if (channels > 4)
+               return 8;
+       else if (channels > 2)
+               return 4;
+       else
+               return 2;
+}
+
+static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
+                                        unsigned int channels)
+{
+       if (mode == TDM_OUT_DSP_A || mode == TDM_OUT_DSP_B)
+               return get_tdm_ch_fixup(channels);
+       else
+               return 2;
+}
+
+/* interconnection */
+enum {
+       HDMI_CONN_CH0 = 0,
+       HDMI_CONN_CH1,
+       HDMI_CONN_CH2,
+       HDMI_CONN_CH3,
+       HDMI_CONN_CH4,
+       HDMI_CONN_CH5,
+       HDMI_CONN_CH6,
+       HDMI_CONN_CH7,
+};
+
+static const char *const hdmi_conn_mux_map[] = {
+       "CH0", "CH1", "CH2", "CH3",
+       "CH4", "CH5", "CH6", "CH7",
+};
+
+static int hdmi_conn_mux_map_value[] = {
+       HDMI_CONN_CH0,
+       HDMI_CONN_CH1,
+       HDMI_CONN_CH2,
+       HDMI_CONN_CH3,
+       HDMI_CONN_CH4,
+       HDMI_CONN_CH5,
+       HDMI_CONN_CH6,
+       HDMI_CONN_CH7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_0_SFT,
+                                 HDMI_O_0_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch0_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_1_SFT,
+                                 HDMI_O_1_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch1_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_2_SFT,
+                                 HDMI_O_2_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch2_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_3_SFT,
+                                 HDMI_O_3_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch3_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_4_SFT,
+                                 HDMI_O_4_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch4_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_5_SFT,
+                                 HDMI_O_5_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch5_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_6_SFT,
+                                 HDMI_O_6_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch6_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
+                                 AFE_HDMI_CONN0,
+                                 HDMI_O_7_SFT,
+                                 HDMI_O_7_MASK,
+                                 hdmi_conn_mux_map,
+                                 hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch7_mux_control =
+       SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
+
+enum {
+       SUPPLY_SEQ_APLL,
+       SUPPLY_SEQ_TDM_MCK_EN,
+       SUPPLY_SEQ_TDM_BCK_EN,
+       SUPPLY_SEQ_TDM_EN,
+};
+
+static int get_tdm_id_by_name(const char *name)
+{
+       return MT8192_DAI_TDM;
+}
+
+static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       if (!tdm_priv) {
+               dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+                __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_afe_gpio_request(afe->dev, true, tdm_priv->id, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               mt8192_afe_gpio_request(afe->dev, false, tdm_priv->id, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol,
+                               int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       if (!tdm_priv) {
+               dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       dev_info(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+                __func__, w->name, event, dai_id);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               mt8192_mck_disable(afe, tdm_priv->bck_id);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol,
+                               int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       if (!tdm_priv) {
+               dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       dev_info(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+                __func__, w->name, event, dai_id);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8192_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               tdm_priv->mclk_rate = 0;
+               mt8192_mck_disable(afe, tdm_priv->mclk_id);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+       SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch0_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch1_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch2_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch3_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch4_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch5_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch6_mux_control),
+       SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,
+                        &hdmi_ch7_mux_control),
+
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
+
+       SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN,
+                             AFE_TDM_CON1, TDM_EN_SFT, 0,
+                             mtk_tdm_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_tdm_bck_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_tdm_mck_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+       int cur_apll;
+
+       /* which apll */
+       cur_apll = mt8192_get_apll_by_name(afe, source->name);
+
+       return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+       {"HDMI_CH0_MUX", "CH0", "HDMI"},
+       {"HDMI_CH0_MUX", "CH1", "HDMI"},
+       {"HDMI_CH0_MUX", "CH2", "HDMI"},
+       {"HDMI_CH0_MUX", "CH3", "HDMI"},
+       {"HDMI_CH0_MUX", "CH4", "HDMI"},
+       {"HDMI_CH0_MUX", "CH5", "HDMI"},
+       {"HDMI_CH0_MUX", "CH6", "HDMI"},
+       {"HDMI_CH0_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH1_MUX", "CH0", "HDMI"},
+       {"HDMI_CH1_MUX", "CH1", "HDMI"},
+       {"HDMI_CH1_MUX", "CH2", "HDMI"},
+       {"HDMI_CH1_MUX", "CH3", "HDMI"},
+       {"HDMI_CH1_MUX", "CH4", "HDMI"},
+       {"HDMI_CH1_MUX", "CH5", "HDMI"},
+       {"HDMI_CH1_MUX", "CH6", "HDMI"},
+       {"HDMI_CH1_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH2_MUX", "CH0", "HDMI"},
+       {"HDMI_CH2_MUX", "CH1", "HDMI"},
+       {"HDMI_CH2_MUX", "CH2", "HDMI"},
+       {"HDMI_CH2_MUX", "CH3", "HDMI"},
+       {"HDMI_CH2_MUX", "CH4", "HDMI"},
+       {"HDMI_CH2_MUX", "CH5", "HDMI"},
+       {"HDMI_CH2_MUX", "CH6", "HDMI"},
+       {"HDMI_CH2_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH3_MUX", "CH0", "HDMI"},
+       {"HDMI_CH3_MUX", "CH1", "HDMI"},
+       {"HDMI_CH3_MUX", "CH2", "HDMI"},
+       {"HDMI_CH3_MUX", "CH3", "HDMI"},
+       {"HDMI_CH3_MUX", "CH4", "HDMI"},
+       {"HDMI_CH3_MUX", "CH5", "HDMI"},
+       {"HDMI_CH3_MUX", "CH6", "HDMI"},
+       {"HDMI_CH3_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH4_MUX", "CH0", "HDMI"},
+       {"HDMI_CH4_MUX", "CH1", "HDMI"},
+       {"HDMI_CH4_MUX", "CH2", "HDMI"},
+       {"HDMI_CH4_MUX", "CH3", "HDMI"},
+       {"HDMI_CH4_MUX", "CH4", "HDMI"},
+       {"HDMI_CH4_MUX", "CH5", "HDMI"},
+       {"HDMI_CH4_MUX", "CH6", "HDMI"},
+       {"HDMI_CH4_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH5_MUX", "CH0", "HDMI"},
+       {"HDMI_CH5_MUX", "CH1", "HDMI"},
+       {"HDMI_CH5_MUX", "CH2", "HDMI"},
+       {"HDMI_CH5_MUX", "CH3", "HDMI"},
+       {"HDMI_CH5_MUX", "CH4", "HDMI"},
+       {"HDMI_CH5_MUX", "CH5", "HDMI"},
+       {"HDMI_CH5_MUX", "CH6", "HDMI"},
+       {"HDMI_CH5_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH6_MUX", "CH0", "HDMI"},
+       {"HDMI_CH6_MUX", "CH1", "HDMI"},
+       {"HDMI_CH6_MUX", "CH2", "HDMI"},
+       {"HDMI_CH6_MUX", "CH3", "HDMI"},
+       {"HDMI_CH6_MUX", "CH4", "HDMI"},
+       {"HDMI_CH6_MUX", "CH5", "HDMI"},
+       {"HDMI_CH6_MUX", "CH6", "HDMI"},
+       {"HDMI_CH6_MUX", "CH7", "HDMI"},
+
+       {"HDMI_CH7_MUX", "CH0", "HDMI"},
+       {"HDMI_CH7_MUX", "CH1", "HDMI"},
+       {"HDMI_CH7_MUX", "CH2", "HDMI"},
+       {"HDMI_CH7_MUX", "CH3", "HDMI"},
+       {"HDMI_CH7_MUX", "CH4", "HDMI"},
+       {"HDMI_CH7_MUX", "CH5", "HDMI"},
+       {"HDMI_CH7_MUX", "CH6", "HDMI"},
+       {"HDMI_CH7_MUX", "CH7", "HDMI"},
+
+       {"TDM", NULL, "HDMI_CH0_MUX"},
+       {"TDM", NULL, "HDMI_CH1_MUX"},
+       {"TDM", NULL, "HDMI_CH2_MUX"},
+       {"TDM", NULL, "HDMI_CH3_MUX"},
+       {"TDM", NULL, "HDMI_CH4_MUX"},
+       {"TDM", NULL, "HDMI_CH5_MUX"},
+       {"TDM", NULL, "HDMI_CH6_MUX"},
+       {"TDM", NULL, "HDMI_CH7_MUX"},
+
+       {"TDM", NULL, "aud_tdm_clk"},
+       {"TDM", NULL, "TDM_BCK"},
+       {"TDM", NULL, "TDM_EN"},
+       {"TDM_BCK", NULL, "TDM_MCK"},
+       {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+       {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+                               struct mtk_afe_tdm_priv *tdm_priv,
+                               int freq)
+{
+       int apll;
+       int apll_rate;
+
+       apll = mt8192_get_apll_by_rate(afe, freq);
+       apll_rate = mt8192_get_apll_rate(afe, apll);
+
+       if (!freq || freq > apll_rate) {
+               dev_warn(afe->dev,
+                        "%s(), freq(%d Hz) invalid\n", __func__, freq);
+               return -EINVAL;
+       }
+
+       if (apll_rate % freq != 0) {
+               dev_warn(afe->dev,
+                        "%s(), APLL cannot generate %d Hz", __func__, freq);
+               return -EINVAL;
+       }
+
+       tdm_priv->mclk_rate = freq;
+       tdm_priv->mclk_apll = apll;
+
+       return 0;
+}
+
+static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int tdm_id = dai->id;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
+       unsigned int tdm_out_mode = tdm_priv->tdm_out_mode;
+       unsigned int rate = params_rate(params);
+       unsigned int channels = params_channels(params);
+       unsigned int out_channels_per_sdata =
+               get_tdm_ch_per_sdata(tdm_out_mode, channels);
+       snd_pcm_format_t format = params_format(params);
+       unsigned int tdm_con = 0;
+
+       /* calculate mclk_rate, if not set explicitly */
+       if (!tdm_priv->mclk_rate) {
+               tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
+               mtk_dai_tdm_cal_mclk(afe,
+                                    tdm_priv,
+                                    tdm_priv->mclk_rate);
+       }
+
+       /* calculate bck */
+       tdm_priv->bck_rate = rate *
+                            out_channels_per_sdata *
+                            snd_pcm_format_physical_width(format);
+
+       if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
+               dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__);
+
+       if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
+               dev_warn(afe->dev, "%s(), bck cannot generate", __func__);
+
+       dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n",
+                __func__,
+                tdm_id, rate, channels, format,
+                tdm_priv->mclk_rate, tdm_priv->bck_rate);
+
+       dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n",
+                __func__, out_channels_per_sdata);
+
+       /* set tdm */
+       if (tdm_priv->bck_invert)
+               tdm_con |= 1 << BCK_INVERSE_SFT;
+
+       if (tdm_priv->lck_invert)
+               tdm_con |= 1 << LRCK_INVERSE_SFT;
+
+       if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) {
+               tdm_con |= 1 << DELAY_DATA_SFT;
+               tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
+       } else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_A) {
+               tdm_con |= 0 << DELAY_DATA_SFT;
+               tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
+       } else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_B) {
+               tdm_con |= 1 << DELAY_DATA_SFT;
+               tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
+       }
+
+       tdm_con |= 1 << LEFT_ALIGN_SFT;
+       tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
+       tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT;
+       tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
+       regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
+
+       if (out_channels_per_sdata == 2) {
+               switch (channels) {
+               case 1:
+               case 2:
+                       tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+                       tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
+                       tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+                       tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+                       break;
+               case 3:
+               case 4:
+                       tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+                       tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+                       tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+                       tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+                       break;
+               case 5:
+               case 6:
+                       tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+                       tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+                       tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+                       tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+                       break;
+               case 7:
+               case 8:
+                       tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+                       tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+                       tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+                       tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
+                       break;
+               default:
+                       tdm_con = 0;
+               }
+       } else {
+               tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+               tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
+               tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+               tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+       }
+
+       regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
+
+       regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+                          HDMI_CH_NUM_MASK_SFT,
+                          channels << HDMI_CH_NUM_SFT);
+       return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+       if (!tdm_priv) {
+               dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       if (dir != SND_SOC_CLOCK_OUT) {
+               dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+               return -EINVAL;
+       }
+
+       dev_info(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+       return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+       if (!tdm_priv) {
+               dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       /* DAI mode*/
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               tdm_priv->tdm_out_mode = TDM_OUT_I2S;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               tdm_priv->tdm_out_mode = TDM_OUT_DSP_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               tdm_priv->tdm_out_mode = TDM_OUT_DSP_B;
+               break;
+       default:
+               tdm_priv->tdm_out_mode = TDM_OUT_I2S;
+       }
+
+       /* DAI clock inversion*/
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               tdm_priv->bck_invert = TDM_BCK_NON_INV;
+               tdm_priv->lck_invert = TDM_LCK_NON_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               tdm_priv->bck_invert = TDM_BCK_NON_INV;
+               tdm_priv->lck_invert = TDM_LCK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               tdm_priv->bck_invert = TDM_BCK_INV;
+               tdm_priv->lck_invert = TDM_LCK_NON_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+       default:
+               tdm_priv->bck_invert = TDM_BCK_INV;
+               tdm_priv->lck_invert = TDM_LCK_INV;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+       .hw_params = mtk_dai_tdm_hw_params,
+       .set_sysclk = mtk_dai_tdm_set_sysclk,
+       .set_fmt = mtk_dai_tdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+       {
+               .name = "TDM",
+               .id = MT8192_DAI_TDM,
+               .playback = {
+                       .stream_name = "TDM",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MTK_TDM_RATES,
+                       .formats = MTK_TDM_FORMATS,
+               },
+               .ops = &mtk_dai_tdm_ops,
+       },
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
+{
+       struct mtk_afe_tdm_priv *tdm_priv;
+
+       tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+                               GFP_KERNEL);
+       if (!tdm_priv)
+               return NULL;
+
+       tdm_priv->mclk_multiple = 128;
+       tdm_priv->bck_id = MT8192_I2S4_BCK;
+       tdm_priv->mclk_id = MT8192_I2S4_MCK;
+       tdm_priv->id = MT8192_DAI_TDM;
+
+       return tdm_priv;
+}
+
+int mt8192_dai_tdm_register(struct mtk_base_afe *afe)
+{
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv;
+       struct mtk_base_afe_dai *dai;
+
+       dev_info(afe->dev, "%s()\n", __func__);
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_tdm_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+       dai->dapm_widgets = mtk_dai_tdm_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+       dai->dapm_routes = mtk_dai_tdm_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+       tdm_priv = init_tdm_priv_data(afe);
+       if (!tdm_priv)
+               return -ENOMEM;
+
+       afe_priv->dai_priv[MT8192_DAI_TDM] = tdm_priv;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-interconnection.h b/sound/soc/mediatek/mt8192/mt8192-interconnection.h
new file mode 100644 (file)
index 0000000..6a1bc7c
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek MT8192 audio driver interconnection definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_INTERCONNECTION_H_
+#define _MT8192_INTERCONNECTION_H_
+
+/* in port define */
+#define I_I2S0_CH1 0
+#define I_I2S0_CH2 1
+#define I_ADDA_UL_CH1 3
+#define I_ADDA_UL_CH2 4
+#define I_DL1_CH1 5
+#define I_DL1_CH2 6
+#define I_DL2_CH1 7
+#define I_DL2_CH2 8
+#define I_PCM_1_CAP_CH1 9
+#define I_GAIN1_OUT_CH1 10
+#define I_GAIN1_OUT_CH2 11
+#define I_GAIN2_OUT_CH1 12
+#define I_GAIN2_OUT_CH2 13
+#define I_PCM_2_CAP_CH1 14
+#define I_ADDA_UL_CH3 17
+#define I_ADDA_UL_CH4 18
+#define I_DL12_CH1 19
+#define I_DL12_CH2 20
+#define I_PCM_2_CAP_CH2 21
+#define I_PCM_1_CAP_CH2 22
+#define I_DL3_CH1 23
+#define I_DL3_CH2 24
+#define I_I2S2_CH1 25
+#define I_I2S2_CH2 26
+#define I_I2S2_CH3 27
+#define I_I2S2_CH4 28
+
+/* in port define >= 32 */
+#define I_32_OFFSET 32
+#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET)
+#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET)
+#define I_DL4_CH1 (40 - I_32_OFFSET)
+#define I_DL4_CH2 (41 - I_32_OFFSET)
+#define I_DL5_CH1 (42 - I_32_OFFSET)
+#define I_DL5_CH2 (43 - I_32_OFFSET)
+#define I_DL6_CH1 (44 - I_32_OFFSET)
+#define I_DL6_CH2 (45 - I_32_OFFSET)
+#define I_DL7_CH1 (46 - I_32_OFFSET)
+#define I_DL7_CH2 (47 - I_32_OFFSET)
+#define I_DL8_CH1 (48 - I_32_OFFSET)
+#define I_DL8_CH2 (49 - I_32_OFFSET)
+#define I_DL9_CH1 (50 - I_32_OFFSET)
+#define I_DL9_CH2 (51 - I_32_OFFSET)
+#define I_I2S6_CH1 (52 - I_32_OFFSET)
+#define I_I2S6_CH2 (53 - I_32_OFFSET)
+#define I_I2S8_CH1 (54 - I_32_OFFSET)
+#define I_I2S8_CH2 (55 - I_32_OFFSET)
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
new file mode 100644 (file)
index 0000000..716fbb4
--- /dev/null
@@ -0,0 +1,1137 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8192-mt6359-rt1015-rt5682.c  --
+//     MT8192-MT6359-RT1015-RT6358 ALSA SoC machine driver
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+
+#include "../../codecs/mt6359.h"
+#include "../../codecs/rt1015.h"
+#include "../../codecs/rt5682.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-gpio.h"
+
+#define RT1015_CODEC_DAI       "rt1015-aif"
+#define RT1015_DEV0_NAME       "rt1015.1-0028"
+#define RT1015_DEV1_NAME       "rt1015.1-0029"
+
+#define RT5682_CODEC_DAI       "rt5682-aif1"
+#define RT5682_DEV0_NAME       "rt5682.1-001a"
+
+static struct snd_soc_jack headset_jack;
+
+static int mt8192_rt1015_i2s_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_card *card = rtd->card;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai;
+       unsigned int rate = params_rate(params);
+       unsigned int mclk_fs_ratio = 128;
+       unsigned int mclk_fs = rate * mclk_fs_ratio;
+       int ret, i;
+
+       for_each_rtd_codec_dais(rtd, i, codec_dai) {
+               ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
+               if (ret) {
+                       dev_err(card->dev, "failed to set bclk ratio\n");
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(codec_dai, 0,
+                                         RT1015_PLL_S_BCLK,
+                                         params_rate(params) * 64,
+                                         params_rate(params) * 256);
+               if (ret) {
+                       dev_err(card->dev, "failed to set pll\n");
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_sysclk(codec_dai,
+                                            RT1015_SCLK_S_PLL,
+                                            params_rate(params) * 256,
+                                            SND_SOC_CLOCK_IN);
+               if (ret) {
+                       dev_err(card->dev, "failed to set sysclk\n");
+                       return ret;
+               }
+       }
+
+       return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static int mt8192_rt5682_i2s_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_card *card = rtd->card;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       unsigned int rate = params_rate(params);
+       unsigned int mclk_fs_ratio = 128;
+       unsigned int mclk_fs = rate * mclk_fs_ratio;
+       int bitwidth;
+       int ret;
+
+       bitwidth = snd_pcm_format_width(params_format(params));
+       if (bitwidth < 0) {
+               dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+               return bitwidth;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+       if (ret) {
+               dev_err(card->dev, "failed to set tdm slot\n");
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1,
+                                 RT5682_PLL1_S_BCLK1,
+                                 params_rate(params) * 64,
+                                 params_rate(params) * 512);
+       if (ret) {
+               dev_err(card->dev, "failed to set pll\n");
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                    RT5682_SCLK_S_PLL1,
+                                    params_rate(params) * 512,
+                                    SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(card->dev, "failed to set sysclk\n");
+               return ret;
+       }
+
+       return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8192_rt1015_i2s_ops = {
+       .hw_params = mt8192_rt1015_i2s_hw_params,
+};
+
+static const struct snd_soc_ops mt8192_rt5682_i2s_ops = {
+       .hw_params = mt8192_rt5682_i2s_hw_params,
+};
+
+static int mt8192_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_afe =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+       int phase;
+       unsigned int monitor;
+       int test_done_1, test_done_2, test_done_3;
+       int cycle_1, cycle_2, cycle_3;
+       int prev_cycle_1, prev_cycle_2, prev_cycle_3;
+       int chosen_phase_1, chosen_phase_2, chosen_phase_3;
+       int counter;
+       int mtkaif_calib_ok;
+
+       dev_info(afe->dev, "%s(), start\n", __func__);
+
+       pm_runtime_get_sync(afe->dev);
+       mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1);
+       mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0);
+       mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 1);
+       mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 0);
+
+       mt6359_mtkaif_calibration_enable(cmpnt_codec);
+
+       /* set clock protocol 2 */
+       regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38);
+       regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x39);
+
+       /* set test type to synchronizer pulse */
+       regmap_update_bits(afe_priv->topckgen,
+                          CKSYS_AUD_TOP_CFG, 0xffff, 0x4);
+
+       mtkaif_calib_ok = true;
+       afe_priv->mtkaif_calibration_num_phase = 42;    /* mt6359: 0 ~ 42 */
+       afe_priv->mtkaif_chosen_phase[0] = -1;
+       afe_priv->mtkaif_chosen_phase[1] = -1;
+       afe_priv->mtkaif_chosen_phase[2] = -1;
+
+       for (phase = 0;
+            phase <= afe_priv->mtkaif_calibration_num_phase &&
+            mtkaif_calib_ok;
+            phase++) {
+               mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
+                                                   phase, phase, phase);
+
+               regmap_update_bits(afe_priv->topckgen,
+                                  CKSYS_AUD_TOP_CFG, 0x1, 0x1);
+
+               test_done_1 = 0;
+               test_done_2 = 0;
+               test_done_3 = 0;
+               cycle_1 = -1;
+               cycle_2 = -1;
+               cycle_3 = -1;
+               counter = 0;
+               while (test_done_1 == 0 ||
+                      test_done_2 == 0 ||
+                      test_done_3 == 0) {
+                       regmap_read(afe_priv->topckgen,
+                                   CKSYS_AUD_TOP_MON, &monitor);
+
+                       test_done_1 = (monitor >> 28) & 0x1;
+                       test_done_2 = (monitor >> 29) & 0x1;
+                       test_done_3 = (monitor >> 30) & 0x1;
+                       if (test_done_1 == 1)
+                               cycle_1 = monitor & 0xf;
+
+                       if (test_done_2 == 1)
+                               cycle_2 = (monitor >> 4) & 0xf;
+
+                       if (test_done_3 == 1)
+                               cycle_3 = (monitor >> 8) & 0xf;
+
+                       /* handle if never test done */
+                       if (++counter > 10000) {
+                               dev_err(afe->dev, "%s(), test fail, cycle_1 %d, cycle_2 %d, cycle_3 %d, monitor 0x%x\n",
+                                       __func__,
+                                       cycle_1, cycle_2, cycle_3, monitor);
+                               mtkaif_calib_ok = false;
+                               break;
+                       }
+               }
+
+               if (phase == 0) {
+                       prev_cycle_1 = cycle_1;
+                       prev_cycle_2 = cycle_2;
+                       prev_cycle_3 = cycle_3;
+               }
+
+               if (cycle_1 != prev_cycle_1 &&
+                   afe_priv->mtkaif_chosen_phase[0] < 0) {
+                       afe_priv->mtkaif_chosen_phase[0] = phase - 1;
+                       afe_priv->mtkaif_phase_cycle[0] = prev_cycle_1;
+               }
+
+               if (cycle_2 != prev_cycle_2 &&
+                   afe_priv->mtkaif_chosen_phase[1] < 0) {
+                       afe_priv->mtkaif_chosen_phase[1] = phase - 1;
+                       afe_priv->mtkaif_phase_cycle[1] = prev_cycle_2;
+               }
+
+               if (cycle_3 != prev_cycle_3 &&
+                   afe_priv->mtkaif_chosen_phase[2] < 0) {
+                       afe_priv->mtkaif_chosen_phase[2] = phase - 1;
+                       afe_priv->mtkaif_phase_cycle[2] = prev_cycle_3;
+               }
+
+               regmap_update_bits(afe_priv->topckgen,
+                                  CKSYS_AUD_TOP_CFG, 0x1, 0x0);
+
+               if (afe_priv->mtkaif_chosen_phase[0] >= 0 &&
+                   afe_priv->mtkaif_chosen_phase[1] >= 0 &&
+                   afe_priv->mtkaif_chosen_phase[2] >= 0)
+                       break;
+       }
+
+       if (afe_priv->mtkaif_chosen_phase[0] < 0)
+               chosen_phase_1 = 0;
+       else
+               chosen_phase_1 = afe_priv->mtkaif_chosen_phase[0];
+
+       if (afe_priv->mtkaif_chosen_phase[1] < 0)
+               chosen_phase_2 = 0;
+       else
+               chosen_phase_2 = afe_priv->mtkaif_chosen_phase[1];
+
+       if (afe_priv->mtkaif_chosen_phase[2] < 0)
+               chosen_phase_3 = 0;
+       else
+               chosen_phase_3 = afe_priv->mtkaif_chosen_phase[2];
+
+       mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
+                                           chosen_phase_1,
+                                           chosen_phase_2,
+                                           chosen_phase_3);
+
+       /* disable rx fifo */
+       regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38);
+
+       mt6359_mtkaif_calibration_disable(cmpnt_codec);
+
+       mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1);
+       mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0);
+       mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 1);
+       mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 0);
+       pm_runtime_put(afe->dev);
+
+       dev_info(afe->dev, "%s(), mtkaif_chosen_phase[0/1/2]:%d/%d/%d\n",
+                __func__,
+                afe_priv->mtkaif_chosen_phase[0],
+                afe_priv->mtkaif_chosen_phase[1],
+                afe_priv->mtkaif_chosen_phase[2]);
+
+       return 0;
+}
+
+static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_afe =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
+       struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+       /* set mtkaif protocol */
+       mt6359_set_mtkaif_protocol(cmpnt_codec,
+                                  MT6359_MTKAIF_PROTOCOL_2_CLK_P2);
+       afe_priv->mtkaif_protocol = MTKAIF_PROTOCOL_2_CLK_P2;
+
+       /* mtkaif calibration */
+       mt8192_mt6359_mtkaif_calibration(rtd);
+
+       return 0;
+}
+
+static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct snd_soc_jack *jack = &headset_jack;
+       int ret;
+
+       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                   SND_JACK_BTN_3,
+                                   jack, NULL, 0);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       ret = snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack set failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+};
+
+static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                     struct snd_pcm_hw_params *params)
+{
+       /* fix BE i2s format to 32bit, clean param mask first */
+       snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+                            0, SNDRV_PCM_FORMAT_LAST);
+
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int
+mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       static const unsigned int channels[] = {
+               1, 2, 4
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_channels = {
+               .count = ARRAY_SIZE(channels),
+               .list = channels,
+               .mask = 0,
+       };
+       static const unsigned int rates[] = {
+               8000, 16000, 32000, 48000, 96000, 192000
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list  = rates,
+               .mask = 0,
+       };
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_CHANNELS,
+                                        &constraints_channels);
+       if (ret < 0) {
+               dev_err(afe->dev, "hw_constraint_list channels failed\n");
+               return ret;
+       }
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_RATE,
+                                        &constraints_rates);
+       if (ret < 0) {
+               dev_err(afe->dev, "hw_constraint_list rate failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8192_mt6359_rt1015_rt5682_capture1_ops = {
+       .startup = mt8192_mt6359_rt1015_rt5682_cap1_startup,
+};
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback12,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback4,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback8,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback9,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL9")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture4,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture8,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL8")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback_hdmi,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* BE */
+SND_SOC_DAILINK_DEFS(primary_codec,
+                    DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
+                                                  "mt6359-snd-codec-aif1"),
+                                       COMP_CODEC("dmic-codec",
+                                                  "dmic-hifi")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(primary_codec_ch34,
+                    DAILINK_COMP_ARRAY(COMP_CPU("ADDA_CH34")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
+                                                  "mt6359-snd-codec-aif2")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(ap_dmic,
+                    DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
+                    DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s0,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_rt1015,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC(RT1015_DEV0_NAME,
+                                                  RT1015_CODEC_DAI),
+                                       COMP_CODEC(RT1015_DEV1_NAME,
+                                                  RT1015_CODEC_DAI)),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_rt1015p,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("rt1015p", "HiFi")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s8,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S8")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME,
+                                                  RT5682_CODEC_DAI)),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s9,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S9")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME,
+                                                  RT5682_CODEC_DAI)),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(connsys_i2s,
+                    DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("PCM 2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(tdm,
+                    DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
+       /* Front End DAI links */
+       {
+               .name = "Playback_1",
+               .stream_name = "Playback_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback1),
+       },
+       {
+               .name = "Playback_12",
+               .stream_name = "Playback_12",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback12),
+       },
+       {
+               .name = "Playback_2",
+               .stream_name = "Playback_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback2),
+       },
+       {
+               .name = "Playback_3",
+               .stream_name = "Playback_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback3),
+       },
+       {
+               .name = "Playback_4",
+               .stream_name = "Playback_4",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback4),
+       },
+       {
+               .name = "Playback_5",
+               .stream_name = "Playback_5",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback5),
+       },
+       {
+               .name = "Playback_6",
+               .stream_name = "Playback_6",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback6),
+       },
+       {
+               .name = "Playback_7",
+               .stream_name = "Playback_7",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback7),
+       },
+       {
+               .name = "Playback_8",
+               .stream_name = "Playback_8",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback8),
+       },
+       {
+               .name = "Playback_9",
+               .stream_name = "Playback_9",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback9),
+       },
+       {
+               .name = "Capture_1",
+               .stream_name = "Capture_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .ops = &mt8192_mt6359_rt1015_rt5682_capture1_ops,
+               SND_SOC_DAILINK_REG(capture1),
+       },
+       {
+               .name = "Capture_2",
+               .stream_name = "Capture_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture2),
+       },
+       {
+               .name = "Capture_3",
+               .stream_name = "Capture_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture3),
+       },
+       {
+               .name = "Capture_4",
+               .stream_name = "Capture_4",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture4),
+       },
+       {
+               .name = "Capture_5",
+               .stream_name = "Capture_5",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture5),
+       },
+       {
+               .name = "Capture_6",
+               .stream_name = "Capture_6",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture6),
+       },
+       {
+               .name = "Capture_7",
+               .stream_name = "Capture_7",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture7),
+       },
+       {
+               .name = "Capture_8",
+               .stream_name = "Capture_8",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture8),
+       },
+       {
+               .name = "Capture_Mono_1",
+               .stream_name = "Capture_Mono_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture_mono1),
+       },
+       {
+               .name = "Capture_Mono_2",
+               .stream_name = "Capture_Mono_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture_mono2),
+       },
+       {
+               .name = "Capture_Mono_3",
+               .stream_name = "Capture_Mono_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture_mono3),
+       },
+       {
+               .name = "playback_hdmi",
+               .stream_name = "Playback_HDMI",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback_hdmi),
+       },
+       /* Back End DAI links */
+       {
+               .name = "Primary Codec",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .init = mt8192_mt6359_init,
+               SND_SOC_DAILINK_REG(primary_codec),
+       },
+       {
+               .name = "Primary Codec CH34",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(primary_codec_ch34),
+       },
+       {
+               .name = "AP_DMIC",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(ap_dmic),
+       },
+       {
+               .name = "AP_DMIC_CH34",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(ap_dmic_ch34),
+       },
+       {
+               .name = "I2S0",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s0),
+       },
+       {
+               .name = "I2S1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s1),
+       },
+       {
+               .name = "I2S2",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s2),
+       },
+       {
+               .name = "I2S3",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+       },
+       {
+               .name = "I2S5",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s5),
+       },
+       {
+               .name = "I2S6",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s6),
+       },
+       {
+               .name = "I2S7",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s7),
+       },
+       {
+               .name = "I2S8",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .init = mt8192_rt5682_init,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s8),
+               .ops = &mt8192_rt5682_i2s_ops,
+       },
+       {
+               .name = "I2S9",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s9),
+               .ops = &mt8192_rt5682_i2s_ops,
+       },
+       {
+               .name = "CONNSYS_I2S",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(connsys_i2s),
+       },
+       {
+               .name = "PCM 1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(pcm1),
+       },
+       {
+               .name = "PCM 2",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(pcm2),
+       },
+       {
+               .name = "TDM",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(tdm),
+       },
+};
+
+static const struct snd_soc_dapm_widget
+mt8192_mt6359_rt1015_rt5682_widgets[] = {
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
+       /* speaker */
+       { "Left Spk", NULL, "Left SPO" },
+       { "Right Spk", NULL, "Right SPO" },
+       /* headset */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+       { "IN1P", NULL, "Headset Mic" },
+};
+
+static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static struct snd_soc_codec_conf rt1015_amp_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),
+               .name_prefix = "Left",
+       },
+       {
+               .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),
+               .name_prefix = "Right",
+       },
+};
+
+static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = {
+       .name = "mt8192_mt6359_rt1015_rt5682",
+       .owner = THIS_MODULE,
+       .dai_link = mt8192_mt6359_dai_links,
+       .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links),
+       .controls = mt8192_mt6359_rt1015_rt5682_controls,
+       .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_controls),
+       .dapm_widgets = mt8192_mt6359_rt1015_rt5682_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_widgets),
+       .dapm_routes = mt8192_mt6359_rt1015_rt5682_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_routes),
+       .codec_conf = rt1015_amp_conf,
+       .num_configs = ARRAY_SIZE(rt1015_amp_conf),
+};
+
+static const struct snd_soc_dapm_widget
+mt8192_mt6359_rt1015p_rt5682_widgets[] = {
+       SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682_routes[] = {
+       /* speaker */
+       { "Speakers", NULL, "Speaker" },
+       /* headset */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+       { "IN1P", NULL, "Headset Mic" },
+};
+
+static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682_card = {
+       .name = "mt8192_mt6359_rt1015p_rt5682",
+       .owner = THIS_MODULE,
+       .dai_link = mt8192_mt6359_dai_links,
+       .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links),
+       .controls = mt8192_mt6359_rt1015p_rt5682_controls,
+       .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_controls),
+       .dapm_widgets = mt8192_mt6359_rt1015p_rt5682_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_widgets),
+       .dapm_routes = mt8192_mt6359_rt1015p_rt5682_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_routes),
+};
+
+static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct device_node *platform_node;
+       int ret, i;
+       struct snd_soc_dai_link *dai_link;
+       const struct of_device_id *match;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
+       if (!match || !match->data)
+               return -EINVAL;
+
+       card = (struct snd_soc_card *)match->data;
+       card->dev = &pdev->dev;
+
+       for_each_card_prelinks(card, i, dai_link) {
+               if (strcmp(dai_link->name, "I2S3") == 0) {
+                       if (card == &mt8192_mt6359_rt1015_rt5682_card) {
+                               dai_link->ops = &mt8192_rt1015_i2s_ops;
+                               dai_link->cpus = i2s3_rt1015_cpus;
+                               dai_link->num_cpus =
+                                       ARRAY_SIZE(i2s3_rt1015_cpus);
+                               dai_link->codecs = i2s3_rt1015_codecs;
+                               dai_link->num_codecs =
+                                       ARRAY_SIZE(i2s3_rt1015_codecs);
+                               dai_link->platforms = i2s3_rt1015_platforms;
+                               dai_link->num_platforms =
+                                       ARRAY_SIZE(i2s3_rt1015_platforms);
+                       } else if (card == &mt8192_mt6359_rt1015p_rt5682_card) {
+                               dai_link->cpus = i2s3_rt1015p_cpus;
+                               dai_link->num_cpus =
+                                       ARRAY_SIZE(i2s3_rt1015p_cpus);
+                               dai_link->codecs = i2s3_rt1015p_codecs;
+                               dai_link->num_codecs =
+                                       ARRAY_SIZE(i2s3_rt1015p_codecs);
+                               dai_link->platforms = i2s3_rt1015p_platforms;
+                               dai_link->num_platforms =
+                                       ARRAY_SIZE(i2s3_rt1015p_platforms);
+                       }
+               }
+
+               if (!dai_link->platforms->name)
+                       dai_link->platforms->of_node = platform_node;
+       }
+
+       ret = mt8192_afe_gpio_init(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "init gpio error %d\n", ret);
+               return ret;
+       }
+
+       return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt8192_mt6359_dt_match[] = {
+       {
+               .compatible = "mediatek,mt8192_mt6359_rt1015_rt5682",
+               .data = &mt8192_mt6359_rt1015_rt5682_card,
+       },
+       {
+               .compatible = "mediatek,mt8192_mt6359_rt1015p_rt5682",
+               .data = &mt8192_mt6359_rt1015p_rt5682_card,
+       },
+       {}
+};
+#endif
+
+static const struct dev_pm_ops mt8192_mt6359_pm_ops = {
+       .poweroff = snd_soc_poweroff,
+       .restore = snd_soc_resume,
+};
+
+static struct platform_driver mt8192_mt6359_driver = {
+       .driver = {
+               .name = "mt8192_mt6359",
+#ifdef CONFIG_OF
+               .of_match_table = mt8192_mt6359_dt_match,
+#endif
+               .pm = &mt8192_mt6359_pm_ops,
+       },
+       .probe = mt8192_mt6359_dev_probe,
+};
+
+module_platform_driver(mt8192_mt6359_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8192-MT6359 ALSA SoC machine driver");
+MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt8192_mt6359 soc card");
diff --git a/sound/soc/mediatek/mt8192/mt8192-reg.h b/sound/soc/mediatek/mt8192/mt8192-reg.h
new file mode 100644 (file)
index 0000000..562f25c
--- /dev/null
@@ -0,0 +1,3131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-reg.h  --  Mediatek 8192 audio driver reg definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_REG_H_
+#define _MT8192_REG_H_
+
+/* reg bit enum */
+enum {
+       MT8192_MEMIF_PBUF_SIZE_32_BYTES,
+       MT8192_MEMIF_PBUF_SIZE_64_BYTES,
+       MT8192_MEMIF_PBUF_SIZE_128_BYTES,
+       MT8192_MEMIF_PBUF_SIZE_256_BYTES,
+       MT8192_MEMIF_PBUF_SIZE_NUM,
+};
+
+/*****************************************************************************
+ *                  R E G I S T E R       D E F I N I T I O N
+ *****************************************************************************/
+/* AFE_DAC_CON0 */
+#define VUL12_ON_SFT                                   31
+#define VUL12_ON_MASK                                  0x1
+#define VUL12_ON_MASK_SFT                              (0x1 << 31)
+#define MOD_DAI_ON_SFT                                 30
+#define MOD_DAI_ON_MASK                                0x1
+#define MOD_DAI_ON_MASK_SFT                            (0x1 << 30)
+#define DAI_ON_SFT                                     29
+#define DAI_ON_MASK                                    0x1
+#define DAI_ON_MASK_SFT                                (0x1 << 29)
+#define DAI2_ON_SFT                                    28
+#define DAI2_ON_MASK                                   0x1
+#define DAI2_ON_MASK_SFT                               (0x1 << 28)
+#define VUL6_ON_SFT                                    23
+#define VUL6_ON_MASK                                   0x1
+#define VUL6_ON_MASK_SFT                               (0x1 << 23)
+#define VUL5_ON_SFT                                    22
+#define VUL5_ON_MASK                                   0x1
+#define VUL5_ON_MASK_SFT                               (0x1 << 22)
+#define VUL4_ON_SFT                                    21
+#define VUL4_ON_MASK                                   0x1
+#define VUL4_ON_MASK_SFT                               (0x1 << 21)
+#define VUL3_ON_SFT                                    20
+#define VUL3_ON_MASK                                   0x1
+#define VUL3_ON_MASK_SFT                               (0x1 << 20)
+#define VUL2_ON_SFT                                    19
+#define VUL2_ON_MASK                                   0x1
+#define VUL2_ON_MASK_SFT                               (0x1 << 19)
+#define VUL_ON_SFT                                     18
+#define VUL_ON_MASK                                    0x1
+#define VUL_ON_MASK_SFT                                (0x1 << 18)
+#define AWB2_ON_SFT                                    17
+#define AWB2_ON_MASK                                   0x1
+#define AWB2_ON_MASK_SFT                               (0x1 << 17)
+#define AWB_ON_SFT                                     16
+#define AWB_ON_MASK                                    0x1
+#define AWB_ON_MASK_SFT                                (0x1 << 16)
+#define DL12_ON_SFT                                    15
+#define DL12_ON_MASK                                   0x1
+#define DL12_ON_MASK_SFT                               (0x1 << 15)
+#define DL9_ON_SFT                                     12
+#define DL9_ON_MASK                                    0x1
+#define DL9_ON_MASK_SFT                                (0x1 << 12)
+#define DL8_ON_SFT                                     11
+#define DL8_ON_MASK                                    0x1
+#define DL8_ON_MASK_SFT                                (0x1 << 11)
+#define DL7_ON_SFT                                     10
+#define DL7_ON_MASK                                    0x1
+#define DL7_ON_MASK_SFT                                (0x1 << 10)
+#define DL6_ON_SFT                                     9
+#define DL6_ON_MASK                                    0x1
+#define DL6_ON_MASK_SFT                                (0x1 << 9)
+#define DL5_ON_SFT                                     8
+#define DL5_ON_MASK                                    0x1
+#define DL5_ON_MASK_SFT                                (0x1 << 8)
+#define DL4_ON_SFT                                     7
+#define DL4_ON_MASK                                    0x1
+#define DL4_ON_MASK_SFT                                (0x1 << 7)
+#define DL3_ON_SFT                                     6
+#define DL3_ON_MASK                                    0x1
+#define DL3_ON_MASK_SFT                                (0x1 << 6)
+#define DL2_ON_SFT                                     5
+#define DL2_ON_MASK                                    0x1
+#define DL2_ON_MASK_SFT                                (0x1 << 5)
+#define DL1_ON_SFT                                     4
+#define DL1_ON_MASK                                    0x1
+#define DL1_ON_MASK_SFT                                (0x1 << 4)
+#define HDMI_OUT_ON_SFT                                1
+#define HDMI_OUT_ON_MASK                               0x1
+#define HDMI_OUT_ON_MASK_SFT                           (0x1 << 1)
+#define AFE_ON_SFT                                     0
+#define AFE_ON_MASK                                    0x1
+#define AFE_ON_MASK_SFT                                (0x1 << 0)
+
+/* AFE_DAC_MON */
+#define AFE_ON_RETM_SFT                                0
+#define AFE_ON_RETM_MASK                               0x1
+#define AFE_ON_RETM_MASK_SFT                           (0x1 << 0)
+
+/* AFE_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT                           30
+#define BCK_NEG_EG_LATCH_MASK                          0x1
+#define BCK_NEG_EG_LATCH_MASK_SFT                      (0x1 << 30)
+#define BCK_INV_SFT                                    29
+#define BCK_INV_MASK                                   0x1
+#define BCK_INV_MASK_SFT                               (0x1 << 29)
+#define I2SIN_PAD_SEL_SFT                              28
+#define I2SIN_PAD_SEL_MASK                             0x1
+#define I2SIN_PAD_SEL_MASK_SFT                         (0x1 << 28)
+#define I2S_LOOPBACK_SFT                               20
+#define I2S_LOOPBACK_MASK                              0x1
+#define I2S_LOOPBACK_MASK_SFT                          (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S1_HD_EN_SFT                                 12
+#define I2S1_HD_EN_MASK                                0x1
+#define I2S1_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S_OUT_MODE_SFT                               8
+#define I2S_OUT_MODE_MASK                              0xf
+#define I2S_OUT_MODE_MASK_SFT                          (0xf << 8)
+#define INV_PAD_CTRL_SFT                               7
+#define INV_PAD_CTRL_MASK                              0x1
+#define INV_PAD_CTRL_MASK_SFT                          (0x1 << 7)
+#define I2S_BYPSRC_SFT                                 6
+#define I2S_BYPSRC_MASK                                0x1
+#define I2S_BYPSRC_MASK_SFT                            (0x1 << 6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S_FMT_SFT                                    3
+#define I2S_FMT_MASK                                   0x1
+#define I2S_FMT_MASK_SFT                               (0x1 << 3)
+#define I2S_SRC_SFT                                    2
+#define I2S_SRC_MASK                                   0x1
+#define I2S_SRC_MASK_SFT                               (0x1 << 2)
+#define I2S_WLEN_SFT                                   1
+#define I2S_WLEN_MASK                                  0x1
+#define I2S_WLEN_MASK_SFT                              (0x1 << 1)
+#define I2S_EN_SFT                                     0
+#define I2S_EN_MASK                                    0x1
+#define I2S_EN_MASK_SFT                                (0x1 << 0)
+
+/* AFE_I2S_CON1 */
+#define I2S2_LR_SWAP_SFT                               31
+#define I2S2_LR_SWAP_MASK                              0x1
+#define I2S2_LR_SWAP_MASK_SFT                          (0x1 << 31)
+#define I2S2_SEL_O19_O20_SFT                           18
+#define I2S2_SEL_O19_O20_MASK                          0x1
+#define I2S2_SEL_O19_O20_MASK_SFT                      (0x1 << 18)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S2_SEL_O03_O04_SFT                           16
+#define I2S2_SEL_O03_O04_MASK                          0x1
+#define I2S2_SEL_O03_O04_MASK_SFT                      (0x1 << 16)
+#define I2S2_32BIT_EN_SFT                              13
+#define I2S2_32BIT_EN_MASK                             0x1
+#define I2S2_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S2_HD_EN_SFT                                 12
+#define I2S2_HD_EN_MASK                                0x1
+#define I2S2_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S2_OUT_MODE_SFT                              8
+#define I2S2_OUT_MODE_MASK                             0xf
+#define I2S2_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S2_FMT_SFT                                   3
+#define I2S2_FMT_MASK                                  0x1
+#define I2S2_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S2_WLEN_SFT                                  1
+#define I2S2_WLEN_MASK                                 0x1
+#define I2S2_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S2_EN_SFT                                    0
+#define I2S2_EN_MASK                                   0x1
+#define I2S2_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON2 */
+#define I2S3_LR_SWAP_SFT                               31
+#define I2S3_LR_SWAP_MASK                              0x1
+#define I2S3_LR_SWAP_MASK_SFT                          (0x1 << 31)
+#define I2S3_UPDATE_WORD_SFT                           24
+#define I2S3_UPDATE_WORD_MASK                          0x1f
+#define I2S3_UPDATE_WORD_MASK_SFT                      (0x1f << 24)
+#define I2S3_BCK_INV_SFT                               23
+#define I2S3_BCK_INV_MASK                              0x1
+#define I2S3_BCK_INV_MASK_SFT                          (0x1 << 23)
+#define I2S3_FPGA_BIT_TEST_SFT                         22
+#define I2S3_FPGA_BIT_TEST_MASK                        0x1
+#define I2S3_FPGA_BIT_TEST_MASK_SFT                    (0x1 << 22)
+#define I2S3_FPGA_BIT_SFT                              21
+#define I2S3_FPGA_BIT_MASK                             0x1
+#define I2S3_FPGA_BIT_MASK_SFT                         (0x1 << 21)
+#define I2S3_LOOPBACK_SFT                              20
+#define I2S3_LOOPBACK_MASK                             0x1
+#define I2S3_LOOPBACK_MASK_SFT                         (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S3_HD_EN_SFT                                 12
+#define I2S3_HD_EN_MASK                                0x1
+#define I2S3_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S3_OUT_MODE_SFT                              8
+#define I2S3_OUT_MODE_MASK                             0xf
+#define I2S3_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define I2S3_FMT_SFT                                   3
+#define I2S3_FMT_MASK                                  0x1
+#define I2S3_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S3_WLEN_SFT                                  1
+#define I2S3_WLEN_MASK                                 0x1
+#define I2S3_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S3_EN_SFT                                    0
+#define I2S3_EN_MASK                                   0x1
+#define I2S3_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON3 */
+#define I2S4_LR_SWAP_SFT                               31
+#define I2S4_LR_SWAP_MASK                              0x1
+#define I2S4_LR_SWAP_MASK_SFT                          (0x1 << 31)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S4_32BIT_EN_SFT                              13
+#define I2S4_32BIT_EN_MASK                             0x1
+#define I2S4_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S4_HD_EN_SFT                                 12
+#define I2S4_HD_EN_MASK                                0x1
+#define I2S4_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S4_OUT_MODE_SFT                              8
+#define I2S4_OUT_MODE_MASK                             0xf
+#define I2S4_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S4_FMT_SFT                                   3
+#define I2S4_FMT_MASK                                  0x1
+#define I2S4_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S4_WLEN_SFT                                  1
+#define I2S4_WLEN_MASK                                 0x1
+#define I2S4_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S4_EN_SFT                                    0
+#define I2S4_EN_MASK                                   0x1
+#define I2S4_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON4 */
+#define I2S5_LR_SWAP_SFT                               31
+#define I2S5_LR_SWAP_MASK                              0x1
+#define I2S5_LR_SWAP_MASK_SFT                          (0x1 << 31)
+#define I2S_LOOPBACK_SFT                               20
+#define I2S_LOOPBACK_MASK                              0x1
+#define I2S_LOOPBACK_MASK_SFT                          (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S5_32BIT_EN_SFT                              13
+#define I2S5_32BIT_EN_MASK                             0x1
+#define I2S5_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S5_HD_EN_SFT                                 12
+#define I2S5_HD_EN_MASK                                0x1
+#define I2S5_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S5_OUT_MODE_SFT                              8
+#define I2S5_OUT_MODE_MASK                             0xf
+#define I2S5_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S5_FMT_SFT                                   3
+#define I2S5_FMT_MASK                                  0x1
+#define I2S5_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S5_WLEN_SFT                                  1
+#define I2S5_WLEN_MASK                                 0x1
+#define I2S5_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S5_EN_SFT                                    0
+#define I2S5_EN_MASK                                   0x1
+#define I2S5_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_CONNSYS_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT                           30
+#define BCK_NEG_EG_LATCH_MASK                          0x1
+#define BCK_NEG_EG_LATCH_MASK_SFT                      (0x1 << 30)
+#define BCK_INV_SFT                                    29
+#define BCK_INV_MASK                                   0x1
+#define BCK_INV_MASK_SFT                               (0x1 << 29)
+#define I2SIN_PAD_SEL_SFT                              28
+#define I2SIN_PAD_SEL_MASK                             0x1
+#define I2SIN_PAD_SEL_MASK_SFT                         (0x1 << 28)
+#define I2S_LOOPBACK_SFT                               20
+#define I2S_LOOPBACK_MASK                              0x1
+#define I2S_LOOPBACK_MASK_SFT                          (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S_MODE_SFT                                   8
+#define I2S_MODE_MASK                                  0xf
+#define I2S_MODE_MASK_SFT                              (0xf << 8)
+#define INV_PAD_CTRL_SFT                               7
+#define INV_PAD_CTRL_MASK                              0x1
+#define INV_PAD_CTRL_MASK_SFT                          (0x1 << 7)
+#define I2S_BYPSRC_SFT                                 6
+#define I2S_BYPSRC_MASK                                0x1
+#define I2S_BYPSRC_MASK_SFT                            (0x1 << 6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S_FMT_SFT                                    3
+#define I2S_FMT_MASK                                   0x1
+#define I2S_FMT_MASK_SFT                               (0x1 << 3)
+#define I2S_SRC_SFT                                    2
+#define I2S_SRC_MASK                                   0x1
+#define I2S_SRC_MASK_SFT                               (0x1 << 2)
+#define I2S_WLEN_SFT                                   1
+#define I2S_WLEN_MASK                                  0x1
+#define I2S_WLEN_MASK_SFT                              (0x1 << 1)
+#define I2S_EN_SFT                                     0
+#define I2S_EN_MASK                                    0x1
+#define I2S_EN_MASK_SFT                                (0x1 << 0)
+
+/* AFE_I2S_CON6 */
+#define BCK_NEG_EG_LATCH_SFT                           30
+#define BCK_NEG_EG_LATCH_MASK                          0x1
+#define BCK_NEG_EG_LATCH_MASK_SFT                      (0x1 << 30)
+#define BCK_INV_SFT                                    29
+#define BCK_INV_MASK                                   0x1
+#define BCK_INV_MASK_SFT                               (0x1 << 29)
+#define I2S6_LOOPBACK_SFT                              20
+#define I2S6_LOOPBACK_MASK                             0x1
+#define I2S6_LOOPBACK_MASK_SFT                         (0x1 << 20)
+#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_SFT             17
+#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_MASK            0x1
+#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT        (0x1 << 17)
+#define I2S6_HD_EN_SFT                                 12
+#define I2S6_HD_EN_MASK                                0x1
+#define I2S6_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S6_OUT_MODE_SFT                              8
+#define I2S6_OUT_MODE_MASK                             0xf
+#define I2S6_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define I2S6_BYPSRC_SFT                                6
+#define I2S6_BYPSRC_MASK                               0x1
+#define I2S6_BYPSRC_MASK_SFT                           (0x1 << 6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S6_FMT_SFT                                   3
+#define I2S6_FMT_MASK                                  0x1
+#define I2S6_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S6_SRC_SFT                                   2
+#define I2S6_SRC_MASK                                  0x1
+#define I2S6_SRC_MASK_SFT                              (0x1 << 2)
+#define I2S6_WLEN_SFT                                  1
+#define I2S6_WLEN_MASK                                 0x1
+#define I2S6_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S6_EN_SFT                                    0
+#define I2S6_EN_MASK                                   0x1
+#define I2S6_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON7 */
+#define I2S7_LR_SWAP_SFT                               31
+#define I2S7_LR_SWAP_MASK                              0x1
+#define I2S7_LR_SWAP_MASK_SFT                          (0x1 << 31)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S7_32BIT_EN_SFT                              13
+#define I2S7_32BIT_EN_MASK                             0x1
+#define I2S7_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S7_HD_EN_SFT                                 12
+#define I2S7_HD_EN_MASK                                0x1
+#define I2S7_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S7_OUT_MODE_SFT                              8
+#define I2S7_OUT_MODE_MASK                             0xf
+#define I2S7_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S7_FMT_SFT                                   3
+#define I2S7_FMT_MASK                                  0x1
+#define I2S7_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S7_WLEN_SFT                                  1
+#define I2S7_WLEN_MASK                                 0x1
+#define I2S7_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S7_EN_SFT                                    0
+#define I2S7_EN_MASK                                   0x1
+#define I2S7_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON8 */
+#define BCK_NEG_EG_LATCH_SFT                           30
+#define BCK_NEG_EG_LATCH_MASK                          0x1
+#define BCK_NEG_EG_LATCH_MASK_SFT                      (0x1 << 30)
+#define BCK_INV_SFT                                    29
+#define BCK_INV_MASK                                   0x1
+#define BCK_INV_MASK_SFT                               (0x1 << 29)
+#define I2S8_LOOPBACK_SFT                              20
+#define I2S8_LOOPBACK_MASK                             0x1
+#define I2S8_LOOPBACK_MASK_SFT                         (0x1 << 20)
+#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_SFT             17
+#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_MASK            0x1
+#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT        (0x1 << 17)
+#define I2S8_HD_EN_SFT                                 12
+#define I2S8_HD_EN_MASK                                0x1
+#define I2S8_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S8_OUT_MODE_SFT                              8
+#define I2S8_OUT_MODE_MASK                             0xf
+#define I2S8_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define I2S8_BYPSRC_SFT                                6
+#define I2S8_BYPSRC_MASK                               0x1
+#define I2S8_BYPSRC_MASK_SFT                           (0x1 << 6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S8_FMT_SFT                                   3
+#define I2S8_FMT_MASK                                  0x1
+#define I2S8_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S8_SRC_SFT                                   2
+#define I2S8_SRC_MASK                                  0x1
+#define I2S8_SRC_MASK_SFT                              (0x1 << 2)
+#define I2S8_WLEN_SFT                                  1
+#define I2S8_WLEN_MASK                                 0x1
+#define I2S8_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S8_EN_SFT                                    0
+#define I2S8_EN_MASK                                   0x1
+#define I2S8_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON9 */
+#define I2S9_LR_SWAP_SFT                               31
+#define I2S9_LR_SWAP_MASK                              0x1
+#define I2S9_LR_SWAP_MASK_SFT                          (0x1 << 31)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         (0x1 << 17)
+#define I2S9_32BIT_EN_SFT                              13
+#define I2S9_32BIT_EN_MASK                             0x1
+#define I2S9_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S9_HD_EN_SFT                                 12
+#define I2S9_HD_EN_MASK                                0x1
+#define I2S9_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S9_OUT_MODE_SFT                              8
+#define I2S9_OUT_MODE_MASK                             0xf
+#define I2S9_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S9_FMT_SFT                                   3
+#define I2S9_FMT_MASK                                  0x1
+#define I2S9_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S9_WLEN_SFT                                  1
+#define I2S9_WLEN_MASK                                 0x1
+#define I2S9_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S9_EN_SFT                                    0
+#define I2S9_EN_MASK                                   0x1
+#define I2S9_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_ASRC_2CH_CON2 */
+#define CHSET_O16BIT_SFT                               19
+#define CHSET_O16BIT_MASK                              0x1
+#define CHSET_O16BIT_MASK_SFT                          (0x1 << 19)
+#define CHSET_CLR_IIR_HISTORY_SFT                      17
+#define CHSET_CLR_IIR_HISTORY_MASK                     0x1
+#define CHSET_CLR_IIR_HISTORY_MASK_SFT                 (0x1 << 17)
+#define CHSET_IS_MONO_SFT                              16
+#define CHSET_IS_MONO_MASK                             0x1
+#define CHSET_IS_MONO_MASK_SFT                         (0x1 << 16)
+#define CHSET_IIR_EN_SFT                               11
+#define CHSET_IIR_EN_MASK                              0x1
+#define CHSET_IIR_EN_MASK_SFT                          (0x1 << 11)
+#define CHSET_IIR_STAGE_SFT                            8
+#define CHSET_IIR_STAGE_MASK                           0x7
+#define CHSET_IIR_STAGE_MASK_SFT                       (0x7 << 8)
+#define CHSET_STR_CLR_SFT                              5
+#define CHSET_STR_CLR_MASK                             0x1
+#define CHSET_STR_CLR_MASK_SFT                         (0x1 << 5)
+#define CHSET_ON_SFT                                   2
+#define CHSET_ON_MASK                                  0x1
+#define CHSET_ON_MASK_SFT                              (0x1 << 2)
+#define COEFF_SRAM_CTRL_SFT                            1
+#define COEFF_SRAM_CTRL_MASK                           0x1
+#define COEFF_SRAM_CTRL_MASK_SFT                       (0x1 << 1)
+#define ASM_ON_SFT                                     0
+#define ASM_ON_MASK                                    0x1
+#define ASM_ON_MASK_SFT                                (0x1 << 0)
+
+/* AFE_GAIN1_CON0 */
+#define GAIN1_SAMPLE_PER_STEP_SFT                      8
+#define GAIN1_SAMPLE_PER_STEP_MASK                     0xff
+#define GAIN1_SAMPLE_PER_STEP_MASK_SFT                 (0xff << 8)
+#define GAIN1_MODE_SFT                                 4
+#define GAIN1_MODE_MASK                                0xf
+#define GAIN1_MODE_MASK_SFT                            (0xf << 4)
+#define GAIN1_ON_SFT                                   0
+#define GAIN1_ON_MASK                                  0x1
+#define GAIN1_ON_MASK_SFT                              (0x1 << 0)
+
+/* AFE_GAIN1_CON1 */
+#define GAIN1_TARGET_SFT                               0
+#define GAIN1_TARGET_MASK                              0xfffffff
+#define GAIN1_TARGET_MASK_SFT                          (0xfffffff << 0)
+
+/* AFE_GAIN2_CON0 */
+#define GAIN2_SAMPLE_PER_STEP_SFT                      8
+#define GAIN2_SAMPLE_PER_STEP_MASK                     0xff
+#define GAIN2_SAMPLE_PER_STEP_MASK_SFT                 (0xff << 8)
+#define GAIN2_MODE_SFT                                 4
+#define GAIN2_MODE_MASK                                0xf
+#define GAIN2_MODE_MASK_SFT                            (0xf << 4)
+#define GAIN2_ON_SFT                                   0
+#define GAIN2_ON_MASK                                  0x1
+#define GAIN2_ON_MASK_SFT                              (0x1 << 0)
+
+/* AFE_GAIN2_CON1 */
+#define GAIN2_TARGET_SFT                               0
+#define GAIN2_TARGET_MASK                              0xfffffff
+#define GAIN2_TARGET_MASK_SFT                          (0xfffffff << 0)
+
+/* AFE_GAIN1_CUR */
+#define AFE_GAIN1_CUR_SFT                              0
+#define AFE_GAIN1_CUR_MASK                             0xfffffff
+#define AFE_GAIN1_CUR_MASK_SFT                         (0xfffffff << 0)
+
+/* AFE_GAIN2_CUR */
+#define AFE_GAIN2_CUR_SFT                              0
+#define AFE_GAIN2_CUR_MASK                             0xfffffff
+#define AFE_GAIN2_CUR_MASK_SFT                         (0xfffffff << 0)
+
+/* PCM_INTF_CON1 */
+#define PCM_FIX_VALUE_SEL_SFT                          31
+#define PCM_FIX_VALUE_SEL_MASK                         0x1
+#define PCM_FIX_VALUE_SEL_MASK_SFT                     (0x1 << 31)
+#define PCM_BUFFER_LOOPBACK_SFT                        30
+#define PCM_BUFFER_LOOPBACK_MASK                       0x1
+#define PCM_BUFFER_LOOPBACK_MASK_SFT                   (0x1 << 30)
+#define PCM_PARALLEL_LOOPBACK_SFT                      29
+#define PCM_PARALLEL_LOOPBACK_MASK                     0x1
+#define PCM_PARALLEL_LOOPBACK_MASK_SFT                 (0x1 << 29)
+#define PCM_SERIAL_LOOPBACK_SFT                        28
+#define PCM_SERIAL_LOOPBACK_MASK                       0x1
+#define PCM_SERIAL_LOOPBACK_MASK_SFT                   (0x1 << 28)
+#define PCM_DAI_PCM_LOOPBACK_SFT                       27
+#define PCM_DAI_PCM_LOOPBACK_MASK                      0x1
+#define PCM_DAI_PCM_LOOPBACK_MASK_SFT                  (0x1 << 27)
+#define PCM_I2S_PCM_LOOPBACK_SFT                       26
+#define PCM_I2S_PCM_LOOPBACK_MASK                      0x1
+#define PCM_I2S_PCM_LOOPBACK_MASK_SFT                  (0x1 << 26)
+#define PCM_SYNC_DELSEL_SFT                            25
+#define PCM_SYNC_DELSEL_MASK                           0x1
+#define PCM_SYNC_DELSEL_MASK_SFT                       (0x1 << 25)
+#define PCM_TX_LR_SWAP_SFT                             24
+#define PCM_TX_LR_SWAP_MASK                            0x1
+#define PCM_TX_LR_SWAP_MASK_SFT                        (0x1 << 24)
+#define PCM_SYNC_OUT_INV_SFT                           23
+#define PCM_SYNC_OUT_INV_MASK                          0x1
+#define PCM_SYNC_OUT_INV_MASK_SFT                      (0x1 << 23)
+#define PCM_BCLK_OUT_INV_SFT                           22
+#define PCM_BCLK_OUT_INV_MASK                          0x1
+#define PCM_BCLK_OUT_INV_MASK_SFT                      (0x1 << 22)
+#define PCM_SYNC_IN_INV_SFT                            21
+#define PCM_SYNC_IN_INV_MASK                           0x1
+#define PCM_SYNC_IN_INV_MASK_SFT                       (0x1 << 21)
+#define PCM_BCLK_IN_INV_SFT                            20
+#define PCM_BCLK_IN_INV_MASK                           0x1
+#define PCM_BCLK_IN_INV_MASK_SFT                       (0x1 << 20)
+#define PCM_TX_LCH_RPT_SFT                             19
+#define PCM_TX_LCH_RPT_MASK                            0x1
+#define PCM_TX_LCH_RPT_MASK_SFT                        (0x1 << 19)
+#define PCM_VBT_16K_MODE_SFT                           18
+#define PCM_VBT_16K_MODE_MASK                          0x1
+#define PCM_VBT_16K_MODE_MASK_SFT                      (0x1 << 18)
+#define PCM_EXT_MODEM_SFT                              17
+#define PCM_EXT_MODEM_MASK                             0x1
+#define PCM_EXT_MODEM_MASK_SFT                         (0x1 << 17)
+#define PCM_24BIT_SFT                                  16
+#define PCM_24BIT_MASK                                 0x1
+#define PCM_24BIT_MASK_SFT                             (0x1 << 16)
+#define PCM_WLEN_SFT                                   14
+#define PCM_WLEN_MASK                                  0x3
+#define PCM_WLEN_MASK_SFT                              (0x3 << 14)
+#define PCM_SYNC_LENGTH_SFT                            9
+#define PCM_SYNC_LENGTH_MASK                           0x1f
+#define PCM_SYNC_LENGTH_MASK_SFT                       (0x1f << 9)
+#define PCM_SYNC_TYPE_SFT                              8
+#define PCM_SYNC_TYPE_MASK                             0x1
+#define PCM_SYNC_TYPE_MASK_SFT                         (0x1 << 8)
+#define PCM_BT_MODE_SFT                                7
+#define PCM_BT_MODE_MASK                               0x1
+#define PCM_BT_MODE_MASK_SFT                           (0x1 << 7)
+#define PCM_BYP_ASRC_SFT                               6
+#define PCM_BYP_ASRC_MASK                              0x1
+#define PCM_BYP_ASRC_MASK_SFT                          (0x1 << 6)
+#define PCM_SLAVE_SFT                                  5
+#define PCM_SLAVE_MASK                                 0x1
+#define PCM_SLAVE_MASK_SFT                             (0x1 << 5)
+#define PCM_MODE_SFT                                   3
+#define PCM_MODE_MASK                                  0x3
+#define PCM_MODE_MASK_SFT                              (0x3 << 3)
+#define PCM_FMT_SFT                                    1
+#define PCM_FMT_MASK                                   0x3
+#define PCM_FMT_MASK_SFT                               (0x3 << 1)
+#define PCM_EN_SFT                                     0
+#define PCM_EN_MASK                                    0x1
+#define PCM_EN_MASK_SFT                                (0x1 << 0)
+
+/* PCM_INTF_CON2 */
+#define PCM1_TX_FIFO_OV_SFT                            31
+#define PCM1_TX_FIFO_OV_MASK                           0x1
+#define PCM1_TX_FIFO_OV_MASK_SFT                       (0x1 << 31)
+#define PCM1_RX_FIFO_OV_SFT                            30
+#define PCM1_RX_FIFO_OV_MASK                           0x1
+#define PCM1_RX_FIFO_OV_MASK_SFT                       (0x1 << 30)
+#define PCM2_TX_FIFO_OV_SFT                            29
+#define PCM2_TX_FIFO_OV_MASK                           0x1
+#define PCM2_TX_FIFO_OV_MASK_SFT                       (0x1 << 29)
+#define PCM2_RX_FIFO_OV_SFT                            28
+#define PCM2_RX_FIFO_OV_MASK                           0x1
+#define PCM2_RX_FIFO_OV_MASK_SFT                       (0x1 << 28)
+#define PCM1_SYNC_GLITCH_SFT                           27
+#define PCM1_SYNC_GLITCH_MASK                          0x1
+#define PCM1_SYNC_GLITCH_MASK_SFT                      (0x1 << 27)
+#define PCM2_SYNC_GLITCH_SFT                           26
+#define PCM2_SYNC_GLITCH_MASK                          0x1
+#define PCM2_SYNC_GLITCH_MASK_SFT                      (0x1 << 26)
+#define TX3_RCH_DBG_MODE_SFT                           17
+#define TX3_RCH_DBG_MODE_MASK                          0x1
+#define TX3_RCH_DBG_MODE_MASK_SFT                      (0x1 << 17)
+#define PCM1_PCM2_LOOPBACK_SFT                         16
+#define PCM1_PCM2_LOOPBACK_MASK                        0x1
+#define PCM1_PCM2_LOOPBACK_MASK_SFT                    (0x1 << 16)
+#define DAI_PCM_LOOPBACK_CH_SFT                        14
+#define DAI_PCM_LOOPBACK_CH_MASK                       0x3
+#define DAI_PCM_LOOPBACK_CH_MASK_SFT                   (0x3 << 14)
+#define I2S_PCM_LOOPBACK_CH_SFT                        12
+#define I2S_PCM_LOOPBACK_CH_MASK                       0x3
+#define I2S_PCM_LOOPBACK_CH_MASK_SFT                   (0x3 << 12)
+#define TX_FIX_VALUE_SFT                               0
+#define TX_FIX_VALUE_MASK                              0xff
+#define TX_FIX_VALUE_MASK_SFT                          (0xff << 0)
+
+/* PCM2_INTF_CON */
+#define PCM2_TX_FIX_VALUE_SFT                          24
+#define PCM2_TX_FIX_VALUE_MASK                         0xff
+#define PCM2_TX_FIX_VALUE_MASK_SFT                     (0xff << 24)
+#define PCM2_FIX_VALUE_SEL_SFT                         23
+#define PCM2_FIX_VALUE_SEL_MASK                        0x1
+#define PCM2_FIX_VALUE_SEL_MASK_SFT                    (0x1 << 23)
+#define PCM2_BUFFER_LOOPBACK_SFT                       22
+#define PCM2_BUFFER_LOOPBACK_MASK                      0x1
+#define PCM2_BUFFER_LOOPBACK_MASK_SFT                  (0x1 << 22)
+#define PCM2_PARALLEL_LOOPBACK_SFT                     21
+#define PCM2_PARALLEL_LOOPBACK_MASK                    0x1
+#define PCM2_PARALLEL_LOOPBACK_MASK_SFT                (0x1 << 21)
+#define PCM2_SERIAL_LOOPBACK_SFT                       20
+#define PCM2_SERIAL_LOOPBACK_MASK                      0x1
+#define PCM2_SERIAL_LOOPBACK_MASK_SFT                  (0x1 << 20)
+#define PCM2_DAI_PCM_LOOPBACK_SFT                      19
+#define PCM2_DAI_PCM_LOOPBACK_MASK                     0x1
+#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT                 (0x1 << 19)
+#define PCM2_I2S_PCM_LOOPBACK_SFT                      18
+#define PCM2_I2S_PCM_LOOPBACK_MASK                     0x1
+#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT                 (0x1 << 18)
+#define PCM2_SYNC_DELSEL_SFT                           17
+#define PCM2_SYNC_DELSEL_MASK                          0x1
+#define PCM2_SYNC_DELSEL_MASK_SFT                      (0x1 << 17)
+#define PCM2_TX_LR_SWAP_SFT                            16
+#define PCM2_TX_LR_SWAP_MASK                           0x1
+#define PCM2_TX_LR_SWAP_MASK_SFT                       (0x1 << 16)
+#define PCM2_SYNC_IN_INV_SFT                           15
+#define PCM2_SYNC_IN_INV_MASK                          0x1
+#define PCM2_SYNC_IN_INV_MASK_SFT                      (0x1 << 15)
+#define PCM2_BCLK_IN_INV_SFT                           14
+#define PCM2_BCLK_IN_INV_MASK                          0x1
+#define PCM2_BCLK_IN_INV_MASK_SFT                      (0x1 << 14)
+#define PCM2_TX_LCH_RPT_SFT                            13
+#define PCM2_TX_LCH_RPT_MASK                           0x1
+#define PCM2_TX_LCH_RPT_MASK_SFT                       (0x1 << 13)
+#define PCM2_VBT_16K_MODE_SFT                          12
+#define PCM2_VBT_16K_MODE_MASK                         0x1
+#define PCM2_VBT_16K_MODE_MASK_SFT                     (0x1 << 12)
+#define PCM2_LOOPBACK_CH_SEL_SFT                       10
+#define PCM2_LOOPBACK_CH_SEL_MASK                      0x3
+#define PCM2_LOOPBACK_CH_SEL_MASK_SFT                  (0x3 << 10)
+#define PCM2_TX2_BT_MODE_SFT                           8
+#define PCM2_TX2_BT_MODE_MASK                          0x1
+#define PCM2_TX2_BT_MODE_MASK_SFT                      (0x1 << 8)
+#define PCM2_BT_MODE_SFT                               7
+#define PCM2_BT_MODE_MASK                              0x1
+#define PCM2_BT_MODE_MASK_SFT                          (0x1 << 7)
+#define PCM2_AFIFO_SFT                                 6
+#define PCM2_AFIFO_MASK                                0x1
+#define PCM2_AFIFO_MASK_SFT                            (0x1 << 6)
+#define PCM2_WLEN_SFT                                  5
+#define PCM2_WLEN_MASK                                 0x1
+#define PCM2_WLEN_MASK_SFT                             (0x1 << 5)
+#define PCM2_MODE_SFT                                  3
+#define PCM2_MODE_MASK                                 0x3
+#define PCM2_MODE_MASK_SFT                             (0x3 << 3)
+#define PCM2_FMT_SFT                                   1
+#define PCM2_FMT_MASK                                  0x3
+#define PCM2_FMT_MASK_SFT                              (0x3 << 1)
+#define PCM2_EN_SFT                                    0
+#define PCM2_EN_MASK                                   0x1
+#define PCM2_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_ADDA_MTKAIF_CFG0 */
+#define MTKAIF_RXIF_CLKINV_ADC_SFT                     31
+#define MTKAIF_RXIF_CLKINV_ADC_MASK                    0x1
+#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT                (0x1 << 31)
+#define MTKAIF_RXIF_BYPASS_SRC_SFT                     17
+#define MTKAIF_RXIF_BYPASS_SRC_MASK                    0x1
+#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT                (0x1 << 17)
+#define MTKAIF_RXIF_PROTOCOL2_SFT                      16
+#define MTKAIF_RXIF_PROTOCOL2_MASK                     0x1
+#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT                 (0x1 << 16)
+#define MTKAIF_TXIF_BYPASS_SRC_SFT                     5
+#define MTKAIF_TXIF_BYPASS_SRC_MASK                    0x1
+#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT                (0x1 << 5)
+#define MTKAIF_TXIF_PROTOCOL2_SFT                      4
+#define MTKAIF_TXIF_PROTOCOL2_MASK                     0x1
+#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT                 (0x1 << 4)
+#define MTKAIF_TXIF_8TO5_SFT                           2
+#define MTKAIF_TXIF_8TO5_MASK                          0x1
+#define MTKAIF_TXIF_8TO5_MASK_SFT                      (0x1 << 2)
+#define MTKAIF_RXIF_8TO5_SFT                           1
+#define MTKAIF_RXIF_8TO5_MASK                          0x1
+#define MTKAIF_RXIF_8TO5_MASK_SFT                      (0x1 << 1)
+#define MTKAIF_IF_LOOPBACK1_SFT                        0
+#define MTKAIF_IF_LOOPBACK1_MASK                       0x1
+#define MTKAIF_IF_LOOPBACK1_MASK_SFT                   (0x1 << 0)
+
+/* AFE_ADDA_MTKAIF_RX_CFG2 */
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT            16
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK           0x1
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT       (0x1 << 16)
+#define MTKAIF_RXIF_DELAY_CYCLE_SFT                    12
+#define MTKAIF_RXIF_DELAY_CYCLE_MASK                   0xf
+#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT               (0xf << 12)
+#define MTKAIF_RXIF_DELAY_DATA_SFT                     8
+#define MTKAIF_RXIF_DELAY_DATA_MASK                    0x1
+#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT                (0x1 << 8)
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT             4
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK            0x7
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT        (0x7 << 4)
+
+/* AFE_ADDA_DL_SRC2_CON0 */
+#define DL_2_INPUT_MODE_CTL_SFT                        28
+#define DL_2_INPUT_MODE_CTL_MASK                       0xf
+#define DL_2_INPUT_MODE_CTL_MASK_SFT                   (0xf << 28)
+#define DL_2_CH1_SATURATION_EN_CTL_SFT                 27
+#define DL_2_CH1_SATURATION_EN_CTL_MASK                0x1
+#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT            (0x1 << 27)
+#define DL_2_CH2_SATURATION_EN_CTL_SFT                 26
+#define DL_2_CH2_SATURATION_EN_CTL_MASK                0x1
+#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT            (0x1 << 26)
+#define DL_2_OUTPUT_SEL_CTL_SFT                        24
+#define DL_2_OUTPUT_SEL_CTL_MASK                       0x3
+#define DL_2_OUTPUT_SEL_CTL_MASK_SFT                   (0x3 << 24)
+#define DL_2_FADEIN_0START_EN_SFT                      16
+#define DL_2_FADEIN_0START_EN_MASK                     0x3
+#define DL_2_FADEIN_0START_EN_MASK_SFT                 (0x3 << 16)
+#define DL_DISABLE_HW_CG_CTL_SFT                       15
+#define DL_DISABLE_HW_CG_CTL_MASK                      0x1
+#define DL_DISABLE_HW_CG_CTL_MASK_SFT                  (0x1 << 15)
+#define C_DATA_EN_SEL_CTL_PRE_SFT                      14
+#define C_DATA_EN_SEL_CTL_PRE_MASK                     0x1
+#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT                 (0x1 << 14)
+#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT                  13
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK                 0x1
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT             (0x1 << 13)
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT                  12
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK                 0x1
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT             (0x1 << 12)
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT                  11
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK                 0x1
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT             (0x1 << 11)
+#define DL2_ARAMPSP_CTL_PRE_SFT                        9
+#define DL2_ARAMPSP_CTL_PRE_MASK                       0x3
+#define DL2_ARAMPSP_CTL_PRE_MASK_SFT                   (0x3 << 9)
+#define DL_2_IIRMODE_CTL_PRE_SFT                       6
+#define DL_2_IIRMODE_CTL_PRE_MASK                      0x7
+#define DL_2_IIRMODE_CTL_PRE_MASK_SFT                  (0x7 << 6)
+#define DL_2_VOICE_MODE_CTL_PRE_SFT                    5
+#define DL_2_VOICE_MODE_CTL_PRE_MASK                   0x1
+#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT               (0x1 << 5)
+#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT                   4
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK                  0x1
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT              (0x1 << 4)
+#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT                   3
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK                  0x1
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT              (0x1 << 3)
+#define DL_2_IIR_ON_CTL_PRE_SFT                        2
+#define DL_2_IIR_ON_CTL_PRE_MASK                       0x1
+#define DL_2_IIR_ON_CTL_PRE_MASK_SFT                   (0x1 << 2)
+#define DL_2_GAIN_ON_CTL_PRE_SFT                       1
+#define DL_2_GAIN_ON_CTL_PRE_MASK                      0x1
+#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT                  (0x1 << 1)
+#define DL_2_SRC_ON_TMP_CTL_PRE_SFT                    0
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK                   0x1
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT               (0x1 << 0)
+
+/* AFE_ADDA_DL_SRC2_CON1 */
+#define DL_2_GAIN_CTL_PRE_SFT                          16
+#define DL_2_GAIN_CTL_PRE_MASK                         0xffff
+#define DL_2_GAIN_CTL_PRE_MASK_SFT                     (0xffff << 16)
+#define DL_2_GAIN_MODE_CTL_SFT                         0
+#define DL_2_GAIN_MODE_CTL_MASK                        0x1
+#define DL_2_GAIN_MODE_CTL_MASK_SFT                    (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON0 */
+#define ULCF_CFG_EN_CTL_SFT                            31
+#define ULCF_CFG_EN_CTL_MASK                           0x1
+#define ULCF_CFG_EN_CTL_MASK_SFT                       (0x1 << 31)
+#define UL_DMIC_PHASE_SEL_CH1_SFT                      27
+#define UL_DMIC_PHASE_SEL_CH1_MASK                     0x7
+#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT                 (0x7 << 27)
+#define UL_DMIC_PHASE_SEL_CH2_SFT                      24
+#define UL_DMIC_PHASE_SEL_CH2_MASK                     0x7
+#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT                 (0x7 << 24)
+#define UL_MODE_3P25M_CH2_CTL_SFT                      22
+#define UL_MODE_3P25M_CH2_CTL_MASK                     0x1
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT                 (0x1 << 22)
+#define UL_MODE_3P25M_CH1_CTL_SFT                      21
+#define UL_MODE_3P25M_CH1_CTL_MASK                     0x1
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT                 (0x1 << 21)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT                  17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK                 0x7
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT             (0x7 << 17)
+#define UL_AP_DMIC_ON_SFT                              16
+#define UL_AP_DMIC_ON_MASK                             0x1
+#define UL_AP_DMIC_ON_MASK_SFT                         (0x1 << 16)
+#define DMIC_LOW_POWER_MODE_CTL_SFT                    14
+#define DMIC_LOW_POWER_MODE_CTL_MASK                   0x3
+#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT               (0x3 << 14)
+#define UL_DISABLE_HW_CG_CTL_SFT                       12
+#define UL_DISABLE_HW_CG_CTL_MASK                      0x1
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT                  (0x1 << 12)
+#define UL_IIR_ON_TMP_CTL_SFT                          10
+#define UL_IIR_ON_TMP_CTL_MASK                         0x1
+#define UL_IIR_ON_TMP_CTL_MASK_SFT                     (0x1 << 10)
+#define UL_IIRMODE_CTL_SFT                             7
+#define UL_IIRMODE_CTL_MASK                            0x7
+#define UL_IIRMODE_CTL_MASK_SFT                        (0x7 << 7)
+#define DIGMIC_4P33M_SEL_SFT                           6
+#define DIGMIC_4P33M_SEL_MASK                          0x1
+#define DIGMIC_4P33M_SEL_MASK_SFT                      (0x1 << 6)
+#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT                5
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK               0x1
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT           (0x1 << 5)
+#define UL_LOOP_BACK_MODE_CTL_SFT                      2
+#define UL_LOOP_BACK_MODE_CTL_MASK                     0x1
+#define UL_LOOP_BACK_MODE_CTL_MASK_SFT                 (0x1 << 2)
+#define UL_SDM_3_LEVEL_CTL_SFT                         1
+#define UL_SDM_3_LEVEL_CTL_MASK                        0x1
+#define UL_SDM_3_LEVEL_CTL_MASK_SFT                    (0x1 << 1)
+#define UL_SRC_ON_TMP_CTL_SFT                          0
+#define UL_SRC_ON_TMP_CTL_MASK                         0x1
+#define UL_SRC_ON_TMP_CTL_MASK_SFT                     (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON1 */
+#define C_DAC_EN_CTL_SFT                               27
+#define C_DAC_EN_CTL_MASK                              0x1
+#define C_DAC_EN_CTL_MASK_SFT                          (0x1 << 27)
+#define C_MUTE_SW_CTL_SFT                              26
+#define C_MUTE_SW_CTL_MASK                             0x1
+#define C_MUTE_SW_CTL_MASK_SFT                         (0x1 << 26)
+#define ASDM_SRC_SEL_CTL_SFT                           25
+#define ASDM_SRC_SEL_CTL_MASK                          0x1
+#define ASDM_SRC_SEL_CTL_MASK_SFT                      (0x1 << 25)
+#define C_AMP_DIV_CH2_CTL_SFT                          21
+#define C_AMP_DIV_CH2_CTL_MASK                         0x7
+#define C_AMP_DIV_CH2_CTL_MASK_SFT                     (0x7 << 21)
+#define C_FREQ_DIV_CH2_CTL_SFT                         16
+#define C_FREQ_DIV_CH2_CTL_MASK                        0x1f
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT                    (0x1f << 16)
+#define C_SINE_MODE_CH2_CTL_SFT                        12
+#define C_SINE_MODE_CH2_CTL_MASK                       0xf
+#define C_SINE_MODE_CH2_CTL_MASK_SFT                   (0xf << 12)
+#define C_AMP_DIV_CH1_CTL_SFT                          9
+#define C_AMP_DIV_CH1_CTL_MASK                         0x7
+#define C_AMP_DIV_CH1_CTL_MASK_SFT                     (0x7 << 9)
+#define C_FREQ_DIV_CH1_CTL_SFT                         4
+#define C_FREQ_DIV_CH1_CTL_MASK                        0x1f
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT                    (0x1f << 4)
+#define C_SINE_MODE_CH1_CTL_SFT                        0
+#define C_SINE_MODE_CH1_CTL_MASK                       0xf
+#define C_SINE_MODE_CH1_CTL_MASK_SFT                   (0xf << 0)
+
+/* AFE_ADDA_TOP_CON0 */
+#define C_LOOP_BACK_MODE_CTL_SFT                       12
+#define C_LOOP_BACK_MODE_CTL_MASK                      0xf
+#define C_LOOP_BACK_MODE_CTL_MASK_SFT                  (0xf << 12)
+#define ADDA_UL_GAIN_MODE_SFT                          8
+#define ADDA_UL_GAIN_MODE_MASK                         0x3
+#define ADDA_UL_GAIN_MODE_MASK_SFT                     (0x3 << 8)
+#define C_EXT_ADC_CTL_SFT                              0
+#define C_EXT_ADC_CTL_MASK                             0x1
+#define C_EXT_ADC_CTL_MASK_SFT                         (0x1 << 0)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_ADDA_UL_LR_SWAP_SFT                        31
+#define AFE_ADDA_UL_LR_SWAP_MASK                       0x1
+#define AFE_ADDA_UL_LR_SWAP_MASK_SFT                   (0x1 << 31)
+#define AFE_ADDA_CKDIV_RST_SFT                         30
+#define AFE_ADDA_CKDIV_RST_MASK                        0x1
+#define AFE_ADDA_CKDIV_RST_MASK_SFT                    (0x1 << 30)
+#define AFE_ADDA_FIFO_AUTO_RST_SFT                     29
+#define AFE_ADDA_FIFO_AUTO_RST_MASK                    0x1
+#define AFE_ADDA_FIFO_AUTO_RST_MASK_SFT                (0x1 << 29)
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_SFT             21
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK            0x3
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK_SFT        (0x3 << 21)
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT       20
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK      0x1
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT  (0x1 << 20)
+#define AFE_ADDA6_UL_LR_SWAP_SFT                       15
+#define AFE_ADDA6_UL_LR_SWAP_MASK                      0x1
+#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT                  (0x1 << 15)
+#define AFE_ADDA6_CKDIV_RST_SFT                        14
+#define AFE_ADDA6_CKDIV_RST_MASK                       0x1
+#define AFE_ADDA6_CKDIV_RST_MASK_SFT                   (0x1 << 14)
+#define AFE_ADDA6_FIFO_AUTO_RST_SFT                    13
+#define AFE_ADDA6_FIFO_AUTO_RST_MASK                   0x1
+#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT               (0x1 << 13)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_SFT            5
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK           0x3
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK_SFT       (0x3 << 5)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT      4
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK     0x1
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 4)
+#define ADDA_AFE_ON_SFT                                0
+#define ADDA_AFE_ON_MASK                               0x1
+#define ADDA_AFE_ON_MASK_SFT                           (0x1 << 0)
+
+/* AFE_SIDETONE_CON0 */
+#define R_RDY_SFT                                      30
+#define R_RDY_MASK                                     0x1
+#define R_RDY_MASK_SFT                                 (0x1 << 30)
+#define W_RDY_SFT                                      29
+#define W_RDY_MASK                                     0x1
+#define W_RDY_MASK_SFT                                 (0x1 << 29)
+#define R_W_EN_SFT                                     25
+#define R_W_EN_MASK                                    0x1
+#define R_W_EN_MASK_SFT                                (0x1 << 25)
+#define R_W_SEL_SFT                                    24
+#define R_W_SEL_MASK                                   0x1
+#define R_W_SEL_MASK_SFT                               (0x1 << 24)
+#define SEL_CH2_SFT                                    23
+#define SEL_CH2_MASK                                   0x1
+#define SEL_CH2_MASK_SFT                               (0x1 << 23)
+#define SIDE_TONE_COEFFICIENT_ADDR_SFT                 16
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK                0x1f
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT            (0x1f << 16)
+#define SIDE_TONE_COEFFICIENT_SFT                      0
+#define SIDE_TONE_COEFFICIENT_MASK                     0xffff
+#define SIDE_TONE_COEFFICIENT_MASK_SFT                 (0xffff << 0)
+
+/* AFE_SIDETONE_COEFF */
+#define SIDE_TONE_COEFF_SFT                            0
+#define SIDE_TONE_COEFF_MASK                           0xffff
+#define SIDE_TONE_COEFF_MASK_SFT                       (0xffff << 0)
+
+/* AFE_SIDETONE_CON1 */
+#define STF_BYPASS_MODE_SFT                            31
+#define STF_BYPASS_MODE_MASK                           0x1
+#define STF_BYPASS_MODE_MASK_SFT                       (0x1 << 31)
+#define STF_BYPASS_MODE_O28_O29_SFT                    30
+#define STF_BYPASS_MODE_O28_O29_MASK                   0x1
+#define STF_BYPASS_MODE_O28_O29_MASK_SFT               (0x1 << 30)
+#define STF_BYPASS_MODE_I2S4_SFT                       29
+#define STF_BYPASS_MODE_I2S4_MASK                      0x1
+#define STF_BYPASS_MODE_I2S4_MASK_SFT                  (0x1 << 29)
+#define STF_BYPASS_MODE_I2S5_SFT                       28
+#define STF_BYPASS_MODE_I2S5_MASK                      0x1
+#define STF_BYPASS_MODE_I2S5_MASK_SFT                  (0x1 << 28)
+#define STF_BYPASS_MODE_DL3_SFT                        27
+#define STF_BYPASS_MODE_DL3_MASK                       0x1
+#define STF_BYPASS_MODE_DL3_MASK_SFT                   (0x1 << 27)
+#define STF_BYPASS_MODE_I2S7_SFT                       26
+#define STF_BYPASS_MODE_I2S7_MASK                      0x1
+#define STF_BYPASS_MODE_I2S7_MASK_SFT                  (0x1 << 26)
+#define STF_BYPASS_MODE_I2S9_SFT                       25
+#define STF_BYPASS_MODE_I2S9_MASK                      0x1
+#define STF_BYPASS_MODE_I2S9_MASK_SFT                  (0x1 << 25)
+#define STF_O19O20_OUT_EN_SEL_SFT                      13
+#define STF_O19O20_OUT_EN_SEL_MASK                     0x1
+#define STF_O19O20_OUT_EN_SEL_MASK_SFT                 (0x1 << 13)
+#define STF_SOURCE_FROM_O19O20_SFT                     12
+#define STF_SOURCE_FROM_O19O20_MASK                    0x1
+#define STF_SOURCE_FROM_O19O20_MASK_SFT                (0x1 << 12)
+#define SIDE_TONE_ON_SFT                               8
+#define SIDE_TONE_ON_MASK                              0x1
+#define SIDE_TONE_ON_MASK_SFT                          (0x1 << 8)
+#define SIDE_TONE_HALF_TAP_NUM_SFT                     0
+#define SIDE_TONE_HALF_TAP_NUM_MASK                    0x3f
+#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT                (0x3f << 0)
+
+/* AFE_SIDETONE_GAIN */
+#define POSITIVE_GAIN_SFT                              16
+#define POSITIVE_GAIN_MASK                             0x7
+#define POSITIVE_GAIN_MASK_SFT                         (0x7 << 16)
+#define SIDE_TONE_GAIN_SFT                             0
+#define SIDE_TONE_GAIN_MASK                            0xffff
+#define SIDE_TONE_GAIN_MASK_SFT                        (0xffff << 0)
+
+/* AFE_ADDA_DL_SDM_DCCOMP_CON */
+#define USE_3RD_SDM_SFT                                28
+#define USE_3RD_SDM_MASK                               0x1
+#define USE_3RD_SDM_MASK_SFT                           (0x1 << 28)
+#define DL_FIFO_START_POINT_SFT                        24
+#define DL_FIFO_START_POINT_MASK                       0x7
+#define DL_FIFO_START_POINT_MASK_SFT                   (0x7 << 24)
+#define DL_FIFO_SWAP_SFT                               20
+#define DL_FIFO_SWAP_MASK                              0x1
+#define DL_FIFO_SWAP_MASK_SFT                          (0x1 << 20)
+#define C_AUDSDM1ORDSELECT_CTL_SFT                     19
+#define C_AUDSDM1ORDSELECT_CTL_MASK                    0x1
+#define C_AUDSDM1ORDSELECT_CTL_MASK_SFT                (0x1 << 19)
+#define C_SDM7BITSEL_CTL_SFT                           18
+#define C_SDM7BITSEL_CTL_MASK                          0x1
+#define C_SDM7BITSEL_CTL_MASK_SFT                      (0x1 << 18)
+#define GAIN_AT_SDM_RST_PRE_CTL_SFT                    15
+#define GAIN_AT_SDM_RST_PRE_CTL_MASK                   0x1
+#define GAIN_AT_SDM_RST_PRE_CTL_MASK_SFT               (0x1 << 15)
+#define DL_DCM_AUTO_IDLE_EN_SFT                        14
+#define DL_DCM_AUTO_IDLE_EN_MASK                       0x1
+#define DL_DCM_AUTO_IDLE_EN_MASK_SFT                   (0x1 << 14)
+#define AFE_DL_SRC_DCM_EN_SFT                          13
+#define AFE_DL_SRC_DCM_EN_MASK                         0x1
+#define AFE_DL_SRC_DCM_EN_MASK_SFT                     (0x1 << 13)
+#define AFE_DL_POST_SRC_DCM_EN_SFT                     12
+#define AFE_DL_POST_SRC_DCM_EN_MASK                    0x1
+#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT                (0x1 << 12)
+#define AUD_SDM_MONO_SFT                               9
+#define AUD_SDM_MONO_MASK                              0x1
+#define AUD_SDM_MONO_MASK_SFT                          (0x1 << 9)
+#define AUD_DC_COMP_EN_SFT                             8
+#define AUD_DC_COMP_EN_MASK                            0x1
+#define AUD_DC_COMP_EN_MASK_SFT                        (0x1 << 8)
+#define ATTGAIN_CTL_SFT                                0
+#define ATTGAIN_CTL_MASK                               0x3f
+#define ATTGAIN_CTL_MASK_SFT                           (0x3f << 0)
+
+/* AFE_SINEGEN_CON0 */
+#define DAC_EN_SFT                                     26
+#define DAC_EN_MASK                                    0x1
+#define DAC_EN_MASK_SFT                                (0x1 << 26)
+#define MUTE_SW_CH2_SFT                                25
+#define MUTE_SW_CH2_MASK                               0x1
+#define MUTE_SW_CH2_MASK_SFT                           (0x1 << 25)
+#define MUTE_SW_CH1_SFT                                24
+#define MUTE_SW_CH1_MASK                               0x1
+#define MUTE_SW_CH1_MASK_SFT                           (0x1 << 24)
+#define SINE_MODE_CH2_SFT                              20
+#define SINE_MODE_CH2_MASK                             0xf
+#define SINE_MODE_CH2_MASK_SFT                         (0xf << 20)
+#define AMP_DIV_CH2_SFT                                17
+#define AMP_DIV_CH2_MASK                               0x7
+#define AMP_DIV_CH2_MASK_SFT                           (0x7 << 17)
+#define FREQ_DIV_CH2_SFT                               12
+#define FREQ_DIV_CH2_MASK                              0x1f
+#define FREQ_DIV_CH2_MASK_SFT                          (0x1f << 12)
+#define SINE_MODE_CH1_SFT                              8
+#define SINE_MODE_CH1_MASK                             0xf
+#define SINE_MODE_CH1_MASK_SFT                         (0xf << 8)
+#define AMP_DIV_CH1_SFT                                5
+#define AMP_DIV_CH1_MASK                               0x7
+#define AMP_DIV_CH1_MASK_SFT                           (0x7 << 5)
+#define FREQ_DIV_CH1_SFT                               0
+#define FREQ_DIV_CH1_MASK                              0x1f
+#define FREQ_DIV_CH1_MASK_SFT                          (0x1f << 0)
+
+/* AFE_SINEGEN_CON2 */
+#define INNER_LOOP_BACK_MODE_SFT                       0
+#define INNER_LOOP_BACK_MODE_MASK                      0x3f
+#define INNER_LOOP_BACK_MODE_MASK_SFT                  (0x3f << 0)
+
+/* AFE_HD_ENGEN_ENABLE */
+#define AFE_24M_ON_SFT                                 1
+#define AFE_24M_ON_MASK                                0x1
+#define AFE_24M_ON_MASK_SFT                            (0x1 << 1)
+#define AFE_22M_ON_SFT                                 0
+#define AFE_22M_ON_MASK                                0x1
+#define AFE_22M_ON_MASK_SFT                            (0x1 << 0)
+
+/* AFE_ADDA_DL_NLE_FIFO_MON */
+#define DL_NLE_FIFO_WBIN_SFT                           8
+#define DL_NLE_FIFO_WBIN_MASK                          0xf
+#define DL_NLE_FIFO_WBIN_MASK_SFT                      (0xf << 8)
+#define DL_NLE_FIFO_RBIN_SFT                           4
+#define DL_NLE_FIFO_RBIN_MASK                          0xf
+#define DL_NLE_FIFO_RBIN_MASK_SFT                      (0xf << 4)
+#define DL_NLE_FIFO_RDACTIVE_SFT                       3
+#define DL_NLE_FIFO_RDACTIVE_MASK                      0x1
+#define DL_NLE_FIFO_RDACTIVE_MASK_SFT                  (0x1 << 3)
+#define DL_NLE_FIFO_STARTRD_SFT                        2
+#define DL_NLE_FIFO_STARTRD_MASK                       0x1
+#define DL_NLE_FIFO_STARTRD_MASK_SFT                   (0x1 << 2)
+#define DL_NLE_FIFO_RD_EMPTY_SFT                       1
+#define DL_NLE_FIFO_RD_EMPTY_MASK                      0x1
+#define DL_NLE_FIFO_RD_EMPTY_MASK_SFT                  (0x1 << 1)
+#define DL_NLE_FIFO_WR_FULL_SFT                        0
+#define DL_NLE_FIFO_WR_FULL_MASK                       0x1
+#define DL_NLE_FIFO_WR_FULL_MASK_SFT                   (0x1 << 0)
+
+/* AFE_DL1_CON0 */
+#define DL1_MODE_SFT                                   24
+#define DL1_MODE_MASK                                  0xf
+#define DL1_MODE_MASK_SFT                              (0xf << 24)
+#define DL1_MINLEN_SFT                                 20
+#define DL1_MINLEN_MASK                                0xf
+#define DL1_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL1_MAXLEN_SFT                                 16
+#define DL1_MAXLEN_MASK                                0xf
+#define DL1_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL1_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL1_PBUF_SIZE_SFT                              12
+#define DL1_PBUF_SIZE_MASK                             0x3
+#define DL1_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL1_MONO_SFT                                   8
+#define DL1_MONO_MASK                                  0x1
+#define DL1_MONO_MASK_SFT                              (0x1 << 8)
+#define DL1_NORMAL_MODE_SFT                            5
+#define DL1_NORMAL_MODE_MASK                           0x1
+#define DL1_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL1_HALIGN_SFT                                 4
+#define DL1_HALIGN_MASK                                0x1
+#define DL1_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL1_HD_MODE_SFT                                0
+#define DL1_HD_MODE_MASK                               0x3
+#define DL1_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL2_CON0 */
+#define DL2_MODE_SFT                                   24
+#define DL2_MODE_MASK                                  0xf
+#define DL2_MODE_MASK_SFT                              (0xf << 24)
+#define DL2_MINLEN_SFT                                 20
+#define DL2_MINLEN_MASK                                0xf
+#define DL2_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL2_MAXLEN_SFT                                 16
+#define DL2_MAXLEN_MASK                                0xf
+#define DL2_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL2_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL2_PBUF_SIZE_SFT                              12
+#define DL2_PBUF_SIZE_MASK                             0x3
+#define DL2_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL2_MONO_SFT                                   8
+#define DL2_MONO_MASK                                  0x1
+#define DL2_MONO_MASK_SFT                              (0x1 << 8)
+#define DL2_NORMAL_MODE_SFT                            5
+#define DL2_NORMAL_MODE_MASK                           0x1
+#define DL2_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL2_HALIGN_SFT                                 4
+#define DL2_HALIGN_MASK                                0x1
+#define DL2_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL2_HD_MODE_SFT                                0
+#define DL2_HD_MODE_MASK                               0x3
+#define DL2_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL3_CON0 */
+#define DL3_MODE_SFT                                   24
+#define DL3_MODE_MASK                                  0xf
+#define DL3_MODE_MASK_SFT                              (0xf << 24)
+#define DL3_MINLEN_SFT                                 20
+#define DL3_MINLEN_MASK                                0xf
+#define DL3_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL3_MAXLEN_SFT                                 16
+#define DL3_MAXLEN_MASK                                0xf
+#define DL3_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL3_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL3_PBUF_SIZE_SFT                              12
+#define DL3_PBUF_SIZE_MASK                             0x3
+#define DL3_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL3_MONO_SFT                                   8
+#define DL3_MONO_MASK                                  0x1
+#define DL3_MONO_MASK_SFT                              (0x1 << 8)
+#define DL3_NORMAL_MODE_SFT                            5
+#define DL3_NORMAL_MODE_MASK                           0x1
+#define DL3_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL3_HALIGN_SFT                                 4
+#define DL3_HALIGN_MASK                                0x1
+#define DL3_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL3_HD_MODE_SFT                                0
+#define DL3_HD_MODE_MASK                               0x3
+#define DL3_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL4_CON0 */
+#define DL4_MODE_SFT                                   24
+#define DL4_MODE_MASK                                  0xf
+#define DL4_MODE_MASK_SFT                              (0xf << 24)
+#define DL4_MINLEN_SFT                                 20
+#define DL4_MINLEN_MASK                                0xf
+#define DL4_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL4_MAXLEN_SFT                                 16
+#define DL4_MAXLEN_MASK                                0xf
+#define DL4_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL4_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL4_PBUF_SIZE_SFT                              12
+#define DL4_PBUF_SIZE_MASK                             0x3
+#define DL4_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL4_MONO_SFT                                   8
+#define DL4_MONO_MASK                                  0x1
+#define DL4_MONO_MASK_SFT                              (0x1 << 8)
+#define DL4_NORMAL_MODE_SFT                            5
+#define DL4_NORMAL_MODE_MASK                           0x1
+#define DL4_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL4_HALIGN_SFT                                 4
+#define DL4_HALIGN_MASK                                0x1
+#define DL4_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL4_HD_MODE_SFT                                0
+#define DL4_HD_MODE_MASK                               0x3
+#define DL4_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL5_CON0 */
+#define DL5_MODE_SFT                                   24
+#define DL5_MODE_MASK                                  0xf
+#define DL5_MODE_MASK_SFT                              (0xf << 24)
+#define DL5_MINLEN_SFT                                 20
+#define DL5_MINLEN_MASK                                0xf
+#define DL5_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL5_MAXLEN_SFT                                 16
+#define DL5_MAXLEN_MASK                                0xf
+#define DL5_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL5_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL5_PBUF_SIZE_SFT                              12
+#define DL5_PBUF_SIZE_MASK                             0x3
+#define DL5_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL5_MONO_SFT                                   8
+#define DL5_MONO_MASK                                  0x1
+#define DL5_MONO_MASK_SFT                              (0x1 << 8)
+#define DL5_NORMAL_MODE_SFT                            5
+#define DL5_NORMAL_MODE_MASK                           0x1
+#define DL5_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL5_HALIGN_SFT                                 4
+#define DL5_HALIGN_MASK                                0x1
+#define DL5_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL5_HD_MODE_SFT                                0
+#define DL5_HD_MODE_MASK                               0x3
+#define DL5_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL6_CON0 */
+#define DL6_MODE_SFT                                   24
+#define DL6_MODE_MASK                                  0xf
+#define DL6_MODE_MASK_SFT                              (0xf << 24)
+#define DL6_MINLEN_SFT                                 20
+#define DL6_MINLEN_MASK                                0xf
+#define DL6_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL6_MAXLEN_SFT                                 16
+#define DL6_MAXLEN_MASK                                0xf
+#define DL6_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL6_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL6_PBUF_SIZE_SFT                              12
+#define DL6_PBUF_SIZE_MASK                             0x3
+#define DL6_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL6_MONO_SFT                                   8
+#define DL6_MONO_MASK                                  0x1
+#define DL6_MONO_MASK_SFT                              (0x1 << 8)
+#define DL6_NORMAL_MODE_SFT                            5
+#define DL6_NORMAL_MODE_MASK                           0x1
+#define DL6_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL6_HALIGN_SFT                                 4
+#define DL6_HALIGN_MASK                                0x1
+#define DL6_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL6_HD_MODE_SFT                                0
+#define DL6_HD_MODE_MASK                               0x3
+#define DL6_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL7_CON0 */
+#define DL7_MODE_SFT                                   24
+#define DL7_MODE_MASK                                  0xf
+#define DL7_MODE_MASK_SFT                              (0xf << 24)
+#define DL7_MINLEN_SFT                                 20
+#define DL7_MINLEN_MASK                                0xf
+#define DL7_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL7_MAXLEN_SFT                                 16
+#define DL7_MAXLEN_MASK                                0xf
+#define DL7_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL7_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL7_PBUF_SIZE_SFT                              12
+#define DL7_PBUF_SIZE_MASK                             0x3
+#define DL7_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL7_MONO_SFT                                   8
+#define DL7_MONO_MASK                                  0x1
+#define DL7_MONO_MASK_SFT                              (0x1 << 8)
+#define DL7_NORMAL_MODE_SFT                            5
+#define DL7_NORMAL_MODE_MASK                           0x1
+#define DL7_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL7_HALIGN_SFT                                 4
+#define DL7_HALIGN_MASK                                0x1
+#define DL7_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL7_HD_MODE_SFT                                0
+#define DL7_HD_MODE_MASK                               0x3
+#define DL7_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL8_CON0 */
+#define DL8_MODE_SFT                                   24
+#define DL8_MODE_MASK                                  0xf
+#define DL8_MODE_MASK_SFT                              (0xf << 24)
+#define DL8_MINLEN_SFT                                 20
+#define DL8_MINLEN_MASK                                0xf
+#define DL8_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL8_MAXLEN_SFT                                 16
+#define DL8_MAXLEN_MASK                                0xf
+#define DL8_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL8_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL8_PBUF_SIZE_SFT                              12
+#define DL8_PBUF_SIZE_MASK                             0x3
+#define DL8_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL8_MONO_SFT                                   8
+#define DL8_MONO_MASK                                  0x1
+#define DL8_MONO_MASK_SFT                              (0x1 << 8)
+#define DL8_NORMAL_MODE_SFT                            5
+#define DL8_NORMAL_MODE_MASK                           0x1
+#define DL8_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL8_HALIGN_SFT                                 4
+#define DL8_HALIGN_MASK                                0x1
+#define DL8_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL8_HD_MODE_SFT                                0
+#define DL8_HD_MODE_MASK                               0x3
+#define DL8_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL9_CON0 */
+#define DL9_MODE_SFT                                   24
+#define DL9_MODE_MASK                                  0xf
+#define DL9_MODE_MASK_SFT                              (0xf << 24)
+#define DL9_MINLEN_SFT                                 20
+#define DL9_MINLEN_MASK                                0xf
+#define DL9_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL9_MAXLEN_SFT                                 16
+#define DL9_MAXLEN_MASK                                0xf
+#define DL9_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL9_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL9_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL9_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL9_PBUF_SIZE_SFT                              12
+#define DL9_PBUF_SIZE_MASK                             0x3
+#define DL9_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL9_MONO_SFT                                   8
+#define DL9_MONO_MASK                                  0x1
+#define DL9_MONO_MASK_SFT                              (0x1 << 8)
+#define DL9_NORMAL_MODE_SFT                            5
+#define DL9_NORMAL_MODE_MASK                           0x1
+#define DL9_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL9_HALIGN_SFT                                 4
+#define DL9_HALIGN_MASK                                0x1
+#define DL9_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL9_HD_MODE_SFT                                0
+#define DL9_HD_MODE_MASK                               0x3
+#define DL9_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL12_CON0 */
+#define DL12_MODE_SFT                                  24
+#define DL12_MODE_MASK                                 0xf
+#define DL12_MODE_MASK_SFT                             (0xf << 24)
+#define DL12_MINLEN_SFT                                20
+#define DL12_MINLEN_MASK                               0xf
+#define DL12_MINLEN_MASK_SFT                           (0xf << 20)
+#define DL12_MAXLEN_SFT                                16
+#define DL12_MAXLEN_MASK                               0xf
+#define DL12_MAXLEN_MASK_SFT                           (0xf << 16)
+#define DL12_SW_CLEAR_BUF_EMPTY_SFT                    15
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK                   0x1
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK_SFT               (0x1 << 15)
+#define DL12_PBUF_SIZE_SFT                             12
+#define DL12_PBUF_SIZE_MASK                            0x3
+#define DL12_PBUF_SIZE_MASK_SFT                        (0x3 << 12)
+#define DL12_4CH_EN_SFT                                11
+#define DL12_4CH_EN_MASK                               0x1
+#define DL12_4CH_EN_MASK_SFT                           (0x1 << 11)
+#define DL12_MONO_SFT                                  8
+#define DL12_MONO_MASK                                 0x1
+#define DL12_MONO_MASK_SFT                             (0x1 << 8)
+#define DL12_NORMAL_MODE_SFT                           5
+#define DL12_NORMAL_MODE_MASK                          0x1
+#define DL12_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define DL12_HALIGN_SFT                                4
+#define DL12_HALIGN_MASK                               0x1
+#define DL12_HALIGN_MASK_SFT                           (0x1 << 4)
+#define DL12_HD_MODE_SFT                               0
+#define DL12_HD_MODE_MASK                              0x3
+#define DL12_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_AWB_CON0 */
+#define AWB_MODE_SFT                                   24
+#define AWB_MODE_MASK                                  0xf
+#define AWB_MODE_MASK_SFT                              (0xf << 24)
+#define AWB_SW_CLEAR_BUF_FULL_SFT                      15
+#define AWB_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define AWB_SW_CLEAR_BUF_FULL_MASK_SFT                 (0x1 << 15)
+#define AWB_R_MONO_SFT                                 9
+#define AWB_R_MONO_MASK                                0x1
+#define AWB_R_MONO_MASK_SFT                            (0x1 << 9)
+#define AWB_MONO_SFT                                   8
+#define AWB_MONO_MASK                                  0x1
+#define AWB_MONO_MASK_SFT                              (0x1 << 8)
+#define AWB_WR_SIGN_SFT                                6
+#define AWB_WR_SIGN_MASK                               0x1
+#define AWB_WR_SIGN_MASK_SFT                           (0x1 << 6)
+#define AWB_NORMAL_MODE_SFT                            5
+#define AWB_NORMAL_MODE_MASK                           0x1
+#define AWB_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define AWB_HALIGN_SFT                                 4
+#define AWB_HALIGN_MASK                                0x1
+#define AWB_HALIGN_MASK_SFT                            (0x1 << 4)
+#define AWB_HD_MODE_SFT                                0
+#define AWB_HD_MODE_MASK                               0x3
+#define AWB_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_AWB2_CON0 */
+#define AWB2_MODE_SFT                                  24
+#define AWB2_MODE_MASK                                 0xf
+#define AWB2_MODE_MASK_SFT                             (0xf << 24)
+#define AWB2_SW_CLEAR_BUF_FULL_SFT                     15
+#define AWB2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define AWB2_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define AWB2_R_MONO_SFT                                9
+#define AWB2_R_MONO_MASK                               0x1
+#define AWB2_R_MONO_MASK_SFT                           (0x1 << 9)
+#define AWB2_MONO_SFT                                  8
+#define AWB2_MONO_MASK                                 0x1
+#define AWB2_MONO_MASK_SFT                             (0x1 << 8)
+#define AWB2_WR_SIGN_SFT                               6
+#define AWB2_WR_SIGN_MASK                              0x1
+#define AWB2_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define AWB2_NORMAL_MODE_SFT                           5
+#define AWB2_NORMAL_MODE_MASK                          0x1
+#define AWB2_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define AWB2_HALIGN_SFT                                4
+#define AWB2_HALIGN_MASK                               0x1
+#define AWB2_HALIGN_MASK_SFT                           (0x1 << 4)
+#define AWB2_HD_MODE_SFT                               0
+#define AWB2_HD_MODE_MASK                              0x3
+#define AWB2_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL_CON0 */
+#define VUL_MODE_SFT                                   24
+#define VUL_MODE_MASK                                  0xf
+#define VUL_MODE_MASK_SFT                              (0xf << 24)
+#define VUL_SW_CLEAR_BUF_FULL_SFT                      15
+#define VUL_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define VUL_SW_CLEAR_BUF_FULL_MASK_SFT                 (0x1 << 15)
+#define VUL_R_MONO_SFT                                 9
+#define VUL_R_MONO_MASK                                0x1
+#define VUL_R_MONO_MASK_SFT                            (0x1 << 9)
+#define VUL_MONO_SFT                                   8
+#define VUL_MONO_MASK                                  0x1
+#define VUL_MONO_MASK_SFT                              (0x1 << 8)
+#define VUL_WR_SIGN_SFT                                6
+#define VUL_WR_SIGN_MASK                               0x1
+#define VUL_WR_SIGN_MASK_SFT                           (0x1 << 6)
+#define VUL_NORMAL_MODE_SFT                            5
+#define VUL_NORMAL_MODE_MASK                           0x1
+#define VUL_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define VUL_HALIGN_SFT                                 4
+#define VUL_HALIGN_MASK                                0x1
+#define VUL_HALIGN_MASK_SFT                            (0x1 << 4)
+#define VUL_HD_MODE_SFT                                0
+#define VUL_HD_MODE_MASK                               0x3
+#define VUL_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_VUL12_CON0 */
+#define VUL12_MODE_SFT                                 24
+#define VUL12_MODE_MASK                                0xf
+#define VUL12_MODE_MASK_SFT                            (0xf << 24)
+#define VUL12_SW_CLEAR_BUF_FULL_SFT                    15
+#define VUL12_SW_CLEAR_BUF_FULL_MASK                   0x1
+#define VUL12_SW_CLEAR_BUF_FULL_MASK_SFT               (0x1 << 15)
+#define VUL12_4CH_EN_SFT                               11
+#define VUL12_4CH_EN_MASK                              0x1
+#define VUL12_4CH_EN_MASK_SFT                          (0x1 << 11)
+#define VUL12_R_MONO_SFT                               9
+#define VUL12_R_MONO_MASK                              0x1
+#define VUL12_R_MONO_MASK_SFT                          (0x1 << 9)
+#define VUL12_MONO_SFT                                 8
+#define VUL12_MONO_MASK                                0x1
+#define VUL12_MONO_MASK_SFT                            (0x1 << 8)
+#define VUL12_WR_SIGN_SFT                              6
+#define VUL12_WR_SIGN_MASK                             0x1
+#define VUL12_WR_SIGN_MASK_SFT                         (0x1 << 6)
+#define VUL12_NORMAL_MODE_SFT                          5
+#define VUL12_NORMAL_MODE_MASK                         0x1
+#define VUL12_NORMAL_MODE_MASK_SFT                     (0x1 << 5)
+#define VUL12_HALIGN_SFT                               4
+#define VUL12_HALIGN_MASK                              0x1
+#define VUL12_HALIGN_MASK_SFT                          (0x1 << 4)
+#define VUL12_HD_MODE_SFT                              0
+#define VUL12_HD_MODE_MASK                             0x3
+#define VUL12_HD_MODE_MASK_SFT                         (0x3 << 0)
+
+/* AFE_VUL2_CON0 */
+#define VUL2_MODE_SFT                                  24
+#define VUL2_MODE_MASK                                 0xf
+#define VUL2_MODE_MASK_SFT                             (0xf << 24)
+#define VUL2_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL2_R_MONO_SFT                                9
+#define VUL2_R_MONO_MASK                               0x1
+#define VUL2_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL2_MONO_SFT                                  8
+#define VUL2_MONO_MASK                                 0x1
+#define VUL2_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL2_WR_SIGN_SFT                               6
+#define VUL2_WR_SIGN_MASK                              0x1
+#define VUL2_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL2_NORMAL_MODE_SFT                           5
+#define VUL2_NORMAL_MODE_MASK                          0x1
+#define VUL2_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL2_HALIGN_SFT                                4
+#define VUL2_HALIGN_MASK                               0x1
+#define VUL2_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL2_HD_MODE_SFT                               0
+#define VUL2_HD_MODE_MASK                              0x3
+#define VUL2_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL3_CON0 */
+#define VUL3_MODE_SFT                                  24
+#define VUL3_MODE_MASK                                 0xf
+#define VUL3_MODE_MASK_SFT                             (0xf << 24)
+#define VUL3_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL3_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL3_R_MONO_SFT                                9
+#define VUL3_R_MONO_MASK                               0x1
+#define VUL3_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL3_MONO_SFT                                  8
+#define VUL3_MONO_MASK                                 0x1
+#define VUL3_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL3_WR_SIGN_SFT                               6
+#define VUL3_WR_SIGN_MASK                              0x1
+#define VUL3_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL3_NORMAL_MODE_SFT                           5
+#define VUL3_NORMAL_MODE_MASK                          0x1
+#define VUL3_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL3_HALIGN_SFT                                4
+#define VUL3_HALIGN_MASK                               0x1
+#define VUL3_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL3_HD_MODE_SFT                               0
+#define VUL3_HD_MODE_MASK                              0x3
+#define VUL3_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL4_CON0 */
+#define VUL4_MODE_SFT                                  24
+#define VUL4_MODE_MASK                                 0xf
+#define VUL4_MODE_MASK_SFT                             (0xf << 24)
+#define VUL4_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL4_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL4_R_MONO_SFT                                9
+#define VUL4_R_MONO_MASK                               0x1
+#define VUL4_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL4_MONO_SFT                                  8
+#define VUL4_MONO_MASK                                 0x1
+#define VUL4_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL4_WR_SIGN_SFT                               6
+#define VUL4_WR_SIGN_MASK                              0x1
+#define VUL4_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL4_NORMAL_MODE_SFT                           5
+#define VUL4_NORMAL_MODE_MASK                          0x1
+#define VUL4_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL4_HALIGN_SFT                                4
+#define VUL4_HALIGN_MASK                               0x1
+#define VUL4_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL4_HD_MODE_SFT                               0
+#define VUL4_HD_MODE_MASK                              0x3
+#define VUL4_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL5_CON0 */
+#define VUL5_MODE_SFT                                  24
+#define VUL5_MODE_MASK                                 0xf
+#define VUL5_MODE_MASK_SFT                             (0xf << 24)
+#define VUL5_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL5_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL5_R_MONO_SFT                                9
+#define VUL5_R_MONO_MASK                               0x1
+#define VUL5_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL5_MONO_SFT                                  8
+#define VUL5_MONO_MASK                                 0x1
+#define VUL5_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL5_WR_SIGN_SFT                               6
+#define VUL5_WR_SIGN_MASK                              0x1
+#define VUL5_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL5_NORMAL_MODE_SFT                           5
+#define VUL5_NORMAL_MODE_MASK                          0x1
+#define VUL5_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL5_HALIGN_SFT                                4
+#define VUL5_HALIGN_MASK                               0x1
+#define VUL5_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL5_HD_MODE_SFT                               0
+#define VUL5_HD_MODE_MASK                              0x3
+#define VUL5_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL6_CON0 */
+#define VUL6_MODE_SFT                                  24
+#define VUL6_MODE_MASK                                 0xf
+#define VUL6_MODE_MASK_SFT                             (0xf << 24)
+#define VUL6_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL6_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL6_R_MONO_SFT                                9
+#define VUL6_R_MONO_MASK                               0x1
+#define VUL6_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL6_MONO_SFT                                  8
+#define VUL6_MONO_MASK                                 0x1
+#define VUL6_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL6_WR_SIGN_SFT                               6
+#define VUL6_WR_SIGN_MASK                              0x1
+#define VUL6_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL6_NORMAL_MODE_SFT                           5
+#define VUL6_NORMAL_MODE_MASK                          0x1
+#define VUL6_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL6_HALIGN_SFT                                4
+#define VUL6_HALIGN_MASK                               0x1
+#define VUL6_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL6_HD_MODE_SFT                               0
+#define VUL6_HD_MODE_MASK                              0x3
+#define VUL6_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_DAI_CON0 */
+#define DAI_MODE_SFT                                   24
+#define DAI_MODE_MASK                                  0x3
+#define DAI_MODE_MASK_SFT                              (0x3 << 24)
+#define DAI_SW_CLEAR_BUF_FULL_SFT                      15
+#define DAI_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define DAI_SW_CLEAR_BUF_FULL_MASK_SFT                 (0x1 << 15)
+#define DAI_DUPLICATE_WR_SFT                           10
+#define DAI_DUPLICATE_WR_MASK                          0x1
+#define DAI_DUPLICATE_WR_MASK_SFT                      (0x1 << 10)
+#define DAI_MONO_SFT                                   8
+#define DAI_MONO_MASK                                  0x1
+#define DAI_MONO_MASK_SFT                              (0x1 << 8)
+#define DAI_WR_SIGN_SFT                                6
+#define DAI_WR_SIGN_MASK                               0x1
+#define DAI_WR_SIGN_MASK_SFT                           (0x1 << 6)
+#define DAI_NORMAL_MODE_SFT                            5
+#define DAI_NORMAL_MODE_MASK                           0x1
+#define DAI_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DAI_HALIGN_SFT                                 4
+#define DAI_HALIGN_MASK                                0x1
+#define DAI_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DAI_HD_MODE_SFT                                0
+#define DAI_HD_MODE_MASK                               0x3
+#define DAI_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_MOD_DAI_CON0 */
+#define MOD_DAI_MODE_SFT                               24
+#define MOD_DAI_MODE_MASK                              0x3
+#define MOD_DAI_MODE_MASK_SFT                          (0x3 << 24)
+#define MOD_DAI_SW_CLEAR_BUF_FULL_SFT                  15
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK                 0x1
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK_SFT             (0x1 << 15)
+#define MOD_DAI_DUPLICATE_WR_SFT                       10
+#define MOD_DAI_DUPLICATE_WR_MASK                      0x1
+#define MOD_DAI_DUPLICATE_WR_MASK_SFT                  (0x1 << 10)
+#define MOD_DAI_MONO_SFT                               8
+#define MOD_DAI_MONO_MASK                              0x1
+#define MOD_DAI_MONO_MASK_SFT                          (0x1 << 8)
+#define MOD_DAI_WR_SIGN_SFT                            6
+#define MOD_DAI_WR_SIGN_MASK                           0x1
+#define MOD_DAI_WR_SIGN_MASK_SFT                       (0x1 << 6)
+#define MOD_DAI_NORMAL_MODE_SFT                        5
+#define MOD_DAI_NORMAL_MODE_MASK                       0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT                   (0x1 << 5)
+#define MOD_DAI_HALIGN_SFT                             4
+#define MOD_DAI_HALIGN_MASK                            0x1
+#define MOD_DAI_HALIGN_MASK_SFT                        (0x1 << 4)
+#define MOD_DAI_HD_MODE_SFT                            0
+#define MOD_DAI_HD_MODE_MASK                           0x3
+#define MOD_DAI_HD_MODE_MASK_SFT                       (0x3 << 0)
+
+/* AFE_DAI2_CON0 */
+#define DAI2_MODE_SFT                                  24
+#define DAI2_MODE_MASK                                 0xf
+#define DAI2_MODE_MASK_SFT                             (0xf << 24)
+#define DAI2_SW_CLEAR_BUF_FULL_SFT                     15
+#define DAI2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define DAI2_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define DAI2_DUPLICATE_WR_SFT                          10
+#define DAI2_DUPLICATE_WR_MASK                         0x1
+#define DAI2_DUPLICATE_WR_MASK_SFT                     (0x1 << 10)
+#define DAI2_MONO_SFT                                  8
+#define DAI2_MONO_MASK                                 0x1
+#define DAI2_MONO_MASK_SFT                             (0x1 << 8)
+#define DAI2_WR_SIGN_SFT                               6
+#define DAI2_WR_SIGN_MASK                              0x1
+#define DAI2_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define DAI2_NORMAL_MODE_SFT                           5
+#define DAI2_NORMAL_MODE_MASK                          0x1
+#define DAI2_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define DAI2_HALIGN_SFT                                4
+#define DAI2_HALIGN_MASK                               0x1
+#define DAI2_HALIGN_MASK_SFT                           (0x1 << 4)
+#define DAI2_HD_MODE_SFT                               0
+#define DAI2_HD_MODE_MASK                              0x3
+#define DAI2_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_MEMIF_CON0 */
+#define CPU_COMPACT_MODE_SFT                           2
+#define CPU_COMPACT_MODE_MASK                          0x1
+#define CPU_COMPACT_MODE_MASK_SFT                      (0x1 << 2)
+#define CPU_HD_ALIGN_SFT                               1
+#define CPU_HD_ALIGN_MASK                              0x1
+#define CPU_HD_ALIGN_MASK_SFT                          (0x1 << 1)
+#define SYSRAM_SIGN_SFT                                0
+#define SYSRAM_SIGN_MASK                               0x1
+#define SYSRAM_SIGN_MASK_SFT                           (0x1 << 0)
+
+/* AFE_HDMI_OUT_CON0 */
+#define HDMI_CH_NUM_SFT                                24
+#define HDMI_CH_NUM_MASK                               0xf
+#define HDMI_CH_NUM_MASK_SFT                           (0xf << 24)
+#define HDMI_OUT_MINLEN_SFT                            20
+#define HDMI_OUT_MINLEN_MASK                           0xf
+#define HDMI_OUT_MINLEN_MASK_SFT                       (0xf << 20)
+#define HDMI_OUT_MAXLEN_SFT                            16
+#define HDMI_OUT_MAXLEN_MASK                           0xf
+#define HDMI_OUT_MAXLEN_MASK_SFT                       (0xf << 16)
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_SFT                15
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK               0x1
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK_SFT           (0x1 << 15)
+#define HDMI_OUT_PBUF_SIZE_SFT                         12
+#define HDMI_OUT_PBUF_SIZE_MASK                        0x3
+#define HDMI_OUT_PBUF_SIZE_MASK_SFT                    (0x3 << 12)
+#define HDMI_OUT_NORMAL_MODE_SFT                       5
+#define HDMI_OUT_NORMAL_MODE_MASK                      0x1
+#define HDMI_OUT_NORMAL_MODE_MASK_SFT                  (0x1 << 5)
+#define HDMI_OUT_HALIGN_SFT                            4
+#define HDMI_OUT_HALIGN_MASK                           0x1
+#define HDMI_OUT_HALIGN_MASK_SFT                       (0x1 << 4)
+#define HDMI_OUT_HD_MODE_SFT                           0
+#define HDMI_OUT_HD_MODE_MASK                          0x3
+#define HDMI_OUT_HD_MODE_MASK_SFT                      (0x3 << 0)
+
+/* AFE_IRQ_MCU_CON0 */
+#define IRQ31_MCU_ON_SFT                               31
+#define IRQ31_MCU_ON_MASK                              0x1
+#define IRQ31_MCU_ON_MASK_SFT                          (0x1 << 31)
+#define IRQ26_MCU_ON_SFT                               26
+#define IRQ26_MCU_ON_MASK                              0x1
+#define IRQ26_MCU_ON_MASK_SFT                          (0x1 << 26)
+#define IRQ25_MCU_ON_SFT                               25
+#define IRQ25_MCU_ON_MASK                              0x1
+#define IRQ25_MCU_ON_MASK_SFT                          (0x1 << 25)
+#define IRQ24_MCU_ON_SFT                               24
+#define IRQ24_MCU_ON_MASK                              0x1
+#define IRQ24_MCU_ON_MASK_SFT                          (0x1 << 24)
+#define IRQ23_MCU_ON_SFT                               23
+#define IRQ23_MCU_ON_MASK                              0x1
+#define IRQ23_MCU_ON_MASK_SFT                          (0x1 << 23)
+#define IRQ22_MCU_ON_SFT                               22
+#define IRQ22_MCU_ON_MASK                              0x1
+#define IRQ22_MCU_ON_MASK_SFT                          (0x1 << 22)
+#define IRQ21_MCU_ON_SFT                               21
+#define IRQ21_MCU_ON_MASK                              0x1
+#define IRQ21_MCU_ON_MASK_SFT                          (0x1 << 21)
+#define IRQ20_MCU_ON_SFT                               20
+#define IRQ20_MCU_ON_MASK                              0x1
+#define IRQ20_MCU_ON_MASK_SFT                          (0x1 << 20)
+#define IRQ19_MCU_ON_SFT                               19
+#define IRQ19_MCU_ON_MASK                              0x1
+#define IRQ19_MCU_ON_MASK_SFT                          (0x1 << 19)
+#define IRQ18_MCU_ON_SFT                               18
+#define IRQ18_MCU_ON_MASK                              0x1
+#define IRQ18_MCU_ON_MASK_SFT                          (0x1 << 18)
+#define IRQ17_MCU_ON_SFT                               17
+#define IRQ17_MCU_ON_MASK                              0x1
+#define IRQ17_MCU_ON_MASK_SFT                          (0x1 << 17)
+#define IRQ16_MCU_ON_SFT                               16
+#define IRQ16_MCU_ON_MASK                              0x1
+#define IRQ16_MCU_ON_MASK_SFT                          (0x1 << 16)
+#define IRQ15_MCU_ON_SFT                               15
+#define IRQ15_MCU_ON_MASK                              0x1
+#define IRQ15_MCU_ON_MASK_SFT                          (0x1 << 15)
+#define IRQ14_MCU_ON_SFT                               14
+#define IRQ14_MCU_ON_MASK                              0x1
+#define IRQ14_MCU_ON_MASK_SFT                          (0x1 << 14)
+#define IRQ13_MCU_ON_SFT                               13
+#define IRQ13_MCU_ON_MASK                              0x1
+#define IRQ13_MCU_ON_MASK_SFT                          (0x1 << 13)
+#define IRQ12_MCU_ON_SFT                               12
+#define IRQ12_MCU_ON_MASK                              0x1
+#define IRQ12_MCU_ON_MASK_SFT                          (0x1 << 12)
+#define IRQ11_MCU_ON_SFT                               11
+#define IRQ11_MCU_ON_MASK                              0x1
+#define IRQ11_MCU_ON_MASK_SFT                          (0x1 << 11)
+#define IRQ10_MCU_ON_SFT                               10
+#define IRQ10_MCU_ON_MASK                              0x1
+#define IRQ10_MCU_ON_MASK_SFT                          (0x1 << 10)
+#define IRQ9_MCU_ON_SFT                                9
+#define IRQ9_MCU_ON_MASK                               0x1
+#define IRQ9_MCU_ON_MASK_SFT                           (0x1 << 9)
+#define IRQ8_MCU_ON_SFT                                8
+#define IRQ8_MCU_ON_MASK                               0x1
+#define IRQ8_MCU_ON_MASK_SFT                           (0x1 << 8)
+#define IRQ7_MCU_ON_SFT                                7
+#define IRQ7_MCU_ON_MASK                               0x1
+#define IRQ7_MCU_ON_MASK_SFT                           (0x1 << 7)
+#define IRQ6_MCU_ON_SFT                                6
+#define IRQ6_MCU_ON_MASK                               0x1
+#define IRQ6_MCU_ON_MASK_SFT                           (0x1 << 6)
+#define IRQ5_MCU_ON_SFT                                5
+#define IRQ5_MCU_ON_MASK                               0x1
+#define IRQ5_MCU_ON_MASK_SFT                           (0x1 << 5)
+#define IRQ4_MCU_ON_SFT                                4
+#define IRQ4_MCU_ON_MASK                               0x1
+#define IRQ4_MCU_ON_MASK_SFT                           (0x1 << 4)
+#define IRQ3_MCU_ON_SFT                                3
+#define IRQ3_MCU_ON_MASK                               0x1
+#define IRQ3_MCU_ON_MASK_SFT                           (0x1 << 3)
+#define IRQ2_MCU_ON_SFT                                2
+#define IRQ2_MCU_ON_MASK                               0x1
+#define IRQ2_MCU_ON_MASK_SFT                           (0x1 << 2)
+#define IRQ1_MCU_ON_SFT                                1
+#define IRQ1_MCU_ON_MASK                               0x1
+#define IRQ1_MCU_ON_MASK_SFT                           (0x1 << 1)
+#define IRQ0_MCU_ON_SFT                                0
+#define IRQ0_MCU_ON_MASK                               0x1
+#define IRQ0_MCU_ON_MASK_SFT                           (0x1 << 0)
+
+/* AFE_IRQ_MCU_CON1 */
+#define IRQ7_MCU_MODE_SFT                              28
+#define IRQ7_MCU_MODE_MASK                             0xf
+#define IRQ7_MCU_MODE_MASK_SFT                         (0xf << 28)
+#define IRQ6_MCU_MODE_SFT                              24
+#define IRQ6_MCU_MODE_MASK                             0xf
+#define IRQ6_MCU_MODE_MASK_SFT                         (0xf << 24)
+#define IRQ5_MCU_MODE_SFT                              20
+#define IRQ5_MCU_MODE_MASK                             0xf
+#define IRQ5_MCU_MODE_MASK_SFT                         (0xf << 20)
+#define IRQ4_MCU_MODE_SFT                              16
+#define IRQ4_MCU_MODE_MASK                             0xf
+#define IRQ4_MCU_MODE_MASK_SFT                         (0xf << 16)
+#define IRQ3_MCU_MODE_SFT                              12
+#define IRQ3_MCU_MODE_MASK                             0xf
+#define IRQ3_MCU_MODE_MASK_SFT                         (0xf << 12)
+#define IRQ2_MCU_MODE_SFT                              8
+#define IRQ2_MCU_MODE_MASK                             0xf
+#define IRQ2_MCU_MODE_MASK_SFT                         (0xf << 8)
+#define IRQ1_MCU_MODE_SFT                              4
+#define IRQ1_MCU_MODE_MASK                             0xf
+#define IRQ1_MCU_MODE_MASK_SFT                         (0xf << 4)
+#define IRQ0_MCU_MODE_SFT                              0
+#define IRQ0_MCU_MODE_MASK                             0xf
+#define IRQ0_MCU_MODE_MASK_SFT                         (0xf << 0)
+
+/* AFE_IRQ_MCU_CON2 */
+#define IRQ15_MCU_MODE_SFT                             28
+#define IRQ15_MCU_MODE_MASK                            0xf
+#define IRQ15_MCU_MODE_MASK_SFT                        (0xf << 28)
+#define IRQ14_MCU_MODE_SFT                             24
+#define IRQ14_MCU_MODE_MASK                            0xf
+#define IRQ14_MCU_MODE_MASK_SFT                        (0xf << 24)
+#define IRQ13_MCU_MODE_SFT                             20
+#define IRQ13_MCU_MODE_MASK                            0xf
+#define IRQ13_MCU_MODE_MASK_SFT                        (0xf << 20)
+#define IRQ12_MCU_MODE_SFT                             16
+#define IRQ12_MCU_MODE_MASK                            0xf
+#define IRQ12_MCU_MODE_MASK_SFT                        (0xf << 16)
+#define IRQ11_MCU_MODE_SFT                             12
+#define IRQ11_MCU_MODE_MASK                            0xf
+#define IRQ11_MCU_MODE_MASK_SFT                        (0xf << 12)
+#define IRQ10_MCU_MODE_SFT                             8
+#define IRQ10_MCU_MODE_MASK                            0xf
+#define IRQ10_MCU_MODE_MASK_SFT                        (0xf << 8)
+#define IRQ9_MCU_MODE_SFT                              4
+#define IRQ9_MCU_MODE_MASK                             0xf
+#define IRQ9_MCU_MODE_MASK_SFT                         (0xf << 4)
+#define IRQ8_MCU_MODE_SFT                              0
+#define IRQ8_MCU_MODE_MASK                             0xf
+#define IRQ8_MCU_MODE_MASK_SFT                         (0xf << 0)
+
+/* AFE_IRQ_MCU_CON3 */
+#define IRQ23_MCU_MODE_SFT                             28
+#define IRQ23_MCU_MODE_MASK                            0xf
+#define IRQ23_MCU_MODE_MASK_SFT                        (0xf << 28)
+#define IRQ22_MCU_MODE_SFT                             24
+#define IRQ22_MCU_MODE_MASK                            0xf
+#define IRQ22_MCU_MODE_MASK_SFT                        (0xf << 24)
+#define IRQ21_MCU_MODE_SFT                             20
+#define IRQ21_MCU_MODE_MASK                            0xf
+#define IRQ21_MCU_MODE_MASK_SFT                        (0xf << 20)
+#define IRQ20_MCU_MODE_SFT                             16
+#define IRQ20_MCU_MODE_MASK                            0xf
+#define IRQ20_MCU_MODE_MASK_SFT                        (0xf << 16)
+#define IRQ19_MCU_MODE_SFT                             12
+#define IRQ19_MCU_MODE_MASK                            0xf
+#define IRQ19_MCU_MODE_MASK_SFT                        (0xf << 12)
+#define IRQ18_MCU_MODE_SFT                             8
+#define IRQ18_MCU_MODE_MASK                            0xf
+#define IRQ18_MCU_MODE_MASK_SFT                        (0xf << 8)
+#define IRQ17_MCU_MODE_SFT                             4
+#define IRQ17_MCU_MODE_MASK                            0xf
+#define IRQ17_MCU_MODE_MASK_SFT                        (0xf << 4)
+#define IRQ16_MCU_MODE_SFT                             0
+#define IRQ16_MCU_MODE_MASK                            0xf
+#define IRQ16_MCU_MODE_MASK_SFT                        (0xf << 0)
+
+/* AFE_IRQ_MCU_CON4 */
+#define IRQ26_MCU_MODE_SFT                             8
+#define IRQ26_MCU_MODE_MASK                            0xf
+#define IRQ26_MCU_MODE_MASK_SFT                        (0xf << 8)
+#define IRQ25_MCU_MODE_SFT                             4
+#define IRQ25_MCU_MODE_MASK                            0xf
+#define IRQ25_MCU_MODE_MASK_SFT                        (0xf << 4)
+#define IRQ24_MCU_MODE_SFT                             0
+#define IRQ24_MCU_MODE_MASK                            0xf
+#define IRQ24_MCU_MODE_MASK_SFT                        (0xf << 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ31_MCU_CLR_SFT                              31
+#define IRQ31_MCU_CLR_MASK                             0x1
+#define IRQ31_MCU_CLR_MASK_SFT                         (0x1 << 31)
+#define IRQ26_MCU_CLR_SFT                              26
+#define IRQ26_MCU_CLR_MASK                             0x1
+#define IRQ26_MCU_CLR_MASK_SFT                         (0x1 << 26)
+#define IRQ25_MCU_CLR_SFT                              25
+#define IRQ25_MCU_CLR_MASK                             0x1
+#define IRQ25_MCU_CLR_MASK_SFT                         (0x1 << 25)
+#define IRQ24_MCU_CLR_SFT                              24
+#define IRQ24_MCU_CLR_MASK                             0x1
+#define IRQ24_MCU_CLR_MASK_SFT                         (0x1 << 24)
+#define IRQ23_MCU_CLR_SFT                              23
+#define IRQ23_MCU_CLR_MASK                             0x1
+#define IRQ23_MCU_CLR_MASK_SFT                         (0x1 << 23)
+#define IRQ22_MCU_CLR_SFT                              22
+#define IRQ22_MCU_CLR_MASK                             0x1
+#define IRQ22_MCU_CLR_MASK_SFT                         (0x1 << 22)
+#define IRQ21_MCU_CLR_SFT                              21
+#define IRQ21_MCU_CLR_MASK                             0x1
+#define IRQ21_MCU_CLR_MASK_SFT                         (0x1 << 21)
+#define IRQ20_MCU_CLR_SFT                              20
+#define IRQ20_MCU_CLR_MASK                             0x1
+#define IRQ20_MCU_CLR_MASK_SFT                         (0x1 << 20)
+#define IRQ19_MCU_CLR_SFT                              19
+#define IRQ19_MCU_CLR_MASK                             0x1
+#define IRQ19_MCU_CLR_MASK_SFT                         (0x1 << 19)
+#define IRQ18_MCU_CLR_SFT                              18
+#define IRQ18_MCU_CLR_MASK                             0x1
+#define IRQ18_MCU_CLR_MASK_SFT                         (0x1 << 18)
+#define IRQ17_MCU_CLR_SFT                              17
+#define IRQ17_MCU_CLR_MASK                             0x1
+#define IRQ17_MCU_CLR_MASK_SFT                         (0x1 << 17)
+#define IRQ16_MCU_CLR_SFT                              16
+#define IRQ16_MCU_CLR_MASK                             0x1
+#define IRQ16_MCU_CLR_MASK_SFT                         (0x1 << 16)
+#define IRQ15_MCU_CLR_SFT                              15
+#define IRQ15_MCU_CLR_MASK                             0x1
+#define IRQ15_MCU_CLR_MASK_SFT                         (0x1 << 15)
+#define IRQ14_MCU_CLR_SFT                              14
+#define IRQ14_MCU_CLR_MASK                             0x1
+#define IRQ14_MCU_CLR_MASK_SFT                         (0x1 << 14)
+#define IRQ13_MCU_CLR_SFT                              13
+#define IRQ13_MCU_CLR_MASK                             0x1
+#define IRQ13_MCU_CLR_MASK_SFT                         (0x1 << 13)
+#define IRQ12_MCU_CLR_SFT                              12
+#define IRQ12_MCU_CLR_MASK                             0x1
+#define IRQ12_MCU_CLR_MASK_SFT                         (0x1 << 12)
+#define IRQ11_MCU_CLR_SFT                              11
+#define IRQ11_MCU_CLR_MASK                             0x1
+#define IRQ11_MCU_CLR_MASK_SFT                         (0x1 << 11)
+#define IRQ10_MCU_CLR_SFT                              10
+#define IRQ10_MCU_CLR_MASK                             0x1
+#define IRQ10_MCU_CLR_MASK_SFT                         (0x1 << 10)
+#define IRQ9_MCU_CLR_SFT                               9
+#define IRQ9_MCU_CLR_MASK                              0x1
+#define IRQ9_MCU_CLR_MASK_SFT                          (0x1 << 9)
+#define IRQ8_MCU_CLR_SFT                               8
+#define IRQ8_MCU_CLR_MASK                              0x1
+#define IRQ8_MCU_CLR_MASK_SFT                          (0x1 << 8)
+#define IRQ7_MCU_CLR_SFT                               7
+#define IRQ7_MCU_CLR_MASK                              0x1
+#define IRQ7_MCU_CLR_MASK_SFT                          (0x1 << 7)
+#define IRQ6_MCU_CLR_SFT                               6
+#define IRQ6_MCU_CLR_MASK                              0x1
+#define IRQ6_MCU_CLR_MASK_SFT                          (0x1 << 6)
+#define IRQ5_MCU_CLR_SFT                               5
+#define IRQ5_MCU_CLR_MASK                              0x1
+#define IRQ5_MCU_CLR_MASK_SFT                          (0x1 << 5)
+#define IRQ4_MCU_CLR_SFT                               4
+#define IRQ4_MCU_CLR_MASK                              0x1
+#define IRQ4_MCU_CLR_MASK_SFT                          (0x1 << 4)
+#define IRQ3_MCU_CLR_SFT                               3
+#define IRQ3_MCU_CLR_MASK                              0x1
+#define IRQ3_MCU_CLR_MASK_SFT                          (0x1 << 3)
+#define IRQ2_MCU_CLR_SFT                               2
+#define IRQ2_MCU_CLR_MASK                              0x1
+#define IRQ2_MCU_CLR_MASK_SFT                          (0x1 << 2)
+#define IRQ1_MCU_CLR_SFT                               1
+#define IRQ1_MCU_CLR_MASK                              0x1
+#define IRQ1_MCU_CLR_MASK_SFT                          (0x1 << 1)
+#define IRQ0_MCU_CLR_SFT                               0
+#define IRQ0_MCU_CLR_MASK                              0x1
+#define IRQ0_MCU_CLR_MASK_SFT                          (0x1 << 0)
+
+/* AFE_IRQ_MCU_EN */
+#define IRQ31_MCU_EN_SFT                               31
+#define IRQ30_MCU_EN_SFT                               30
+#define IRQ29_MCU_EN_SFT                               29
+#define IRQ28_MCU_EN_SFT                               28
+#define IRQ27_MCU_EN_SFT                               27
+#define IRQ26_MCU_EN_SFT                               26
+#define IRQ25_MCU_EN_SFT                               25
+#define IRQ24_MCU_EN_SFT                               24
+#define IRQ23_MCU_EN_SFT                               23
+#define IRQ22_MCU_EN_SFT                               22
+#define IRQ21_MCU_EN_SFT                               21
+#define IRQ20_MCU_EN_SFT                               20
+#define IRQ19_MCU_EN_SFT                               19
+#define IRQ18_MCU_EN_SFT                               18
+#define IRQ17_MCU_EN_SFT                               17
+#define IRQ16_MCU_EN_SFT                               16
+#define IRQ15_MCU_EN_SFT                               15
+#define IRQ14_MCU_EN_SFT                               14
+#define IRQ13_MCU_EN_SFT                               13
+#define IRQ12_MCU_EN_SFT                               12
+#define IRQ11_MCU_EN_SFT                               11
+#define IRQ10_MCU_EN_SFT                               10
+#define IRQ9_MCU_EN_SFT                                9
+#define IRQ8_MCU_EN_SFT                                8
+#define IRQ7_MCU_EN_SFT                                7
+#define IRQ6_MCU_EN_SFT                                6
+#define IRQ5_MCU_EN_SFT                                5
+#define IRQ4_MCU_EN_SFT                                4
+#define IRQ3_MCU_EN_SFT                                3
+#define IRQ2_MCU_EN_SFT                                2
+#define IRQ1_MCU_EN_SFT                                1
+#define IRQ0_MCU_EN_SFT                                0
+
+/* AFE_IRQ_MCU_SCP_EN */
+#define IRQ31_MCU_SCP_EN_SFT                           31
+#define IRQ30_MCU_SCP_EN_SFT                           30
+#define IRQ29_MCU_SCP_EN_SFT                           29
+#define IRQ28_MCU_SCP_EN_SFT                           28
+#define IRQ27_MCU_SCP_EN_SFT                           27
+#define IRQ26_MCU_SCP_EN_SFT                           26
+#define IRQ25_MCU_SCP_EN_SFT                           25
+#define IRQ24_MCU_SCP_EN_SFT                           24
+#define IRQ23_MCU_SCP_EN_SFT                           23
+#define IRQ22_MCU_SCP_EN_SFT                           22
+#define IRQ21_MCU_SCP_EN_SFT                           21
+#define IRQ20_MCU_SCP_EN_SFT                           20
+#define IRQ19_MCU_SCP_EN_SFT                           19
+#define IRQ18_MCU_SCP_EN_SFT                           18
+#define IRQ17_MCU_SCP_EN_SFT                           17
+#define IRQ16_MCU_SCP_EN_SFT                           16
+#define IRQ15_MCU_SCP_EN_SFT                           15
+#define IRQ14_MCU_SCP_EN_SFT                           14
+#define IRQ13_MCU_SCP_EN_SFT                           13
+#define IRQ12_MCU_SCP_EN_SFT                           12
+#define IRQ11_MCU_SCP_EN_SFT                           11
+#define IRQ10_MCU_SCP_EN_SFT                           10
+#define IRQ9_MCU_SCP_EN_SFT                            9
+#define IRQ8_MCU_SCP_EN_SFT                            8
+#define IRQ7_MCU_SCP_EN_SFT                            7
+#define IRQ6_MCU_SCP_EN_SFT                            6
+#define IRQ5_MCU_SCP_EN_SFT                            5
+#define IRQ4_MCU_SCP_EN_SFT                            4
+#define IRQ3_MCU_SCP_EN_SFT                            3
+#define IRQ2_MCU_SCP_EN_SFT                            2
+#define IRQ1_MCU_SCP_EN_SFT                            1
+#define IRQ0_MCU_SCP_EN_SFT                            0
+
+/* AFE_TDM_CON1 */
+#define TDM_EN_SFT                                     0
+#define TDM_EN_MASK                                    0x1
+#define TDM_EN_MASK_SFT                                (0x1 << 0)
+#define BCK_INVERSE_SFT                                1
+#define BCK_INVERSE_MASK                               0x1
+#define BCK_INVERSE_MASK_SFT                           (0x1 << 1)
+#define LRCK_INVERSE_SFT                               2
+#define LRCK_INVERSE_MASK                              0x1
+#define LRCK_INVERSE_MASK_SFT                          (0x1 << 2)
+#define DELAY_DATA_SFT                                 3
+#define DELAY_DATA_MASK                                0x1
+#define DELAY_DATA_MASK_SFT                            (0x1 << 3)
+#define LEFT_ALIGN_SFT                                 4
+#define LEFT_ALIGN_MASK                                0x1
+#define LEFT_ALIGN_MASK_SFT                            (0x1 << 4)
+#define WLEN_SFT                                       8
+#define WLEN_MASK                                      0x3
+#define WLEN_MASK_SFT                                  (0x3 << 8)
+#define CHANNEL_NUM_SFT                                10
+#define CHANNEL_NUM_MASK                               0x3
+#define CHANNEL_NUM_MASK_SFT                           (0x3 << 10)
+#define CHANNEL_BCK_CYCLES_SFT                         12
+#define CHANNEL_BCK_CYCLES_MASK                        0x3
+#define CHANNEL_BCK_CYCLES_MASK_SFT                    (0x3 << 12)
+#define DAC_BIT_NUM_SFT                                16
+#define DAC_BIT_NUM_MASK                               0x1f
+#define DAC_BIT_NUM_MASK_SFT                           (0x1f << 16)
+#define LRCK_TDM_WIDTH_SFT                             24
+#define LRCK_TDM_WIDTH_MASK                            0xff
+#define LRCK_TDM_WIDTH_MASK_SFT                        (0xff << 24)
+
+/* AFE_TDM_CON2 */
+#define ST_CH_PAIR_SOUT0_SFT                           0
+#define ST_CH_PAIR_SOUT0_MASK                          0x7
+#define ST_CH_PAIR_SOUT0_MASK_SFT                      (0x7 << 0)
+#define ST_CH_PAIR_SOUT1_SFT                           4
+#define ST_CH_PAIR_SOUT1_MASK                          0x7
+#define ST_CH_PAIR_SOUT1_MASK_SFT                      (0x7 << 4)
+#define ST_CH_PAIR_SOUT2_SFT                           8
+#define ST_CH_PAIR_SOUT2_MASK                          0x7
+#define ST_CH_PAIR_SOUT2_MASK_SFT                      (0x7 << 8)
+#define ST_CH_PAIR_SOUT3_SFT                           12
+#define ST_CH_PAIR_SOUT3_MASK                          0x7
+#define ST_CH_PAIR_SOUT3_MASK_SFT                      (0x7 << 12)
+#define TDM_FIX_VALUE_SEL_SFT                          16
+#define TDM_FIX_VALUE_SEL_MASK                         0x1
+#define TDM_FIX_VALUE_SEL_MASK_SFT                     (0x1 << 16)
+#define TDM_I2S_LOOPBACK_SFT                           20
+#define TDM_I2S_LOOPBACK_MASK                          0x1
+#define TDM_I2S_LOOPBACK_MASK_SFT                      (0x1 << 20)
+#define TDM_I2S_LOOPBACK_CH_SFT                        21
+#define TDM_I2S_LOOPBACK_CH_MASK                       0x3
+#define TDM_I2S_LOOPBACK_CH_MASK_SFT                   (0x3 << 21)
+#define TDM_FIX_VALUE_SFT                              24
+#define TDM_FIX_VALUE_MASK                             0xff
+#define TDM_FIX_VALUE_MASK_SFT                         (0xff << 24)
+
+/* AFE_HDMI_CONN0 */
+#define HDMI_O_7_SFT                                   21
+#define HDMI_O_7_MASK                                  0x7
+#define HDMI_O_7_MASK_SFT                              (0x7 << 21)
+#define HDMI_O_6_SFT                                   18
+#define HDMI_O_6_MASK                                  0x7
+#define HDMI_O_6_MASK_SFT                              (0x7 << 18)
+#define HDMI_O_5_SFT                                   15
+#define HDMI_O_5_MASK                                  0x7
+#define HDMI_O_5_MASK_SFT                              (0x7 << 15)
+#define HDMI_O_4_SFT                                   12
+#define HDMI_O_4_MASK                                  0x7
+#define HDMI_O_4_MASK_SFT                              (0x7 << 12)
+#define HDMI_O_3_SFT                                   9
+#define HDMI_O_3_MASK                                  0x7
+#define HDMI_O_3_MASK_SFT                              (0x7 << 9)
+#define HDMI_O_2_SFT                                   6
+#define HDMI_O_2_MASK                                  0x7
+#define HDMI_O_2_MASK_SFT                              (0x7 << 6)
+#define HDMI_O_1_SFT                                   3
+#define HDMI_O_1_MASK                                  0x7
+#define HDMI_O_1_MASK_SFT                              (0x7 << 3)
+#define HDMI_O_0_SFT                                   0
+#define HDMI_O_0_MASK                                  0x7
+#define HDMI_O_0_MASK_SFT                              (0x7 << 0)
+
+/* AFE_AUD_PAD_TOP */
+#define AUD_PAD_TOP_MON_SFT                            15
+#define AUD_PAD_TOP_MON_MASK                           0x1ffff
+#define AUD_PAD_TOP_MON_MASK_SFT                       (0x1ffff << 15)
+#define AUD_PAD_TOP_FIFO_RSP_SFT                       4
+#define AUD_PAD_TOP_FIFO_RSP_MASK                      0xf
+#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT                  (0xf << 4)
+#define RG_RX_PROTOCOL2_SFT                            3
+#define RG_RX_PROTOCOL2_MASK                           0x1
+#define RG_RX_PROTOCOL2_MASK_SFT                       (0x1 << 3)
+#define RESERVDED_01_SFT                               1
+#define RESERVDED_01_MASK                              0x3
+#define RESERVDED_01_MASK_SFT                          (0x3 << 1)
+#define RG_RX_FIFO_ON_SFT                              0
+#define RG_RX_FIFO_ON_MASK                             0x1
+#define RG_RX_FIFO_ON_MASK_SFT                         (0x1 << 0)
+
+/* AFE_ADDA_MTKAIF_SYNCWORD_CFG */
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT      23
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK     0x1
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK_SFT (0x1 << 23)
+
+/* AFE_ADDA_MTKAIF_RX_CFG0 */
+#define MTKAIF_RXIF_VOICE_MODE_SFT                     20
+#define MTKAIF_RXIF_VOICE_MODE_MASK                    0xf
+#define MTKAIF_RXIF_VOICE_MODE_MASK_SFT                (0xf << 20)
+#define MTKAIF_RXIF_DETECT_ON_SFT                      16
+#define MTKAIF_RXIF_DETECT_ON_MASK                     0x1
+#define MTKAIF_RXIF_DETECT_ON_MASK_SFT                 (0x1 << 16)
+#define MTKAIF_RXIF_DATA_BIT_SFT                       8
+#define MTKAIF_RXIF_DATA_BIT_MASK                      0x7
+#define MTKAIF_RXIF_DATA_BIT_MASK_SFT                  (0x7 << 8)
+#define MTKAIF_RXIF_FIFO_RSP_SFT                       4
+#define MTKAIF_RXIF_FIFO_RSP_MASK                      0x7
+#define MTKAIF_RXIF_FIFO_RSP_MASK_SFT                  (0x7 << 4)
+#define MTKAIF_RXIF_DATA_MODE_SFT                      0
+#define MTKAIF_RXIF_DATA_MODE_MASK                     0x1
+#define MTKAIF_RXIF_DATA_MODE_MASK_SFT                 (0x1 << 0)
+
+/* GENERAL_ASRC_MODE */
+#define GENERAL2_ASRCOUT_MODE_SFT                      12
+#define GENERAL2_ASRCOUT_MODE_MASK                     0xf
+#define GENERAL2_ASRCOUT_MODE_MASK_SFT                 (0xf << 12)
+#define GENERAL2_ASRCIN_MODE_SFT                       8
+#define GENERAL2_ASRCIN_MODE_MASK                      0xf
+#define GENERAL2_ASRCIN_MODE_MASK_SFT                  (0xf << 8)
+#define GENERAL1_ASRCOUT_MODE_SFT                      4
+#define GENERAL1_ASRCOUT_MODE_MASK                     0xf
+#define GENERAL1_ASRCOUT_MODE_MASK_SFT                 (0xf << 4)
+#define GENERAL1_ASRCIN_MODE_SFT                       0
+#define GENERAL1_ASRCIN_MODE_MASK                      0xf
+#define GENERAL1_ASRCIN_MODE_MASK_SFT                  (0xf << 0)
+
+/* GENERAL_ASRC_EN_ON */
+#define GENERAL2_ASRC_EN_ON_SFT                        1
+#define GENERAL2_ASRC_EN_ON_MASK                       0x1
+#define GENERAL2_ASRC_EN_ON_MASK_SFT                   (0x1 << 1)
+#define GENERAL1_ASRC_EN_ON_SFT                        0
+#define GENERAL1_ASRC_EN_ON_MASK                       0x1
+#define GENERAL1_ASRC_EN_ON_MASK_SFT                   (0x1 << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON0 */
+#define G_SRC_CHSET_STR_CLR_SFT                        4
+#define G_SRC_CHSET_STR_CLR_MASK                       0x1
+#define G_SRC_CHSET_STR_CLR_MASK_SFT                   (0x1 << 4)
+#define G_SRC_CHSET_ON_SFT                             2
+#define G_SRC_CHSET_ON_MASK                            0x1
+#define G_SRC_CHSET_ON_MASK_SFT                        (0x1 << 2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT                      1
+#define G_SRC_COEFF_SRAM_CTRL_MASK                     0x1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT                 (0x1 << 1)
+#define G_SRC_ASM_ON_SFT                               0
+#define G_SRC_ASM_ON_MASK                              0x1
+#define G_SRC_ASM_ON_MASK_SFT                          (0x1 << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON3 */
+#define G_SRC_ASM_FREQ_4_SFT                           0
+#define G_SRC_ASM_FREQ_4_MASK                          0xffffff
+#define G_SRC_ASM_FREQ_4_MASK_SFT                      (0xffffff << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON4 */
+#define G_SRC_ASM_FREQ_5_SFT                           0
+#define G_SRC_ASM_FREQ_5_MASK                          0xffffff
+#define G_SRC_ASM_FREQ_5_MASK_SFT                      (0xffffff << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON13 */
+#define G_SRC_COEFF_SRAM_ADR_SFT                       0
+#define G_SRC_COEFF_SRAM_ADR_MASK                      0x3f
+#define G_SRC_COEFF_SRAM_ADR_MASK_SFT                  (0x3f << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON2 */
+#define G_SRC_CHSET_O16BIT_SFT                         19
+#define G_SRC_CHSET_O16BIT_MASK                        0x1
+#define G_SRC_CHSET_O16BIT_MASK_SFT                    (0x1 << 19)
+#define G_SRC_CHSET_CLR_IIR_HISTORY_SFT                17
+#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK               0x1
+#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK_SFT           (0x1 << 17)
+#define G_SRC_CHSET_IS_MONO_SFT                        16
+#define G_SRC_CHSET_IS_MONO_MASK                       0x1
+#define G_SRC_CHSET_IS_MONO_MASK_SFT                   (0x1 << 16)
+#define G_SRC_CHSET_IIR_EN_SFT                         11
+#define G_SRC_CHSET_IIR_EN_MASK                        0x1
+#define G_SRC_CHSET_IIR_EN_MASK_SFT                    (0x1 << 11)
+#define G_SRC_CHSET_IIR_STAGE_SFT                      8
+#define G_SRC_CHSET_IIR_STAGE_MASK                     0x7
+#define G_SRC_CHSET_IIR_STAGE_MASK_SFT                 (0x7 << 8)
+#define G_SRC_CHSET_STR_CLR_RU_SFT                     5
+#define G_SRC_CHSET_STR_CLR_RU_MASK                    0x1
+#define G_SRC_CHSET_STR_CLR_RU_MASK_SFT                (0x1 << 5)
+#define G_SRC_CHSET_ON_SFT                             2
+#define G_SRC_CHSET_ON_MASK                            0x1
+#define G_SRC_CHSET_ON_MASK_SFT                        (0x1 << 2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT                      1
+#define G_SRC_COEFF_SRAM_CTRL_MASK                     0x1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT                 (0x1 << 1)
+#define G_SRC_ASM_ON_SFT                               0
+#define G_SRC_ASM_ON_MASK                              0x1
+#define G_SRC_ASM_ON_MASK_SFT                          (0x1 << 0)
+
+/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */
+#define ADDA_SDM_AUTO_RESET_ONOFF_SFT                  31
+#define ADDA_SDM_AUTO_RESET_ONOFF_MASK                 0x1
+#define ADDA_SDM_AUTO_RESET_ONOFF_MASK_SFT             (0x1 << 31)
+
+/* AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON */
+#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_SFT          31
+#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK         0x1
+#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK_SFT     (0x1 << 31)
+
+/* AFE_TINY_CONN0 */
+#define O_3_CFG_SFT                                    24
+#define O_3_CFG_MASK                                   0x1f
+#define O_3_CFG_MASK_SFT                               (0x1f << 24)
+#define O_2_CFG_SFT                                    16
+#define O_2_CFG_MASK                                   0x1f
+#define O_2_CFG_MASK_SFT                               (0x1f << 16)
+#define O_1_CFG_SFT                                    8
+#define O_1_CFG_MASK                                   0x1f
+#define O_1_CFG_MASK_SFT                               (0x1f << 8)
+#define O_0_CFG_SFT                                    0
+#define O_0_CFG_MASK                                   0x1f
+#define O_0_CFG_MASK_SFT                               (0x1f << 0)
+
+/* AFE_TINY_CONN5 */
+#define O_23_CFG_SFT                                    24
+#define O_23_CFG_MASK                                   0x1f
+#define O_23_CFG_MASK_SFT                               (0x1f << 24)
+#define O_22_CFG_SFT                                    16
+#define O_22_CFG_MASK                                   0x1f
+#define O_22_CFG_MASK_SFT                               (0x1f << 16)
+#define O_21_CFG_SFT                                    8
+#define O_21_CFG_MASK                                   0x1f
+#define O_21_CFG_MASK_SFT                               (0x1f << 8)
+#define O_20_CFG_SFT                                    0
+#define O_20_CFG_MASK                                   0x1f
+#define O_20_CFG_MASK_SFT                               (0x1f << 0)
+
+/* AFE_MEMIF_CONN */
+#define VUL6_USE_TINY_SFT                              8
+#define VUL6_USE_TINY_MASK                             1
+#define VUL6_USE_TINY_MASK_SFT                         (0x1 << 8)
+#define VUL5_USE_TINY_SFT                              7
+#define VUL5_USE_TINY_MASK                             1
+#define VUL5_USE_TINY_MASK_SFT                         (0x1 << 7)
+#define VUL4_USE_TINY_SFT                              6
+#define VUL4_USE_TINY_MASK                             1
+#define VUL4_USE_TINY_MASK_SFT                         (0x1 << 6)
+#define VUL3_USE_TINY_SFT                              5
+#define VUL3_USE_TINY_MASK                             1
+#define VUL3_USE_TINY_MASK_SFT                         (0x1 << 5)
+#define AWB2_USE_TINY_SFT                              4
+#define AWB2_USE_TINY_MASK                             1
+#define AWB2_USE_TINY_MASK_SFT                         (0x1 << 4)
+#define AWB_USE_TINY_SFT                               3
+#define AWB_USE_TINY_MASK                              1
+#define AWB_USE_TINY_MASK_SFT                          (0x1 << 3)
+#define VUL12_USE_TINY_SFT                             2
+#define VUL12_USE_TINY_MASK                            1
+#define VUL12_USE_TINY_MASK_SFT                        (0x1 << 2)
+#define VUL2_USE_TINY_SFT                              1
+#define VUL2_USE_TINY_MASK                             1
+#define VUL2_USE_TINY_MASK_SFT                         (0x1 << 1)
+#define VUL1_USE_TINY_SFT                              0
+#define VUL1_USE_TINY_MASK                             1
+#define VUL1_USE_TINY_MASK_SFT                         (0x1 << 0)
+
+/* AFE_ASRC_2CH_CON0 */
+#define CON0_CHSET_STR_CLR_SFT                         4
+#define CON0_CHSET_STR_CLR_MASK                        1
+#define CON0_CHSET_STR_CLR_MASK_SFT                    (0x1 << 4)
+#define CON0_ASM_ON_SFT                                0
+#define CON0_ASM_ON_MASK                               1
+#define CON0_ASM_ON_MASK_SFT                           (0x1 << 0)
+
+/* AFE_ASRC_2CH_CON5 */
+#define CALI_EN_SFT                                    0
+#define CALI_EN_MASK                                   1
+#define CALI_EN_MASK_SFT                               (0x1 << 0)
+
+#define AUDIO_TOP_CON0                                 0x0000
+#define AUDIO_TOP_CON1                                 0x0004
+#define AUDIO_TOP_CON2                                 0x0008
+#define AUDIO_TOP_CON3                                 0x000c
+#define AFE_DAC_CON0                                   0x0010
+#define AFE_I2S_CON                                    0x0018
+#define AFE_CONN0                                      0x0020
+#define AFE_CONN1                                      0x0024
+#define AFE_CONN2                                      0x0028
+#define AFE_CONN3                                      0x002c
+#define AFE_CONN4                                      0x0030
+#define AFE_I2S_CON1                                   0x0034
+#define AFE_I2S_CON2                                   0x0038
+#define AFE_I2S_CON3                                   0x0040
+#define AFE_CONN5                                      0x0044
+#define AFE_CONN_24BIT                                 0x0048
+#define AFE_DL1_CON0                                   0x004c
+#define AFE_DL1_BASE_MSB                               0x0050
+#define AFE_DL1_BASE                                   0x0054
+#define AFE_DL1_CUR_MSB                                0x0058
+#define AFE_DL1_CUR                                    0x005c
+#define AFE_DL1_END_MSB                                0x0060
+#define AFE_DL1_END                                    0x0064
+#define AFE_DL2_CON0                                   0x0068
+#define AFE_DL2_BASE_MSB                               0x006c
+#define AFE_DL2_BASE                                   0x0070
+#define AFE_DL2_CUR_MSB                                0x0074
+#define AFE_DL2_CUR                                    0x0078
+#define AFE_DL2_END_MSB                                0x007c
+#define AFE_DL2_END                                    0x0080
+#define AFE_DL3_CON0                                   0x0084
+#define AFE_DL3_BASE_MSB                               0x0088
+#define AFE_DL3_BASE                                   0x008c
+#define AFE_DL3_CUR_MSB                                0x0090
+#define AFE_DL3_CUR                                    0x0094
+#define AFE_DL3_END_MSB                                0x0098
+#define AFE_DL3_END                                    0x009c
+#define AFE_CONN6                                      0x00bc
+#define AFE_DL4_CON0                                   0x00cc
+#define AFE_DL4_BASE_MSB                               0x00d0
+#define AFE_DL4_BASE                                   0x00d4
+#define AFE_DL4_CUR_MSB                                0x00d8
+#define AFE_DL4_CUR                                    0x00dc
+#define AFE_DL4_END_MSB                                0x00e0
+#define AFE_DL4_END                                    0x00e4
+#define AFE_DL12_CON0                                  0x00e8
+#define AFE_DL12_BASE_MSB                              0x00ec
+#define AFE_DL12_BASE                                  0x00f0
+#define AFE_DL12_CUR_MSB                               0x00f4
+#define AFE_DL12_CUR                                   0x00f8
+#define AFE_DL12_END_MSB                               0x00fc
+#define AFE_DL12_END                                   0x0100
+#define AFE_ADDA_DL_SRC2_CON0                          0x0108
+#define AFE_ADDA_DL_SRC2_CON1                          0x010c
+#define AFE_ADDA_UL_SRC_CON0                           0x0114
+#define AFE_ADDA_UL_SRC_CON1                           0x0118
+#define AFE_ADDA_TOP_CON0                              0x0120
+#define AFE_ADDA_UL_DL_CON0                            0x0124
+#define AFE_ADDA_SRC_DEBUG                             0x012c
+#define AFE_ADDA_SRC_DEBUG_MON0                        0x0130
+#define AFE_ADDA_SRC_DEBUG_MON1                        0x0134
+#define AFE_ADDA_UL_SRC_MON0                           0x0148
+#define AFE_ADDA_UL_SRC_MON1                           0x014c
+#define AFE_SECURE_CON0                                0x0150
+#define AFE_SRAM_BOUND                                 0x0154
+#define AFE_SECURE_CON1                                0x0158
+#define AFE_SECURE_CONN0                               0x015c
+#define AFE_VUL_CON0                                   0x0170
+#define AFE_VUL_BASE_MSB                               0x0174
+#define AFE_VUL_BASE                                   0x0178
+#define AFE_VUL_CUR_MSB                                0x017c
+#define AFE_VUL_CUR                                    0x0180
+#define AFE_VUL_END_MSB                                0x0184
+#define AFE_VUL_END                                    0x0188
+#define AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON         0x018c
+#define AFE_ADDA_3RD_DAC_DL_SRC2_CON0                  0x0190
+#define AFE_ADDA_3RD_DAC_DL_SRC2_CON1                  0x0194
+#define AFE_ADDA_3RD_DAC_PREDIS_CON0                   0x01a0
+#define AFE_ADDA_3RD_DAC_PREDIS_CON1                   0x01a4
+#define AFE_ADDA_3RD_DAC_PREDIS_CON2                   0x01a8
+#define AFE_ADDA_3RD_DAC_PREDIS_CON3                   0x01ac
+#define AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON             0x01b0
+#define AFE_ADDA_3RD_DAC_DL_SDM_TEST                   0x01b4
+#define AFE_ADDA_3RD_DAC_DL_DC_COMP_CFG0               0x01b8
+#define AFE_ADDA_3RD_DAC_DL_DC_COMP_CFG1               0x01bc
+#define AFE_ADDA_3RD_DAC_DL_SDM_FIFO_MON               0x01c0
+#define AFE_ADDA_3RD_DAC_DL_SRC_LCH_MON                0x01c4
+#define AFE_ADDA_3RD_DAC_DL_SRC_RCH_MON                0x01c8
+#define AFE_ADDA_3RD_DAC_DL_SDM_OUT_MON                0x01cc
+#define AFE_SIDETONE_DEBUG                             0x01d0
+#define AFE_SIDETONE_MON                               0x01d4
+#define AFE_ADDA_3RD_DAC_DL_SDM_DITHER_CON             0x01d8
+#define AFE_SINEGEN_CON2                               0x01dc
+#define AFE_SIDETONE_CON0                              0x01e0
+#define AFE_SIDETONE_COEFF                             0x01e4
+#define AFE_SIDETONE_CON1                              0x01e8
+#define AFE_SIDETONE_GAIN                              0x01ec
+#define AFE_SINEGEN_CON0                               0x01f0
+#define AFE_I2S_MON2                                   0x01f8
+#define AFE_SINEGEN_CON_TDM                            0x01fc
+#define AFE_TOP_CON0                                   0x0200
+#define AFE_VUL2_CON0                                  0x020c
+#define AFE_VUL2_BASE_MSB                              0x0210
+#define AFE_VUL2_BASE                                  0x0214
+#define AFE_VUL2_CUR_MSB                               0x0218
+#define AFE_VUL2_CUR                                   0x021c
+#define AFE_VUL2_END_MSB                               0x0220
+#define AFE_VUL2_END                                   0x0224
+#define AFE_VUL3_CON0                                  0x0228
+#define AFE_VUL3_BASE_MSB                              0x022c
+#define AFE_VUL3_BASE                                  0x0230
+#define AFE_VUL3_CUR_MSB                               0x0234
+#define AFE_VUL3_CUR                                   0x0238
+#define AFE_VUL3_END_MSB                               0x023c
+#define AFE_VUL3_END                                   0x0240
+#define AFE_BUSY                                       0x0244
+#define AFE_BUS_CFG                                    0x0250
+#define AFE_ADDA_PREDIS_CON0                           0x0260
+#define AFE_ADDA_PREDIS_CON1                           0x0264
+#define AFE_I2S_MON                                    0x027c
+#define AFE_ADDA_IIR_COEF_02_01                        0x0290
+#define AFE_ADDA_IIR_COEF_04_03                        0x0294
+#define AFE_ADDA_IIR_COEF_06_05                        0x0298
+#define AFE_ADDA_IIR_COEF_08_07                        0x029c
+#define AFE_ADDA_IIR_COEF_10_09                        0x02a0
+#define AFE_IRQ_MCU_CON1                               0x02e4
+#define AFE_IRQ_MCU_CON2                               0x02e8
+#define AFE_DAC_MON                                    0x02ec
+#define AFE_IRQ_MCU_CON3                               0x02f0
+#define AFE_IRQ_MCU_CON4                               0x02f4
+#define AFE_IRQ_MCU_CNT0                               0x0300
+#define AFE_IRQ_MCU_CNT6                               0x0304
+#define AFE_IRQ_MCU_CNT8                               0x0308
+#define AFE_IRQ_MCU_DSP2_EN                            0x030c
+#define AFE_IRQ0_MCU_CNT_MON                           0x0310
+#define AFE_IRQ6_MCU_CNT_MON                           0x0314
+#define AFE_VUL4_CON0                                  0x0358
+#define AFE_VUL4_BASE_MSB                              0x035c
+#define AFE_VUL4_BASE                                  0x0360
+#define AFE_VUL4_CUR_MSB                               0x0364
+#define AFE_VUL4_CUR                                   0x0368
+#define AFE_VUL4_END_MSB                               0x036c
+#define AFE_VUL4_END                                   0x0370
+#define AFE_VUL12_CON0                                 0x0374
+#define AFE_VUL12_BASE_MSB                             0x0378
+#define AFE_VUL12_BASE                                 0x037c
+#define AFE_VUL12_CUR_MSB                              0x0380
+#define AFE_VUL12_CUR                                  0x0384
+#define AFE_VUL12_END_MSB                              0x0388
+#define AFE_VUL12_END                                  0x038c
+#define AFE_HDMI_CONN0                                 0x0390
+#define AFE_IRQ3_MCU_CNT_MON                           0x0398
+#define AFE_IRQ4_MCU_CNT_MON                           0x039c
+#define AFE_IRQ_MCU_CON0                               0x03a0
+#define AFE_IRQ_MCU_STATUS                             0x03a4
+#define AFE_IRQ_MCU_CLR                                0x03a8
+#define AFE_IRQ_MCU_CNT1                               0x03ac
+#define AFE_IRQ_MCU_CNT2                               0x03b0
+#define AFE_IRQ_MCU_EN                                 0x03b4
+#define AFE_IRQ_MCU_MON2                               0x03b8
+#define AFE_IRQ_MCU_CNT5                               0x03bc
+#define AFE_IRQ1_MCU_CNT_MON                           0x03c0
+#define AFE_IRQ2_MCU_CNT_MON                           0x03c4
+#define AFE_IRQ5_MCU_CNT_MON                           0x03cc
+#define AFE_IRQ_MCU_DSP_EN                             0x03d0
+#define AFE_IRQ_MCU_SCP_EN                             0x03d4
+#define AFE_IRQ_MCU_CNT7                               0x03dc
+#define AFE_IRQ7_MCU_CNT_MON                           0x03e0
+#define AFE_IRQ_MCU_CNT3                               0x03e4
+#define AFE_IRQ_MCU_CNT4                               0x03e8
+#define AFE_IRQ_MCU_CNT11                              0x03ec
+#define AFE_APLL1_TUNER_CFG                            0x03f0
+#define AFE_APLL2_TUNER_CFG                            0x03f4
+#define AFE_IRQ_MCU_MISS_CLR                           0x03f8
+#define AFE_CONN33                                     0x0408
+#define AFE_IRQ_MCU_CNT12                              0x040c
+#define AFE_GAIN1_CON0                                 0x0410
+#define AFE_GAIN1_CON1                                 0x0414
+#define AFE_GAIN1_CON2                                 0x0418
+#define AFE_GAIN1_CON3                                 0x041c
+#define AFE_CONN7                                      0x0420
+#define AFE_GAIN1_CUR                                  0x0424
+#define AFE_GAIN2_CON0                                 0x0428
+#define AFE_GAIN2_CON1                                 0x042c
+#define AFE_GAIN2_CON2                                 0x0430
+#define AFE_GAIN2_CON3                                 0x0434
+#define AFE_CONN8                                      0x0438
+#define AFE_GAIN2_CUR                                  0x043c
+#define AFE_CONN9                                      0x0440
+#define AFE_CONN10                                     0x0444
+#define AFE_CONN11                                     0x0448
+#define AFE_CONN12                                     0x044c
+#define AFE_CONN13                                     0x0450
+#define AFE_CONN14                                     0x0454
+#define AFE_CONN15                                     0x0458
+#define AFE_CONN16                                     0x045c
+#define AFE_CONN17                                     0x0460
+#define AFE_CONN18                                     0x0464
+#define AFE_CONN19                                     0x0468
+#define AFE_CONN20                                     0x046c
+#define AFE_CONN21                                     0x0470
+#define AFE_CONN22                                     0x0474
+#define AFE_CONN23                                     0x0478
+#define AFE_CONN24                                     0x047c
+#define AFE_CONN_RS                                    0x0494
+#define AFE_CONN_DI                                    0x0498
+#define AFE_CONN25                                     0x04b0
+#define AFE_CONN26                                     0x04b4
+#define AFE_CONN27                                     0x04b8
+#define AFE_CONN28                                     0x04bc
+#define AFE_CONN29                                     0x04c0
+#define AFE_CONN30                                     0x04c4
+#define AFE_CONN31                                     0x04c8
+#define AFE_CONN32                                     0x04cc
+#define AFE_SRAM_DELSEL_CON1                           0x04f4
+#define AFE_CONN56                                     0x0500
+#define AFE_CONN57                                     0x0504
+#define AFE_CONN56_1                                   0x0510
+#define AFE_CONN57_1                                   0x0514
+#define AFE_TINY_CONN2                                 0x0520
+#define AFE_TINY_CONN3                                 0x0524
+#define AFE_TINY_CONN4                                 0x0528
+#define AFE_TINY_CONN5                                 0x052c
+#define PCM_INTF_CON1                                  0x0530
+#define PCM_INTF_CON2                                  0x0538
+#define PCM2_INTF_CON                                  0x053c
+#define AFE_TDM_CON1                                   0x0548
+#define AFE_TDM_CON2                                   0x054c
+#define AFE_I2S_CON6                                   0x0564
+#define AFE_I2S_CON7                                   0x0568
+#define AFE_I2S_CON8                                   0x056c
+#define AFE_I2S_CON9                                   0x0570
+#define AFE_CONN34                                     0x0580
+#define FPGA_CFG0                                      0x05b0
+#define FPGA_CFG1                                      0x05b4
+#define FPGA_CFG2                                      0x05c0
+#define FPGA_CFG3                                      0x05c4
+#define AUDIO_TOP_DBG_CON                              0x05c8
+#define AUDIO_TOP_DBG_MON0                             0x05cc
+#define AUDIO_TOP_DBG_MON1                             0x05d0
+#define AFE_IRQ8_MCU_CNT_MON                           0x05e4
+#define AFE_IRQ11_MCU_CNT_MON                          0x05e8
+#define AFE_IRQ12_MCU_CNT_MON                          0x05ec
+#define AFE_IRQ_MCU_CNT9                               0x0600
+#define AFE_IRQ_MCU_CNT10                              0x0604
+#define AFE_IRQ_MCU_CNT13                              0x0608
+#define AFE_IRQ_MCU_CNT14                              0x060c
+#define AFE_IRQ_MCU_CNT15                              0x0610
+#define AFE_IRQ_MCU_CNT16                              0x0614
+#define AFE_IRQ_MCU_CNT17                              0x0618
+#define AFE_IRQ_MCU_CNT18                              0x061c
+#define AFE_IRQ_MCU_CNT19                              0x0620
+#define AFE_IRQ_MCU_CNT20                              0x0624
+#define AFE_IRQ_MCU_CNT21                              0x0628
+#define AFE_IRQ_MCU_CNT22                              0x062c
+#define AFE_IRQ_MCU_CNT23                              0x0630
+#define AFE_IRQ_MCU_CNT24                              0x0634
+#define AFE_IRQ_MCU_CNT25                              0x0638
+#define AFE_IRQ_MCU_CNT26                              0x063c
+#define AFE_IRQ_MCU_CNT31                              0x0640
+#define AFE_TINY_CONN6                                 0x0650
+#define AFE_TINY_CONN7                                 0x0654
+#define AFE_IRQ9_MCU_CNT_MON                           0x0660
+#define AFE_IRQ10_MCU_CNT_MON                          0x0664
+#define AFE_IRQ13_MCU_CNT_MON                          0x0668
+#define AFE_IRQ14_MCU_CNT_MON                          0x066c
+#define AFE_IRQ15_MCU_CNT_MON                          0x0670
+#define AFE_IRQ16_MCU_CNT_MON                          0x0674
+#define AFE_IRQ17_MCU_CNT_MON                          0x0678
+#define AFE_IRQ18_MCU_CNT_MON                          0x067c
+#define AFE_IRQ19_MCU_CNT_MON                          0x0680
+#define AFE_IRQ20_MCU_CNT_MON                          0x0684
+#define AFE_IRQ21_MCU_CNT_MON                          0x0688
+#define AFE_IRQ22_MCU_CNT_MON                          0x068c
+#define AFE_IRQ23_MCU_CNT_MON                          0x0690
+#define AFE_IRQ24_MCU_CNT_MON                          0x0694
+#define AFE_IRQ25_MCU_CNT_MON                          0x0698
+#define AFE_IRQ26_MCU_CNT_MON                          0x069c
+#define AFE_IRQ31_MCU_CNT_MON                          0x06a0
+#define AFE_GENERAL_REG0                               0x0800
+#define AFE_GENERAL_REG1                               0x0804
+#define AFE_GENERAL_REG2                               0x0808
+#define AFE_GENERAL_REG3                               0x080c
+#define AFE_GENERAL_REG4                               0x0810
+#define AFE_GENERAL_REG5                               0x0814
+#define AFE_GENERAL_REG6                               0x0818
+#define AFE_GENERAL_REG7                               0x081c
+#define AFE_GENERAL_REG8                               0x0820
+#define AFE_GENERAL_REG9                               0x0824
+#define AFE_GENERAL_REG10                              0x0828
+#define AFE_GENERAL_REG11                              0x082c
+#define AFE_GENERAL_REG12                              0x0830
+#define AFE_GENERAL_REG13                              0x0834
+#define AFE_GENERAL_REG14                              0x0838
+#define AFE_GENERAL_REG15                              0x083c
+#define AFE_CBIP_CFG0                                  0x0840
+#define AFE_CBIP_MON0                                  0x0844
+#define AFE_CBIP_SLV_MUX_MON0                          0x0848
+#define AFE_CBIP_SLV_DECODER_MON0                      0x084c
+#define AFE_ADDA6_MTKAIF_MON0                          0x0854
+#define AFE_ADDA6_MTKAIF_MON1                          0x0858
+#define AFE_AWB_CON0                                   0x085c
+#define AFE_AWB_BASE_MSB                               0x0860
+#define AFE_AWB_BASE                                   0x0864
+#define AFE_AWB_CUR_MSB                                0x0868
+#define AFE_AWB_CUR                                    0x086c
+#define AFE_AWB_END_MSB                                0x0870
+#define AFE_AWB_END                                    0x0874
+#define AFE_AWB2_CON0                                  0x0878
+#define AFE_AWB2_BASE_MSB                              0x087c
+#define AFE_AWB2_BASE                                  0x0880
+#define AFE_AWB2_CUR_MSB                               0x0884
+#define AFE_AWB2_CUR                                   0x0888
+#define AFE_AWB2_END_MSB                               0x088c
+#define AFE_AWB2_END                                   0x0890
+#define AFE_DAI_CON0                                   0x0894
+#define AFE_DAI_BASE_MSB                               0x0898
+#define AFE_DAI_BASE                                   0x089c
+#define AFE_DAI_CUR_MSB                                0x08a0
+#define AFE_DAI_CUR                                    0x08a4
+#define AFE_DAI_END_MSB                                0x08a8
+#define AFE_DAI_END                                    0x08ac
+#define AFE_DAI2_CON0                                  0x08b0
+#define AFE_DAI2_BASE_MSB                              0x08b4
+#define AFE_DAI2_BASE                                  0x08b8
+#define AFE_DAI2_CUR_MSB                               0x08bc
+#define AFE_DAI2_CUR                                   0x08c0
+#define AFE_DAI2_END_MSB                               0x08c4
+#define AFE_DAI2_END                                   0x08c8
+#define AFE_MEMIF_CON0                                 0x08cc
+#define AFE_CONN0_1                                    0x0900
+#define AFE_CONN1_1                                    0x0904
+#define AFE_CONN2_1                                    0x0908
+#define AFE_CONN3_1                                    0x090c
+#define AFE_CONN4_1                                    0x0910
+#define AFE_CONN5_1                                    0x0914
+#define AFE_CONN6_1                                    0x0918
+#define AFE_CONN7_1                                    0x091c
+#define AFE_CONN8_1                                    0x0920
+#define AFE_CONN9_1                                    0x0924
+#define AFE_CONN10_1                                   0x0928
+#define AFE_CONN11_1                                   0x092c
+#define AFE_CONN12_1                                   0x0930
+#define AFE_CONN13_1                                   0x0934
+#define AFE_CONN14_1                                   0x0938
+#define AFE_CONN15_1                                   0x093c
+#define AFE_CONN16_1                                   0x0940
+#define AFE_CONN17_1                                   0x0944
+#define AFE_CONN18_1                                   0x0948
+#define AFE_CONN19_1                                   0x094c
+#define AFE_CONN20_1                                   0x0950
+#define AFE_CONN21_1                                   0x0954
+#define AFE_CONN22_1                                   0x0958
+#define AFE_CONN23_1                                   0x095c
+#define AFE_CONN24_1                                   0x0960
+#define AFE_CONN25_1                                   0x0964
+#define AFE_CONN26_1                                   0x0968
+#define AFE_CONN27_1                                   0x096c
+#define AFE_CONN28_1                                   0x0970
+#define AFE_CONN29_1                                   0x0974
+#define AFE_CONN30_1                                   0x0978
+#define AFE_CONN31_1                                   0x097c
+#define AFE_CONN32_1                                   0x0980
+#define AFE_CONN33_1                                   0x0984
+#define AFE_CONN34_1                                   0x0988
+#define AFE_CONN_RS_1                                  0x098c
+#define AFE_CONN_DI_1                                  0x0990
+#define AFE_CONN_24BIT_1                               0x0994
+#define AFE_CONN_REG                                   0x0998
+#define AFE_CONN35                                     0x09a0
+#define AFE_CONN36                                     0x09a4
+#define AFE_CONN37                                     0x09a8
+#define AFE_CONN38                                     0x09ac
+#define AFE_CONN35_1                                   0x09b0
+#define AFE_CONN36_1                                   0x09b4
+#define AFE_CONN37_1                                   0x09b8
+#define AFE_CONN38_1                                   0x09bc
+#define AFE_CONN39                                     0x09c0
+#define AFE_CONN40                                     0x09c4
+#define AFE_CONN41                                     0x09c8
+#define AFE_CONN42                                     0x09cc
+#define AFE_SGEN_CON_SGEN32                            0x09d0
+#define AFE_CONN39_1                                   0x09e0
+#define AFE_CONN40_1                                   0x09e4
+#define AFE_CONN41_1                                   0x09e8
+#define AFE_CONN42_1                                   0x09ec
+#define AFE_I2S_CON4                                   0x09f8
+#define AFE_ADDA6_TOP_CON0                             0x0a80
+#define AFE_ADDA6_UL_SRC_CON0                          0x0a84
+#define AFE_ADDA6_UL_SRC_CON1                          0x0a88
+#define AFE_ADDA6_SRC_DEBUG                            0x0a8c
+#define AFE_ADDA6_SRC_DEBUG_MON0                       0x0a90
+#define AFE_ADDA6_ULCF_CFG_02_01                       0x0aa0
+#define AFE_ADDA6_ULCF_CFG_04_03                       0x0aa4
+#define AFE_ADDA6_ULCF_CFG_06_05                       0x0aa8
+#define AFE_ADDA6_ULCF_CFG_08_07                       0x0aac
+#define AFE_ADDA6_ULCF_CFG_10_09                       0x0ab0
+#define AFE_ADDA6_ULCF_CFG_12_11                       0x0ab4
+#define AFE_ADDA6_ULCF_CFG_14_13                       0x0ab8
+#define AFE_ADDA6_ULCF_CFG_16_15                       0x0abc
+#define AFE_ADDA6_ULCF_CFG_18_17                       0x0ac0
+#define AFE_ADDA6_ULCF_CFG_20_19                       0x0ac4
+#define AFE_ADDA6_ULCF_CFG_22_21                       0x0ac8
+#define AFE_ADDA6_ULCF_CFG_24_23                       0x0acc
+#define AFE_ADDA6_ULCF_CFG_26_25                       0x0ad0
+#define AFE_ADDA6_ULCF_CFG_28_27                       0x0ad4
+#define AFE_ADDA6_ULCF_CFG_30_29                       0x0ad8
+#define AFE_ADD6A_UL_SRC_MON0                          0x0ae4
+#define AFE_ADDA6_UL_SRC_MON1                          0x0ae8
+#define AFE_TINY_CONN0                                 0x0af0
+#define AFE_TINY_CONN1                                 0x0af4
+#define AFE_CONN43                                     0x0af8
+#define AFE_CONN43_1                                   0x0afc
+#define AFE_MOD_DAI_CON0                               0x0b00
+#define AFE_MOD_DAI_BASE_MSB                           0x0b04
+#define AFE_MOD_DAI_BASE                               0x0b08
+#define AFE_MOD_DAI_CUR_MSB                            0x0b0c
+#define AFE_MOD_DAI_CUR                                0x0b10
+#define AFE_MOD_DAI_END_MSB                            0x0b14
+#define AFE_MOD_DAI_END                                0x0b18
+#define AFE_HDMI_OUT_CON0                              0x0b1c
+#define AFE_HDMI_OUT_BASE_MSB                          0x0b20
+#define AFE_HDMI_OUT_BASE                              0x0b24
+#define AFE_HDMI_OUT_CUR_MSB                           0x0b28
+#define AFE_HDMI_OUT_CUR                               0x0b2c
+#define AFE_HDMI_OUT_END_MSB                           0x0b30
+#define AFE_HDMI_OUT_END                               0x0b34
+#define AFE_AWB_RCH_MON                                0x0b70
+#define AFE_AWB_LCH_MON                                0x0b74
+#define AFE_VUL_RCH_MON                                0x0b78
+#define AFE_VUL_LCH_MON                                0x0b7c
+#define AFE_VUL12_RCH_MON                              0x0b80
+#define AFE_VUL12_LCH_MON                              0x0b84
+#define AFE_VUL2_RCH_MON                               0x0b88
+#define AFE_VUL2_LCH_MON                               0x0b8c
+#define AFE_DAI_DATA_MON                               0x0b90
+#define AFE_MOD_DAI_DATA_MON                           0x0b94
+#define AFE_DAI2_DATA_MON                              0x0b98
+#define AFE_AWB2_RCH_MON                               0x0b9c
+#define AFE_AWB2_LCH_MON                               0x0ba0
+#define AFE_VUL3_RCH_MON                               0x0ba4
+#define AFE_VUL3_LCH_MON                               0x0ba8
+#define AFE_VUL4_RCH_MON                               0x0bac
+#define AFE_VUL4_LCH_MON                               0x0bb0
+#define AFE_VUL5_RCH_MON                               0x0bb4
+#define AFE_VUL5_LCH_MON                               0x0bb8
+#define AFE_VUL6_RCH_MON                               0x0bbc
+#define AFE_VUL6_LCH_MON                               0x0bc0
+#define AFE_DL1_RCH_MON                                0x0bc4
+#define AFE_DL1_LCH_MON                                0x0bc8
+#define AFE_DL2_RCH_MON                                0x0bcc
+#define AFE_DL2_LCH_MON                                0x0bd0
+#define AFE_DL12_RCH1_MON                              0x0bd4
+#define AFE_DL12_LCH1_MON                              0x0bd8
+#define AFE_DL12_RCH2_MON                              0x0bdc
+#define AFE_DL12_LCH2_MON                              0x0be0
+#define AFE_DL3_RCH_MON                                0x0be4
+#define AFE_DL3_LCH_MON                                0x0be8
+#define AFE_DL4_RCH_MON                                0x0bec
+#define AFE_DL4_LCH_MON                                0x0bf0
+#define AFE_DL5_RCH_MON                                0x0bf4
+#define AFE_DL5_LCH_MON                                0x0bf8
+#define AFE_DL6_RCH_MON                                0x0bfc
+#define AFE_DL6_LCH_MON                                0x0c00
+#define AFE_DL7_RCH_MON                                0x0c04
+#define AFE_DL7_LCH_MON                                0x0c08
+#define AFE_DL8_RCH_MON                                0x0c0c
+#define AFE_DL8_LCH_MON                                0x0c10
+#define AFE_VUL5_CON0                                  0x0c14
+#define AFE_VUL5_BASE_MSB                              0x0c18
+#define AFE_VUL5_BASE                                  0x0c1c
+#define AFE_VUL5_CUR_MSB                               0x0c20
+#define AFE_VUL5_CUR                                   0x0c24
+#define AFE_VUL5_END_MSB                               0x0c28
+#define AFE_VUL5_END                                   0x0c2c
+#define AFE_VUL6_CON0                                  0x0c30
+#define AFE_VUL6_BASE_MSB                              0x0c34
+#define AFE_VUL6_BASE                                  0x0c38
+#define AFE_VUL6_CUR_MSB                               0x0c3c
+#define AFE_VUL6_CUR                                   0x0c40
+#define AFE_VUL6_END_MSB                               0x0c44
+#define AFE_VUL6_END                                   0x0c48
+#define AFE_ADDA_DL_SDM_DCCOMP_CON                     0x0c50
+#define AFE_ADDA_DL_SDM_TEST                           0x0c54
+#define AFE_ADDA_DL_DC_COMP_CFG0                       0x0c58
+#define AFE_ADDA_DL_DC_COMP_CFG1                       0x0c5c
+#define AFE_ADDA_DL_SDM_FIFO_MON                       0x0c60
+#define AFE_ADDA_DL_SRC_LCH_MON                        0x0c64
+#define AFE_ADDA_DL_SRC_RCH_MON                        0x0c68
+#define AFE_ADDA_DL_SDM_OUT_MON                        0x0c6c
+#define AFE_ADDA_DL_SDM_DITHER_CON                     0x0c70
+#define AFE_ADDA_DL_SDM_AUTO_RESET_CON                 0x0c74
+#define AFE_CONNSYS_I2S_CON                            0x0c78
+#define AFE_CONNSYS_I2S_MON                            0x0c7c
+#define AFE_ASRC_2CH_CON0                              0x0c80
+#define AFE_ASRC_2CH_CON1                              0x0c84
+#define AFE_ASRC_2CH_CON2                              0x0c88
+#define AFE_ASRC_2CH_CON3                              0x0c8c
+#define AFE_ASRC_2CH_CON4                              0x0c90
+#define AFE_ASRC_2CH_CON5                              0x0c94
+#define AFE_ASRC_2CH_CON6                              0x0c98
+#define AFE_ASRC_2CH_CON7                              0x0c9c
+#define AFE_ASRC_2CH_CON8                              0x0ca0
+#define AFE_ASRC_2CH_CON9                              0x0ca4
+#define AFE_ASRC_2CH_CON10                             0x0ca8
+#define AFE_ASRC_2CH_CON12                             0x0cb0
+#define AFE_ASRC_2CH_CON13                             0x0cb4
+#define AFE_ADDA6_IIR_COEF_02_01                       0x0ce0
+#define AFE_ADDA6_IIR_COEF_04_03                       0x0ce4
+#define AFE_ADDA6_IIR_COEF_06_05                       0x0ce8
+#define AFE_ADDA6_IIR_COEF_08_07                       0x0cec
+#define AFE_ADDA6_IIR_COEF_10_09                       0x0cf0
+#define AFE_SE_PROT_SIDEBAND                           0x0d38
+#define AFE_SE_DOMAIN_SIDEBAND0                        0x0d3c
+#define AFE_ADDA_PREDIS_CON2                           0x0d40
+#define AFE_ADDA_PREDIS_CON3                           0x0d44
+#define AFE_MEMIF_CONN                                 0x0d50
+#define AFE_SE_DOMAIN_SIDEBAND1                        0x0d54
+#define AFE_SE_DOMAIN_SIDEBAND2                        0x0d58
+#define AFE_SE_DOMAIN_SIDEBAND3                        0x0d5c
+#define AFE_CONN44                                     0x0d70
+#define AFE_CONN45                                     0x0d74
+#define AFE_CONN46                                     0x0d78
+#define AFE_CONN47                                     0x0d7c
+#define AFE_CONN44_1                                   0x0d80
+#define AFE_CONN45_1                                   0x0d84
+#define AFE_CONN46_1                                   0x0d88
+#define AFE_CONN47_1                                   0x0d8c
+#define AFE_DL9_CUR_MSB                                0x0dc0
+#define AFE_DL9_CUR                                    0x0dc4
+#define AFE_DL9_END_MSB                                0x0dc8
+#define AFE_DL9_END                                    0x0dcc
+#define AFE_HD_ENGEN_ENABLE                            0x0dd0
+#define AFE_ADDA_DL_NLE_FIFO_MON                       0x0dfc
+#define AFE_ADDA_MTKAIF_CFG0                           0x0e00
+#define AFE_ADDA_MTKAIF_SYNCWORD_CFG                   0x0e14
+#define AFE_ADDA_MTKAIF_RX_CFG0                        0x0e20
+#define AFE_ADDA_MTKAIF_RX_CFG1                        0x0e24
+#define AFE_ADDA_MTKAIF_RX_CFG2                        0x0e28
+#define AFE_ADDA_MTKAIF_MON0                           0x0e34
+#define AFE_ADDA_MTKAIF_MON1                           0x0e38
+#define AFE_AUD_PAD_TOP                                0x0e40
+#define AFE_DL_NLE_R_CFG0                              0x0e44
+#define AFE_DL_NLE_R_CFG1                              0x0e48
+#define AFE_DL_NLE_L_CFG0                              0x0e4c
+#define AFE_DL_NLE_L_CFG1                              0x0e50
+#define AFE_DL_NLE_R_MON0                              0x0e54
+#define AFE_DL_NLE_R_MON1                              0x0e58
+#define AFE_DL_NLE_R_MON2                              0x0e5c
+#define AFE_DL_NLE_L_MON0                              0x0e60
+#define AFE_DL_NLE_L_MON1                              0x0e64
+#define AFE_DL_NLE_L_MON2                              0x0e68
+#define AFE_DL_NLE_GAIN_CFG0                           0x0e6c
+#define AFE_ADDA6_MTKAIF_CFG0                          0x0e70
+#define AFE_ADDA6_MTKAIF_RX_CFG0                       0x0e74
+#define AFE_ADDA6_MTKAIF_RX_CFG1                       0x0e78
+#define AFE_ADDA6_MTKAIF_RX_CFG2                       0x0e7c
+#define AFE_GENERAL1_ASRC_2CH_CON0                     0x0e80
+#define AFE_GENERAL1_ASRC_2CH_CON1                     0x0e84
+#define AFE_GENERAL1_ASRC_2CH_CON2                     0x0e88
+#define AFE_GENERAL1_ASRC_2CH_CON3                     0x0e8c
+#define AFE_GENERAL1_ASRC_2CH_CON4                     0x0e90
+#define AFE_GENERAL1_ASRC_2CH_CON5                     0x0e94
+#define AFE_GENERAL1_ASRC_2CH_CON6                     0x0e98
+#define AFE_GENERAL1_ASRC_2CH_CON7                     0x0e9c
+#define AFE_GENERAL1_ASRC_2CH_CON8                     0x0ea0
+#define AFE_GENERAL1_ASRC_2CH_CON9                     0x0ea4
+#define AFE_GENERAL1_ASRC_2CH_CON10                    0x0ea8
+#define AFE_GENERAL1_ASRC_2CH_CON12                    0x0eb0
+#define AFE_GENERAL1_ASRC_2CH_CON13                    0x0eb4
+#define GENERAL_ASRC_MODE                              0x0eb8
+#define GENERAL_ASRC_EN_ON                             0x0ebc
+#define AFE_CONN48                                     0x0ec0
+#define AFE_CONN49                                     0x0ec4
+#define AFE_CONN50                                     0x0ec8
+#define AFE_CONN51                                     0x0ecc
+#define AFE_CONN52                                     0x0ed0
+#define AFE_CONN53                                     0x0ed4
+#define AFE_CONN54                                     0x0ed8
+#define AFE_CONN55                                     0x0edc
+#define AFE_CONN48_1                                   0x0ee0
+#define AFE_CONN49_1                                   0x0ee4
+#define AFE_CONN50_1                                   0x0ee8
+#define AFE_CONN51_1                                   0x0eec
+#define AFE_CONN52_1                                   0x0ef0
+#define AFE_CONN53_1                                   0x0ef4
+#define AFE_CONN54_1                                   0x0ef8
+#define AFE_CONN55_1                                   0x0efc
+#define AFE_GENERAL2_ASRC_2CH_CON0                     0x0f00
+#define AFE_GENERAL2_ASRC_2CH_CON1                     0x0f04
+#define AFE_GENERAL2_ASRC_2CH_CON2                     0x0f08
+#define AFE_GENERAL2_ASRC_2CH_CON3                     0x0f0c
+#define AFE_GENERAL2_ASRC_2CH_CON4                     0x0f10
+#define AFE_GENERAL2_ASRC_2CH_CON5                     0x0f14
+#define AFE_GENERAL2_ASRC_2CH_CON6                     0x0f18
+#define AFE_GENERAL2_ASRC_2CH_CON7                     0x0f1c
+#define AFE_GENERAL2_ASRC_2CH_CON8                     0x0f20
+#define AFE_GENERAL2_ASRC_2CH_CON9                     0x0f24
+#define AFE_GENERAL2_ASRC_2CH_CON10                    0x0f28
+#define AFE_GENERAL2_ASRC_2CH_CON12                    0x0f30
+#define AFE_GENERAL2_ASRC_2CH_CON13                    0x0f34
+#define AFE_DL9_RCH_MON                                0x0f38
+#define AFE_DL9_LCH_MON                                0x0f3c
+#define AFE_DL5_CON0                                   0x0f4c
+#define AFE_DL5_BASE_MSB                               0x0f50
+#define AFE_DL5_BASE                                   0x0f54
+#define AFE_DL5_CUR_MSB                                0x0f58
+#define AFE_DL5_CUR                                    0x0f5c
+#define AFE_DL5_END_MSB                                0x0f60
+#define AFE_DL5_END                                    0x0f64
+#define AFE_DL6_CON0                                   0x0f68
+#define AFE_DL6_BASE_MSB                               0x0f6c
+#define AFE_DL6_BASE                                   0x0f70
+#define AFE_DL6_CUR_MSB                                0x0f74
+#define AFE_DL6_CUR                                    0x0f78
+#define AFE_DL6_END_MSB                                0x0f7c
+#define AFE_DL6_END                                    0x0f80
+#define AFE_DL7_CON0                                   0x0f84
+#define AFE_DL7_BASE_MSB                               0x0f88
+#define AFE_DL7_BASE                                   0x0f8c
+#define AFE_DL7_CUR_MSB                                0x0f90
+#define AFE_DL7_CUR                                    0x0f94
+#define AFE_DL7_END_MSB                                0x0f98
+#define AFE_DL7_END                                    0x0f9c
+#define AFE_DL8_CON0                                   0x0fa0
+#define AFE_DL8_BASE_MSB                               0x0fa4
+#define AFE_DL8_BASE                                   0x0fa8
+#define AFE_DL8_CUR_MSB                                0x0fac
+#define AFE_DL8_CUR                                    0x0fb0
+#define AFE_DL8_END_MSB                                0x0fb4
+#define AFE_DL8_END                                    0x0fb8
+#define AFE_DL9_CON0                                   0x0fbc
+#define AFE_DL9_BASE_MSB                               0x0fc0
+#define AFE_DL9_BASE                                   0x0fc4
+#define AFE_SE_SECURE_CON                              0x1004
+#define AFE_PROT_SIDEBAND_MON                          0x1008
+#define AFE_DOMAIN_SIDEBAND0_MON                       0x100c
+#define AFE_DOMAIN_SIDEBAND1_MON                       0x1010
+#define AFE_DOMAIN_SIDEBAND2_MON                       0x1014
+#define AFE_DOMAIN_SIDEBAND3_MON                       0x1018
+#define AFE_SECURE_MASK_CONN0                          0x1020
+#define AFE_SECURE_MASK_CONN1                          0x1024
+#define AFE_SECURE_MASK_CONN2                          0x1028
+#define AFE_SECURE_MASK_CONN3                          0x102c
+#define AFE_SECURE_MASK_CONN4                          0x1030
+#define AFE_SECURE_MASK_CONN5                          0x1034
+#define AFE_SECURE_MASK_CONN6                          0x1038
+#define AFE_SECURE_MASK_CONN7                          0x103c
+#define AFE_SECURE_MASK_CONN8                          0x1040
+#define AFE_SECURE_MASK_CONN9                          0x1044
+#define AFE_SECURE_MASK_CONN10                         0x1048
+#define AFE_SECURE_MASK_CONN11                         0x104c
+#define AFE_SECURE_MASK_CONN12                         0x1050
+#define AFE_SECURE_MASK_CONN13                         0x1054
+#define AFE_SECURE_MASK_CONN14                         0x1058
+#define AFE_SECURE_MASK_CONN15                         0x105c
+#define AFE_SECURE_MASK_CONN16                         0x1060
+#define AFE_SECURE_MASK_CONN17                         0x1064
+#define AFE_SECURE_MASK_CONN18                         0x1068
+#define AFE_SECURE_MASK_CONN19                         0x106c
+#define AFE_SECURE_MASK_CONN20                         0x1070
+#define AFE_SECURE_MASK_CONN21                         0x1074
+#define AFE_SECURE_MASK_CONN22                         0x1078
+#define AFE_SECURE_MASK_CONN23                         0x107c
+#define AFE_SECURE_MASK_CONN24                         0x1080
+#define AFE_SECURE_MASK_CONN25                         0x1084
+#define AFE_SECURE_MASK_CONN26                         0x1088
+#define AFE_SECURE_MASK_CONN27                         0x108c
+#define AFE_SECURE_MASK_CONN28                         0x1090
+#define AFE_SECURE_MASK_CONN29                         0x1094
+#define AFE_SECURE_MASK_CONN30                         0x1098
+#define AFE_SECURE_MASK_CONN31                         0x109c
+#define AFE_SECURE_MASK_CONN32                         0x10a0
+#define AFE_SECURE_MASK_CONN33                         0x10a4
+#define AFE_SECURE_MASK_CONN34                         0x10a8
+#define AFE_SECURE_MASK_CONN35                         0x10ac
+#define AFE_SECURE_MASK_CONN36                         0x10b0
+#define AFE_SECURE_MASK_CONN37                         0x10b4
+#define AFE_SECURE_MASK_CONN38                         0x10b8
+#define AFE_SECURE_MASK_CONN39                         0x10bc
+#define AFE_SECURE_MASK_CONN40                         0x10c0
+#define AFE_SECURE_MASK_CONN41                         0x10c4
+#define AFE_SECURE_MASK_CONN42                         0x10c8
+#define AFE_SECURE_MASK_CONN43                         0x10cc
+#define AFE_SECURE_MASK_CONN44                         0x10d0
+#define AFE_SECURE_MASK_CONN45                         0x10d4
+#define AFE_SECURE_MASK_CONN46                         0x10d8
+#define AFE_SECURE_MASK_CONN47                         0x10dc
+#define AFE_SECURE_MASK_CONN48                         0x10e0
+#define AFE_SECURE_MASK_CONN49                         0x10e4
+#define AFE_SECURE_MASK_CONN50                         0x10e8
+#define AFE_SECURE_MASK_CONN51                         0x10ec
+#define AFE_SECURE_MASK_CONN52                         0x10f0
+#define AFE_SECURE_MASK_CONN53                         0x10f4
+#define AFE_SECURE_MASK_CONN54                         0x10f8
+#define AFE_SECURE_MASK_CONN55                         0x10fc
+#define AFE_SECURE_MASK_CONN56                         0x1100
+#define AFE_SECURE_MASK_CONN57                         0x1104
+#define AFE_SECURE_MASK_CONN0_1                        0x1108
+#define AFE_SECURE_MASK_CONN1_1                        0x110c
+#define AFE_SECURE_MASK_CONN2_1                        0x1110
+#define AFE_SECURE_MASK_CONN3_1                        0x1114
+#define AFE_SECURE_MASK_CONN4_1                        0x1118
+#define AFE_SECURE_MASK_CONN5_1                        0x111c
+#define AFE_SECURE_MASK_CONN6_1                        0x1120
+#define AFE_SECURE_MASK_CONN7_1                        0x1124
+#define AFE_SECURE_MASK_CONN8_1                        0x1128
+#define AFE_SECURE_MASK_CONN9_1                        0x112c
+#define AFE_SECURE_MASK_CONN10_1                       0x1130
+#define AFE_SECURE_MASK_CONN11_1                       0x1134
+#define AFE_SECURE_MASK_CONN12_1                       0x1138
+#define AFE_SECURE_MASK_CONN13_1                       0x113c
+#define AFE_SECURE_MASK_CONN14_1                       0x1140
+#define AFE_SECURE_MASK_CONN15_1                       0x1144
+#define AFE_SECURE_MASK_CONN16_1                       0x1148
+#define AFE_SECURE_MASK_CONN17_1                       0x114c
+#define AFE_SECURE_MASK_CONN18_1                       0x1150
+#define AFE_SECURE_MASK_CONN19_1                       0x1154
+#define AFE_SECURE_MASK_CONN20_1                       0x1158
+#define AFE_SECURE_MASK_CONN21_1                       0x115c
+#define AFE_SECURE_MASK_CONN22_1                       0x1160
+#define AFE_SECURE_MASK_CONN23_1                       0x1164
+#define AFE_SECURE_MASK_CONN24_1                       0x1168
+#define AFE_SECURE_MASK_CONN25_1                       0x116c
+#define AFE_SECURE_MASK_CONN26_1                       0x1170
+#define AFE_SECURE_MASK_CONN27_1                       0x1174
+#define AFE_SECURE_MASK_CONN28_1                       0x1178
+#define AFE_SECURE_MASK_CONN29_1                       0x117c
+#define AFE_SECURE_MASK_CONN30_1                       0x1180
+#define AFE_SECURE_MASK_CONN31_1                       0x1184
+#define AFE_SECURE_MASK_CONN32_1                       0x1188
+#define AFE_SECURE_MASK_CONN33_1                       0x118c
+#define AFE_SECURE_MASK_CONN34_1                       0x1190
+#define AFE_SECURE_MASK_CONN35_1                       0x1194
+#define AFE_SECURE_MASK_CONN36_1                       0x1198
+#define AFE_SECURE_MASK_CONN37_1                       0x119c
+#define AFE_SECURE_MASK_CONN38_1                       0x11a0
+#define AFE_SECURE_MASK_CONN39_1                       0x11a4
+#define AFE_SECURE_MASK_CONN40_1                       0x11a8
+#define AFE_SECURE_MASK_CONN41_1                       0x11ac
+#define AFE_SECURE_MASK_CONN42_1                       0x11b0
+#define AFE_SECURE_MASK_CONN43_1                       0x11b4
+#define AFE_SECURE_MASK_CONN44_1                       0x11b8
+#define AFE_SECURE_MASK_CONN45_1                       0x11bc
+#define AFE_SECURE_MASK_CONN46_1                       0x11c0
+#define AFE_SECURE_MASK_CONN47_1                       0x11c4
+#define AFE_SECURE_MASK_CONN48_1                       0x11c8
+#define AFE_SECURE_MASK_CONN49_1                       0x11cc
+#define AFE_SECURE_MASK_CONN50_1                       0x11d0
+#define AFE_SECURE_MASK_CONN51_1                       0x11d4
+#define AFE_SECURE_MASK_CONN52_1                       0x11d8
+#define AFE_SECURE_MASK_CONN53_1                       0x11dc
+#define AFE_SECURE_MASK_CONN54_1                       0x11e0
+#define AFE_SECURE_MASK_CONN55_1                       0x11e4
+#define AFE_SECURE_MASK_CONN56_1                       0x11e8
+#define AFE_SECURE_MASK_TINY_CONN0                     0x1200
+#define AFE_SECURE_MASK_TINY_CONN1                     0x1204
+#define AFE_SECURE_MASK_TINY_CONN2                     0x1208
+#define AFE_SECURE_MASK_TINY_CONN3                     0x120c
+#define AFE_SECURE_MASK_TINY_CONN4                     0x1210
+#define AFE_SECURE_MASK_TINY_CONN5                     0x1214
+#define AFE_SECURE_MASK_TINY_CONN6                     0x1218
+#define AFE_SECURE_MASK_TINY_CONN7                     0x121c
+
+#define AFE_MAX_REGISTER AFE_SECURE_MASK_TINY_CONN7
+
+#define AFE_IRQ_STATUS_BITS 0x87FFFFFF
+#define AFE_IRQ_CNT_SHIFT 0
+#define AFE_IRQ_CNT_MASK 0x3ffff
+
+#endif
index 363dc3b..b93ea33 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "ASoC support for Amlogic platforms"
-       depends on ARCH_MESON || COMPILE_TEST
+       depends on ARCH_MESON || (COMPILE_TEST && COMMON_CLK)
 
 config SND_MESON_AIU
        tristate "Amlogic AIU"
@@ -98,7 +98,7 @@ config SND_MESON_AXG_PDM
          in the Amlogic AXG SoC family
 
 config SND_MESON_CARD_UTILS
-       tristate
+       tristate
 
 config SND_MESON_CODEC_GLUE
        tristate
index 56d2592..4c1349d 100644 (file)
@@ -312,7 +312,7 @@ static int t9015_probe(struct platform_device *pdev)
                                               &t9015_dai, 1);
 }
 
-static const struct of_device_id t9015_ids[] = {
+static const struct of_device_id t9015_ids[] __maybe_unused = {
        { .compatible = "amlogic,t9015", },
        { }
 };
index 0ac85ea..9d40e8a 100644 (file)
@@ -221,13 +221,13 @@ config SND_PXA2XX_SOC_MIOA701
          MIO A701.
 
 config SND_PXA2XX_SOC_IMOTE2
-       tristate "SoC Audio support for IMote 2"
-       depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C
-       select SND_PXA2XX_SOC_I2S
-       select SND_SOC_WM8940
-       help
-        Say Y if you want to add support for SoC audio on the
-        IMote 2.
+       tristate "SoC Audio support for IMote 2"
+       depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C
+       select SND_PXA2XX_SOC_I2S
+       select SND_SOC_WM8940
+       help
+         Say Y if you want to add support for SoC audio on the
+         IMote 2.
 
 config SND_MMP_SOC_BROWNSTONE
        tristate "SoC Audio support for Marvell Brownstone"
index 4255851..4803972 100644 (file)
@@ -239,12 +239,16 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       sspa_ctrl &= ~SSPA_CTL_XPH;
        if (dev->of_node || params_channels(params) == 2)
                sspa_ctrl |= SSPA_CTL_XPH;
 
        sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
        sspa_ctrl |= SSPA_CTL_XWDLEN1(bitval);
 
+       sspa_ctrl &= ~SSPA_CTL_XWDLEN2_MASK;
+       sspa_ctrl |= SSPA_CTL_XWDLEN2(bitval);
+
        sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
        sspa_ctrl |= SSPA_CTL_XSSZ1(bitval);
 
index c4e7307..b941adc 100644 (file)
@@ -99,8 +99,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
                pxa_ssp_disable(ssp);
        }
 
-       if (priv->extclk)
-               clk_prepare_enable(priv->extclk);
+       clk_prepare_enable(priv->extclk);
 
        dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
        if (!dma)
@@ -124,8 +123,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
                clk_disable_unprepare(ssp->clk);
        }
 
-       if (priv->extclk)
-               clk_disable_unprepare(priv->extclk);
+       clk_disable_unprepare(priv->extclk);
 
        kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
        snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
index 2696ffc..cc7c1de 100644 (file)
@@ -106,6 +106,7 @@ config SND_SOC_QDSP6
 config SND_SOC_MSM8996
        tristate "SoC Machine driver for MSM8996 and APQ8096 boards"
        depends on QCOM_APR
+       depends on COMMON_CLK
        select SND_SOC_QDSP6
        select SND_SOC_QCOM_COMMON
        help
@@ -127,4 +128,28 @@ config SND_SOC_SDM845
          SDM845 SoC-based systems.
          Say Y if you want to use audio device on this SoCs.
 
+config SND_SOC_SM8250
+       tristate "SoC Machine driver for SM8250 boards"
+       depends on QCOM_APR && SOUNDWIRE
+       depends on COMMON_CLK
+       select SND_SOC_QDSP6
+       select SND_SOC_QCOM_COMMON
+       help
+         To add support for audio on Qualcomm Technologies Inc.
+         SM8250 SoC-based systems.
+         Say Y if you want to use audio device on this SoCs.
+
+config SND_SOC_SC7180
+       tristate "SoC Machine driver for SC7180 boards"
+       depends on I2C
+       select SND_SOC_QCOM_COMMON
+       select SND_SOC_LPASS_SC7180
+       select SND_SOC_MAX98357A
+       select SND_SOC_RT5682_I2C
+       select SND_SOC_ADAU7002
+       help
+         To add support for audio on Qualcomm Technologies Inc.
+         SC7180 SoC-based systems.
+         Say Y if you want to use audio device on this SoCs.
+
 endif #SND_SOC_QCOM
index 0bd90d7..1600ae5 100644 (file)
@@ -18,13 +18,17 @@ obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
 snd-soc-storm-objs := storm.o
 snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 snd-soc-apq8096-objs := apq8096.o
+snd-soc-sc7180-objs := sc7180.o
 snd-soc-sdm845-objs := sdm845.o
+snd-soc-sm8250-objs := sm8250.o
 snd-soc-qcom-common-objs := common.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
 obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
 obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
+obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o
 obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
 obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
 
 #DSP lib
index 575e2ae..270986b 100644 (file)
@@ -167,7 +167,7 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
        return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
-static const struct of_device_id apq8016_sbc_device_id[]  = {
+static const struct of_device_id apq8016_sbc_device_id[] __maybe_unused = {
        { .compatible = "qcom,apq8016-sbc-sndcard" },
        {},
 };
index 54660f1..09af007 100644 (file)
@@ -58,7 +58,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
                dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
                if (!dlc) {
                        ret = -ENOMEM;
-                       goto err;
+                       goto err_put_np;
                }
 
                link->cpus      = &dlc[0];
@@ -70,7 +70,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
                ret = of_property_read_string(np, "link-name", &link->name);
                if (ret) {
                        dev_err(card->dev, "error getting codec dai_link name\n");
-                       goto err;
+                       goto err_put_np;
                }
 
                cpu = of_get_child_by_name(np, "cpu");
@@ -130,8 +130,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
                } else {
                        /* DPCM frontend */
                        dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL);
-                       if (!dlc)
-                               return -ENOMEM;
+                       if (!dlc) {
+                               ret = -ENOMEM;
+                               goto err;
+                       }
 
                        link->codecs     = dlc;
                        link->num_codecs = 1;
@@ -158,10 +160,11 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 
        return 0;
 err:
-       of_node_put(np);
        of_node_put(cpu);
        of_node_put(codec);
        of_node_put(platform);
+err_put_np:
+       of_node_put(np);
        return ret;
 }
 EXPORT_SYMBOL(qcom_snd_parse_of);
index 0aedb3a..8507ef8 100644 (file)
@@ -291,7 +291,7 @@ static struct lpass_variant apq8016_data = {
        .free_dma_channel       = apq8016_lpass_free_dma_channel,
 };
 
-static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
+static const struct of_device_id apq8016_lpass_cpu_device_id[] __maybe_unused = {
        { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
        {}
 };
index 426235a..af684fd 100644 (file)
@@ -673,7 +673,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
        return false;
 }
 
-struct regmap_config lpass_hdmi_regmap_config = {
+static struct regmap_config lpass_hdmi_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -914,5 +914,15 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
 
+void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev)
+{
+       struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+       if (drvdata->variant->exit)
+               drvdata->variant->exit(pdev);
+
+}
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown);
+
 MODULE_DESCRIPTION("QTi LPASS CPU Driver");
 MODULE_LICENSE("GPL v2");
index 172952d..abfb873 100644 (file)
@@ -24,7 +24,7 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
        unsigned int rate = params_rate(params);
        unsigned int channels = params_channels(params);
        unsigned int ret;
-       unsigned int bitwidth;
+       int bitwidth;
        unsigned int word_length;
        unsigned int ch_sts_buf0;
        unsigned int ch_sts_buf1;
index 832a916..92f98b4 100644 (file)
@@ -161,7 +161,7 @@ static struct lpass_variant ipq806x_data = {
        .free_dma_channel       = ipq806x_lpass_free_dma_channel,
 };
 
-static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
+static const struct of_device_id ipq806x_lpass_cpu_device_id[] __maybe_unused = {
        { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
        {}
 };
index bc998d5..85db650 100644 (file)
@@ -34,7 +34,8 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
                },
                .capture = {
                        .stream_name = "Primary Capture",
-                       .formats = SNDRV_PCM_FMTBIT_S16,
+                       .formats = SNDRV_PCM_FMTBIT_S16 |
+                               SNDRV_PCM_FMTBIT_S32,
                        .rates = SNDRV_PCM_RATE_48000,
                        .rate_min       = 48000,
                        .rate_max       = 48000,
@@ -96,8 +97,8 @@ static int sc7180_lpass_alloc_dma_channel(struct lpass_data *drvdata,
                        chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
                                                v->rdma_channels);
 
-               if (chan >= v->rdma_channels)
-                       return -EBUSY;
+                       if (chan >= v->rdma_channels)
+                               return -EBUSY;
                } else {
                        chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
                                        v->wrdma_channel_start +
@@ -284,7 +285,7 @@ static struct lpass_variant sc7180_data = {
        .free_dma_channel       = sc7180_lpass_free_dma_channel,
 };
 
-static const struct of_device_id sc7180_lpass_cpu_device_id[] = {
+static const struct of_device_id sc7180_lpass_cpu_device_id[] __maybe_unused = {
        {.compatible = "qcom,sc7180-lpass-cpu", .data = &sc7180_data},
        {}
 };
@@ -297,6 +298,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = {
        },
        .probe = asoc_qcom_lpass_cpu_platform_probe,
        .remove = asoc_qcom_lpass_cpu_platform_remove,
+       .shutdown = asoc_qcom_lpass_cpu_platform_shutdown,
 };
 
 module_platform_driver(sc7180_lpass_cpu_platform_driver);
index bccd1a0..0195372 100644 (file)
@@ -256,6 +256,7 @@ struct lpass_variant {
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
+void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
 extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
index 72f2972..1855b80 100644 (file)
@@ -601,14 +601,7 @@ static int q6adm_probe(struct apr_device *adev)
        INIT_LIST_HEAD(&adm->copps_list);
        spin_lock_init(&adm->copps_list_lock);
 
-       return of_platform_populate(dev->of_node, NULL, NULL, dev);
-}
-
-static int q6adm_remove(struct apr_device *adev)
-{
-       of_platform_depopulate(&adev->dev);
-
-       return 0;
+       return devm_of_platform_populate(dev);
 }
 
 #ifdef CONFIG_OF
@@ -621,7 +614,6 @@ MODULE_DEVICE_TABLE(of, q6adm_device_id);
 
 static struct apr_driver qcom_q6adm_driver = {
        .probe = q6adm_probe,
-       .remove = q6adm_remove,
        .callback = q6adm_callback,
        .driver = {
                .name = "qcom-q6adm",
index 2efc2ea..f0362f0 100644 (file)
@@ -16,6 +16,7 @@
                .afe_clk_id     = Q6AFE_##id,           \
                .name = #id,                            \
                .attributes = LPASS_CLK_ATTRIBUTE_COUPLE_NO, \
+               .rate = 19200000,                       \
                .hw.init = &(struct clk_init_data) {    \
                        .ops = &clk_q6afe_ops,          \
                        .name = #id,                    \
@@ -119,7 +120,7 @@ static const struct clk_ops clk_vote_q6afe_ops = {
        .unprepare      = clk_unvote_q6afe_block,
 };
 
-struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = {
+static struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = {
        [LPASS_CLK_ID_PRI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT),
        [LPASS_CLK_ID_PRI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT),
        [LPASS_CLK_ID_SEC_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT),
index 0ca1e4a..daa58b5 100644 (file)
@@ -1740,14 +1740,7 @@ static int q6afe_probe(struct apr_device *adev)
 
        dev_set_drvdata(dev, afe);
 
-       return of_platform_populate(dev->of_node, NULL, NULL, dev);
-}
-
-static int q6afe_remove(struct apr_device *adev)
-{
-       of_platform_depopulate(&adev->dev);
-
-       return 0;
+       return devm_of_platform_populate(dev);
 }
 
 #ifdef CONFIG_OF
@@ -1760,7 +1753,6 @@ MODULE_DEVICE_TABLE(of, q6afe_device_id);
 
 static struct apr_driver qcom_q6afe_driver = {
        .probe = q6afe_probe,
-       .remove = q6afe_remove,
        .callback = q6afe_callback,
        .driver = {
                .name = "qcom-q6afe",
index c547c56..a6618ef 100644 (file)
@@ -1727,14 +1727,7 @@ static int q6asm_probe(struct apr_device *adev)
        spin_lock_init(&q6asm->slock);
        dev_set_drvdata(dev, q6asm);
 
-       return of_platform_populate(dev->of_node, NULL, NULL, dev);
-}
-
-static int q6asm_remove(struct apr_device *adev)
-{
-       of_platform_depopulate(&adev->dev);
-
-       return 0;
+       return devm_of_platform_populate(dev);
 }
 
 #ifdef CONFIG_OF
@@ -1747,7 +1740,6 @@ MODULE_DEVICE_TABLE(of, q6asm_device_id);
 
 static struct apr_driver qcom_q6asm_driver = {
        .probe = q6asm_probe,
-       .remove = q6asm_remove,
        .callback = q6asm_srvc_callback,
        .driver = {
                .name = "qcom-q6asm",
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c
new file mode 100644 (file)
index 0000000..768566b
--- /dev/null
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright (c) 2020, The Linux Foundation. All rights reserved.
+//
+// sc7180.c -- ALSA SoC Machine driver for SC7180
+
+#include <dt-bindings/sound/sc7180-lpass.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
+
+#include "../codecs/rt5682.h"
+#include "common.h"
+#include "lpass.h"
+
+#define DEFAULT_MCLK_RATE              19200000
+#define RT5682_PLL1_FREQ (48000 * 512)
+
+#define DRIVER_NAME "SC7180"
+
+struct sc7180_snd_data {
+       struct snd_soc_card card;
+       u32 pri_mi2s_clk_count;
+       struct snd_soc_jack hs_jack;
+       struct snd_soc_jack hdmi_jack;
+       struct gpio_desc *dmic_sel;
+       int dmic_switch;
+};
+
+static void sc7180_jack_free(struct snd_jack *jack)
+{
+       struct snd_soc_component *component = jack->private_data;
+
+       snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       struct snd_jack *jack;
+       int rval;
+
+       rval = snd_soc_card_jack_new(
+                       card, "Headset Jack",
+                       SND_JACK_HEADSET |
+                       SND_JACK_HEADPHONE |
+                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                       &pdata->hs_jack, NULL, 0);
+
+       if (rval < 0) {
+               dev_err(card->dev, "Unable to add Headset Jack\n");
+               return rval;
+       }
+
+       jack = pdata->hs_jack.jack;
+
+       snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       jack->private_data = component;
+       jack->private_free = sc7180_jack_free;
+
+       return snd_soc_component_set_jack(component, &pdata->hs_jack, NULL);
+}
+
+static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       struct snd_jack *jack;
+       int rval;
+
+       rval = snd_soc_card_jack_new(
+                       card, "HDMI Jack",
+                       SND_JACK_LINEOUT,
+                       &pdata->hdmi_jack, NULL, 0);
+
+       if (rval < 0) {
+               dev_err(card->dev, "Unable to add HDMI Jack\n");
+               return rval;
+       }
+
+       jack = pdata->hdmi_jack.jack;
+       jack->private_data = component;
+       jack->private_free = sc7180_jack_free;
+
+       return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL);
+}
+
+static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case MI2S_PRIMARY:
+               return sc7180_headset_init(rtd);
+       case MI2S_SECONDARY:
+               return 0;
+       case LPASS_DP_RX:
+               return sc7180_hdmi_init(rtd);
+       default:
+               dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+                       cpu_dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int sc7180_snd_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+       struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int ret;
+
+       switch (cpu_dai->id) {
+       case MI2S_PRIMARY:
+               if (++data->pri_mi2s_clk_count == 1) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                                              LPASS_MCLK0,
+                                              DEFAULT_MCLK_RATE,
+                                              SNDRV_PCM_STREAM_PLAYBACK);
+               }
+
+               snd_soc_dai_set_fmt(codec_dai,
+                                   SND_SOC_DAIFMT_CBS_CFS |
+                                   SND_SOC_DAIFMT_NB_NF |
+                                   SND_SOC_DAIFMT_I2S);
+
+               /* Configure PLL1 for codec */
+               ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
+                                         DEFAULT_MCLK_RATE, RT5682_PLL1_FREQ);
+               if (ret) {
+                       dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+                       return ret;
+               }
+
+               /* Configure sysclk for codec */
+               ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
+                                            RT5682_PLL1_FREQ,
+                                            SND_SOC_CLOCK_IN);
+               if (ret)
+                       dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",
+                               ret);
+
+               break;
+       case MI2S_SECONDARY:
+               break;
+       case LPASS_DP_RX:
+               break;
+       default:
+               dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+                       cpu_dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int dmic_get(struct snd_kcontrol *kcontrol,
+                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
+
+       ucontrol->value.integer.value[0] = data->dmic_switch;
+       return 0;
+}
+
+static int dmic_set(struct snd_kcontrol *kcontrol,
+                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
+
+       data->dmic_switch = ucontrol->value.integer.value[0];
+       gpiod_set_value(data->dmic_sel, data->dmic_switch);
+       return 0;
+}
+
+static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+       struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case MI2S_PRIMARY:
+               if (--data->pri_mi2s_clk_count == 0) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                                              LPASS_MCLK0,
+                                              0,
+                                              SNDRV_PCM_STREAM_PLAYBACK);
+               }
+               break;
+       case MI2S_SECONDARY:
+               break;
+       case LPASS_DP_RX:
+               break;
+       default:
+               dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+                       cpu_dai->id);
+               break;
+       }
+}
+
+static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case MI2S_PRIMARY:
+               return 0;
+       case MI2S_SECONDARY:
+               return 0;
+       case LPASS_DP_RX:
+               return sc7180_hdmi_init(rtd);
+       default:
+               dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+                       cpu_dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       switch (cpu_dai->id) {
+       case MI2S_PRIMARY:
+               snd_soc_dai_set_fmt(codec_dai,
+                                   SND_SOC_DAIFMT_CBS_CFS |
+                                   SND_SOC_DAIFMT_NB_NF |
+                                   SND_SOC_DAIFMT_I2S);
+               runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+               snd_pcm_hw_constraint_msbits(runtime, 0, 32, 32);
+
+               break;
+       case MI2S_SECONDARY:
+               break;
+       case LPASS_DP_RX:
+               break;
+       default:
+               dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+                       cpu_dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct snd_soc_ops sc7180_ops = {
+       .startup = sc7180_snd_startup,
+       .shutdown = sc7180_snd_shutdown,
+};
+
+static const struct snd_soc_ops sc7180_adau7002_ops = {
+       .startup = sc7180_adau7002_snd_startup,
+};
+
+static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = {
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static const char * const dmic_mux_text[] = {
+       "Front Mic",
+       "Rear Mic",
+};
+
+static SOC_ENUM_SINGLE_DECL(sc7180_dmic_enum,
+                           SND_SOC_NOPM, 0, dmic_mux_text);
+
+static const struct snd_kcontrol_new sc7180_dmic_mux_control =
+       SOC_DAPM_ENUM_EXT("DMIC Select Mux", sc7180_dmic_enum,
+                         dmic_get, dmic_set);
+
+static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+       SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control),
+};
+
+static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = {
+       {"Dmic Mux", "Front Mic", "DMIC"},
+       {"Dmic Mux", "Rear Mic", "DMIC"},
+};
+
+static int sc7180_snd_platform_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct sc7180_snd_data *data;
+       struct device *dev = &pdev->dev;
+       struct snd_soc_dai_link *link;
+       int ret;
+       int i;
+       bool no_headphone = false;
+
+       /* Allocate the private data */
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       card = &data->card;
+       snd_soc_card_set_drvdata(card, data);
+
+       card->owner = THIS_MODULE;
+       card->driver_name = DRIVER_NAME;
+       card->dev = dev;
+       card->dapm_widgets = sc7180_snd_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets);
+
+       if (of_property_read_bool(dev->of_node, "dmic-gpios")) {
+               card->dapm_widgets = sc7180_snd_dual_mic_widgets,
+               card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets),
+               card->dapm_routes = sc7180_snd_dual_mic_audio_route,
+               card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route),
+               data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
+               if (IS_ERR(data->dmic_sel)) {
+                       dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n", PTR_ERR(data->dmic_sel));
+                       return PTR_ERR(data->dmic_sel);
+               }
+       }
+
+       if (of_device_is_compatible(dev->of_node, "google,sc7180-coachz")) {
+               no_headphone = true;
+               card->dapm_widgets = sc7180_adau7002_snd_widgets;
+               card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets);
+       }
+
+       ret = qcom_snd_parse_of(card);
+       if (ret)
+               return ret;
+
+       for_each_card_prelinks(card, i, link) {
+               if (no_headphone) {
+                       link->ops = &sc7180_adau7002_ops;
+                       link->init = sc7180_adau7002_init;
+               } else {
+                       link->ops = &sc7180_ops;
+                       link->init = sc7180_init;
+               }
+       }
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id sc7180_snd_device_id[]  = {
+       {.compatible = "google,sc7180-trogdor"},
+       {.compatible = "google,sc7180-coachz"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, sc7180_snd_device_id);
+
+static struct platform_driver sc7180_snd_driver = {
+       .probe = sc7180_snd_platform_probe,
+       .driver = {
+               .name = "msm-snd-sc7180",
+               .of_match_table = sc7180_snd_device_id,
+               .pm = &snd_soc_pm_ops,
+       },
+};
+module_platform_driver(sc7180_snd_driver);
+
+MODULE_DESCRIPTION("sc7180 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
new file mode 100644 (file)
index 0000000..fe8fd73
--- /dev/null
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <linux/soundwire/sdw.h>
+#include "qdsp6/q6afe.h"
+#include "common.h"
+
+#define DRIVER_NAME            "sm8250"
+#define MI2S_BCLK_RATE         1536000
+
+struct sm8250_snd_data {
+       bool stream_prepared[AFE_PORT_MAX];
+       struct snd_soc_card *card;
+       struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
+};
+
+static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       return 0;
+}
+
+static int sm8250_snd_startup(struct snd_pcm_substream *substream)
+{
+       unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case TERTIARY_MI2S_RX:
+               codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+               snd_soc_dai_set_sysclk(cpu_dai,
+                       Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+                       MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+               snd_soc_dai_set_fmt(cpu_dai, fmt);
+               snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int sm8250_snd_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;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+       struct sdw_stream_runtime *sruntime;
+       int i;
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+               for_each_rtd_codec_dais(rtd, i, codec_dai) {
+                       sruntime = snd_soc_dai_get_sdw_stream(codec_dai,
+                                                     substream->stream);
+                       if (sruntime != ERR_PTR(-ENOTSUPP))
+                               pdata->sruntime[cpu_dai->id] = sruntime;
+               }
+               break;
+       }
+
+       return 0;
+
+}
+
+static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+       struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+       int ret;
+
+       if (!sruntime)
+               return 0;
+
+       if (data->stream_prepared[cpu_dai->id]) {
+               sdw_disable_stream(sruntime);
+               sdw_deprepare_stream(sruntime);
+               data->stream_prepared[cpu_dai->id] = false;
+       }
+
+       ret = sdw_prepare_stream(sruntime);
+       if (ret)
+               return ret;
+
+       /**
+        * NOTE: there is a strict hw requirement about the ordering of port
+        * enables and actual WSA881x PA enable. PA enable should only happen
+        * after soundwire ports are enabled if not DC on the line is
+        * accumulated resulting in Click/Pop Noise
+        * PA enable/mute are handled as part of codec DAPM and digital mute.
+        */
+
+       ret = sdw_enable_stream(sruntime);
+       if (ret) {
+               sdw_deprepare_stream(sruntime);
+               return ret;
+       }
+       data->stream_prepared[cpu_dai->id]  = true;
+
+       return ret;
+}
+
+static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case WSA_CODEC_DMA_RX_1:
+               return sm8250_snd_wsa_dma_prepare(substream);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case WSA_CODEC_DMA_RX_1:
+               if (sruntime && data->stream_prepared[cpu_dai->id]) {
+                       sdw_disable_stream(sruntime);
+                       sdw_deprepare_stream(sruntime);
+                       data->stream_prepared[cpu_dai->id] = false;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops sm8250_be_ops = {
+       .startup = sm8250_snd_startup,
+       .hw_params = sm8250_snd_hw_params,
+       .hw_free = sm8250_snd_hw_free,
+       .prepare = sm8250_snd_prepare,
+};
+
+static void sm8250_add_be_ops(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link;
+       int i;
+
+       for_each_card_prelinks(card, i, link) {
+               if (link->no_pcm == 1) {
+                       link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
+                       link->ops = &sm8250_be_ops;
+               }
+       }
+}
+
+static int sm8250_platform_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct sm8250_snd_data *data;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       /* Allocate the private data */
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       card->dev = dev;
+       dev_set_drvdata(dev, card);
+       snd_soc_card_set_drvdata(card, data);
+       ret = qcom_snd_parse_of(card);
+       if (ret)
+               return ret;
+
+       card->driver_name = DRIVER_NAME;
+       sm8250_add_be_ops(card);
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id snd_sm8250_dt_match[] = {
+       {.compatible = "qcom,sm8250-sndcard"},
+       {.compatible = "qcom,qrb5165-rb5-sndcard"},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match);
+
+static struct platform_driver snd_sm8250_driver = {
+       .probe  = sm8250_platform_probe,
+       .driver = {
+               .name = "snd-sm8250",
+               .of_match_table = snd_sm8250_dt_match,
+       },
+};
+module_platform_driver(snd_sm8250_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
index 5932996..eae287d 100644 (file)
@@ -566,7 +566,7 @@ static const struct rk_i2s_pins rk3399_i2s_pins = {
        .shift = 11,
 };
 
-static const struct of_device_id rockchip_i2s_match[] = {
+static const struct of_device_id rockchip_i2s_match[] __maybe_unused = {
        { .compatible = "rockchip,rk3066-i2s", },
        { .compatible = "rockchip,rk3188-i2s", },
        { .compatible = "rockchip,rk3288-i2s", },
index 5adb293..e5f7327 100644 (file)
@@ -460,7 +460,7 @@ static const struct regmap_config rockchip_pdm_regmap_config = {
        .cache_type = REGCACHE_FLAT,
 };
 
-static const struct of_device_id rockchip_pdm_match[] = {
+static const struct of_device_id rockchip_pdm_match[] __maybe_unused = {
        { .compatible = "rockchip,pdm",
          .data = (void *)RK_PDM_RK3229 },
        { .compatible = "rockchip,px30-pdm",
index 6748108..ffb4ec3 100644 (file)
@@ -41,7 +41,7 @@ struct rk_spdif_dev {
        struct regmap *regmap;
 };
 
-static const struct of_device_id rk_spdif_match[] = {
+static const struct of_device_id rk_spdif_match[] __maybe_unused = {
        { .compatible = "rockchip,rk3066-spdif",
          .data = (void *)RK_SPDIF_RK3066 },
        { .compatible = "rockchip,rk3188-spdif",
index df53d4e..4bdc268 100644 (file)
@@ -1212,8 +1212,7 @@ static int i2s_runtime_suspend(struct device *dev)
        priv->suspend_i2scon = readl(priv->addr + I2SCON);
        priv->suspend_i2spsr = readl(priv->addr + I2SPSR);
 
-       if (priv->op_clk)
-               clk_disable_unprepare(priv->op_clk);
+       clk_disable_unprepare(priv->op_clk);
        clk_disable_unprepare(priv->clk);
 
        return 0;
@@ -1622,28 +1621,28 @@ static const struct samsung_i2s_dai_data i2sv3_dai_type = {
        .i2s_variant_regs = &i2sv3_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv5_dai_type = {
+static const struct samsung_i2s_dai_data i2sv5_dai_type __maybe_unused = {
        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
                        QUIRK_SUPPORTS_IDMA,
        .pcm_rates = SNDRV_PCM_RATE_8000_96000,
        .i2s_variant_regs = &i2sv3_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv6_dai_type = {
+static const struct samsung_i2s_dai_data i2sv6_dai_type __maybe_unused = {
        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
                        QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
        .pcm_rates = SNDRV_PCM_RATE_8000_96000,
        .i2s_variant_regs = &i2sv6_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv7_dai_type = {
+static const struct samsung_i2s_dai_data i2sv7_dai_type __maybe_unused = {
        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
                        QUIRK_SUPPORTS_TDM,
        .pcm_rates = SNDRV_PCM_RATE_8000_192000,
        .i2s_variant_regs = &i2sv7_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
+static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 __maybe_unused = {
        .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
        .pcm_rates = SNDRV_PCM_RATE_8000_96000,
        .i2s_variant_regs = &i2sv5_i2s1_regs,
index d03340c..1f9a553 100644 (file)
@@ -531,7 +531,6 @@ static struct platform_driver midas_driver = {
        .driver = {
                .name = "midas-audio",
                .of_match_table = midas_of_match,
-               .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
        },
        .probe = midas_probe,
index 64a1a64..681b244 100644 (file)
@@ -136,7 +136,7 @@ static struct snd_soc_card smdk = {
        .num_links = ARRAY_SIZE(smdk_dai),
 };
 
-static const struct of_device_id samsung_wm8994_of_match[] = {
+static const struct of_device_id samsung_wm8994_of_match[] __maybe_unused = {
        { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
        {},
 };
@@ -170,7 +170,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
                smdk_dai[0].platforms->of_node = smdk_dai[0].cpus->of_node;
        }
 
-       id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev);
+       id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
        if (id)
                *board = *((struct smdk_wm8994_data *)id->data);
 
index 07163f0..989af62 100644 (file)
@@ -189,7 +189,7 @@ static int snow_probe(struct platform_device *pdev)
                        return PTR_ERR(priv->clk_i2s_bus);
                }
        } else {
-               link->codecs->dai_name = "HiFi",
+               link->codecs->dai_name = "HiFi";
 
                link->cpus->of_node = of_parse_phandle(dev->of_node,
                                                "samsung,i2s-controller", 0);
index ef8a29b..346c806 100644 (file)
@@ -23,6 +23,7 @@ config SND_SOC_SH4_SSI
 
 config SND_SOC_SH4_FSI
        tristate "SH4 FSI support"
+       depends on SUPERH || COMMON_CLK
        select SND_SIMPLE_CARD
        help
          This option enables FSI sound support
index 728e93f..7605233 100644 (file)
@@ -421,6 +421,260 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
 
 #endif
 
+int snd_soc_component_compr_open(struct snd_compr_stream *cstream)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->open) {
+                       ret = component->driver->compress_ops->open(component, cstream);
+                       if (ret < 0)
+                               return soc_component_ret(component, ret);
+               }
+               soc_component_mark_push(component, cstream, compr_open);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_open);
+
+void snd_soc_component_compr_free(struct snd_compr_stream *cstream,
+                                 int rollback)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (rollback && !soc_component_mark_match(component, cstream, compr_open))
+                       continue;
+
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->free)
+                       component->driver->compress_ops->free(component, cstream);
+
+               soc_component_mark_pop(component, cstream, compr_open);
+       }
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_free);
+
+int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->trigger) {
+                       ret = component->driver->compress_ops->trigger(
+                               component, cstream, cmd);
+                       if (ret < 0)
+                               return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger);
+
+int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream,
+                                      struct snd_compr_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->set_params) {
+                       ret = component->driver->compress_ops->set_params(
+                               component, cstream, params);
+                       if (ret < 0)
+                               return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_params);
+
+int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream,
+                                      struct snd_codec *params)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->get_params) {
+                       ret = component->driver->compress_ops->get_params(
+                               component, cstream, params);
+                       return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_params);
+
+int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream,
+                                    struct snd_compr_caps *caps)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret = 0;
+
+       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->get_caps) {
+                       ret = component->driver->compress_ops->get_caps(
+                               component, cstream, caps);
+                       break;
+               }
+       }
+
+       mutex_unlock(&rtd->card->pcm_mutex);
+
+       return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_caps);
+
+int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream,
+                                          struct snd_compr_codec_caps *codec)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret = 0;
+
+       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->get_codec_caps) {
+                       ret = component->driver->compress_ops->get_codec_caps(
+                               component, cstream, codec);
+                       break;
+               }
+       }
+
+       mutex_unlock(&rtd->card->pcm_mutex);
+
+       return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_codec_caps);
+
+int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->ack) {
+                       ret = component->driver->compress_ops->ack(
+                               component, cstream, bytes);
+                       if (ret < 0)
+                               return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack);
+
+int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream,
+                                   struct snd_compr_tstamp *tstamp)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->pointer) {
+                       ret = component->driver->compress_ops->pointer(
+                               component, cstream, tstamp);
+                       return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_pointer);
+
+int snd_soc_component_compr_copy(struct snd_compr_stream *cstream,
+                                char __user *buf, size_t count)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret = 0;
+
+       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->copy) {
+                       ret = component->driver->compress_ops->copy(
+                               component, cstream, buf, count);
+                       break;
+               }
+       }
+
+       mutex_unlock(&rtd->card->pcm_mutex);
+
+       return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy);
+
+int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream,
+                                        struct snd_compr_metadata *metadata)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->set_metadata) {
+                       ret = component->driver->compress_ops->set_metadata(
+                               component, cstream, metadata);
+                       if (ret < 0)
+                               return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_metadata);
+
+int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream,
+                                        struct snd_compr_metadata *metadata)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_component *component;
+       int i, ret;
+
+       for_each_rtd_components(rtd, i, component) {
+               if (component->driver->compress_ops &&
+                   component->driver->compress_ops->get_metadata) {
+                       ret = component->driver->compress_ops->get_metadata(
+                               component, cstream, metadata);
+                       return soc_component_ret(component, ret);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_metadata);
+
 static unsigned int soc_component_read_no_lock(
        struct snd_soc_component *component,
        unsigned int reg)
@@ -779,8 +1033,7 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
 }
 
 int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
-                                   struct snd_pcm_hw_params *params,
-                                   struct snd_soc_component **last)
+                                   struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_component *component;
@@ -790,52 +1043,83 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
                if (component->driver->hw_params) {
                        ret = component->driver->hw_params(component,
                                                           substream, params);
-                       if (ret < 0) {
-                               *last = component;
+                       if (ret < 0)
                                return soc_component_ret(component, ret);
-                       }
                }
+               /* mark substream if succeeded */
+               soc_component_mark_push(component, substream, hw_params);
        }
 
-       *last = NULL;
        return 0;
 }
 
 void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
-                                  struct snd_soc_component *last)
+                                  int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_component *component;
        int i, ret;
 
        for_each_rtd_components(rtd, i, component) {
-               if (component == last)
-                       break;
+               if (rollback && !soc_component_mark_match(component, substream, hw_params))
+                       continue;
 
                if (component->driver->hw_free) {
                        ret = component->driver->hw_free(component, substream);
                        if (ret < 0)
                                soc_component_ret(component, ret);
                }
+
+               /* remove marked substream */
+               soc_component_mark_pop(component, substream, hw_params);
        }
 }
 
+static int soc_component_trigger(struct snd_soc_component *component,
+                                struct snd_pcm_substream *substream,
+                                int cmd)
+{
+       int ret = 0;
+
+       if (component->driver->trigger)
+               ret = component->driver->trigger(component, substream, cmd);
+
+       return soc_component_ret(component, ret);
+}
+
 int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
-                                 int cmd)
+                                 int cmd, int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_component *component;
-       int i, ret;
-
-       for_each_rtd_components(rtd, i, component) {
-               if (component->driver->trigger) {
-                       ret = component->driver->trigger(component, substream, cmd);
+       int i, r, ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               for_each_rtd_components(rtd, i, component) {
+                       ret = soc_component_trigger(component, substream, cmd);
                        if (ret < 0)
-                               return soc_component_ret(component, ret);
+                               break;
+                       soc_component_mark_push(component, substream, trigger);
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               for_each_rtd_components(rtd, i, component) {
+                       if (rollback && !soc_component_mark_match(component, substream, trigger))
+                               continue;
+
+                       r = soc_component_trigger(component, substream, cmd);
+                       if (r < 0)
+                               ret = r; /* use last ret */
+                       soc_component_mark_pop(component, substream, trigger);
                }
        }
 
-       return 0;
+       return ret;
 }
 
 int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
index 3a6a602..246a5e3 100644 (file)
 #include <sound/soc-link.h>
 #include <linux/pm_runtime.h>
 
-static int soc_compr_components_open(struct snd_compr_stream *cstream,
-                                    struct snd_soc_component **last)
+static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
 
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->open)
-                       continue;
+       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
-               ret = component->driver->compress_ops->open(component, cstream);
-               if (ret < 0) {
-                       dev_err(component->dev,
-                               "Compress ASoC: can't open platform %s: %d\n",
-                               component->name, ret);
+       if (!rollback)
+               snd_soc_runtime_deactivate(rtd, stream);
 
-                       *last = component;
-                       return ret;
-               }
-       }
+       snd_soc_dai_digital_mute(codec_dai, 1, stream);
 
-       *last = NULL;
-       return 0;
-}
+       if (!snd_soc_dai_active(cpu_dai))
+               cpu_dai->rate = 0;
 
-static int soc_compr_components_free(struct snd_compr_stream *cstream,
-                                    struct snd_soc_component *last)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i;
+       if (!snd_soc_dai_active(codec_dai))
+               codec_dai->rate = 0;
 
-       for_each_rtd_components(rtd, i, component) {
-               if (component == last)
-                       break;
+       snd_soc_link_compr_shutdown(cstream, rollback);
 
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->free)
-                       continue;
+       snd_soc_component_compr_free(cstream, rollback);
 
-               component->driver->compress_ops->free(component, cstream);
-       }
+       snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback);
+
+       if (!rollback)
+               snd_soc_dapm_stream_stop(rtd, stream);
+
+       mutex_unlock(&rtd->card->pcm_mutex);
+
+       snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback);
 
        return 0;
 }
 
+static int soc_compr_free(struct snd_compr_stream *cstream)
+{
+       return soc_compr_clean(cstream, 0);
+}
+
 static int soc_compr_open(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component = NULL;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
        int ret;
 
        ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream);
        if (ret < 0)
-               goto pm_err;
+               goto err_no_lock;
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
        ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
        if (ret < 0)
-               goto out;
+               goto err;
 
-       ret = soc_compr_components_open(cstream, &component);
+       ret = snd_soc_component_compr_open(cstream);
        if (ret < 0)
-               goto machine_err;
+               goto err;
 
        ret = snd_soc_link_compr_startup(cstream);
        if (ret < 0)
-               goto machine_err;
-
-       snd_soc_runtime_activate(rtd, cstream->direction);
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-
-       return 0;
-
-machine_err:
-       soc_compr_components_free(cstream, component);
+               goto err;
 
-       snd_soc_dai_compr_shutdown(cpu_dai, cstream);
-out:
+       snd_soc_runtime_activate(rtd, stream);
+err:
        mutex_unlock(&rtd->card->pcm_mutex);
-pm_err:
-       snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 1);
+err_no_lock:
+       if (ret < 0)
+               soc_compr_clean(cstream, 1);
 
        return ret;
 }
@@ -118,18 +103,12 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_pcm_substream *fe_substream =
                 fe->pcm->streams[cstream->direction].substream;
-       struct snd_soc_component *component;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
        struct snd_soc_dpcm *dpcm;
        struct snd_soc_dapm_widget_list *list;
-       int stream;
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
        int ret;
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK)
-               stream = SNDRV_PCM_STREAM_PLAYBACK;
-       else
-               stream = SNDRV_PCM_STREAM_CAPTURE;
-
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
        fe->dpcm[stream].runtime = fe_substream->runtime;
 
@@ -160,7 +139,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
        if (ret < 0)
                goto out;
 
-       ret = soc_compr_components_open(cstream, &component);
+       ret = snd_soc_component_compr_open(cstream);
        if (ret < 0)
                goto open_err;
 
@@ -181,9 +160,9 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
        return 0;
 
 machine_err:
-       soc_compr_components_free(cstream, component);
+       snd_soc_component_compr_free(cstream, 1);
 open_err:
-       snd_soc_dai_compr_shutdown(cpu_dai, cstream);
+       snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1);
 out:
        dpcm_path_put(&list);
 be_err:
@@ -192,59 +171,16 @@ be_err:
        return ret;
 }
 
-static int soc_compr_free(struct snd_compr_stream *cstream)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       int stream;
-
-       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-       if (cstream->direction == SND_COMPRESS_PLAYBACK)
-               stream = SNDRV_PCM_STREAM_PLAYBACK;
-       else
-               stream = SNDRV_PCM_STREAM_CAPTURE;
-
-       snd_soc_runtime_deactivate(rtd, stream);
-
-       snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
-
-       if (!snd_soc_dai_active(cpu_dai))
-               cpu_dai->rate = 0;
-
-       if (!snd_soc_dai_active(codec_dai))
-               codec_dai->rate = 0;
-
-       snd_soc_link_compr_shutdown(cstream);
-
-       soc_compr_components_free(cstream, NULL);
-
-       snd_soc_dai_compr_shutdown(cpu_dai, cstream);
-
-       snd_soc_dapm_stream_stop(rtd, stream);
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-
-       snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 0);
-
-       return 0;
-}
-
 static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
        struct snd_soc_dpcm *dpcm;
-       int stream, ret;
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
+       int ret;
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK)
-               stream = SNDRV_PCM_STREAM_PLAYBACK;
-       else
-               stream = SNDRV_PCM_STREAM_CAPTURE;
-
        snd_soc_runtime_deactivate(fe, stream);
 
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
@@ -268,47 +204,27 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 
        fe->dpcm[stream].runtime = NULL;
 
-       snd_soc_link_compr_shutdown(cstream);
+       snd_soc_link_compr_shutdown(cstream, 0);
 
-       soc_compr_components_free(cstream, NULL);
+       snd_soc_component_compr_free(cstream, 0);
 
-       snd_soc_dai_compr_shutdown(cpu_dai, cstream);
+       snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);
 
        mutex_unlock(&fe->card->mutex);
        return 0;
 }
 
-static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
-                                       int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret;
-
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->trigger)
-                       continue;
-
-               ret = component->driver->compress_ops->trigger(
-                       component, cstream, cmd);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
 static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
        int ret;
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
-       ret = soc_compr_components_trigger(cstream, cmd);
+       ret = snd_soc_component_compr_trigger(cstream, cmd);
        if (ret < 0)
                goto out;
 
@@ -318,10 +234,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
+               snd_soc_dai_digital_mute(codec_dai, 0, stream);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+               snd_soc_dai_digital_mute(codec_dai, 1, stream);
                break;
        }
 
@@ -334,16 +250,12 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 {
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
-       int ret, stream;
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
+       int ret;
 
        if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
            cmd == SND_COMPR_TRIGGER_DRAIN)
-               return soc_compr_components_trigger(cstream, cmd);
-
-       if (cstream->direction == SND_COMPRESS_PLAYBACK)
-               stream = SNDRV_PCM_STREAM_PLAYBACK;
-       else
-               stream = SNDRV_PCM_STREAM_CAPTURE;
+               return snd_soc_component_compr_trigger(cstream, cmd);
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
@@ -351,7 +263,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
        if (ret < 0)
                goto out;
 
-       ret = soc_compr_components_trigger(cstream, cmd);
+       ret = snd_soc_component_compr_trigger(cstream, cmd);
        if (ret < 0)
                goto out;
 
@@ -380,32 +292,12 @@ out:
        return ret;
 }
 
-static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
-                                          struct snd_compr_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret;
-
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->set_params)
-                       continue;
-
-               ret = component->driver->compress_ops->set_params(
-                       component, cstream, params);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
 static int soc_compr_set_params(struct snd_compr_stream *cstream,
                                struct snd_compr_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
        int ret;
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -421,7 +313,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
        if (ret < 0)
                goto err;
 
-       ret = soc_compr_components_set_params(cstream, params);
+       ret = snd_soc_component_compr_set_params(cstream, params);
        if (ret < 0)
                goto err;
 
@@ -429,12 +321,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
        if (ret < 0)
                goto err;
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK)
-               snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
-                                         SND_SOC_DAPM_STREAM_START);
-       else
-               snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
-                                         SND_SOC_DAPM_STREAM_START);
+       snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START);
 
        /* cancel any delayed stream shutdown that is pending */
        rtd->pop_wait = 0;
@@ -456,12 +343,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
        struct snd_pcm_substream *fe_substream =
                 fe->pcm->streams[cstream->direction].substream;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
-       int ret, stream;
-
-       if (cstream->direction == SND_COMPRESS_PLAYBACK)
-               stream = SNDRV_PCM_STREAM_PLAYBACK;
-       else
-               stream = SNDRV_PCM_STREAM_CAPTURE;
+       int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
+       int ret;
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
@@ -487,7 +370,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
        if (ret < 0)
                goto out;
 
-       ret = soc_compr_components_set_params(cstream, params);
+       ret = snd_soc_component_compr_set_params(cstream, params);
        if (ret < 0)
                goto out;
 
@@ -508,9 +391,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
                                struct snd_codec *params)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int i, ret = 0;
+       int ret = 0;
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
@@ -518,73 +400,17 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
        if (ret < 0)
                goto err;
 
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->get_params)
-                       continue;
-
-               ret = component->driver->compress_ops->get_params(
-                       component, cstream, params);
-               break;
-       }
-
+       ret = snd_soc_component_compr_get_params(cstream, params);
 err:
        mutex_unlock(&rtd->card->pcm_mutex);
        return ret;
 }
 
-static int soc_compr_get_caps(struct snd_compr_stream *cstream,
-                             struct snd_compr_caps *caps)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret = 0;
-
-       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->get_caps)
-                       continue;
-
-               ret = component->driver->compress_ops->get_caps(
-                       component, cstream, caps);
-               break;
-       }
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-       return ret;
-}
-
-static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
-                                   struct snd_compr_codec_caps *codec)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret = 0;
-
-       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->get_codec_caps)
-                       continue;
-
-               ret = component->driver->compress_ops->get_codec_caps(
-                       component, cstream, codec);
-               break;
-       }
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-       return ret;
-}
-
 static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int i, ret = 0;
+       int ret;
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
@@ -592,17 +418,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
        if (ret < 0)
                goto err;
 
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->ack)
-                       continue;
-
-               ret = component->driver->compress_ops->ack(
-                       component, cstream, bytes);
-               if (ret < 0)
-                       goto err;
-       }
-
+       ret = snd_soc_component_compr_ack(cstream, bytes);
 err:
        mutex_unlock(&rtd->card->pcm_mutex);
        return ret;
@@ -612,8 +428,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
                             struct snd_compr_tstamp *tstamp)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret = 0;
+       int ret;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -622,91 +437,38 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
        if (ret < 0)
                goto out;
 
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->pointer)
-                       continue;
-
-               ret = component->driver->compress_ops->pointer(
-                       component, cstream, tstamp);
-               break;
-       }
+       ret = snd_soc_component_compr_pointer(cstream, tstamp);
 out:
        mutex_unlock(&rtd->card->pcm_mutex);
        return ret;
 }
 
-static int soc_compr_copy(struct snd_compr_stream *cstream,
-                         char __user *buf, size_t count)
-{
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
-       int i, ret = 0;
-
-       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->copy)
-                       continue;
-
-               ret = component->driver->compress_ops->copy(
-                       component, cstream, buf, count);
-               break;
-       }
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-       return ret;
-}
-
 static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
                                  struct snd_compr_metadata *metadata)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int i, ret;
+       int ret;
 
        ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
        if (ret < 0)
                return ret;
 
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->set_metadata)
-                       continue;
-
-               ret = component->driver->compress_ops->set_metadata(
-                       component, cstream, metadata);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
+       return snd_soc_component_compr_set_metadata(cstream, metadata);
 }
 
 static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
                                  struct snd_compr_metadata *metadata)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_component *component;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int i, ret;
+       int ret;
 
        ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
        if (ret < 0)
                return ret;
 
-       for_each_rtd_components(rtd, i, component) {
-               if (!component->driver->compress_ops ||
-                   !component->driver->compress_ops->get_metadata)
-                       continue;
-
-               return component->driver->compress_ops->get_metadata(
-                       component, cstream, metadata);
-       }
-
-       return 0;
+       return snd_soc_component_compr_get_metadata(cstream, metadata);
 }
 
 /* ASoC Compress operations */
@@ -720,8 +482,8 @@ static struct snd_compr_ops soc_compr_ops = {
        .trigger        = soc_compr_trigger,
        .pointer        = soc_compr_pointer,
        .ack            = soc_compr_ack,
-       .get_caps       = soc_compr_get_caps,
-       .get_codec_caps = soc_compr_get_codec_caps
+       .get_caps       = snd_soc_component_compr_get_caps,
+       .get_codec_caps = snd_soc_component_compr_get_codec_caps,
 };
 
 /* ASoC Dynamic Compress operations */
@@ -735,8 +497,8 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
        .trigger        = soc_compr_trigger_fe,
        .pointer        = soc_compr_pointer,
        .ack            = soc_compr_ack,
-       .get_caps       = soc_compr_get_caps,
-       .get_codec_caps = soc_compr_get_codec_caps
+       .get_caps       = snd_soc_component_compr_get_caps,
+       .get_codec_caps = snd_soc_component_compr_get_codec_caps,
 };
 
 /**
@@ -759,6 +521,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
        int playback = 0, capture = 0;
        int i;
 
+       /*
+        * make sure these are same value,
+        * and then use these as equally
+        */
+       BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK);
+       BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE  != (int)SND_COMPRESS_CAPTURE);
+
        if (rtd->num_cpus > 1 ||
            rtd->num_codecs > 1) {
                dev_err(rtd->card->dev,
@@ -832,7 +601,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
                    !component->driver->compress_ops->copy)
                        continue;
 
-               compr->ops->copy = soc_compr_copy;
+               compr->ops->copy = snd_soc_component_compr_copy;
                break;
        }
 
index 05a085f..f6d4e99 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/of_graph.h>
 #include <linux/dmi.h>
 #include <sound/core.h>
-#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -520,13 +519,46 @@ static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
 }
 
 #ifdef CONFIG_PM_SLEEP
+static void soc_playback_digital_mute(struct snd_soc_card *card, int mute)
+{
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *dai;
+       int playback = SNDRV_PCM_STREAM_PLAYBACK;
+       int i;
+
+       for_each_card_rtds(card, rtd) {
+
+               if (rtd->dai_link->ignore_suspend)
+                       continue;
+
+               for_each_rtd_dais(rtd, i, dai) {
+                       if (snd_soc_dai_stream_active(dai, playback))
+                               snd_soc_dai_digital_mute(dai, mute, playback);
+               }
+       }
+}
+
+static void soc_dapm_suspend_resume(struct snd_soc_card *card, int event)
+{
+       struct snd_soc_pcm_runtime *rtd;
+       int stream;
+
+       for_each_card_rtds(card, rtd) {
+
+               if (rtd->dai_link->ignore_suspend)
+                       continue;
+
+               for_each_pcm_streams(stream)
+                       snd_soc_dapm_stream_event(rtd, stream, event);
+       }
+}
+
 /* powers down audio subsystem for suspend */
 int snd_soc_suspend(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
        struct snd_soc_component *component;
        struct snd_soc_pcm_runtime *rtd;
-       int playback = SNDRV_PCM_STREAM_PLAYBACK;
        int i;
 
        /* If the card is not initialized yet there is nothing to do */
@@ -543,17 +575,7 @@ int snd_soc_suspend(struct device *dev)
        snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
        /* mute any active DACs */
-       for_each_card_rtds(card, rtd) {
-               struct snd_soc_dai *dai;
-
-               if (rtd->dai_link->ignore_suspend)
-                       continue;
-
-               for_each_rtd_dais(rtd, i, dai) {
-                       if (snd_soc_dai_stream_active(dai, playback))
-                               snd_soc_dai_digital_mute(dai, 1, playback);
-               }
-       }
+       soc_playback_digital_mute(card, 1);
 
        /* suspend all pcms */
        for_each_card_rtds(card, rtd) {
@@ -568,16 +590,7 @@ int snd_soc_suspend(struct device *dev)
        /* close any waiting streams */
        snd_soc_flush_all_delayed_work(card);
 
-       for_each_card_rtds(card, rtd) {
-               int stream;
-
-               if (rtd->dai_link->ignore_suspend)
-                       continue;
-
-               for_each_pcm_streams(stream)
-                       snd_soc_dapm_stream_event(rtd, stream,
-                                                 SND_SOC_DAPM_STREAM_SUSPEND);
-       }
+       soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_SUSPEND);
 
        /* Recheck all endpoints too, their state is affected by suspend */
        dapm_mark_endpoints_dirty(card);
@@ -648,9 +661,7 @@ static void soc_resume_deferred(struct work_struct *work)
        struct snd_soc_card *card =
                        container_of(work, struct snd_soc_card,
                                     deferred_resume_work);
-       struct snd_soc_pcm_runtime *rtd;
        struct snd_soc_component *component;
-       int i;
 
        /*
         * our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
@@ -669,30 +680,10 @@ static void soc_resume_deferred(struct work_struct *work)
                        snd_soc_component_resume(component);
        }
 
-       for_each_card_rtds(card, rtd) {
-               int stream;
-
-               if (rtd->dai_link->ignore_suspend)
-                       continue;
-
-               for_each_pcm_streams(stream)
-                       snd_soc_dapm_stream_event(rtd, stream,
-                                                 SND_SOC_DAPM_STREAM_RESUME);
-       }
+       soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_RESUME);
 
        /* unmute any active DACs */
-       for_each_card_rtds(card, rtd) {
-               struct snd_soc_dai *dai;
-               int playback = SNDRV_PCM_STREAM_PLAYBACK;
-
-               if (rtd->dai_link->ignore_suspend)
-                       continue;
-
-               for_each_rtd_dais(rtd, i, dai) {
-                       if (snd_soc_dai_stream_active(dai, playback))
-                               snd_soc_dai_digital_mute(dai, 0, playback);
-               }
-       }
+       soc_playback_digital_mute(card, 0);
 
        snd_soc_card_resume_post(card);
 
@@ -1124,7 +1115,8 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
        for (i = 0; i < card->num_configs; i++) {
                struct snd_soc_codec_conf *map = &card->codec_conf[i];
 
-               if (snd_soc_is_matching_component(&map->dlc, component)) {
+               if (snd_soc_is_matching_component(&map->dlc, component) &&
+                   map->name_prefix) {
                        component->name_prefix = map->name_prefix;
                        return;
                }
index 4705c3d..cd3bb9a 100644 (file)
@@ -335,16 +335,27 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
        if (dai->driver->ops &&
            dai->driver->ops->hw_params)
                ret = dai->driver->ops->hw_params(substream, params, dai);
+
+       /* mark substream if succeeded */
+       if (ret == 0)
+               soc_dai_mark_push(dai, substream, hw_params);
 end:
        return soc_dai_ret(dai, ret);
 }
 
 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
-                        struct snd_pcm_substream *substream)
+                        struct snd_pcm_substream *substream,
+                        int rollback)
 {
+       if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
+               return;
+
        if (dai->driver->ops &&
            dai->driver->ops->hw_free)
                dai->driver->ops->hw_free(substream, dai);
+
+       /* remove marked substream */
+       soc_dai_mark_pop(dai, substream, hw_params);
 }
 
 int snd_soc_dai_startup(struct snd_soc_dai *dai,
@@ -553,23 +564,51 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static int soc_dai_trigger(struct snd_soc_dai *dai,
+                          struct snd_pcm_substream *substream, int cmd)
+{
+       int ret = 0;
+
+       if (dai->driver->ops &&
+           dai->driver->ops->trigger)
+               ret = dai->driver->ops->trigger(substream, cmd, dai);
+
+       return soc_dai_ret(dai, ret);
+}
+
 int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
-                           int cmd)
+                           int cmd, int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *dai;
-       int i, ret;
+       int i, r, ret = 0;
 
-       for_each_rtd_dais(rtd, i, dai) {
-               if (dai->driver->ops &&
-                   dai->driver->ops->trigger) {
-                       ret = dai->driver->ops->trigger(substream, cmd, dai);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               for_each_rtd_dais(rtd, i, dai) {
+                       ret = soc_dai_trigger(dai, substream, cmd);
                        if (ret < 0)
-                               return soc_dai_ret(dai, ret);
+                               break;
+                       soc_dai_mark_push(dai, substream, trigger);
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               for_each_rtd_dais(rtd, i, dai) {
+                       if (rollback && !soc_dai_mark_match(dai, substream, trigger))
+                               continue;
+
+                       r = soc_dai_trigger(dai, substream, cmd);
+                       if (r < 0)
+                               ret = r; /* use last ret */
+                       soc_dai_mark_pop(dai, substream, trigger);
                }
        }
 
-       return 0;
+       return ret;
 }
 
 int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
@@ -601,16 +640,27 @@ int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
            dai->driver->cops->startup)
                ret = dai->driver->cops->startup(cstream, dai);
 
+       /* mark cstream if succeeded */
+       if (ret == 0)
+               soc_dai_mark_push(dai, cstream, compr_startup);
+
        return soc_dai_ret(dai, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
 
 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
-                               struct snd_compr_stream *cstream)
+                               struct snd_compr_stream *cstream,
+                               int rollback)
 {
+       if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
+               return;
+
        if (dai->driver->cops &&
            dai->driver->cops->shutdown)
                dai->driver->cops->shutdown(cstream, dai);
+
+       /* remove marked cstream */
+       soc_dai_mark_pop(dai, cstream, compr_startup);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
 
index 7f87b44..9f0c86c 100644 (file)
@@ -3955,13 +3955,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
                substream->stream = SNDRV_PCM_STREAM_CAPTURE;
                snd_soc_dapm_widget_for_each_source_path(w, path) {
                        source = path->source->priv;
-                       snd_soc_dai_hw_free(source, substream);
+                       snd_soc_dai_hw_free(source, substream, 0);
                }
 
                substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
                snd_soc_dapm_widget_for_each_sink_path(w, path) {
                        sink = path->sink->priv;
-                       snd_soc_dai_hw_free(sink, substream);
+                       snd_soc_dai_hw_free(sink, substream, 0);
                }
 
                substream->stream = SNDRV_PCM_STREAM_CAPTURE;
@@ -4764,7 +4764,7 @@ void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
 
        if (component) {
                dapm->dev               = component->dev;
-               dapm->idle_bias_off     = !component->driver->idle_bias_on,
+               dapm->idle_bias_off     = !component->driver->idle_bias_on;
                dapm->suspend_bias_off  = component->driver->suspend_bias_off;
        } else {
                dapm->dev               = card->dev;
index 2a88819..619664c 100644 (file)
@@ -119,19 +119,29 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
            rtd->dai_link->ops->hw_params)
                ret = rtd->dai_link->ops->hw_params(substream, params);
 
+       /* mark substream if succeeded */
+       if (ret == 0)
+               soc_link_mark_push(rtd, substream, hw_params);
+
        return soc_link_ret(rtd, ret);
 }
 
-void snd_soc_link_hw_free(struct snd_pcm_substream *substream)
+void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 
+       if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
+               return;
+
        if (rtd->dai_link->ops &&
            rtd->dai_link->ops->hw_free)
                rtd->dai_link->ops->hw_free(substream);
+
+       /* remove marked substream */
+       soc_link_mark_pop(rtd, substream, hw_params);
 }
 
-int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
+static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        int ret = 0;
@@ -143,6 +153,34 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
        return soc_link_ret(rtd, ret);
 }
 
+int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
+                        int rollback)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ret = soc_link_trigger(substream, cmd);
+               if (ret < 0)
+                       break;
+               soc_link_mark_push(rtd, substream, trigger);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (rollback && !soc_link_mark_match(rtd, substream, trigger))
+                       break;
+
+               ret = soc_link_trigger(substream, cmd);
+               soc_link_mark_pop(rtd, substream, startup);
+       }
+
+       return ret;
+}
+
 int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -152,17 +190,26 @@ int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
            rtd->dai_link->compr_ops->startup)
                ret = rtd->dai_link->compr_ops->startup(cstream);
 
+       if (ret == 0)
+               soc_link_mark_push(rtd, cstream, compr_startup);
+
        return soc_link_ret(rtd, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup);
 
-void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream)
+void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
+                                int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 
+       if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup))
+               return;
+
        if (rtd->dai_link->compr_ops &&
            rtd->dai_link->compr_ops->shutdown)
                rtd->dai_link->compr_ops->shutdown(cstream);
+
+       soc_link_mark_pop(rtd, cstream, compr_startup);
 }
 EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown);
 
index dcab952..ee51dc7 100644 (file)
@@ -662,8 +662,6 @@ static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
 
        soc_pcm_components_close(substream, rollback);
 
-       if (!rollback)
-               snd_soc_dapm_stream_stop(rtd, substream->stream);
 
        mutex_unlock(&rtd->card->pcm_mutex);
 
@@ -860,6 +858,57 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
        interval->max = channels;
 }
 
+static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *dai;
+       int i;
+
+       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+       /* clear the corresponding DAIs parameters when going to be inactive */
+       for_each_rtd_dais(rtd, i, dai) {
+               int active = snd_soc_dai_stream_active(dai, substream->stream);
+
+               if (snd_soc_dai_active(dai) == 1) {
+                       dai->rate = 0;
+                       dai->channels = 0;
+                       dai->sample_bits = 0;
+               }
+
+               if (active == 1)
+                       snd_soc_dai_digital_mute(dai, 1, substream->stream);
+       }
+
+       /* run the stream event */
+       snd_soc_dapm_stream_stop(rtd, substream->stream);
+
+       /* free any machine hw params */
+       snd_soc_link_hw_free(substream, rollback);
+
+       /* free any component resources */
+       snd_soc_pcm_component_hw_free(substream, rollback);
+
+       /* now free hw params for the DAIs  */
+       for_each_rtd_dais(rtd, i, dai) {
+               if (!snd_soc_dai_stream_valid(dai, substream->stream))
+                       continue;
+
+               snd_soc_dai_hw_free(dai, substream, rollback);
+       }
+
+       mutex_unlock(&rtd->card->pcm_mutex);
+       return 0;
+}
+
+/*
+ * Frees resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return soc_pcm_hw_clean(substream, 0);
+}
+
 /*
  * Called by ALSA when the hardware params are set by application. This
  * function can also be called multiple times and can allocate buffers
@@ -869,7 +918,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_component *component;
        struct snd_soc_dai *cpu_dai;
        struct snd_soc_dai *codec_dai;
        int i, ret = 0;
@@ -921,7 +969,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                ret = snd_soc_dai_hw_params(codec_dai, substream,
                                            &codec_params);
                if(ret < 0)
-                       goto codec_err;
+                       goto out;
 
                codec_dai->rate = params_rate(&codec_params);
                codec_dai->channels = params_channels(&codec_params);
@@ -941,7 +989,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 
                ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
                if (ret < 0)
-                       goto interface_err;
+                       goto out;
 
                /* store the parameters for each DAI */
                cpu_dai->rate = params_rate(params);
@@ -952,121 +1000,73 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                snd_soc_dapm_update_dai(substream, params, cpu_dai);
        }
 
-       ret = snd_soc_pcm_component_hw_params(substream, params, &component);
-       if (ret < 0)
-               goto component_err;
-
+       ret = snd_soc_pcm_component_hw_params(substream, params);
 out:
        mutex_unlock(&rtd->card->pcm_mutex);
-       return ret;
 
-component_err:
-       snd_soc_pcm_component_hw_free(substream, component);
-
-       i = rtd->num_cpus;
-
-interface_err:
-       for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
-               if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
-                       continue;
-
-               snd_soc_dai_hw_free(cpu_dai, substream);
-               cpu_dai->rate = 0;
-       }
-
-       i = rtd->num_codecs;
-
-codec_err:
-       for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
-               if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
-                       continue;
-
-               snd_soc_dai_hw_free(codec_dai, substream);
-               codec_dai->rate = 0;
-       }
-
-       snd_soc_link_hw_free(substream);
+       if (ret < 0)
+               soc_pcm_hw_clean(substream, 1);
 
-       mutex_unlock(&rtd->card->pcm_mutex);
        return ret;
 }
 
-/*
- * Frees resources allocated by hw_params, can be called multiple times
- */
-static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *dai;
-       int i;
-
-       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-       /* clear the corresponding DAIs parameters when going to be inactive */
-       for_each_rtd_dais(rtd, i, dai) {
-               int active = snd_soc_dai_stream_active(dai, substream->stream);
-
-               if (snd_soc_dai_active(dai) == 1) {
-                       dai->rate = 0;
-                       dai->channels = 0;
-                       dai->sample_bits = 0;
-               }
-
-               if (active == 1)
-                       snd_soc_dai_digital_mute(dai, 1, substream->stream);
-       }
-
-       /* free any machine hw params */
-       snd_soc_link_hw_free(substream);
-
-       /* free any component resources */
-       snd_soc_pcm_component_hw_free(substream, NULL);
-
-       /* now free hw params for the DAIs  */
-       for_each_rtd_dais(rtd, i, dai) {
-               if (!snd_soc_dai_stream_valid(dai, substream->stream))
-                       continue;
-
-               snd_soc_dai_hw_free(dai, substream);
-       }
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-       return 0;
-}
-
 static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       int ret = -EINVAL;
+       int ret = -EINVAL, _ret = 0;
+       int rollback = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ret = snd_soc_link_trigger(substream, cmd);
+               ret = snd_soc_link_trigger(substream, cmd, 0);
                if (ret < 0)
-                       break;
+                       goto start_err;
 
-               ret = snd_soc_pcm_component_trigger(substream, cmd);
+               ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
                if (ret < 0)
+                       goto start_err;
+
+               ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
+start_err:
+               if (ret < 0)
+                       rollback = 1;
+       }
+
+       if (rollback) {
+               _ret = ret;
+               switch (cmd) {
+               case SNDRV_PCM_TRIGGER_START:
+                       cmd = SNDRV_PCM_TRIGGER_STOP;
+                       break;
+               case SNDRV_PCM_TRIGGER_RESUME:
+                       cmd = SNDRV_PCM_TRIGGER_SUSPEND;
                        break;
+               case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+                       cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
+                       break;
+               }
+       }
 
-               ret = snd_soc_pcm_dai_trigger(substream, cmd);
-               break;
+       switch (cmd) {
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ret = snd_soc_pcm_dai_trigger(substream, cmd);
+               ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
                if (ret < 0)
                        break;
 
-               ret = snd_soc_pcm_component_trigger(substream, cmd);
+               ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
                if (ret < 0)
                        break;
 
-               ret = snd_soc_link_trigger(substream, cmd);
+               ret = snd_soc_link_trigger(substream, cmd, rollback);
                break;
        }
 
+       if (_ret)
+               ret = _ret;
+
        return ret;
 }
 
@@ -1284,7 +1284,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
 
        /* get number of valid DAI paths and their widgets */
        paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
-                       dpcm_end_walk_at_be);
+                       fe->card->component_chaining ?
+                               NULL : dpcm_end_walk_at_be);
 
        dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
                        stream ? "capture" : "playback");
@@ -1883,7 +1884,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
        /* now shutdown the frontend */
        soc_pcm_close(substream);
 
-       /* run the stream event for each BE */
+       /* run the stream stop event */
        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
@@ -2073,21 +2074,6 @@ out:
        return ret;
 }
 
-static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
-               struct snd_pcm_substream *substream, int cmd)
-{
-       int ret;
-
-       dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
-                       dpcm->be->dai_link->name, cmd);
-
-       ret = soc_pcm_trigger(substream, cmd);
-       if (ret < 0)
-               dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
-
-       return ret;
-}
-
 int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                               int cmd)
 {
@@ -2104,6 +2090,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                if (!snd_soc_dpcm_be_can_update(fe, be, stream))
                        continue;
 
+               dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
+                       be->dai_link->name, cmd);
+
                switch (cmd) {
                case SNDRV_PCM_TRIGGER_START:
                        if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
@@ -2111,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                            (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
                                continue;
 
-                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       ret = soc_pcm_trigger(be_substream, cmd);
                        if (ret)
                                return ret;
 
@@ -2121,7 +2110,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
                                continue;
 
-                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       ret = soc_pcm_trigger(be_substream, cmd);
                        if (ret)
                                return ret;
 
@@ -2131,7 +2120,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
                                continue;
 
-                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       ret = soc_pcm_trigger(be_substream, cmd);
                        if (ret)
                                return ret;
 
@@ -2145,7 +2134,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
                                continue;
 
-                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       ret = soc_pcm_trigger(be_substream, cmd);
                        if (ret)
                                return ret;
 
@@ -2158,7 +2147,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
                                continue;
 
-                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       ret = soc_pcm_trigger(be_substream, cmd);
                        if (ret)
                                return ret;
 
@@ -2171,7 +2160,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
                                continue;
 
-                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       ret = soc_pcm_trigger(be_substream, cmd);
                        if (ret)
                                return ret;
 
@@ -2231,6 +2220,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
                case SNDRV_PCM_TRIGGER_START:
                case SNDRV_PCM_TRIGGER_RESUME:
                case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               case SNDRV_PCM_TRIGGER_DRAIN:
                        ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
                        break;
                case SNDRV_PCM_TRIGGER_STOP:
@@ -2248,6 +2238,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
                case SNDRV_PCM_TRIGGER_START:
                case SNDRV_PCM_TRIGGER_RESUME:
                case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               case SNDRV_PCM_TRIGGER_DRAIN:
                        ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
                        break;
                case SNDRV_PCM_TRIGGER_STOP:
@@ -2385,8 +2376,6 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
                goto out;
        }
 
-       /* run the stream event for each BE */
-       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 
 out:
index c5ef432..950c450 100644 (file)
@@ -64,7 +64,6 @@ struct soc_tplg {
        struct device *dev;
        struct snd_soc_component *comp;
        u32 index;      /* current block index */
-       u32 req_index;  /* required index, only loaded/free matching blocks */
 
        /* vendor specific kcontrol operations */
        const struct snd_soc_tplg_kcontrol_ops *io_ops;
@@ -80,8 +79,6 @@ struct soc_tplg {
 
 static int soc_tplg_process_headers(struct soc_tplg *tplg);
 static void soc_tplg_complete(struct soc_tplg *tplg);
-static void soc_tplg_denum_remove_texts(struct soc_enum *se);
-static void soc_tplg_denum_remove_values(struct soc_enum *se);
 
 /* check we dont overflow the data for this control chunk */
 static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
@@ -360,9 +357,6 @@ static void remove_mixer(struct snd_soc_component *comp,
        struct snd_soc_dobj *dobj, int pass)
 {
        struct snd_card *card = comp->card->snd_card;
-       struct soc_mixer_control *sm =
-               container_of(dobj, struct soc_mixer_control, dobj);
-       const unsigned int *p = NULL;
 
        if (pass != SOC_TPLG_PASS_MIXER)
                return;
@@ -370,12 +364,8 @@ static void remove_mixer(struct snd_soc_component *comp,
        if (dobj->ops && dobj->ops->control_unload)
                dobj->ops->control_unload(comp, dobj);
 
-       if (dobj->control.kcontrol->tlv.p)
-               p = dobj->control.kcontrol->tlv.p;
        snd_ctl_remove(card, dobj->control.kcontrol);
        list_del(&dobj->list);
-       kfree(sm);
-       kfree(p);
 }
 
 /* remove an enum kcontrol */
@@ -383,7 +373,6 @@ static void remove_enum(struct snd_soc_component *comp,
        struct snd_soc_dobj *dobj, int pass)
 {
        struct snd_card *card = comp->card->snd_card;
-       struct soc_enum *se = container_of(dobj, struct soc_enum, dobj);
 
        if (pass != SOC_TPLG_PASS_MIXER)
                return;
@@ -393,10 +382,6 @@ static void remove_enum(struct snd_soc_component *comp,
 
        snd_ctl_remove(card, dobj->control.kcontrol);
        list_del(&dobj->list);
-
-       soc_tplg_denum_remove_values(se);
-       soc_tplg_denum_remove_texts(se);
-       kfree(se);
 }
 
 /* remove a byte kcontrol */
@@ -404,8 +389,6 @@ static void remove_bytes(struct snd_soc_component *comp,
        struct snd_soc_dobj *dobj, int pass)
 {
        struct snd_card *card = comp->card->snd_card;
-       struct soc_bytes_ext *sb =
-               container_of(dobj, struct soc_bytes_ext, dobj);
 
        if (pass != SOC_TPLG_PASS_MIXER)
                return;
@@ -415,16 +398,12 @@ static void remove_bytes(struct snd_soc_component *comp,
 
        snd_ctl_remove(card, dobj->control.kcontrol);
        list_del(&dobj->list);
-       kfree(sb);
 }
 
 /* remove a route */
 static void remove_route(struct snd_soc_component *comp,
                         struct snd_soc_dobj *dobj, int pass)
 {
-       struct snd_soc_dapm_route *route =
-               container_of(dobj, struct snd_soc_dapm_route, dobj);
-
        if (pass != SOC_TPLG_PASS_GRAPH)
                return;
 
@@ -432,7 +411,6 @@ static void remove_route(struct snd_soc_component *comp,
                dobj->ops->dapm_route_unload(comp, dobj);
 
        list_del(&dobj->list);
-       kfree(route);
 }
 
 /* remove a widget and it's kcontrols - routes must be removed first */
@@ -453,47 +431,10 @@ static void remove_widget(struct snd_soc_component *comp,
        if (!w->kcontrols)
                goto free_news;
 
-       /*
-        * Dynamic Widgets either have 1..N enum kcontrols or mixers.
-        * The enum may either have an array of values or strings.
-        */
-       if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) {
-               /* enumerated widget mixer */
-               for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) {
-                       struct snd_kcontrol *kcontrol = w->kcontrols[i];
-                       struct soc_enum *se =
-                               (struct soc_enum *)kcontrol->private_value;
-
-                       snd_ctl_remove(card, kcontrol);
-
-                       /* free enum kcontrol's dvalues and dtexts */
-                       soc_tplg_denum_remove_values(se);
-                       soc_tplg_denum_remove_texts(se);
-
-                       kfree(se);
-                       kfree(w->kcontrol_news[i].name);
-               }
-       } else {
-               /* volume mixer or bytes controls */
-               for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) {
-                       struct snd_kcontrol *kcontrol = w->kcontrols[i];
-
-                       if (dobj->widget.kcontrol_type
-                           == SND_SOC_TPLG_TYPE_MIXER)
-                               kfree(kcontrol->tlv.p);
-
-                       /* Private value is used as struct soc_mixer_control
-                        * for volume mixers or soc_bytes_ext for bytes
-                        * controls.
-                        */
-                       kfree((void *)kcontrol->private_value);
-                       snd_ctl_remove(card, kcontrol);
-                       kfree(w->kcontrol_news[i].name);
-               }
-       }
+       for (i = 0; w->kcontrols && i < w->num_kcontrols; i++)
+               snd_ctl_remove(card, w->kcontrols[i]);
 
 free_news:
-       kfree(w->kcontrol_news);
 
        list_del(&dobj->list);
 
@@ -518,11 +459,7 @@ static void remove_dai(struct snd_soc_component *comp,
                if (dai->driver == dai_drv)
                        dai->driver = NULL;
 
-       kfree(dai_drv->playback.stream_name);
-       kfree(dai_drv->capture.stream_name);
-       kfree(dai_drv->name);
        list_del(&dobj->list);
-       kfree(dai_drv);
 }
 
 /* remove link configurations */
@@ -541,11 +478,6 @@ static void remove_link(struct snd_soc_component *comp,
        list_del(&dobj->list);
        snd_soc_remove_pcm_runtime(comp->card,
                        snd_soc_get_pcm_runtime(comp->card, link));
-
-       kfree(link->name);
-       kfree(link->stream_name);
-       kfree(link->cpus->dai_name);
-       kfree(link);
 }
 
 /* unload dai link */
@@ -700,7 +632,7 @@ static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
        unsigned int item_len = 2 * sizeof(unsigned int);
        unsigned int *p;
 
-       p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
+       p = devm_kzalloc(tplg->dev, item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
 
@@ -741,12 +673,6 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
        return 0;
 }
 
-static inline void soc_tplg_free_tlv(struct soc_tplg *tplg,
-       struct snd_kcontrol_new *kc)
-{
-       kfree(kc->tlv.p);
-}
-
 static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
        size_t size)
 {
@@ -772,7 +698,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
                        SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
                        return -EINVAL;
 
-               sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
+               sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
                if (sbe == NULL)
                        return -ENOMEM;
 
@@ -798,7 +724,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
                err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
                if (err) {
                        soc_control_err(tplg, &be->hdr, be->hdr.name);
-                       kfree(sbe);
                        break;
                }
 
@@ -808,7 +733,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
                if (err < 0) {
                        dev_err(tplg->dev, "ASoC: failed to init %s\n",
                                be->hdr.name);
-                       kfree(sbe);
                        break;
                }
 
@@ -818,7 +742,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
                if (err < 0) {
                        dev_err(tplg->dev, "ASoC: failed to add %s\n",
                                be->hdr.name);
-                       kfree(sbe);
                        break;
                }
 
@@ -854,7 +777,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                        SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
                        return -EINVAL;
 
-               sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+               sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
                if (sm == NULL)
                        return -ENOMEM;
                tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
@@ -893,7 +816,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
                if (err) {
                        soc_control_err(tplg, &mc->hdr, mc->hdr.name);
-                       kfree(sm);
                        break;
                }
 
@@ -902,7 +824,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                if (err < 0) {
                        dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
                                mc->hdr.name);
-                       kfree(sm);
                        break;
                }
 
@@ -912,8 +833,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                if (err < 0) {
                        dev_err(tplg->dev, "ASoC: failed to init %s\n",
                                mc->hdr.name);
-                       soc_tplg_free_tlv(tplg, &kc);
-                       kfree(sm);
                        break;
                }
 
@@ -923,8 +842,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                if (err < 0) {
                        dev_err(tplg->dev, "ASoC: failed to add %s\n",
                                mc->hdr.name);
-                       soc_tplg_free_tlv(tplg, &kc);
-                       kfree(sm);
                        break;
                }
 
@@ -934,13 +851,16 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
        return err;
 }
 
-static int soc_tplg_denum_create_texts(struct soc_enum *se,
-       struct snd_soc_tplg_enum_control *ec)
+static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se,
+                                      struct snd_soc_tplg_enum_control *ec)
 {
        int i, ret;
 
+       if (le32_to_cpu(ec->items) > ARRAY_SIZE(ec->texts))
+               return -EINVAL;
+
        se->dobj.control.dtexts =
-               kcalloc(le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL);
+               devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL);
        if (se->dobj.control.dtexts == NULL)
                return -ENOMEM;
 
@@ -952,7 +872,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
                        goto err;
                }
 
-               se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL);
+               se->dobj.control.dtexts[i] = devm_kstrdup(tplg->dev, ec->texts[i], GFP_KERNEL);
                if (!se->dobj.control.dtexts[i]) {
                        ret = -ENOMEM;
                        goto err;
@@ -964,29 +884,24 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
        return 0;
 
 err:
-       se->items = i;
-       soc_tplg_denum_remove_texts(se);
        return ret;
 }
 
-static inline void soc_tplg_denum_remove_texts(struct soc_enum *se)
-{
-       int i = se->items;
-
-       for (--i; i >= 0; i--)
-               kfree(se->dobj.control.dtexts[i]);
-       kfree(se->dobj.control.dtexts);
-}
-
-static int soc_tplg_denum_create_values(struct soc_enum *se,
-       struct snd_soc_tplg_enum_control *ec)
+static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *se,
+                                       struct snd_soc_tplg_enum_control *ec)
 {
        int i;
 
-       if (le32_to_cpu(ec->items) > sizeof(*ec->values))
+       /*
+        * Following "if" checks if we have at most SND_SOC_TPLG_NUM_TEXTS
+        * values instead of using ARRAY_SIZE(ec->values) due to the fact that
+        * it is oversized for its purpose. Additionally it is done so because
+        * it is defined in UAPI header where it can't be easily changed.
+        */
+       if (le32_to_cpu(ec->items) > SND_SOC_TPLG_NUM_TEXTS)
                return -EINVAL;
 
-       se->dobj.control.dvalues = kzalloc(le32_to_cpu(ec->items) *
+       se->dobj.control.dvalues = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items),
                                           sizeof(u32),
                                           GFP_KERNEL);
        if (!se->dobj.control.dvalues)
@@ -1000,11 +915,6 @@ static int soc_tplg_denum_create_values(struct soc_enum *se,
        return 0;
 }
 
-static inline void soc_tplg_denum_remove_values(struct soc_enum *se)
-{
-       kfree(se->dobj.control.dvalues);
-}
-
 static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
        size_t size)
 {
@@ -1031,7 +941,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
                        SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
                        return -EINVAL;
 
-               se = kzalloc((sizeof(*se)), GFP_KERNEL);
+               se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL);
                if (se == NULL)
                        return -ENOMEM;
 
@@ -1062,7 +972,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
                switch (le32_to_cpu(ec->hdr.ops.info)) {
                case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
                case SND_SOC_TPLG_CTL_ENUM_VALUE:
-                       err = soc_tplg_denum_create_values(se, ec);
+                       err = soc_tplg_denum_create_values(tplg, se, ec);
                        if (err < 0) {
                                dev_err(tplg->dev,
                                        "ASoC: could not create values for %s\n",
@@ -1073,7 +983,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
                case SND_SOC_TPLG_CTL_ENUM:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
-                       err = soc_tplg_denum_create_texts(se, ec);
+                       err = soc_tplg_denum_create_texts(tplg, se, ec);
                        if (err < 0) {
                                dev_err(tplg->dev,
                                        "ASoC: could not create texts for %s\n",
@@ -1119,7 +1029,6 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
        return 0;
 
 err_denum:
-       kfree(se);
        return err;
 }
 
@@ -1196,7 +1105,7 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
        struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
        struct snd_soc_tplg_dapm_graph_elem *elem;
        struct snd_soc_dapm_route **routes;
-       int count, i, j;
+       int count, i;
        int ret = 0;
 
        count = le32_to_cpu(hdr->count);
@@ -1225,15 +1134,9 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
         * each route can be freed when it is removed in remove_route().
         */
        for (i = 0; i < count; i++) {
-               routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL);
-               if (!routes[i]) {
-                       /* free previously allocated memory */
-                       for (j = 0; j < i; j++)
-                               kfree(routes[j]);
-
-                       kfree(routes);
+               routes[i] = devm_kzalloc(tplg->dev, sizeof(*routes[i]), GFP_KERNEL);
+               if (!routes[i])
                        return -ENOMEM;
-               }
        }
 
        for (i = 0; i < count; i++) {
@@ -1290,15 +1193,6 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
                snd_soc_dapm_add_routes(dapm, routes[i], 1);
        }
 
-       /*
-        * free memory allocated for all dapm routes not added to the
-        * list in case of error
-        */
-       if (ret < 0) {
-               while (i < count)
-                       kfree(routes[i++]);
-       }
-
        /*
         * free pointer to array of dapm routes as this is no longer needed.
         * The memory allocated for each dapm route will be freed
@@ -1317,7 +1211,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
        struct snd_soc_tplg_mixer_control *mc;
        int i, err;
 
-       kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
+       kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL);
        if (kc == NULL)
                return NULL;
 
@@ -1329,7 +1223,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
                        SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
                        goto err_sm;
 
-               sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+               sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
                if (sm == NULL)
                        goto err_sm;
 
@@ -1340,7 +1234,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
                        mc->hdr.name, i);
 
                kc[i].private_value = (long)sm;
-               kc[i].name = kstrdup(mc->hdr.name, GFP_KERNEL);
+               kc[i].name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
                if (kc[i].name == NULL)
                        goto err_sm;
                kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1390,14 +1284,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
        return kc;
 
 err_sm:
-       for (; i >= 0; i--) {
-               soc_tplg_free_tlv(tplg, &kc[i]);
-               sm = (struct soc_mixer_control *)kc[i].private_value;
-               kfree(sm);
-               kfree(kc[i].name);
-       }
-       kfree(kc);
-
        return NULL;
 }
 
@@ -1409,7 +1295,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
        struct soc_enum *se;
        int i, err;
 
-       kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
+       kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL);
        if (kc == NULL)
                return NULL;
 
@@ -1420,7 +1306,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
                            SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
                        goto err_se;
 
-               se = kzalloc(sizeof(*se), GFP_KERNEL);
+               se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL);
                if (se == NULL)
                        goto err_se;
 
@@ -1431,7 +1317,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
                        ec->hdr.name);
 
                kc[i].private_value = (long)se;
-               kc[i].name = kstrdup(ec->hdr.name, GFP_KERNEL);
+               kc[i].name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
                if (kc[i].name == NULL)
                        goto err_se;
                kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1451,7 +1337,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
                switch (le32_to_cpu(ec->hdr.ops.info)) {
                case SND_SOC_TPLG_CTL_ENUM_VALUE:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
-                       err = soc_tplg_denum_create_values(se, ec);
+                       err = soc_tplg_denum_create_values(tplg, se, ec);
                        if (err < 0) {
                                dev_err(tplg->dev, "ASoC: could not create values for %s\n",
                                        ec->hdr.name);
@@ -1461,7 +1347,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
                case SND_SOC_TPLG_CTL_ENUM:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
-                       err = soc_tplg_denum_create_texts(se, ec);
+                       err = soc_tplg_denum_create_texts(tplg, se, ec);
                        if (err < 0) {
                                dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
                                        ec->hdr.name);
@@ -1494,20 +1380,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
        return kc;
 
 err_se:
-       for (; i >= 0; i--) {
-               /* free values and texts */
-               se = (struct soc_enum *)kc[i].private_value;
-
-               if (se) {
-                       soc_tplg_denum_remove_values(se);
-                       soc_tplg_denum_remove_texts(se);
-               }
-
-               kfree(se);
-               kfree(kc[i].name);
-       }
-       kfree(kc);
-
        return NULL;
 }
 
@@ -1519,7 +1391,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
        struct snd_kcontrol_new *kc;
        int i, err;
 
-       kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
+       kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL);
        if (!kc)
                return NULL;
 
@@ -1531,7 +1403,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
                        SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
                        goto err_sbe;
 
-               sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
+               sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
                if (sbe == NULL)
                        goto err_sbe;
 
@@ -1543,7 +1415,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
                        be->hdr.name, be->hdr.access);
 
                kc[i].private_value = (long)sbe;
-               kc[i].name = kstrdup(be->hdr.name, GFP_KERNEL);
+               kc[i].name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
                if (kc[i].name == NULL)
                        goto err_sbe;
                kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1572,12 +1444,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
        return kc;
 
 err_sbe:
-       for (; i >= 0; i--) {
-               sbe = (struct soc_bytes_ext *)kc[i].private_value;
-               kfree(sbe);
-               kfree(kc[i].name);
-       }
-       kfree(kc);
 
        return NULL;
 }
@@ -1725,7 +1591,7 @@ widget:
        return 0;
 
 ready_err:
-       snd_soc_tplg_widget_remove(widget);
+       remove_widget(widget->dapm->component, &widget->dobj, SOC_TPLG_PASS_WIDGET);
        snd_soc_dapm_free_widget(widget);
 hdr_err:
        kfree(template.sname);
@@ -1784,10 +1650,10 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
        return 0;
 }
 
-static int set_stream_info(struct snd_soc_pcm_stream *stream,
-       struct snd_soc_tplg_stream_caps *caps)
+static int set_stream_info(struct soc_tplg *tplg, struct snd_soc_pcm_stream *stream,
+                          struct snd_soc_tplg_stream_caps *caps)
 {
-       stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
+       stream->stream_name = devm_kstrdup(tplg->dev, caps->name, GFP_KERNEL);
        if (!stream->stream_name)
                return -ENOMEM;
 
@@ -1831,12 +1697,12 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
                snd_soc_component_get_dapm(tplg->comp);
        int ret;
 
-       dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
+       dai_drv = devm_kzalloc(tplg->dev, sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
        if (dai_drv == NULL)
                return -ENOMEM;
 
        if (strlen(pcm->dai_name)) {
-               dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
+               dai_drv->name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL);
                if (!dai_drv->name) {
                        ret = -ENOMEM;
                        goto err;
@@ -1847,7 +1713,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        if (pcm->playback) {
                stream = &dai_drv->playback;
                caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
-               ret = set_stream_info(stream, caps);
+               ret = set_stream_info(tplg, stream, caps);
                if (ret < 0)
                        goto err;
        }
@@ -1855,7 +1721,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        if (pcm->capture) {
                stream = &dai_drv->capture;
                caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
-               ret = set_stream_info(stream, caps);
+               ret = set_stream_info(tplg, stream, caps);
                if (ret < 0)
                        goto err;
        }
@@ -1866,7 +1732,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        /* pass control to component driver for optional further init */
        ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
        if (ret < 0) {
-               dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
+               dev_err(tplg->dev, "ASoC: DAI loading failed\n");
                goto err;
        }
 
@@ -1876,7 +1742,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
 
        /* register the DAI to the component */
-       dai = devm_snd_soc_register_dai(tplg->comp->dev, tplg->comp, dai_drv, false);
+       dai = devm_snd_soc_register_dai(tplg->dev, tplg->comp, dai_drv, false);
        if (!dai)
                return -ENOMEM;
 
@@ -1890,11 +1756,6 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        return 0;
 
 err:
-       kfree(dai_drv->playback.stream_name);
-       kfree(dai_drv->capture.stream_name);
-       kfree(dai_drv->name);
-       kfree(dai_drv);
-
        return ret;
 }
 
@@ -1930,7 +1791,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
        int ret;
 
        /* link + cpu + codec + platform */
-       link = kzalloc(sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL);
+       link = devm_kzalloc(tplg->dev, sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL);
        if (link == NULL)
                return -ENOMEM;
 
@@ -1949,8 +1810,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
        link->dobj.type = SND_SOC_DOBJ_DAI_LINK;
 
        if (strlen(pcm->pcm_name)) {
-               link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
-               link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
+               link->name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
+               link->stream_name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
                if (!link->name || !link->stream_name) {
                        ret = -ENOMEM;
                        goto err;
@@ -1959,7 +1820,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
        link->id = le32_to_cpu(pcm->pcm_id);
 
        if (strlen(pcm->dai_name)) {
-               link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
+               link->cpus->dai_name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL);
                if (!link->cpus->dai_name) {
                        ret = -ENOMEM;
                        goto err;
@@ -1983,13 +1844,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
        /* pass control to component driver for optional further init */
        ret = soc_tplg_dai_link_load(tplg, link, NULL);
        if (ret < 0) {
-               dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
+               dev_err(tplg->dev, "ASoC: FE link loading failed\n");
                goto err;
        }
 
        ret = snd_soc_add_pcm_runtime(tplg->comp->card, link);
        if (ret < 0) {
-               dev_err(tplg->comp->dev, "ASoC: adding FE link failed\n");
+               dev_err(tplg->dev, "ASoC: adding FE link failed\n");
                goto err;
        }
 
@@ -1997,10 +1858,6 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 
        return 0;
 err:
-       kfree(link->name);
-       kfree(link->stream_name);
-       kfree(link->cpus->dai_name);
-       kfree(link);
        return ret;
 }
 
@@ -2169,7 +2026,7 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
                        struct snd_soc_tplg_link_config *cfg)
 {
        struct snd_soc_tplg_hw_config *hw_config;
-       unsigned char bclk_master, fsync_master;
+       unsigned char bclk_provider, fsync_provider;
        unsigned char invert_bclk, invert_fsync;
        int i;
 
@@ -2209,18 +2066,18 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
                        link->dai_fmt |= SND_SOC_DAIFMT_IB_IF;
 
                /* clock masters */
-               bclk_master = (hw_config->bclk_master ==
-                              SND_SOC_TPLG_BCLK_CM);
-               fsync_master = (hw_config->fsync_master ==
-                               SND_SOC_TPLG_FSYNC_CM);
-               if (bclk_master && fsync_master)
-                       link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
-               else if (!bclk_master && fsync_master)
-                       link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
-               else if (bclk_master && !fsync_master)
-                       link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+               bclk_provider = (hw_config->bclk_provider ==
+                              SND_SOC_TPLG_BCLK_CP);
+               fsync_provider = (hw_config->fsync_provider ==
+                               SND_SOC_TPLG_FSYNC_CP);
+               if (bclk_provider && fsync_provider)
+                       link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
+               else if (!bclk_provider && fsync_provider)
+                       link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFP;
+               else if (bclk_provider && !fsync_provider)
+                       link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFC;
                else
-                       link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+                       link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
        }
 }
 
@@ -2473,7 +2330,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
        if (d->playback) {
                stream = &dai_drv->playback;
                caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
-               ret = set_stream_info(stream, caps);
+               ret = set_stream_info(tplg, stream, caps);
                if (ret < 0)
                        goto err;
        }
@@ -2481,7 +2338,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
        if (d->capture) {
                stream = &dai_drv->capture;
                caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];
-               ret = set_stream_info(stream, caps);
+               ret = set_stream_info(tplg, stream, caps);
                if (ret < 0)
                        goto err;
        }
@@ -2494,15 +2351,13 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
        /* pass control to component driver for optional further init */
        ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
        if (ret < 0) {
-               dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
+               dev_err(tplg->dev, "ASoC: DAI loading failed\n");
                goto err;
        }
 
        return 0;
 
 err:
-       kfree(dai_drv->playback.stream_name);
-       kfree(dai_drv->capture.stream_name);
        return ret;
 }
 
@@ -2680,11 +2535,6 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
 
        tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
 
-       /* check for matching ID */
-       if (le32_to_cpu(hdr->index) != tplg->req_index &&
-               tplg->req_index != SND_SOC_TPLG_INDEX_ALL)
-               return 0;
-
        tplg->index = le32_to_cpu(hdr->index);
 
        switch (le32_to_cpu(hdr->type)) {
@@ -2804,7 +2654,7 @@ static int soc_tplg_load(struct soc_tplg *tplg)
 
 /* load audio component topology from "firmware" file */
 int snd_soc_tplg_component_load(struct snd_soc_component *comp,
-       struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id)
+       struct snd_soc_tplg_ops *ops, const struct firmware *fw)
 {
        struct soc_tplg tplg;
        int ret;
@@ -2819,7 +2669,6 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
        tplg.dev = comp->dev;
        tplg.comp = comp;
        tplg.ops = ops;
-       tplg.req_index = id;
        tplg.io_ops = ops->io_ops;
        tplg.io_ops_count = ops->io_ops_count;
        tplg.bytes_ext_ops = ops->bytes_ext_ops;
@@ -2828,49 +2677,14 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
        ret = soc_tplg_load(&tplg);
        /* free the created components if fail to load topology */
        if (ret)
-               snd_soc_tplg_component_remove(comp, SND_SOC_TPLG_INDEX_ALL);
+               snd_soc_tplg_component_remove(comp);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
 
-/* remove this dynamic widget */
-void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w)
-{
-       /* make sure we are a widget */
-       if (w->dobj.type != SND_SOC_DOBJ_WIDGET)
-               return;
-
-       remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET);
-}
-EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove);
-
-/* remove all dynamic widgets from this DAPM context */
-void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
-       u32 index)
-{
-       struct snd_soc_dapm_widget *w, *next_w;
-
-       for_each_card_widgets_safe(dapm->card, w, next_w) {
-
-               /* make sure we are a widget with correct context */
-               if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)
-                       continue;
-
-               /* match ID */
-               if (w->dobj.index != index &&
-                       w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
-                       continue;
-               /* check and free and dynamic widget kcontrols */
-               snd_soc_tplg_widget_remove(w);
-               snd_soc_dapm_free_widget(w);
-       }
-       snd_soc_dapm_reset_cache(dapm);
-}
-EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
-
 /* remove dynamic controls from the component driver */
-int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
+int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
 {
        struct snd_soc_dobj *dobj, *next_dobj;
        int pass = SOC_TPLG_PASS_END;
@@ -2882,11 +2696,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
                list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
                        list) {
 
-                       /* match index */
-                       if (dobj->index != index &&
-                               index != SND_SOC_TPLG_INDEX_ALL)
-                               continue;
-
                        switch (dobj->type) {
                        case SND_SOC_DOBJ_MIXER:
                                remove_mixer(comp, dobj, pass);
index 8c1f082..031dad5 100644 (file)
@@ -2,7 +2,7 @@
 config SND_SOC_SOF_TOPLEVEL
        bool "Sound Open Firmware Support"
        help
-         This adds support for Sound Open Firmware (SOF). SOF is free and
+         This adds support for Sound Open Firmware (SOF). SOF is free and
          generic open source audio DSP firmware for multiple devices.
          Say Y if you have such a device that is supported by SOF.
          If unsure select "N".
@@ -16,8 +16,8 @@ config SND_SOC_SOF_PCI
        select SND_SOC_ACPI if ACPI
        help
          This adds support for PCI enumeration. This option is
-         required to enable Intel Skylake+ devices
-         Say Y if you need this option
+         required to enable Intel Skylake+ devices.
+         Say Y if you need this option.
          If unsure select "N".
 
 config SND_SOC_SOF_ACPI
@@ -28,8 +28,8 @@ config SND_SOC_SOF_ACPI
        select IOSF_MBI if X86 && PCI
        help
          This adds support for ACPI enumeration. This option is required
-         to enable Intel Broadwell/Baytrail/Cherrytrail devices
-         Say Y if you need this option
+         to enable Intel Broadwell/Baytrail/Cherrytrail devices.
+         Say Y if you need this option.
          If unsure select "N".
 
 config SND_SOC_SOF_OF
@@ -54,12 +54,12 @@ config SND_SOC_SOF_DEVELOPER_SUPPORT
        bool "SOF developer options support"
        depends on EXPERT
        help
-         This option unlock SOF developer options for debug/performance/
+         This option unlocks SOF developer options for debug/performance/
          code hardening.
          Distributions should not select this option, only SOF development
          teams should select it.
-         Say Y if you are involved in SOF development and need this option
-         If not, select N
+         Say Y if you are involved in SOF development and need this option.
+         If not, select N.
 
 if SND_SOC_SOF_DEVELOPER_SUPPORT
 
@@ -72,13 +72,13 @@ config SND_SOC_SOF_NOCODEC_SUPPORT
          This adds support for a dummy/nocodec machine driver fallback
          option if no known codec is detected. This is typically only
          enabled for developers or devices where the sound card is
-         controlled externally
-         This option is mutually exclusive with the Intel HDAudio support,
-         selecting it may have negative impacts and prevent e.g. microphone
+         controlled externally.
+         This option is mutually exclusive with the Intel HDAudio support.
+         Selecting it may have negative impacts and prevent e.g. microphone
          functionality from being enabled on Intel CoffeeLake and later
          platforms.
          Distributions should not select this option!
-         Say Y if you need this nocodec fallback option
+         Say Y if you need this nocodec fallback option.
          If unsure select "N".
 
 config SND_SOC_SOF_STRICT_ABI_CHECKS
@@ -92,8 +92,8 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS
          is invoked.
          This option will stop topology creation and firmware load upfront.
          It is intended for SOF CI/releases and not for users or distros.
-         Say Y if you want strict ABI checks for an SOF release
-         If you are not involved in SOF releases and CI development
+         Say Y if you want strict ABI checks for an SOF release.
+         If you are not involved in SOF releases and CI development,
          select "N".
 
 config SND_SOC_SOF_DEBUG
@@ -114,8 +114,8 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE
          though there is a codec detected on the real platform. This is
          typically only enabled for developers for debug purposes, before
          codec/machine driver is ready, or to exclude the impact of those
-         drivers
-         Say Y if you need this force nocodec mode option
+         drivers.
+         Say Y if you need this force nocodec mode option.
          If unsure select "N".
 
 config SND_SOC_SOF_DEBUG_XRUN_STOP
@@ -137,12 +137,12 @@ config SND_SOC_SOF_DEBUG_VERBOSE_IPC
 config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION
        bool "SOF force to use IPC for position update on SKL+"
        help
-         This option force to handle stream position update IPCs and run pcm
+         This option forces to handle stream position update IPCs and run PCM
          elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that
          with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM.
          On platforms (e.g. Intel SKL-) where position update IPC is the only
          one choice, this setting won't impact anything.
-         if you are trying to debug pointer update with position IPCs or where
+         If you are trying to debug pointer update with position IPCs or where
          DPIB/posbuf is not ready, select "Y".
          If unsure select "N".
 
@@ -161,7 +161,7 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE
        help
          The firmware trace can be enabled either at build-time with
          this option, or dynamically by setting flags in the SOF core
-         module parameter (similar to dynamic debug)
+         module parameter (similar to dynamic debug).
          If unsure, select "N".
 
 config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST
@@ -190,7 +190,7 @@ config SND_SOC_SOF
        select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
          The selection is made at the top level and does not exactly follow
          module dependencies but since the module or built-in type is decided
          at the top level it doesn't matter.
@@ -199,7 +199,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE
        bool
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
          When selected, the probe is handled in two steps, for example to
          avoid lockdeps if request_module is used in the probe.
 
index 0352d2b..a5dd728 100644 (file)
@@ -114,6 +114,28 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_sof_control *scontrol = sm->dobj.private;
+       unsigned int channels = scontrol->num_channels;
+       int platform_max;
+
+       if (!sm->platform_max)
+               sm->platform_max = sm->max;
+       platform_max = sm->platform_max;
+
+       if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+       uinfo->count = channels;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = platform_max - sm->min;
+       return 0;
+}
+
 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol)
 {
@@ -309,7 +331,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
         * the length (as bytes) is needed to know the correct copy
         * length of data from tlvd->tlv.
         */
-       if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
+       if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
                return -EFAULT;
 
        /* make sure TLV info is consistent */
@@ -351,7 +373,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
        }
 
        /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
-       if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+       if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
                dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n");
                return -EINVAL;
        }
@@ -405,15 +427,15 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
                goto out;
 
        /* check data size doesn't exceed max coming from topology */
-       if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+       if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
                dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n",
                                    cdata->data->size,
-                                   be->max - sizeof(const struct sof_abi_hdr));
+                                   be->max - sizeof(struct sof_abi_hdr));
                ret = -EINVAL;
                goto out;
        }
 
-       data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
+       data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
 
        /* make sure we don't exceed size provided by user space for data */
        if (data_size > size) {
@@ -423,7 +445,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
 
        header.numid = scontrol->cmd;
        header.length = data_size;
-       if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
+       if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) {
                ret = -EFAULT;
                goto out;
        }
@@ -466,14 +488,14 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
        cdata->data->abi = SOF_ABI_VERSION;
 
        /* check data size doesn't exceed max coming from topology */
-       if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+       if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
                dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n",
                                    cdata->data->size,
-                                   be->max - sizeof(const struct sof_abi_hdr));
+                                   be->max - sizeof(struct sof_abi_hdr));
                return -EINVAL;
        }
 
-       data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
+       data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
 
        /* make sure we don't exceed size provided by user space for data */
        if (data_size > size)
@@ -481,7 +503,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
 
        header.numid = scontrol->cmd;
        header.length = data_size;
-       if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv)))
+       if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
                return -EFAULT;
 
        if (copy_to_user(tlvd->tlv, cdata->data, data_size))
index 9419a99..30213a1 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/debugfs.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#include <sound/sof/ext_manifest.h>
+#include <sound/sof/debug.h>
 #include "sof-priv.h"
 #include "ops.h"
 
@@ -626,6 +628,121 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
 }
 EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item);
 
+static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size)
+{
+       struct sof_ipc_cmd_hdr msg = {
+               .size = sizeof(struct sof_ipc_cmd_hdr),
+               .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE,
+       };
+       struct sof_ipc_dbg_mem_usage *reply;
+       int len;
+       int ret;
+       int i;
+
+       reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
+       if (!reply)
+               return -ENOMEM;
+
+       ret = pm_runtime_get_sync(sdev->dev);
+       if (ret < 0 && ret != -EACCES) {
+               pm_runtime_put_noidle(sdev->dev);
+               dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
+               goto error;
+       }
+
+       ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
+       pm_runtime_mark_last_busy(sdev->dev);
+       pm_runtime_put_autosuspend(sdev->dev);
+       if (ret < 0 || reply->rhdr.error < 0) {
+               ret = min(ret, reply->rhdr.error);
+               dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret);
+               goto error;
+       }
+
+       if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) {
+               dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n",
+                       reply->rhdr.hdr.size);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       for (i = 0, len = 0; i < reply->num_elems; i++) {
+               ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
+                              reply->elems[i].zone, reply->elems[i].id,
+                              reply->elems[i].used, reply->elems[i].free);
+               if (ret < 0)
+                       goto error;
+               len += ret;
+       }
+
+       ret = len;
+error:
+       kfree(reply);
+       return ret;
+}
+
+static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+       struct snd_sof_dfsentry *dfse = file->private_data;
+       struct snd_sof_dev *sdev = dfse->sdev;
+       int data_length;
+
+       /* read memory info from FW only once for each file read */
+       if (!*ppos) {
+               dfse->buf_data_size = 0;
+               data_length = memory_info_update(sdev, dfse->buf, dfse->size);
+               if (data_length < 0)
+                       return data_length;
+               dfse->buf_data_size = data_length;
+       }
+
+       return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size);
+}
+
+static int memory_info_open(struct inode *inode, struct file *file)
+{
+       struct snd_sof_dfsentry *dfse = inode->i_private;
+       struct snd_sof_dev *sdev = dfse->sdev;
+
+       file->private_data = dfse;
+
+       /* allocate buffer memory only in first open run, to save memory when unused */
+       if (!dfse->buf) {
+               dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL);
+               if (!dfse->buf)
+                       return -ENOMEM;
+               dfse->size = PAGE_SIZE;
+       }
+
+       return 0;
+}
+
+static const struct file_operations memory_info_fops = {
+       .open = memory_info_open,
+       .read = memory_info_read,
+       .llseek = default_llseek,
+};
+
+int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev)
+{
+       struct snd_sof_dfsentry *dfse;
+
+       dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+       if (!dfse)
+               return -ENOMEM;
+
+       /* don't allocate buffer before first usage, to save memory when unused */
+       dfse->type = SOF_DFSENTRY_TYPE_BUF;
+       dfse->sdev = sdev;
+
+       debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops);
+
+       /* add to dfsentry list */
+       list_add(&dfse->list, &sdev->dfsentry_list);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
+
 int snd_sof_dbg_init(struct snd_sof_dev *sdev)
 {
        const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
@@ -700,7 +817,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
        }
 
        /* dump vital information to the logs */
-       snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+       snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
        snd_sof_ipc_dump(sdev);
        snd_sof_trace_notify_for_error(sdev);
 }
index 48f998a..49d605c 100644 (file)
@@ -17,7 +17,7 @@ config SND_SOC_SOF_IMX_OF
        select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_IMX_COMMON
        tristate
@@ -30,7 +30,7 @@ config SND_SOC_SOF_IMX8_SUPPORT
        depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF
        depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_IMX_OF
        help
-         This adds support for Sound Open Firmware for NXP i.MX8 platforms
+         This adds support for Sound Open Firmware for NXP i.MX8 platforms.
          Say Y if you have such a device.
          If unsure select "N".
 
@@ -40,13 +40,13 @@ config SND_SOC_SOF_IMX8
        select SND_SOC_SOF_XTENSA
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_IMX8M_SUPPORT
        bool "SOF support for i.MX8M"
        depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_OF
        help
-         This adds support for Sound Open Firmware for NXP i.MX8M platforms
+         This adds support for Sound Open Firmware for NXP i.MX8M platforms.
          Say Y if you have such a device.
          If unsure select "N".
 
@@ -56,6 +56,6 @@ config SND_SOC_SOF_IMX8M
        select SND_SOC_SOF_XTENSA
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL
index 5fee637..8826ef9 100644 (file)
@@ -47,6 +47,8 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
 /**
  * imx8_dump() - This function is called when a panic message is
  * received from the firmware.
+ * @sdev: SOF device
+ * @flags: parameter not used but required by ops prototype
  */
 void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
 {
index a066e08..d306c37 100644 (file)
@@ -15,7 +15,7 @@ config SND_SOC_SOF_INTEL_ACPI
        select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_PCI
        def_tristate SND_SOC_SOF_PCI
@@ -29,15 +29,16 @@ config SND_SOC_SOF_INTEL_PCI
        select SND_SOC_SOF_TIGERLAKE   if SND_SOC_SOF_TIGERLAKE_SUPPORT
        select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT
        select SND_SOC_SOF_JASPERLAKE  if SND_SOC_SOF_JASPERLAKE_SUPPORT
+       select SND_SOC_SOF_ALDERLAKE   if SND_SOC_SOF_ALDERLAKE_SUPPORT
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_HIFI_EP_IPC
        tristate
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
        tristate
@@ -45,7 +46,7 @@ config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
        select SND_SOC_SOF_INTEL_HIFI_EP_IPC
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_COMMON
        tristate
@@ -55,47 +56,48 @@ config SND_SOC_SOF_INTEL_COMMON
        select SND_SOC_ACPI if ACPI
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 if SND_SOC_SOF_INTEL_ACPI
 
 config SND_SOC_SOF_BAYTRAIL_SUPPORT
        bool "SOF support for Baytrail, Braswell and Cherrytrail"
-       depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n
        help
          This adds support for Sound Open Firmware for Intel(R) platforms
          using the Baytrail, Braswell or Cherrytrail processors.
-         This option is mutually exclusive with the Atom/SST and Baytrail
-         legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail,
-         you need to deselect those options first.
-         SOF does not support Baytrail-CR for now, so this option is not
-         recommended for distros. At some point all legacy drivers will be
-         deprecated but not before all userspace firmware/topology/UCM files
-         are made available to downstream distros.
-         Say Y if you want to enable SOF on Baytrail/Cherrytrail
+         This option can coexist in the same build with the Atom legacy
+         drivers, currently the default but which will be deprecated
+         at some point.
+         Existing firmware/topology binaries and UCM configurations
+         typically located in the root file system are already
+         compatible with both SOF or Atom/SST legacy drivers.
+         This is a recommended option for distributions.
+         Say Y if you want to enable SOF on Baytrail/Cherrytrail.
          If unsure select "N".
 
 config SND_SOC_SOF_BAYTRAIL
        tristate
        select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
+       select SND_INTEL_DSP_CONFIG
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_BROADWELL_SUPPORT
        bool "SOF support for Broadwell"
-       depends on SND_SOC_INTEL_HASWELL=n
+       select SND_INTEL_DSP_CONFIG
        help
          This adds support for Sound Open Firmware for Intel(R) platforms
          using the Broadwell processors.
-         This option is mutually exclusive with the Haswell/Broadwell legacy
-         driver. If you want to enable SOF on Broadwell you need to deselect
-         the legacy driver first.
-         SOF does fully support Broadwell yet, so this option is not
-         recommended for distros. At some point all legacy drivers will be
-         deprecated but not before all userspace firmware/topology/UCM files
-         are made available to downstream distros.
-         Say Y if you want to enable SOF on Broadwell
+         This option can coexist in the same build with the default 'catpt'
+         driver.
+         Existing firmware/topology binaries and UCM configurations typically
+         located in the root file system are already compatible with both SOF
+         or catpt drivers.
+         SOF does not fully support Broadwell and has limitations related to
+         DMA and suspend-resume, this is not a recommended option for
+         distributions.
+         Say Y if you want to enable SOF on Broadwell.
          If unsure select "N".
 
 config SND_SOC_SOF_BROADWELL
@@ -104,7 +106,7 @@ config SND_SOC_SOF_BROADWELL
        select SND_SOC_SOF_INTEL_HIFI_EP_IPC
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 endif ## SND_SOC_SOF_INTEL_ACPI
 
@@ -123,7 +125,7 @@ config SND_SOC_SOF_MERRIFIELD
        select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_APOLLOLAKE_SUPPORT
        bool "SOF support for Apollolake"
@@ -138,7 +140,7 @@ config SND_SOC_SOF_APOLLOLAKE
        select SND_SOC_SOF_HDA_COMMON
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_GEMINILAKE_SUPPORT
        bool "SOF support for GeminiLake"
@@ -153,7 +155,7 @@ config SND_SOC_SOF_GEMINILAKE
        select SND_SOC_SOF_HDA_COMMON
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_CANNONLAKE_SUPPORT
        bool "SOF support for Cannonlake"
@@ -169,7 +171,7 @@ config SND_SOC_SOF_CANNONLAKE
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_COFFEELAKE_SUPPORT
        bool "SOF support for CoffeeLake"
@@ -185,7 +187,7 @@ config SND_SOC_SOF_COFFEELAKE
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_ICELAKE_SUPPORT
        bool "SOF support for Icelake"
@@ -201,7 +203,7 @@ config SND_SOC_SOF_ICELAKE
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_COMETLAKE
        tristate
@@ -209,7 +211,7 @@ config SND_SOC_SOF_COMETLAKE
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_COMETLAKE_SUPPORT
        bool
@@ -236,7 +238,7 @@ config SND_SOC_SOF_TIGERLAKE
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_ELKHARTLAKE_SUPPORT
        bool "SOF support for ElkhartLake"
@@ -252,7 +254,7 @@ config SND_SOC_SOF_ELKHARTLAKE
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_JASPERLAKE_SUPPORT
        bool "SOF support for JasperLake"
@@ -265,17 +267,34 @@ config SND_SOC_SOF_JASPERLAKE_SUPPORT
 config SND_SOC_SOF_JASPERLAKE
        tristate
        select SND_SOC_SOF_HDA_COMMON
+       help
+         This option is not user-selectable but automagically handled by
+         'select' statements at a higher level.
+
+config SND_SOC_SOF_ALDERLAKE_SUPPORT
+       bool "SOF support for Alderlake"
+       help
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the Alderlake processors.
+         Say Y if you have such a device.
+         If unsure select "N".
+
+config SND_SOC_SOF_ALDERLAKE
+       tristate
+       select SND_SOC_SOF_HDA_COMMON
+       select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level
 
 config SND_SOC_SOF_HDA_COMMON
        tristate
+       select SND_INTEL_DSP_CONFIG
        select SND_SOC_SOF_INTEL_COMMON
        select SND_SOC_SOF_HDA_LINK_BASELINE
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 if SND_SOC_SOF_HDA_COMMON
 
@@ -285,7 +304,7 @@ config SND_SOC_SOF_HDA_LINK
        select SND_SOC_SOF_PROBE_WORK_QUEUE
        help
          This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
-                 for Intel(R) platforms.
+         for Intel(R) platforms.
          Say Y if you want to enable HDA links with SOF.
          If unsure select "N".
 
@@ -294,7 +313,7 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
        depends on SND_SOC_SOF_HDA_LINK
        help
          This adds support for HDAudio codecs with Sound Open Firmware
-                 for Intel(R) platforms.
+         for Intel(R) platforms.
          Say Y if you want to enable HDAudio codecs with SOF.
          If unsure select "N".
 
@@ -302,8 +321,8 @@ config SND_SOC_SOF_HDA_PROBES
        bool "SOF enable probes over HDA"
        depends on SND_SOC_SOF_DEBUG_PROBES
        help
-         This option enables the data probing for Intel(R).
-                 Intel(R) Skylake and newer platforms.
+         This option enables the data probing for Intel(R)
+         Skylake and newer platforms.
          Say Y if you want to enable probes.
          If unsure, select "N".
 
@@ -314,7 +333,7 @@ config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1
          and disables known workarounds for specific HDAudio platforms.
          Only use to look into power optimizations on platforms not
          affected by DMI L1 issues. This option is not recommended.
-         Say Y if you want to enable DMI Link L1
+         Say Y if you want to enable DMI Link L1.
          If unsure, select "N".
 
 endif ## SND_SOC_SOF_HDA_COMMON
@@ -324,23 +343,22 @@ config SND_SOC_SOF_HDA_LINK_BASELINE
        select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_HDA
        tristate
        select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
        select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
-       select SND_INTEL_DSP_CONFIG
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
        bool "SOF support for SoundWire"
        depends on SOUNDWIRE && ACPI
        help
          This adds support for SoundWire with Sound Open Firmware
-                 for Intel(R) platforms.
+         for Intel(R) platforms.
          Say Y if you want to enable SoundWire links with SOF.
          If unsure select "N".
 
@@ -349,14 +367,14 @@ config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
        select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_SOUNDWIRE
        tristate
        select SOUNDWIRE_INTEL
        help
          This option is not user-selectable but automagically handled by
-         'select' statements at a higher level
+         'select' statements at a higher level.
 
 endif ## SND_SOC_SOF_INTEL_PCI
 
index 72d85b2..2589111 100644 (file)
@@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o
 snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
                                 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
                                 hda-dai.o hda-bus.o \
-                                apl.o cnl.o tgl.o
+                                apl.o cnl.o tgl.o icl.o
 snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o
 
 snd-sof-intel-hda-objs := hda-codec.o
index 4eeade2..fc29b91 100644 (file)
@@ -92,6 +92,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
        .pre_fw_run = hda_dsp_pre_fw_run,
        .post_fw_run = hda_dsp_post_fw_run,
 
+       /* parse platform specific extended manifest */
+       .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
        /* dsp core power up/down */
        .core_power_up = hda_dsp_enable_core,
        .core_power_down = hda_dsp_core_reset_power_down,
index 186736e..19260db 100644 (file)
@@ -336,7 +336,7 @@ static int byt_run(struct snd_sof_dev *sdev)
        }
        if (tries < 0) {
                dev_err(sdev->dev, "error:  unable to run DSP firmware\n");
-               byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+               byt_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
                return -ENODEV;
        }
 
index a5d3258..e38db51 100644 (file)
@@ -294,6 +294,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
        .pre_fw_run = hda_dsp_pre_fw_run,
        .post_fw_run = hda_dsp_post_fw_run,
 
+       /* parse platform specific extended manifest */
+       .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
        /* dsp core power up/down */
        .core_power_up = hda_dsp_enable_core,
        .core_power_down = hda_dsp_core_reset_power_down,
@@ -346,22 +349,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
 };
 EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
 
-const struct sof_intel_dsp_desc icl_chip_info = {
-       /* Icelake */
-       .cores_num = 4,
-       .init_core_mask = 1,
-       .host_managed_cores_mask = GENMASK(3, 0),
-       .ipc_req = CNL_DSP_REG_HIPCIDR,
-       .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
-       .ipc_ack = CNL_DSP_REG_HIPCIDA,
-       .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
-       .ipc_ctl = CNL_DSP_REG_HIPCCTL,
-       .rom_init_timeout       = 300,
-       .ssp_count = ICL_SSP_COUNT,
-       .ssp_base_offset = CNL_SSP_BASE_OFFSET,
-};
-EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
-
 const struct sof_intel_dsp_desc ehl_chip_info = {
        /* Elkhartlake */
        .cores_num = 4,
diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h
new file mode 100644 (file)
index 0000000..2dfae92
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ */
+
+/*
+ * Intel extended manifest is a extra place to store Intel cavs specific
+ * metadata about firmware, for example LPRO/HPRO configuration is
+ * Intel cavs specific. This part of output binary is not signed.
+ */
+
+#ifndef __INTEL_CAVS_EXT_MANIFEST_H__
+#define __INTEL_CAVS_EXT_MANIFEST_H__
+
+#include <sound/sof/ext_manifest.h>
+
+/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements identificators */
+enum sof_cavs_config_elem_type {
+       SOF_EXT_MAN_CAVS_CONFIG_EMPTY           = 0,
+       SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO       = 1,
+       SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE     = 2,
+       SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE      = 3,
+};
+
+/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements */
+struct sof_ext_man_cavs_config_data {
+       struct sof_ext_man_elem_header hdr;
+
+       struct sof_config_elem elems[];
+} __packed;
+
+#endif /* __INTEL_CAVS_EXT_MANIFEST_H__ */
index 18ff1c2..2b00115 100644 (file)
@@ -44,7 +44,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask)
        reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
        snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
                                         HDA_DSP_REG_ADSPCS,
-                                        reset, reset),
+                                        reset, reset);
 
        /* poll with timeout to check if operation successful */
        ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
index 2707a16..ed77369 100644 (file)
@@ -19,6 +19,7 @@
 #include <sound/hdaudio_ext.h>
 #include <sound/hda_register.h>
 #include <sound/sof.h>
+#include "ext_manifest.h"
 #include "../ops.h"
 #include "hda.h"
 
@@ -87,6 +88,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
        struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        const struct sof_intel_dsp_desc *chip = hda->desc;
        unsigned int status;
+       u32 flags;
        int ret;
        int i;
 
@@ -174,7 +176,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
                        __func__);
 
 err:
-       hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
+       flags = SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX;
+
+       /* force error log level after max boot attempts */
+       if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+               flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL;
+
+       hda_dsp_dump(sdev, flags);
        hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
 
        return ret;
@@ -407,10 +415,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
         * should be ready for code loading and firmware boot
         */
        ret = cl_copy_fw(sdev, stream);
-       if (!ret)
+       if (!ret) {
                dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
-       else
+       } else {
+               hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX |
+                            SOF_DBG_DUMP_FORCE_ERR_LEVEL);
                dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret);
+       }
 
 cleanup:
        /*
@@ -434,9 +445,6 @@ cleanup:
        if (!ret)
                return chip_info->init_core_mask;
 
-       /* dump dsp registers and disable DSP upon error */
-       hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
-
        /* disable DSP */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
                                SOF_HDA_REG_PP_PPCTL,
@@ -470,3 +478,102 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
        /* re-enable clock gating and power gating */
        return hda_dsp_ctrl_clock_power_gating(sdev, true);
 }
+
+/*
+ * post fw run operations for ICL,
+ * Core 3 will be powered up and in stall when HPRO is enabled
+ */
+int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       int ret;
+
+       if (sdev->first_boot) {
+               ret = hda_sdw_startup(sdev);
+               if (ret < 0) {
+                       dev_err(sdev->dev,
+                               "error: could not startup SoundWire links\n");
+                       return ret;
+               }
+       }
+
+       hda_sdw_int_enable(sdev, true);
+
+       /*
+        * The recommended HW programming sequence for ICL is to
+        * power up core 3 and keep it in stall if HPRO is enabled.
+        * Major difference between ICL and TGL, on ICL core 3 is managed by
+        * the host whereas on TGL it is handled by the firmware.
+        */
+       if (!hda->clk_config_lpro) {
+               ret = snd_sof_dsp_core_power_up(sdev, BIT(3));
+               if (ret < 0) {
+                       dev_err(sdev->dev, "error: dsp core power up failed on core 3\n");
+                       return ret;
+               }
+
+               snd_sof_dsp_stall(sdev, BIT(3));
+       }
+
+       /* re-enable clock gating and power gating */
+       return hda_dsp_ctrl_clock_power_gating(sdev, true);
+}
+
+int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
+                                        const struct sof_ext_man_elem_header *hdr)
+{
+       const struct sof_ext_man_cavs_config_data *config_data =
+               container_of(hdr, struct sof_ext_man_cavs_config_data, hdr);
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       int i, elem_num;
+
+       /* calculate total number of config data elements */
+       elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header))
+                  / sizeof(struct sof_config_elem);
+       if (elem_num <= 0) {
+               dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < elem_num; i++)
+               switch (config_data->elems[i].token) {
+               case SOF_EXT_MAN_CAVS_CONFIG_EMPTY:
+                       /* skip empty token */
+                       break;
+               case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO:
+                       hda->clk_config_lpro = config_data->elems[i].value;
+                       dev_dbg(sdev->dev, "FW clock config: %s\n",
+                               hda->clk_config_lpro ? "LPRO" : "HPRO");
+                       break;
+               case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE:
+               case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE:
+                       /* These elements are defined but not being used yet. No warn is required */
+                       break;
+               default:
+                       dev_info(sdev->dev, "unsupported token type: %d\n",
+                                config_data->elems[i].token);
+               }
+
+       return 0;
+}
+
+int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
+
+       /* make sure core_mask in host managed cores */
+       core_mask &= chip->host_managed_cores_mask;
+       if (!core_mask) {
+               dev_err(sdev->dev, "error: core_mask is not in host managed cores\n");
+               return -EINVAL;
+       }
+
+       /* stall core */
+       snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
+                                        HDA_DSP_REG_ADSPCS,
+                                        HDA_DSP_ADSPCS_CSTALL_MASK(core_mask),
+                                        HDA_DSP_ADSPCS_CSTALL_MASK(core_mask));
+
+       return 0;
+}
index b527d59..5d35bb1 100644 (file)
@@ -225,6 +225,13 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
                return -ENODEV;
        }
 
+       /* minimum as per HDA spec */
+       snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
+
+       /* avoid circular buffer wrap in middle of period */
+       snd_pcm_hw_constraint_integer(substream->runtime,
+                                     SNDRV_PCM_HW_PARAM_PERIODS);
+
        /* binding pcm substream to hda stream */
        substream->runtime->private_data = &dsp_stream->hstream;
        return 0;
index bb4128a..509a9b2 100644 (file)
@@ -416,9 +416,8 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
 }
 
 /* dump the first 8 dwords representing the extended ROM status */
-static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev)
+static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags)
 {
-       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        char msg[128];
        int len = 0;
        u32 value;
@@ -429,14 +428,13 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev)
                len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
        }
 
-       sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS,
+       sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL,
                           "extended rom status: %s", msg);
 
 }
 
 void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
 {
-       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        struct sof_ipc_dsp_oops_xtensa xoops;
        struct sof_ipc_panic_info panic_info;
        u32 stack[HDA_DSP_STACK_DUMP_SIZE];
@@ -456,11 +454,11 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
                snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
                                   stack, HDA_DSP_STACK_DUMP_SIZE);
        } else {
-               sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS,
+               sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL,
                                   "status = 0x%8.8x panic = 0x%8.8x\n",
                                   status, panic);
 
-               hda_dsp_dump_ext_rom_status(sdev);
+               hda_dsp_dump_ext_rom_status(sdev, flags);
                hda_dsp_get_status(sdev);
        }
 }
index 1bc4dab..9ec8ae0 100644 (file)
@@ -447,6 +447,9 @@ struct sof_intel_hda_dev {
 
        /* sdw context allocated by SoundWire driver */
        struct sdw_intel_ctx *sdw;
+
+       /* FW clock config, 0:HPRO, 1:LPRO */
+       bool clk_config_lpro;
 };
 
 static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@@ -612,11 +615,18 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
  */
 int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
 int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev);
+int hda_dsp_cl_boot_firmware_iccmax_icl(struct snd_sof_dev *sdev);
 int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev);
 
 /* pre and post fw run ops */
 int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev);
 int hda_dsp_post_fw_run(struct snd_sof_dev *sdev);
+int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev);
+int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask);
+
+/* parse platform specific ext manifest ops */
+int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
+                                        const struct sof_ext_man_elem_header *hdr);
 
 /*
  * HDA Controller Operations.
@@ -733,6 +743,7 @@ extern struct snd_soc_dai_driver skl_dai[];
 extern const struct snd_sof_dsp_ops sof_apl_ops;
 extern const struct snd_sof_dsp_ops sof_cnl_ops;
 extern const struct snd_sof_dsp_ops sof_tgl_ops;
+extern const struct snd_sof_dsp_ops sof_icl_ops;
 
 extern const struct sof_intel_dsp_desc apl_chip_info;
 extern const struct sof_intel_dsp_desc cnl_chip_info;
@@ -742,6 +753,7 @@ extern const struct sof_intel_dsp_desc tgl_chip_info;
 extern const struct sof_intel_dsp_desc tglh_chip_info;
 extern const struct sof_intel_dsp_desc ehl_chip_info;
 extern const struct sof_intel_dsp_desc jsl_chip_info;
+extern const struct sof_intel_dsp_desc adls_chip_info;
 
 /* machine driver select */
 void hda_machine_select(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
new file mode 100644 (file)
index 0000000..e9d5a0a
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Fred Oh <fred.oh@linux.intel.com>
+//
+
+/*
+ * Hardware interface for audio DSP on IceLake.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kconfig.h>
+#include <linux/export.h>
+#include <linux/bits.h>
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+
+static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = {
+       {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
+       {"pp", HDA_DSP_PP_BAR,  0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
+       {"dsp", HDA_DSP_BAR,  0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
+/* Icelake ops */
+const struct snd_sof_dsp_ops sof_icl_ops = {
+       /* probe and remove */
+       .probe          = hda_dsp_probe,
+       .remove         = hda_dsp_remove,
+
+       /* Register IO */
+       .write          = sof_io_write,
+       .read           = sof_io_read,
+       .write64        = sof_io_write64,
+       .read64         = sof_io_read64,
+
+       /* Block IO */
+       .block_read     = sof_block_read,
+       .block_write    = sof_block_write,
+
+       /* doorbell */
+       .irq_thread     = cnl_ipc_irq_thread,
+
+       /* ipc */
+       .send_msg       = cnl_ipc_send_msg,
+       .fw_ready       = sof_fw_ready,
+       .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
+       .get_window_offset = hda_dsp_ipc_get_window_offset,
+
+       .ipc_msg_data   = hda_ipc_msg_data,
+       .ipc_pcm_params = hda_ipc_pcm_params,
+
+       /* machine driver */
+       .machine_select = hda_machine_select,
+       .machine_register = sof_machine_register,
+       .machine_unregister = sof_machine_unregister,
+       .set_mach_params = hda_set_mach_params,
+
+       /* debug */
+       .debug_map      = icl_dsp_debugfs,
+       .debug_map_count        = ARRAY_SIZE(icl_dsp_debugfs),
+       .dbg_dump       = hda_dsp_dump,
+       .ipc_dump       = cnl_ipc_dump,
+
+       /* stream callbacks */
+       .pcm_open       = hda_dsp_pcm_open,
+       .pcm_close      = hda_dsp_pcm_close,
+       .pcm_hw_params  = hda_dsp_pcm_hw_params,
+       .pcm_hw_free    = hda_dsp_stream_hw_free,
+       .pcm_trigger    = hda_dsp_pcm_trigger,
+       .pcm_pointer    = hda_dsp_pcm_pointer,
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
+       /* probe callbacks */
+       .probe_assign   = hda_probe_compr_assign,
+       .probe_free     = hda_probe_compr_free,
+       .probe_set_params       = hda_probe_compr_set_params,
+       .probe_trigger  = hda_probe_compr_trigger,
+       .probe_pointer  = hda_probe_compr_pointer,
+#endif
+
+       /* firmware loading */
+       .load_firmware = snd_sof_load_firmware_raw,
+
+       /* pre/post fw run */
+       .pre_fw_run = hda_dsp_pre_fw_run,
+       .post_fw_run = hda_dsp_post_fw_run_icl,
+
+       /* parse platform specific extended manifest */
+       .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
+       /* dsp core power up/down */
+       .core_power_up = hda_dsp_enable_core,
+       .core_power_down = hda_dsp_core_reset_power_down,
+
+       /* firmware run */
+       .run = hda_dsp_cl_boot_firmware_iccmax,
+       .stall = hda_dsp_core_stall_icl,
+
+       /* trace callback */
+       .trace_init = hda_dsp_trace_init,
+       .trace_release = hda_dsp_trace_release,
+       .trace_trigger = hda_dsp_trace_trigger,
+
+       /* DAI drivers */
+       .drv            = skl_dai,
+       .num_drv        = SOF_SKL_NUM_DAIS,
+
+       /* PM */
+       .suspend                = hda_dsp_suspend,
+       .resume                 = hda_dsp_resume,
+       .runtime_suspend        = hda_dsp_runtime_suspend,
+       .runtime_resume         = hda_dsp_runtime_resume,
+       .runtime_idle           = hda_dsp_runtime_idle,
+       .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
+       .set_power_state        = hda_dsp_set_power_state,
+
+       /* ALSA HW info flags */
+       .hw_info =      SNDRV_PCM_INFO_MMAP |
+                       SNDRV_PCM_INFO_MMAP_VALID |
+                       SNDRV_PCM_INFO_INTERLEAVED |
+                       SNDRV_PCM_INFO_PAUSE |
+                       SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+
+       .arch_ops = &sof_xtensa_arch_ops,
+};
+EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc icl_chip_info = {
+       /* Icelake */
+       .cores_num = 4,
+       .init_core_mask = 1,
+       .host_managed_cores_mask = GENMASK(3, 0),
+       .ipc_req = CNL_DSP_REG_HIPCIDR,
+       .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+       .ipc_ack = CNL_DSP_REG_HIPCIDA,
+       .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+       .ipc_ctl = CNL_DSP_REG_HIPCCTL,
+       .rom_init_timeout       = 300,
+       .ssp_count = ICL_SSP_COUNT,
+       .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
index 310f916..de66f8a 100644 (file)
@@ -73,6 +73,13 @@ int intel_pcm_open(struct snd_sof_dev *sdev,
        /* binding pcm substream to hda stream */
        substream->runtime->private_data = stream;
 
+       /* align to DMA minimum transfer size */
+       snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
+
+       /* avoid circular buffer wrap in middle of period */
+       snd_pcm_hw_constraint_integer(substream->runtime,
+                                     SNDRV_PCM_HW_PARAM_PERIODS);
+
        return 0;
 }
 EXPORT_SYMBOL_NS(intel_pcm_open, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
index 0278b67..2252ca3 100644 (file)
@@ -84,6 +84,9 @@ const struct snd_sof_dsp_ops sof_tgl_ops = {
        .pre_fw_run = hda_dsp_pre_fw_run,
        .post_fw_run = hda_dsp_post_fw_run,
 
+       /* parse platform specific extended manifest */
+       .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
        /* dsp core power up/down */
        .core_power_up = hda_dsp_enable_core,
        .core_power_down = hda_dsp_core_reset_power_down,
@@ -151,3 +154,19 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
 };
 EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc adls_chip_info = {
+       /* Alderlake-S */
+       .cores_num = 2,
+       .init_core_mask = BIT(0),
+       .host_managed_cores_mask = BIT(0),
+       .ipc_req = CNL_DSP_REG_HIPCIDR,
+       .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+       .ipc_ack = CNL_DSP_REG_HIPCIDA,
+       .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+       .ipc_ctl = CNL_DSP_REG_HIPCCTL,
+       .rom_init_timeout       = 300,
+       .ssp_count = ICL_SSP_COUNT,
+       .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
index fd2b96a..fc13bb0 100644 (file)
@@ -181,6 +181,15 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
                        str2 = "unknown type"; break;
                }
                break;
+       case SOF_IPC_GLB_DEBUG:
+               str = "GLB_DEBUG";
+               switch (type) {
+               case SOF_IPC_DEBUG_MEM_USAGE:
+                       str2 = "MEM_USAGE"; break;
+               default:
+                       str2 = "unknown type"; break;
+               }
+               break;
        default:
                str = "unknown GLB command"; break;
        }
index ba9ed66..08a17ab 100644 (file)
@@ -124,7 +124,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
                        /* They are supported but we don't do anything here */
                        break;
                default:
-                       dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
+                       dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
                                 ext_hdr->type, ext_hdr->hdr.size);
                        ret = 0;
                        break;
@@ -197,6 +197,54 @@ static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev,
        return 0;
 }
 
+static int ext_man_get_config_data(struct snd_sof_dev *sdev,
+                                  const struct sof_ext_man_elem_header *hdr)
+{
+       const struct sof_ext_man_config_data *config =
+               container_of(hdr, struct sof_ext_man_config_data, hdr);
+       const struct sof_config_elem *elem;
+       int elems_counter;
+       int elems_size;
+       int ret = 0;
+       int i;
+
+       /* calculate elements counter */
+       elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header);
+       elems_counter = elems_size / sizeof(struct sof_config_elem);
+
+       dev_dbg(sdev->dev, "%s can hold up to %d config elements\n",
+               __func__, elems_counter);
+
+       for (i = 0; i < elems_counter; ++i) {
+               elem = &config->elems[i];
+               dev_dbg(sdev->dev, "%s get index %d token %d val %d\n",
+                       __func__, i, elem->token, elem->value);
+               switch (elem->token) {
+               case SOF_EXT_MAN_CONFIG_EMPTY:
+                       /* unused memory space is zero filled - mapped to EMPTY elements */
+                       break;
+               case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE:
+                       /* TODO: use ipc msg size from config data */
+                       break;
+               case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN:
+                       if (sdev->first_boot && elem->value)
+                               ret = snd_sof_dbg_memory_info_init(sdev);
+                       break;
+               default:
+                       dev_info(sdev->dev, "Unknown firmware configuration token %d value %d",
+                                elem->token, elem->value);
+                       break;
+               }
+               if (ret < 0) {
+                       dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n",
+                               elem->token, elem->value, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
 {
        const struct sof_ext_man_header *head;
@@ -279,8 +327,14 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
                case SOF_EXT_MAN_ELEM_DBG_ABI:
                        ret = ext_man_get_dbg_abi_info(sdev, elem_hdr);
                        break;
+               case SOF_EXT_MAN_ELEM_CONFIG_DATA:
+                       ret = ext_man_get_config_data(sdev, elem_hdr);
+                       break;
+               case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA:
+                       ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr);
+                       break;
                default:
-                       dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
+                       dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n",
                                 elem_hdr->type, elem_hdr->size);
                        break;
                }
@@ -802,8 +856,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
                                 msecs_to_jiffies(sdev->boot_timeout));
        if (ret == 0) {
                dev_err(sdev->dev, "error: firmware boot failure\n");
-               snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
-                       SOF_DBG_TEXT | SOF_DBG_PCI);
+               snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX |
+                       SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_FORCE_ERR_LEVEL);
                sdev->fw_state = SOF_FW_BOOT_FAILED;
                return -EIO;
        }
index 9e922df..3b9bb2e 100644 (file)
 
 #include <linux/module.h>
 #include <sound/sof.h>
+#include "sof-audio.h"
 #include "sof-priv.h"
 
 static struct snd_soc_card sof_nocodec_card = {
        .name = "nocodec", /* the sof- prefix is added by the core */
+       .topology_shortname = "sof-nocodec",
        .owner = THIS_MODULE
 };
 
 static int sof_nocodec_bes_setup(struct device *dev,
                                 const struct snd_sof_dsp_ops *ops,
                                 struct snd_soc_dai_link *links,
-                                int link_num, struct snd_soc_card *card)
+                                int link_num, struct snd_soc_card *card,
+                                int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+                                                          struct snd_pcm_hw_params *params))
 {
        struct snd_soc_dai_link_component *dlc;
        int i;
@@ -39,6 +43,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
                if (!links[i].name)
                        return -ENOMEM;
 
+               links[i].stream_name = links[i].name;
+
                links[i].cpus = &dlc[0];
                links[i].codecs = &dlc[1];
                links[i].platforms = &dlc[2];
@@ -57,6 +63,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
                        links[i].dpcm_playback = 1;
                if (ops->drv[i].capture.channels_min)
                        links[i].dpcm_capture = 1;
+
+               links[i].be_hw_params_fixup = pcm_dai_link_fixup;
        }
 
        card->dai_link = links;
@@ -65,8 +73,9 @@ static int sof_nocodec_bes_setup(struct device *dev,
        return 0;
 }
 
-int sof_nocodec_setup(struct device *dev,
-                     const struct snd_sof_dsp_ops *ops)
+int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops,
+                     int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+                                               struct snd_pcm_hw_params *params))
 {
        struct snd_soc_dai_link *links;
 
@@ -77,7 +86,7 @@ int sof_nocodec_setup(struct device *dev,
                return -ENOMEM;
 
        return sof_nocodec_bes_setup(dev, ops, links, ops->num_drv,
-                                    &sof_nocodec_card);
+                                    &sof_nocodec_card, pcm_dai_link_fixup);
 }
 EXPORT_SYMBOL(sof_nocodec_setup);
 
@@ -86,6 +95,7 @@ static int sof_nocodec_probe(struct platform_device *pdev)
        struct snd_soc_card *card = &sof_nocodec_card;
 
        card->dev = &pdev->dev;
+       card->topology_shortname_created = true;
 
        return devm_snd_soc_register_card(&pdev->dev, card);
 }
index 1a394b4..11ecebd 100644 (file)
@@ -157,7 +157,7 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
                dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n",
                        sdev->dsp_oops_offset, offset);
 
-       snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+       snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
        snd_sof_trace_notify_for_error(sdev);
 }
 EXPORT_SYMBOL(snd_sof_dsp_panic);
index b21632f..95e748b 100644 (file)
@@ -48,10 +48,10 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev)
        return sof_ops(sdev)->run(sdev);
 }
 
-static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev, unsigned int core_mask)
 {
        if (sof_ops(sdev)->stall)
-               return sof_ops(sdev)->stall(sdev);
+               return sof_ops(sdev)->stall(sdev, core_mask);
 
        return 0;
 }
@@ -100,6 +100,16 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev)
        return 0;
 }
 
+/* parse platform specific extended manifest */
+static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev,
+                                                         const struct sof_ext_man_elem_header *hdr)
+{
+       if (sof_ops(sdev)->parse_platform_ext_manifest)
+               return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr);
+
+       return 0;
+}
+
 /* misc */
 
 /**
index cbac6f1..0dc39fb 100644 (file)
@@ -478,17 +478,10 @@ static int sof_pcm_open(struct snd_soc_component *component,
 
        caps = &spcm->pcm.caps[substream->stream];
 
-       /* set any runtime constraints based on topology */
-       snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                  SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-                                  le32_to_cpu(caps->period_size_min));
-       snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                  SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-                                  le32_to_cpu(caps->period_size_min));
-
        /* set runtime config */
        runtime->hw.info = ops->hw_info; /* platform-specific */
 
+       /* set any runtime constraints based on topology */
        runtime->hw.formats = le64_to_cpu(caps->formats);
        runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
        runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
@@ -627,8 +620,7 @@ capture:
 }
 
 /* fixup the BE DAI link to match any values from topology */
-static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
-                                 struct snd_pcm_hw_params *params)
+int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
 {
        struct snd_interval *rate = hw_param_interval(params,
                        SNDRV_PCM_HW_PARAM_RATE);
@@ -780,7 +772,7 @@ static int sof_pcm_probe(struct snd_soc_component *component)
 static void sof_pcm_remove(struct snd_soc_component *component)
 {
        /* remove topology */
-       snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+       snd_soc_tplg_component_remove(component);
 }
 
 void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
index a78b76e..2a369c2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 #include <sound/sof.h>
@@ -120,12 +121,23 @@ static void sof_acpi_probe_complete(struct device *dev)
 static int sof_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct acpi_device_id *id;
        const struct sof_dev_desc *desc;
        struct snd_sof_pdata *sof_pdata;
        const struct snd_sof_dsp_ops *ops;
        int ret;
 
-       dev_dbg(&pdev->dev, "ACPI DSP detected");
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!id)
+               return -ENODEV;
+
+       ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+       if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
+               dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n");
+               return -ENODEV;
+       }
+
+       dev_dbg(dev, "ACPI DSP detected");
 
        sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
        if (!sof_pdata)
index afe7e50..3277489 100644 (file)
@@ -443,11 +443,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
        struct snd_soc_acpi_mach *mach;
        int ret;
 
-       /* force nocodec mode */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
-               dev_warn(sdev->dev, "Force to use nocodec mode\n");
-               goto nocodec;
-#endif
+#if !IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
 
        /* find machine */
        snd_sof_machine_select(sdev);
@@ -460,8 +456,8 @@ int sof_machine_check(struct snd_sof_dev *sdev)
        dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
        return -ENODEV;
 #endif
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
-nocodec:
+#else
+       dev_warn(sdev->dev, "Force to use nocodec mode\n");
 #endif
        /* select nocodec mode */
        dev_warn(sdev->dev, "Using nocodec machine driver\n");
@@ -472,7 +468,7 @@ nocodec:
        mach->drv_name = "sof-nocodec";
        sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
 
-       ret = sof_nocodec_setup(sdev->dev, desc->ops);
+       ret = sof_nocodec_setup(sdev->dev, desc->ops, sof_pcm_dai_link_fixup);
        if (ret < 0)
                return ret;
 
index 9f645a2..dc930fc 100644 (file)
@@ -124,6 +124,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol);
 int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol);
+int snd_sof_volume_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo);
 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol);
 int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
@@ -212,6 +214,9 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
                                  enum sof_ipc_ctrl_cmd ctrl_cmd,
                                  bool send);
 
+/* DAI link fixup */
+int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
+
 /* PM */
 int sof_restore_pipelines(struct device *dev);
 int sof_set_hw_params_upon_resume(struct device *dev);
index 8f62e34..63b989e 100644 (file)
@@ -209,7 +209,7 @@ static const struct sof_dev_desc icl_desc = {
        .default_tplg_path = "intel/sof-tplg",
        .default_fw_filename = "sof-icl.ri",
        .nocodec_tplg_filename = "sof-icl-nocodec.tplg",
-       .ops = &sof_cnl_ops,
+       .ops = &sof_icl_ops,
 };
 #endif
 
@@ -284,6 +284,24 @@ static const struct sof_dev_desc jsl_desc = {
 };
 #endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+static const struct sof_dev_desc adls_desc = {
+       .machines               = snd_soc_acpi_intel_adl_machines,
+       .alt_machines           = snd_soc_acpi_intel_adl_sdw_machines,
+       .resindex_lpe_base      = 0,
+       .resindex_pcicfg_base   = -1,
+       .resindex_imr_base      = -1,
+       .irqindex_host_ipc      = -1,
+       .resindex_dma_base      = -1,
+       .chip_info = &adls_chip_info,
+       .default_fw_path = "intel/sof",
+       .default_tplg_path = "intel/sof-tplg",
+       .default_fw_filename = "sof-adl-s.ri",
+       .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
+       .ops = &sof_tgl_ops,
+};
+#endif
+
 static const struct dev_pm_ops sof_pci_pm = {
        .prepare = snd_sof_prepare,
        .complete = snd_sof_complete,
@@ -490,6 +508,10 @@ static const struct pci_device_id sof_pci_ids[] = {
                .driver_data = (unsigned long)&ehl_desc},
        { PCI_DEVICE(0x8086, 0x4b58),
                .driver_data = (unsigned long)&ehl_desc},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+       { PCI_DEVICE(0x8086, 0x7ad0),
+               .driver_data = (unsigned long)&adls_desc},
 #endif
        { 0, }
 };
index 0aed2a7..68da8f7 100644 (file)
 #include <sound/sof/pm.h>
 #include <sound/sof/trace.h>
 #include <uapi/sound/sof/fw.h>
+#include <sound/sof/ext_manifest.h>
 
 /* debug flags */
 #define SOF_DBG_ENABLE_TRACE   BIT(0)
-#define SOF_DBG_REGS           BIT(1)
-#define SOF_DBG_MBOX           BIT(2)
-#define SOF_DBG_TEXT           BIT(3)
-#define SOF_DBG_PCI            BIT(4)
-#define SOF_DBG_RETAIN_CTX     BIT(5)  /* prevent DSP D3 on FW exception */
+#define SOF_DBG_RETAIN_CTX     BIT(1)  /* prevent DSP D3 on FW exception */
+
+#define SOF_DBG_DUMP_REGS              BIT(0)
+#define SOF_DBG_DUMP_MBOX              BIT(1)
+#define SOF_DBG_DUMP_TEXT              BIT(2)
+#define SOF_DBG_DUMP_PCI               BIT(3)
+#define SOF_DBG_DUMP_FORCE_ERR_LEVEL   BIT(4) /* used to dump dsp status with error log level */
+
 
 /* global debug state set by SOF_DBG_ flags */
 extern int sof_core_debug;
@@ -100,7 +104,7 @@ struct snd_sof_dsp_ops {
 
        /* DSP core boot / reset */
        int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */
-       int (*stall)(struct snd_sof_dev *sof_dev); /* optional */
+       int (*stall)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */
        int (*reset)(struct snd_sof_dev *sof_dev); /* optional */
        int (*core_power_up)(struct snd_sof_dev *sof_dev,
                             unsigned int core_mask); /* optional */
@@ -208,6 +212,10 @@ struct snd_sof_dsp_ops {
        int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
        int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
 
+       /* parse platform specific extended manifest, optional */
+       int (*parse_platform_ext_manifest)(struct snd_sof_dev *sof_dev,
+                                          const struct sof_ext_man_elem_header *hdr);
+
        /* DSP PM */
        int (*suspend)(struct snd_sof_dev *sof_dev,
                       u32 target_state); /* optional */
@@ -290,6 +298,7 @@ enum sof_debugfs_access_type {
 /* FS entry for debug files that can expose DSP memories, registers */
 struct snd_sof_dfsentry {
        size_t size;
+       size_t buf_data_size;  /* length of buffered data for file read operation */
        enum sof_dfsentry_type type;
        /*
         * access_type specifies if the
@@ -523,6 +532,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
                        void *stack, size_t stack_words);
 int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev);
 void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
+int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev);
 
 /*
  * Platform specific ops.
index 69313fb..b6b32a7 100644 (file)
@@ -1041,6 +1041,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
                goto out;
        }
 
+       /*
+        * If control has more than 2 channels we need to override the info. This is because even if
+        * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
+        * pre-defined dapm control types (and related functions) creating the actual control
+        * restrict the channels only to mono or stereo.
+        */
+       if (le32_to_cpu(mc->num_channels) > 2)
+               kc->info = snd_sof_volume_info;
+
        /* init the volume get/put data */
        scontrol->size = struct_size(scontrol->control_data, chanv,
                                     le32_to_cpu(mc->num_channels));
@@ -1201,7 +1210,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
                        ret = -EINVAL;
                        goto out_free;
                }
-               if (cdata->data->size + sizeof(const struct sof_abi_hdr) !=
+               if (cdata->data->size + sizeof(struct sof_abi_hdr) !=
                    le32_to_cpu(control->priv.size)) {
                        dev_err(scomp->dev,
                                "error: Conflict in bytes vs. priv size.\n");
@@ -2777,18 +2786,18 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
                               struct sof_ipc_dai_config *config)
 {
        /* clock directions wrt codec */
-       if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) {
-               /* codec is bclk master */
-               if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
-                       config->format |= SOF_DAI_FMT_CBM_CFM;
+       if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
+               /* codec is bclk provider */
+               if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
+                       config->format |= SOF_DAI_FMT_CBP_CFP;
                else
-                       config->format |= SOF_DAI_FMT_CBM_CFS;
+                       config->format |= SOF_DAI_FMT_CBP_CFC;
        } else {
-               /* codec is bclk slave */
-               if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
-                       config->format |= SOF_DAI_FMT_CBS_CFM;
+               /* codec is bclk consumer */
+               if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
+                       config->format |= SOF_DAI_FMT_CBC_CFP;
                else
-                       config->format |= SOF_DAI_FMT_CBS_CFS;
+                       config->format |= SOF_DAI_FMT_CBC_CFC;
        }
 
        /* inverted clocks ? */
@@ -3734,9 +3743,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
                return ret;
        }
 
-       ret = snd_soc_tplg_component_load(scomp,
-                                         &sof_tplg_ops, fw,
-                                         SND_SOC_TPLG_INDEX_ALL);
+       ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
        if (ret < 0) {
                dev_err(scomp->dev, "error: tplg component load failed %d\n",
                        ret);
index 6988924..f72a6e8 100644 (file)
 #include "sof-priv.h"
 #include "ops.h"
 
+#define TRACE_FILTER_ELEMENTS_PER_ENTRY 4
+#define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024
+
+static int trace_filter_append_elem(struct snd_sof_dev *sdev, uint32_t key, uint32_t value,
+                                   struct sof_ipc_trace_filter_elem *elem_list,
+                                   int capacity, int *counter)
+{
+       if (*counter >= capacity)
+               return -ENOMEM;
+
+       elem_list[*counter].key = key;
+       elem_list[*counter].value = value;
+       ++*counter;
+
+       return 0;
+}
+
+static int trace_filter_parse_entry(struct snd_sof_dev *sdev, const char *line,
+                                   struct sof_ipc_trace_filter_elem *elem,
+                                   int capacity, int *counter)
+{
+       int len = strlen(line);
+       int cnt = *counter;
+       uint32_t uuid_id;
+       int log_level;
+       int pipe_id;
+       int comp_id;
+       int read;
+       int ret;
+
+       /* ignore empty content */
+       ret = sscanf(line, " %n", &read);
+       if (!ret && read == len)
+               return len;
+
+       ret = sscanf(line, " %d %x %d %d %n", &log_level, &uuid_id, &pipe_id, &comp_id, &read);
+       if (ret != TRACE_FILTER_ELEMENTS_PER_ENTRY || read != len) {
+               dev_err(sdev->dev, "error: invalid trace filter entry '%s'\n", line);
+               return -EINVAL;
+       }
+
+       if (uuid_id > 0) {
+               ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_UUID,
+                                              uuid_id, elem, capacity, &cnt);
+               if (ret)
+                       return ret;
+       }
+       if (pipe_id >= 0) {
+               ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE,
+                                              pipe_id, elem, capacity, &cnt);
+               if (ret)
+                       return ret;
+       }
+       if (comp_id >= 0) {
+               ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_COMP,
+                                              comp_id, elem, capacity, &cnt);
+               if (ret)
+                       return ret;
+       }
+
+       ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL |
+                                      SOF_IPC_TRACE_FILTER_ELEM_FIN,
+                                      log_level, elem, capacity, &cnt);
+       if (ret)
+               return ret;
+
+       /* update counter only when parsing whole entry passed */
+       *counter = cnt;
+
+       return len;
+}
+
+static int trace_filter_parse(struct snd_sof_dev *sdev, char *string,
+                             int *out_elem_cnt,
+                             struct sof_ipc_trace_filter_elem **out)
+{
+       static const char entry_delimiter[] = ";";
+       char *entry = string;
+       int capacity = 0;
+       int entry_len;
+       int cnt = 0;
+
+       /*
+        * Each entry contains at least 1, up to TRACE_FILTER_ELEMENTS_PER_ENTRY
+        * IPC elements, depending on content. Calculate IPC elements capacity
+        * for the input string where each element is set.
+        */
+       while (entry) {
+               capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY;
+               entry = strchr(entry + 1, entry_delimiter[0]);
+       }
+       *out = kmalloc(capacity * sizeof(**out), GFP_KERNEL);
+       if (!*out)
+               return -ENOMEM;
+
+       /* split input string by ';', and parse each entry separately in trace_filter_parse_entry */
+       while ((entry = strsep(&string, entry_delimiter))) {
+               entry_len = trace_filter_parse_entry(sdev, entry, *out, capacity, &cnt);
+               if (entry_len < 0) {
+                       dev_err(sdev->dev, "error: %s failed for '%s', %d\n", __func__, entry,
+                               entry_len);
+                       return -EINVAL;
+               }
+       }
+
+       *out_elem_cnt = cnt;
+
+       return 0;
+}
+
+static int sof_ipc_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
+                                      struct sof_ipc_trace_filter_elem *elems)
+{
+       struct sof_ipc_trace_filter *msg;
+       struct sof_ipc_reply reply;
+       size_t size;
+       int ret;
+
+       size = struct_size(msg, elems, num_elems);
+       if (size > SOF_IPC_MSG_MAX_SIZE)
+               return -EINVAL;
+
+       msg = kmalloc(size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->hdr.size = size;
+       msg->hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_FILTER_UPDATE;
+       msg->elem_cnt = num_elems;
+       memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems));
+
+       ret = pm_runtime_get_sync(sdev->dev);
+       if (ret < 0 && ret != -EACCES) {
+               pm_runtime_put_noidle(sdev->dev);
+               dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
+               goto error;
+       }
+       ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
+                                &reply, sizeof(reply));
+       pm_runtime_mark_last_busy(sdev->dev);
+       pm_runtime_put_autosuspend(sdev->dev);
+
+error:
+       kfree(msg);
+       return ret ? ret : reply.error;
+}
+
+static ssize_t sof_dfsentry_trace_filter_write(struct file *file, const char __user *from,
+                                              size_t count, loff_t *ppos)
+{
+       struct snd_sof_dfsentry *dfse = file->private_data;
+       struct sof_ipc_trace_filter_elem *elems = NULL;
+       struct snd_sof_dev *sdev = dfse->sdev;
+       loff_t pos = 0;
+       int num_elems;
+       char *string;
+       int ret;
+
+       if (count > TRACE_FILTER_MAX_CONFIG_STRING_LENGTH) {
+               dev_err(sdev->dev, "%s too long input, %zu > %d\n", __func__, count,
+                       TRACE_FILTER_MAX_CONFIG_STRING_LENGTH);
+               return -EINVAL;
+       }
+
+       string = kmalloc(count + 1, GFP_KERNEL);
+       if (!string)
+               return -ENOMEM;
+
+       /* assert null termination */
+       string[count] = 0;
+       ret = simple_write_to_buffer(string, count, &pos, from, count);
+       if (ret < 0)
+               goto error;
+
+       ret = trace_filter_parse(sdev, string, &num_elems, &elems);
+       if (ret < 0) {
+               dev_err(sdev->dev, "error: fail in trace_filter_parse, %d\n", ret);
+               goto error;
+       }
+
+       if (num_elems) {
+               ret = sof_ipc_trace_update_filter(sdev, num_elems, elems);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "error: fail in sof_ipc_trace_update_filter %d\n", ret);
+                       goto error;
+               }
+       }
+       ret = count;
+error:
+       kfree(string);
+       kfree(elems);
+       return ret;
+}
+
+static const struct file_operations sof_dfs_trace_filter_fops = {
+       .open = simple_open,
+       .write = sof_dfsentry_trace_filter_write,
+       .llseek = default_llseek,
+};
+
+static int trace_debugfs_filter_create(struct snd_sof_dev *sdev)
+{
+       struct snd_sof_dfsentry *dfse;
+
+       dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+       if (!dfse)
+               return -ENOMEM;
+
+       dfse->sdev = sdev;
+       dfse->type = SOF_DFSENTRY_TYPE_BUF;
+
+       debugfs_create_file("filter", 0200, sdev->debugfs_root, dfse,
+                           &sof_dfs_trace_filter_fops);
+       /* add to dfsentry list */
+       list_add(&dfse->list, &sdev->dfsentry_list);
+
+       return 0;
+}
+
 static size_t sof_trace_avail(struct snd_sof_dev *sdev,
                              loff_t pos, size_t buffer_size)
 {
@@ -135,10 +354,15 @@ static const struct file_operations sof_dfs_trace_fops = {
 static int trace_debugfs_create(struct snd_sof_dev *sdev)
 {
        struct snd_sof_dfsentry *dfse;
+       int ret;
 
        if (!sdev)
                return -EINVAL;
 
+       ret = trace_debugfs_filter_create(sdev);
+       if (ret < 0)
+               dev_err(sdev->dev, "error: fail in %s, %d", __func__, ret);
+
        dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
        if (!dfse)
                return -ENOMEM;
index bbade25..da1f7a1 100644 (file)
@@ -15,6 +15,7 @@ config SND_SOC_STM32_SAI
 config SND_SOC_STM32_I2S
        tristate "STM32 I2S interface (SPI/I2S block) support"
        depends on (ARCH_STM32 && OF) || COMPILE_TEST
+       depends on COMMON_CLK
        depends on SND_SOC
        select SND_SOC_GENERIC_DMAENGINE_PCM
        select REGMAP_MMIO
index 9cd7009..ddcaaa9 100644 (file)
@@ -14,6 +14,7 @@ config SND_SUN8I_CODEC
        tristate "Allwinner SUN8I audio codec"
        depends on OF
        depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+       depends on COMMON_CLK
        select REGMAP_MMIO
        help
          This option enables the digital part of the internal audio codec for
index f23ff29..4b8ca5b 100644 (file)
@@ -48,6 +48,9 @@
 #define SUN4I_I2S_FMT0_FMT_I2S                         (0 << 0)
 
 #define SUN4I_I2S_FMT1_REG             0x08
+#define SUN4I_I2S_FMT1_REG_SEXT_MASK           BIT(8)
+#define SUN4I_I2S_FMT1_REG_SEXT(sext)                  ((sext) << 8)
+
 #define SUN4I_I2S_FIFO_TX_REG          0x0c
 #define SUN4I_I2S_FIFO_RX_REG          0x10
 
 #define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED          (1 << 7)
 #define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL            (0 << 7)
 
+#define SUN8I_I2S_FMT1_REG_SEXT_MASK           GENMASK(5, 4)
+#define SUN8I_I2S_FMT1_REG_SEXT(sext)                  ((sext) << 4)
+
 #define SUN8I_I2S_INT_STA_REG          0x0c
 #define SUN8I_I2S_FIFO_TX_REG          0x20
 
 #define SUN8I_I2S_RX_CHAN_SEL_REG      0x54
 #define SUN8I_I2S_RX_CHAN_MAP_REG      0x58
 
+/* Defines required for sun50i-h6 support */
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK  GENMASK(21, 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)       ((offset) << 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK         GENMASK(19, 16)
+#define SUN50I_H6_I2S_TX_CHAN_SEL(chan)                ((chan - 1) << 16)
+#define SUN50I_H6_I2S_TX_CHAN_EN_MASK          GENMASK(15, 0)
+#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan)     (((1 << num_chan) - 1))
+
+#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44
+#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48
+
+#define SUN50I_H6_I2S_RX_CHAN_SEL_REG  0x64
+#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68
+#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C
+
 struct sun4i_i2s;
 
 /**
@@ -159,12 +180,19 @@ struct sun4i_i2s_quirks {
        const struct sun4i_i2s_clk_div  *mclk_dividers;
        unsigned int                    num_mclk_dividers;
 
-       unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
-       s8      (*get_sr)(const struct sun4i_i2s *, int);
-       s8      (*get_wss)(const struct sun4i_i2s *, int);
-       int     (*set_chan_cfg)(const struct sun4i_i2s *,
-                               const struct snd_pcm_hw_params *);
-       int     (*set_fmt)(const struct sun4i_i2s *, unsigned int);
+       unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s);
+       int     (*get_sr)(unsigned int width);
+       int     (*get_wss)(unsigned int width);
+
+       /*
+        * In the set_chan_cfg() function pointer:
+        * @slots: channels per frame + padding slots, regardless of format
+        * @slot_width: bits per sample + padding bits, regardless of format
+        */
+       int     (*set_chan_cfg)(const struct sun4i_i2s *i2s,
+                               unsigned int channels,  unsigned int slots,
+                               unsigned int slot_width);
+       int     (*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt);
 };
 
 struct sun4i_i2s {
@@ -365,44 +393,62 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
        return 0;
 }
 
-static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width)
+static int sun4i_i2s_get_sr(unsigned int width)
 {
-       if (width < 16 || width > 24)
-               return -EINVAL;
-
-       if (width % 4)
-               return -EINVAL;
+       switch (width) {
+       case 16:
+               return 0;
+       case 20:
+               return 1;
+       case 24:
+               return 2;
+       }
 
-       return (width - 16) / 4;
+       return -EINVAL;
 }
 
-static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width)
+static int sun4i_i2s_get_wss(unsigned int width)
 {
-       if (width < 16 || width > 32)
-               return -EINVAL;
-
-       if (width % 4)
-               return -EINVAL;
+       switch (width) {
+       case 16:
+               return 0;
+       case 20:
+               return 1;
+       case 24:
+               return 2;
+       case 32:
+               return 3;
+       }
 
-       return (width - 16) / 4;
+       return -EINVAL;
 }
 
-static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
+static int sun8i_i2s_get_sr_wss(unsigned int width)
 {
-       if (width % 4)
-               return -EINVAL;
-
-       if (width < 8 || width > 32)
-               return -EINVAL;
+       switch (width) {
+       case 8:
+               return 1;
+       case 12:
+               return 2;
+       case 16:
+               return 3;
+       case 20:
+               return 4;
+       case 24:
+               return 5;
+       case 28:
+               return 6;
+       case 32:
+               return 7;
+       }
 
-       return (width - 8) / 4 + 1;
+       return -EINVAL;
 }
 
 static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
-                                 const struct snd_pcm_hw_params *params)
+                                 unsigned int channels, unsigned int slots,
+                                 unsigned int slot_width)
 {
-       unsigned int channels = params_channels(params);
-
        /* Map the channels for playback and capture */
        regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
        regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
@@ -419,15 +465,11 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
 }
 
 static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
-                                 const struct snd_pcm_hw_params *params)
+                                 unsigned int channels, unsigned int slots,
+                                 unsigned int slot_width)
 {
-       unsigned int channels = params_channels(params);
-       unsigned int slots = channels;
        unsigned int lrck_period;
 
-       if (i2s->slots)
-               slots = i2s->slots;
-
        /* Map the channels for playback and capture */
        regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
        regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
@@ -450,13 +492,13 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
        switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_A:
        case SND_SOC_DAIFMT_DSP_B:
-       case SND_SOC_DAIFMT_LEFT_J:
-       case SND_SOC_DAIFMT_RIGHT_J:
-               lrck_period = params_physical_width(params) * slots;
+               lrck_period = slot_width * slots;
                break;
 
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
        case SND_SOC_DAIFMT_I2S:
-               lrck_period = params_physical_width(params);
+               lrck_period = slot_width;
                break;
 
        default:
@@ -474,6 +516,60 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
        return 0;
 }
 
+static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+                                     unsigned int channels, unsigned int slots,
+                                     unsigned int slot_width)
+{
+       unsigned int lrck_period;
+
+       /* Map the channels for playback and capture */
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98);
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210);
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
+       regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
+
+       /* Configure the channels */
+       regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+                          SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+       regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+                          SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+
+       regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+                          SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+                          SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
+       regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+                          SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
+                          SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+
+       switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               lrck_period = slot_width * slots;
+               break;
+
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_I2S:
+               lrck_period = slot_width;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+                          SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+                          SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
+
+       regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+                          SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_EN(channels));
+
+       return 0;
+}
+
 static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
                               struct snd_pcm_hw_params *params,
                               struct snd_soc_dai *dai)
@@ -482,7 +578,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
        unsigned int word_size = params_width(params);
        unsigned int slot_width = params_physical_width(params);
        unsigned int channels = params_channels(params);
+
        unsigned int slots = channels;
+
        int ret, sr, wss;
        u32 width;
 
@@ -492,16 +590,26 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
        if (i2s->slot_width)
                slot_width = i2s->slot_width;
 
-       ret = i2s->variant->set_chan_cfg(i2s, params);
+       ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width);
        if (ret < 0) {
                dev_err(dai->dev, "Invalid channel configuration\n");
                return ret;
        }
 
+       /* Set significant bits in our FIFOs */
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
+                          SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
+                          SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
+                          SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
+                          SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
+
        switch (params_physical_width(params)) {
        case 16:
                width = DMA_SLAVE_BUSWIDTH_2_BYTES;
                break;
+       case 32:
+               width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               break;
        default:
                dev_err(dai->dev, "Unsupported physical sample width: %d\n",
                        params_physical_width(params));
@@ -509,11 +617,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
        }
        i2s->playback_dma_data.addr_width = width;
 
-       sr = i2s->variant->get_sr(i2s, word_size);
+       sr = i2s->variant->get_sr(word_size);
        if (sr < 0)
                return -EINVAL;
 
-       wss = i2s->variant->get_wss(i2s, slot_width);
+       wss = i2s->variant->get_wss(slot_width);
        if (wss < 0)
                return -EINVAL;
 
@@ -594,6 +702,7 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
        }
        regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
                           SUN4I_I2S_CTRL_MODE_MASK, val);
+
        return 0;
 }
 
@@ -696,6 +805,118 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
                           SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
                           val);
 
+       /* Set sign extension to pad out LSB with 0 */
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+                          SUN8I_I2S_FMT1_REG_SEXT_MASK,
+                          SUN8I_I2S_FMT1_REG_SEXT(0));
+
+       return 0;
+}
+
+static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
+                                    unsigned int fmt)
+{
+       u32 mode, val;
+       u8 offset;
+
+       /*
+        * DAI clock polarity
+        *
+        * The setup for LRCK contradicts the datasheet, but under a
+        * scope it's clear that the LRCK polarity is reversed
+        * compared to the expected polarity on the bus.
+        */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_IF:
+               /* Invert both clocks */
+               val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               /* Invert bit clock */
+               val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
+                     SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               /* Invert frame clock */
+               val = 0;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+               val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+                          SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
+                          SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
+                          val);
+
+       /* DAI Mode */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               mode = SUN8I_I2S_CTRL_MODE_PCM;
+               offset = 1;
+               break;
+
+       case SND_SOC_DAIFMT_DSP_B:
+               mode = SUN8I_I2S_CTRL_MODE_PCM;
+               offset = 0;
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+               mode = SUN8I_I2S_CTRL_MODE_LEFT;
+               offset = 1;
+               break;
+
+       case SND_SOC_DAIFMT_LEFT_J:
+               mode = SUN8I_I2S_CTRL_MODE_LEFT;
+               offset = 0;
+               break;
+
+       case SND_SOC_DAIFMT_RIGHT_J:
+               mode = SUN8I_I2S_CTRL_MODE_RIGHT;
+               offset = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+                          SUN8I_I2S_CTRL_MODE_MASK, mode);
+       regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+                          SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+       regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+                          SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+                          SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* BCLK and LRCLK master */
+               val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
+               break;
+
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* BCLK and LRCLK slave */
+               val = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+                          SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
+                          val);
+
+       /* Set sign extension to pad out LSB with 0 */
+       regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+                          SUN8I_I2S_FMT1_REG_SEXT_MASK,
+                          SUN8I_I2S_FMT1_REG_SEXT(0));
+
        return 0;
 }
 
@@ -710,13 +931,6 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return ret;
        }
 
-       /* Set significant bits in our FIFOs */
-       regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
-                          SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
-                          SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
-                          SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
-                          SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
-
        i2s->format = fmt;
 
        return 0;
@@ -870,6 +1084,10 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+#define SUN4I_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | \
+                        SNDRV_PCM_FMTBIT_S20_LE | \
+                        SNDRV_PCM_FMTBIT_S24_LE)
+
 static struct snd_soc_dai_driver sun4i_i2s_dai = {
        .probe = sun4i_i2s_dai_probe,
        .capture = {
@@ -877,14 +1095,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
                .channels_min = 1,
                .channels_max = 8,
                .rates = SNDRV_PCM_RATE_8000_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats = SUN4I_FORMATS,
        },
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 8,
                .rates = SNDRV_PCM_RATE_8000_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats = SUN4I_FORMATS,
        },
        .ops = &sun4i_i2s_dai_ops,
        .symmetric_rates = 1,
@@ -944,12 +1162,19 @@ static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
 
 static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
 {
-       if (reg == SUN8I_I2S_INT_STA_REG)
+       switch (reg) {
+       case SUN4I_I2S_FIFO_CTRL_REG:
+       case SUN4I_I2S_FIFO_RX_REG:
+       case SUN4I_I2S_FIFO_STA_REG:
+       case SUN4I_I2S_RX_CNT_REG:
+       case SUN4I_I2S_TX_CNT_REG:
+       case SUN8I_I2S_FIFO_TX_REG:
+       case SUN8I_I2S_INT_STA_REG:
                return true;
-       if (reg == SUN8I_I2S_FIFO_TX_REG)
-               return false;
 
-       return sun4i_i2s_volatile_reg(dev, reg);
+       default:
+               return false;
+       }
 }
 
 static const struct reg_default sun4i_i2s_reg_defaults[] = {
@@ -979,6 +1204,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = {
        { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
 };
 
+static const struct reg_default sun50i_h6_i2s_reg_defaults[] = {
+       { SUN4I_I2S_CTRL_REG, 0x00060000 },
+       { SUN4I_I2S_FMT0_REG, 0x00000033 },
+       { SUN4I_I2S_FMT1_REG, 0x00000030 },
+       { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
+       { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
+       { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
+       { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
+       { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
+       { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
+       { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
+       { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
+       { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
+       { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
+};
+
 static const struct regmap_config sun4i_i2s_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
@@ -1006,6 +1247,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = {
        .volatile_reg   = sun8i_i2s_volatile_reg,
 };
 
+static const struct regmap_config sun50i_h6_i2s_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = SUN50I_H6_I2S_RX_CHAN_MAP1_REG,
+       .cache_type     = REGCACHE_FLAT,
+       .reg_defaults   = sun50i_h6_i2s_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults),
+       .writeable_reg  = sun4i_i2s_wr_reg,
+       .readable_reg   = sun8i_i2s_rd_reg,
+       .volatile_reg   = sun8i_i2s_volatile_reg,
+};
+
 static int sun4i_i2s_runtime_resume(struct device *dev)
 {
        struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -1164,6 +1418,24 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
        .set_fmt                = sun4i_i2s_set_soc_fmt,
 };
 
+static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
+       .has_reset              = true,
+       .reg_offset_txdata      = SUN8I_I2S_FIFO_TX_REG,
+       .sun4i_i2s_regmap       = &sun50i_h6_i2s_regmap_config,
+       .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
+       .field_fmt_wss          = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
+       .field_fmt_sr           = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
+       .bclk_dividers          = sun8i_i2s_clk_div,
+       .num_bclk_dividers      = ARRAY_SIZE(sun8i_i2s_clk_div),
+       .mclk_dividers          = sun8i_i2s_clk_div,
+       .num_mclk_dividers      = ARRAY_SIZE(sun8i_i2s_clk_div),
+       .get_bclk_parent_rate   = sun8i_i2s_get_bclk_parent_rate,
+       .get_sr                 = sun8i_i2s_get_sr_wss,
+       .get_wss                = sun8i_i2s_get_sr_wss,
+       .set_chan_cfg           = sun50i_h6_i2s_set_chan_cfg,
+       .set_fmt                = sun50i_h6_i2s_set_soc_fmt,
+};
+
 static int sun4i_i2s_init_regmap_fields(struct device *dev,
                                        struct sun4i_i2s *i2s)
 {
@@ -1333,6 +1605,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
                .compatible = "allwinner,sun50i-a64-codec-i2s",
                .data = &sun50i_a64_codec_i2s_quirks,
        },
+       {
+               .compatible = "allwinner,sun50i-h6-i2s",
+               .data = &sun50i_h6_i2s_quirks,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
index 7590c4b..180442c 100644 (file)
 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK            (0x1 << 0)
 #define SUN8I_MOD_CLK_ENA                              0x010
 #define SUN8I_MOD_CLK_ENA_AIF1                         15
+#define SUN8I_MOD_CLK_ENA_AIF2                         14
+#define SUN8I_MOD_CLK_ENA_AIF3                         13
 #define SUN8I_MOD_CLK_ENA_ADC                          3
 #define SUN8I_MOD_CLK_ENA_DAC                          2
 #define SUN8I_MOD_RST_CTL                              0x014
 #define SUN8I_MOD_RST_CTL_AIF1                         15
+#define SUN8I_MOD_RST_CTL_AIF2                         14
+#define SUN8I_MOD_RST_CTL_AIF3                         13
 #define SUN8I_MOD_RST_CTL_ADC                          3
 #define SUN8I_MOD_RST_CTL_DAC                          2
 #define SUN8I_SYS_SR_CTRL                              0x018
 #define SUN8I_SYS_SR_CTRL_AIF1_FS                      12
 #define SUN8I_SYS_SR_CTRL_AIF2_FS                      8
-#define SUN8I_AIF1CLK_CTRL                             0x040
-#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD               15
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV               14
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV               13
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV               9
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV               6
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ               4
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16            (1 << 4)
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT               2
+#define SUN8I_AIF_CLK_CTRL(n)                          (0x040 * (1 + (n)))
+#define SUN8I_AIF_CLK_CTRL_MSTR_MOD                    15
+#define SUN8I_AIF_CLK_CTRL_CLK_INV                     13
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV                    9
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV                    6
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ                    4
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT                    2
 #define SUN8I_AIF1_ADCDAT_CTRL                         0x044
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA           15
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA           14
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR       10
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR           9
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL       8
+#define SUN8I_AIF2_ADCDAT_CTRL                         0x084
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA           15
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA           14
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC           10
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC           8
+#define SUN8I_AIF2_DACDAT_CTRL                         0x088
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA           15
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA           14
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC           10
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC           8
+#define SUN8I_AIF2_MXR_SRC                             0x08c
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L       15
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L       14
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR       13
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL           12
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R       11
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R       10
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL       9
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR           8
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1          (0x0 << 0)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2          (0x1 << 0)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK       (0x2 << 0)
+#define SUN8I_AIF3_PATH_CTRL                           0x0cc
+#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC              10
+#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC              8
+#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI             7
 #define SUN8I_ADC_DIG_CTRL                             0x100
 #define SUN8I_ADC_DIG_CTRL_ENAD                                15
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS                   2
 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK      GENMASK(5, 4)
 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK         GENMASK(15, 12)
 #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK         GENMASK(11, 8)
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK  GENMASK(12, 9)
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK  GENMASK(8, 6)
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK  GENMASK(5, 4)
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK  GENMASK(3, 2)
+#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK                GENMASK(14, 13)
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK       GENMASK(12, 9)
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK       GENMASK(8, 6)
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK       GENMASK(5, 4)
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK       GENMASK(3, 2)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK  GENMASK(1, 0)
+
+#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
+
+#define SUN8I_CODEC_PCM_FORMATS        (SNDRV_PCM_FMTBIT_S8     |\
+                                SNDRV_PCM_FMTBIT_S16_LE |\
+                                SNDRV_PCM_FMTBIT_S20_LE |\
+                                SNDRV_PCM_FMTBIT_S24_LE |\
+                                SNDRV_PCM_FMTBIT_S20_3LE|\
+                                SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define SUN8I_CODEC_PCM_RATES  (SNDRV_PCM_RATE_8000_48000|\
+                                SNDRV_PCM_RATE_88200     |\
+                                SNDRV_PCM_RATE_96000     |\
+                                SNDRV_PCM_RATE_176400    |\
+                                SNDRV_PCM_RATE_192000    |\
+                                SNDRV_PCM_RATE_KNOT)
+
+enum {
+       SUN8I_CODEC_AIF1,
+       SUN8I_CODEC_AIF2,
+       SUN8I_CODEC_AIF3,
+       SUN8I_CODEC_NAIFS
+};
+
+struct sun8i_codec_aif {
+       unsigned int    lrck_div_order;
+       unsigned int    sample_rate;
+       unsigned int    slots;
+       unsigned int    slot_width;
+       unsigned int    active_streams  : 2;
+       unsigned int    open_streams    : 2;
+};
 
 struct sun8i_codec_quirks {
        bool legacy_widgets     : 1;
@@ -104,8 +166,13 @@ struct sun8i_codec {
        struct regmap                   *regmap;
        struct clk                      *clk_module;
        const struct sun8i_codec_quirks *quirks;
+       struct sun8i_codec_aif          aifs[SUN8I_CODEC_NAIFS];
+       unsigned int                    sysclk_rate;
+       int                             sysclk_refcnt;
 };
 
+static struct snd_soc_dai_driver sun8i_codec_dais[];
+
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
        struct sun8i_codec *scodec = dev_get_drvdata(dev);
@@ -132,32 +199,34 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
 {
-       unsigned int rate = params_rate(params);
-
-       switch (rate) {
-       case 8000:
+       switch (sample_rate) {
        case 7350:
+       case 8000:
                return 0x0;
        case 11025:
                return 0x1;
        case 12000:
                return 0x2;
+       case 14700:
        case 16000:
                return 0x3;
        case 22050:
                return 0x4;
        case 24000:
                return 0x5;
+       case 29400:
        case 32000:
                return 0x6;
        case 44100:
                return 0x7;
        case 48000:
                return 0x8;
+       case 88200:
        case 96000:
                return 0x9;
+       case 176400:
        case 192000:
                return 0xa;
        default:
@@ -165,10 +234,37 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
        }
 }
 
-static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
+{
+       unsigned int max_rate = 0;
+       int hw_rate, i;
+
+       for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
+               struct sun8i_codec_aif *aif = &scodec->aifs[i];
+
+               if (aif->active_streams)
+                       max_rate = max(max_rate, aif->sample_rate);
+       }
+
+       /* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
+       if (!max_rate)
+               max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
+
+       hw_rate = sun8i_codec_get_hw_rate(max_rate);
+       if (hw_rate < 0)
+               return hw_rate;
+
+       regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+                          SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
+                          hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+
+       return 0;
+}
+
+static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-       u32 value;
+       u32 dsp_format, format, invert, value;
 
        /* clock masters */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -181,65 +277,162 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        default:
                return -EINVAL;
        }
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
-                          value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
 
-       /* clock inversion */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF: /* Normal */
-               value = 0x0;
-               break;
-       case SND_SOC_DAIFMT_IB_IF: /* Inversion */
-               value = 0x1;
-               break;
-       default:
-               return -EINVAL;
+       if (dai->id == SUN8I_CODEC_AIF3) {
+               /* AIF3 only supports master mode. */
+               if (value)
+                       return -EINVAL;
+
+               /* Use the AIF2 BCLK and LRCK for AIF3. */
+               regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+                                  SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
+                                  SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
+       } else {
+               regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+                                  BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+                                  value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
        }
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
-                          value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
-
-       /*
-        * It appears that the DAI and the codec in the A33 SoC don't
-        * share the same polarity for the LRCK signal when they mean
-        * 'normal' and 'inverted' in the datasheet.
-        *
-        * Since the DAI here is our regular i2s driver that have been
-        * tested with way more codecs than just this one, it means
-        * that the codec probably gets it backward, and we have to
-        * invert the value here.
-        */
-       value ^= scodec->quirks->lrck_inversion;
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
-                          value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
 
        /* DAI format */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               value = 0x0;
+               format = 0x0;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               value = 0x1;
+               format = 0x1;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               value = 0x2;
+               format = 0x2;
                break;
        case SND_SOC_DAIFMT_DSP_A:
+               format = 0x3;
+               dsp_format = 0x0; /* Set LRCK_INV to 0 */
+               break;
        case SND_SOC_DAIFMT_DSP_B:
-               value = 0x3;
+               format = 0x3;
+               dsp_format = 0x1; /* Set LRCK_INV to 1 */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (dai->id == SUN8I_CODEC_AIF3) {
+               /* AIF3 only supports DSP mode. */
+               if (format != 3)
+                       return -EINVAL;
+       } else {
+               regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+                                  SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+                                  format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF: /* Normal */
+               invert = 0x0;
+               break;
+       case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
+               invert = 0x1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
+               invert = 0x2;
+               break;
+       case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
+               invert = 0x3;
                break;
        default:
                return -EINVAL;
        }
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-                          value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
+       if (format == 0x3) {
+               /* Inverted LRCK is not available in DSP mode. */
+               if (invert & BIT(0))
+                       return -EINVAL;
+
+               /* Instead, the bit selects between DSP A/B formats. */
+               invert |= dsp_format;
+       } else {
+               /*
+                * It appears that the DAI and the codec in the A33 SoC don't
+                * share the same polarity for the LRCK signal when they mean
+                * 'normal' and 'inverted' in the datasheet.
+                *
+                * Since the DAI here is our regular i2s driver that have been
+                * tested with way more codecs than just this one, it means
+                * that the codec probably gets it backward, and we have to
+                * invert the value here.
+                */
+               invert ^= scodec->quirks->lrck_inversion;
+       }
+
+       regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+                          SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
+                          invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
 
        return 0;
 }
 
+static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
+                                   unsigned int tx_mask, unsigned int rx_mask,
+                                   int slots, int slot_width)
+{
+       struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+       struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+       if (slot_width && !is_power_of_2(slot_width))
+               return -EINVAL;
+
+       aif->slots = slots;
+       aif->slot_width = slot_width;
+
+       return 0;
+}
+
+static const unsigned int sun8i_codec_rates[] = {
+         7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
+        29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
+       .list   = sun8i_codec_rates,
+       .count  = ARRAY_SIZE(sun8i_codec_rates),
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
+       .list   = sun8i_codec_rates,
+       .count  = ARRAY_SIZE(sun8i_codec_rates),
+       .mask   = 0x5555,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
+       .list   = sun8i_codec_rates,
+       .count  = ARRAY_SIZE(sun8i_codec_rates),
+       .mask   = 0xaaaa,
+};
+
+static int sun8i_codec_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+       const struct snd_pcm_hw_constraint_list *list;
+
+       /* hw_constraints is not relevant for codec2codec DAIs. */
+       if (dai->id != SUN8I_CODEC_AIF1)
+               return 0;
+
+       if (!scodec->sysclk_refcnt)
+               list = &sun8i_codec_all_rates;
+       else if (scodec->sysclk_rate == 22579200)
+               list = &sun8i_codec_22M_rates;
+       else if (scodec->sysclk_rate == 24576000)
+               list = &sun8i_codec_24M_rates;
+       else
+               return -EINVAL;
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_RATE, list);
+}
+
 struct sun8i_codec_clk_div {
        u8      div;
        u8      val;
@@ -262,37 +455,37 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
        { .div = 192,   .val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
-                                  unsigned int rate,
-                                  unsigned int word_size)
+static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
+                                   unsigned int lrck_div_order,
+                                   unsigned int sample_rate)
 {
-       unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-       unsigned int div = clk_rate / rate / word_size / 2;
-       unsigned int best_val = 0, best_diff = ~0;
+       unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
                const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
-               unsigned int diff = abs(bdiv->div - div);
 
-               if (diff < best_diff) {
-                       best_diff = diff;
-                       best_val = bdiv->val;
-               }
+               if (bdiv->div == div)
+                       return bdiv->val;
        }
 
-       return best_val;
+       return -EINVAL;
 }
 
-static int sun8i_codec_get_lrck_div(unsigned int channels,
-                                   unsigned int word_size)
+static int sun8i_codec_get_lrck_div_order(unsigned int slots,
+                                         unsigned int slot_width)
 {
-       unsigned int div = word_size * channels;
+       unsigned int div = slots * slot_width;
 
        if (div < 16 || div > 256)
                return -EINVAL;
 
-       return ilog2(div) - 4;
+       return order_base_2(div);
+}
+
+static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
+{
+       return sample_rate % 4000 ? 22579200 : 24576000;
 }
 
 static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
@@ -300,42 +493,225 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-       int sample_rate, lrck_div;
-       u8 bclk_div;
+       struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+       unsigned int sample_rate = params_rate(params);
+       unsigned int slots = aif->slots ?: params_channels(params);
+       unsigned int slot_width = aif->slot_width ?: params_width(params);
+       unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
+       int bclk_div, lrck_div_order, ret, word_size;
+       u32 clk_reg;
+
+       /* word size */
+       switch (params_width(params)) {
+       case 8:
+               word_size = 0x0;
+               break;
+       case 16:
+               word_size = 0x1;
+               break;
+       case 20:
+               word_size = 0x2;
+               break;
+       case 24:
+               word_size = 0x3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+                          SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
+                          word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
+
+       /* LRCK divider (BCLK/LRCK ratio) */
+       lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
+       if (lrck_div_order < 0)
+               return lrck_div_order;
+
+       if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) {
+               /* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */
+               int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id;
+               const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
+               const char *partner_name = sun8i_codec_dais[partner].name;
+
+               if (partner_aif->open_streams &&
+                   (lrck_div_order != partner_aif->lrck_div_order ||
+                    sample_rate != partner_aif->sample_rate)) {
+                       dev_err(dai->dev,
+                               "%s sample and bit rates must match %s when both are used\n",
+                               dai->name, partner_name);
+                       return -EBUSY;
+               }
+
+               clk_reg = SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF2);
+       } else {
+               clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
+       }
+
+       regmap_update_bits(scodec->regmap, clk_reg,
+                          SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
+                          (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
+
+       /* BCLK divider (SYSCLK/BCLK ratio) */
+       bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
+       if (bclk_div < 0)
+               return bclk_div;
+
+       regmap_update_bits(scodec->regmap, clk_reg,
+                          SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
+                          bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
        /*
-        * The CPU DAI handles only a sample of 16 bits. Configure the
-        * codec to handle this type of sample resolution.
+        * SYSCLK rate
+        *
+        * Clock rate protection is reference counted; but hw_params may be
+        * called many times per substream, without matching calls to hw_free.
+        * Protect the clock rate once per AIF, on the first hw_params call
+        * for the first substream. clk_set_rate() will allow clock rate
+        * changes on subsequent calls if only one AIF has open streams.
         */
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-                          SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+       ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
+                                                                         sysclk_rate);
+       if (ret == -EBUSY)
+               dev_err(dai->dev,
+                       "%s sample rate (%u Hz) conflicts with other audio streams\n",
+                       dai->name, sample_rate);
+       if (ret < 0)
+               return ret;
 
-       bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-                          bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+       if (!aif->open_streams)
+               scodec->sysclk_refcnt++;
+       scodec->sysclk_rate = sysclk_rate;
 
-       lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
-                                           params_physical_width(params));
-       if (lrck_div < 0)
-               return lrck_div;
+       aif->lrck_div_order = lrck_div_order;
+       aif->sample_rate = sample_rate;
+       aif->open_streams |= BIT(substream->stream);
 
-       regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-                          SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-                          lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+       return sun8i_codec_update_sample_rate(scodec);
+}
 
-       sample_rate = sun8i_codec_get_hw_rate(params);
-       if (sample_rate < 0)
-               return sample_rate;
+static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+       struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
-       regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
-                          SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
-                          sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+       /* Drop references when the last substream for the AIF is freed. */
+       if (aif->open_streams != BIT(substream->stream))
+               goto done;
 
+       clk_rate_exclusive_put(scodec->clk_module);
+       scodec->sysclk_refcnt--;
+       aif->lrck_div_order = 0;
+       aif->sample_rate = 0;
+
+done:
+       aif->open_streams &= ~BIT(substream->stream);
        return 0;
 }
 
+static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+       .set_fmt        = sun8i_codec_set_fmt,
+       .set_tdm_slot   = sun8i_codec_set_tdm_slot,
+       .startup        = sun8i_codec_startup,
+       .hw_params      = sun8i_codec_hw_params,
+       .hw_free        = sun8i_codec_hw_free,
+};
+
+static struct snd_soc_dai_driver sun8i_codec_dais[] = {
+       {
+               .name   = "sun8i-codec-aif1",
+               .id     = SUN8I_CODEC_AIF1,
+               .ops    = &sun8i_codec_dai_ops,
+               /* capture capabilities */
+               .capture = {
+                       .stream_name    = "AIF1 Capture",
+                       .channels_min   = 1,
+                       .channels_max   = 2,
+                       .rates          = SUN8I_CODEC_PCM_RATES,
+                       .formats        = SUN8I_CODEC_PCM_FORMATS,
+                       .sig_bits       = 24,
+               },
+               /* playback capabilities */
+               .playback = {
+                       .stream_name    = "AIF1 Playback",
+                       .channels_min   = 1,
+                       .channels_max   = 2,
+                       .rates          = SUN8I_CODEC_PCM_RATES,
+                       .formats        = SUN8I_CODEC_PCM_FORMATS,
+               },
+               .symmetric_rates        = true,
+               .symmetric_channels     = true,
+               .symmetric_samplebits   = true,
+       },
+       {
+               .name   = "sun8i-codec-aif2",
+               .id     = SUN8I_CODEC_AIF2,
+               .ops    = &sun8i_codec_dai_ops,
+               /* capture capabilities */
+               .capture = {
+                       .stream_name    = "AIF2 Capture",
+                       .channels_min   = 1,
+                       .channels_max   = 2,
+                       .rates          = SUN8I_CODEC_PCM_RATES,
+                       .formats        = SUN8I_CODEC_PCM_FORMATS,
+                       .sig_bits       = 24,
+               },
+               /* playback capabilities */
+               .playback = {
+                       .stream_name    = "AIF2 Playback",
+                       .channels_min   = 1,
+                       .channels_max   = 2,
+                       .rates          = SUN8I_CODEC_PCM_RATES,
+                       .formats        = SUN8I_CODEC_PCM_FORMATS,
+               },
+               .symmetric_rates        = true,
+               .symmetric_channels     = true,
+               .symmetric_samplebits   = true,
+       },
+       {
+               .name   = "sun8i-codec-aif3",
+               .id     = SUN8I_CODEC_AIF3,
+               .ops    = &sun8i_codec_dai_ops,
+               /* capture capabilities */
+               .capture = {
+                       .stream_name    = "AIF3 Capture",
+                       .channels_min   = 1,
+                       .channels_max   = 1,
+                       .rates          = SUN8I_CODEC_PCM_RATES,
+                       .formats        = SUN8I_CODEC_PCM_FORMATS,
+                       .sig_bits       = 24,
+               },
+               /* playback capabilities */
+               .playback = {
+                       .stream_name    = "AIF3 Playback",
+                       .channels_min   = 1,
+                       .channels_max   = 1,
+                       .rates          = SUN8I_CODEC_PCM_RATES,
+                       .formats        = SUN8I_CODEC_PCM_FORMATS,
+               },
+               .symmetric_rates        = true,
+               .symmetric_channels     = true,
+               .symmetric_samplebits   = true,
+       },
+};
+
+static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+       struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
+       int stream = w->id == snd_soc_dapm_aif_out;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               aif->active_streams |= BIT(stream);
+       else
+               aif->active_streams &= ~BIT(stream);
+
+       return sun8i_codec_update_sample_rate(scodec);
+}
+
 static const char *const sun8i_aif_stereo_mux_enum_values[] = {
        "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
 };
@@ -350,6 +726,29 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
        SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
                      sun8i_aif1_ad0_stereo_mux_enum);
 
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
+                           SUN8I_AIF2_ADCDAT_CTRL,
+                           SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
+                           SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
+                           sun8i_aif_stereo_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control =
+       SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
+                     sun8i_aif2_adc_stereo_mux_enum);
+
+static const char *const sun8i_aif3_adc_mux_enum_values[] = {
+       "None", "AIF2 ADCL", "AIF2 ADCR"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
+                           SUN8I_AIF3_PATH_CTRL,
+                           SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
+                           sun8i_aif3_adc_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
+       SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
+                     sun8i_aif3_adc_mux_enum);
+
 static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
        SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
                        SUN8I_AIF1_MXR_SRC,
@@ -369,6 +768,38 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
                        SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
 };
 
+static const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
+       SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
+                       SUN8I_AIF2_MXR_SRC,
+                       SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
+                       SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
+       SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
+                       SUN8I_AIF2_MXR_SRC,
+                       SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
+                       SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
+       SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
+                       SUN8I_AIF2_MXR_SRC,
+                       SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
+                       SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
+       SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
+                       SUN8I_AIF2_MXR_SRC,
+                       SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
+                       SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
+};
+
+static const char *const sun8i_aif2_dac_mux_enum_values[] = {
+       "AIF2", "AIF3+2", "AIF2+3"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
+                           SUN8I_AIF3_PATH_CTRL,
+                           SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
+                           sun8i_aif2_dac_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
+       SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
+                     sun8i_aif2_dac_mux_enum);
+
 static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
                            SUN8I_AIF1_DACDAT_CTRL,
                            SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
@@ -379,6 +810,16 @@ static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
        SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
                      sun8i_aif1_da0_stereo_mux_enum);
 
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum,
+                           SUN8I_AIF2_DACDAT_CTRL,
+                           SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC,
+                           SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC,
+                           sun8i_aif_stereo_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control =
+       SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
+                     sun8i_aif2_dac_stereo_mux_enum);
+
 static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
        SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
                        SUN8I_DAC_MXR_SRC,
@@ -403,6 +844,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("AIF1CLK",
                            SUN8I_SYSCLK_CTL,
                            SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("AIF2CLK",
+                           SUN8I_SYSCLK_CTL,
+                           SUN8I_SYSCLK_CTL_AIF2CLK_ENA, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("SYSCLK",
                            SUN8I_SYSCLK_CTL,
                            SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
@@ -411,6 +855,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("CLK AIF1",
                            SUN8I_MOD_CLK_ENA,
                            SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLK AIF2",
+                           SUN8I_MOD_CLK_ENA,
+                           SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLK AIF3",
+                           SUN8I_MOD_CLK_ENA,
+                           SUN8I_MOD_CLK_ENA_AIF3, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("CLK ADC",
                            SUN8I_MOD_CLK_ENA,
                            SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
@@ -422,6 +872,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("RST AIF1",
                            SUN8I_MOD_RST_CTL,
                            SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RST AIF2",
+                           SUN8I_MOD_RST_CTL,
+                           SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RST AIF3",
+                           SUN8I_MOD_RST_CTL,
+                           SUN8I_MOD_RST_CTL_AIF3, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("RST ADC",
                            SUN8I_MOD_RST_CTL,
                            SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
@@ -438,39 +894,96 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
                            SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
 
        /* AIF "ADC" Outputs */
-       SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0,
-                            SUN8I_AIF1_ADCDAT_CTRL,
-                            SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-       SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
+       SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
+                              SUN8I_AIF1_ADCDAT_CTRL,
+                              SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
+                              sun8i_codec_aif_event,
+                              SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
                             SUN8I_AIF1_ADCDAT_CTRL,
                             SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+       SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
+                              SUN8I_AIF2_ADCDAT_CTRL,
+                              SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
+                              sun8i_codec_aif_event,
+                              SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
+                            SUN8I_AIF2_ADCDAT_CTRL,
+                            SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
+
+       SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
+                              SND_SOC_NOPM, 0, 0,
+                              sun8i_codec_aif_event,
+                              SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
        /* AIF "ADC" Mono/Stereo Muxes */
        SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
                         &sun8i_aif1_ad0_stereo_mux_control),
        SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
                         &sun8i_aif1_ad0_stereo_mux_control),
 
+       SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif2_adc_stereo_mux_control),
+       SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif2_adc_stereo_mux_control),
+
+       /* AIF "ADC" Output Muxes */
+       SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif3_adc_mux_control),
+
        /* AIF "ADC" Mixers */
        SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
                        sun8i_aif1_ad0_mixer_controls),
        SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
                        sun8i_aif1_ad0_mixer_controls),
 
+       SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
+                       sun8i_aif2_adc_mixer_controls),
+       SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
+                       sun8i_aif2_adc_mixer_controls),
+
+       /* AIF "DAC" Input Muxes */
+       SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif2_dac_mux_control),
+       SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif2_dac_mux_control),
+
        /* AIF "DAC" Mono/Stereo Muxes */
        SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
                         &sun8i_aif1_da0_stereo_mux_control),
        SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
                         &sun8i_aif1_da0_stereo_mux_control),
 
+       SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif2_dac_stereo_mux_control),
+       SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
+                        &sun8i_aif2_dac_stereo_mux_control),
+
        /* AIF "DAC" Inputs */
-       SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
-                           SUN8I_AIF1_DACDAT_CTRL,
-                           SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
-       SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
+       SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
+                             SUN8I_AIF1_DACDAT_CTRL,
+                             SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
+                             sun8i_codec_aif_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
                            SUN8I_AIF1_DACDAT_CTRL,
                            SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
+       SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
+                             SUN8I_AIF2_DACDAT_CTRL,
+                             SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
+                             sun8i_codec_aif_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
+                           SUN8I_AIF2_DACDAT_CTRL,
+                           SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
+
+       SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
+                             SND_SOC_NOPM, 0, 0,
+                             sun8i_codec_aif_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
        /* ADC Inputs (connected to analog codec DAPM context) */
        SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
@@ -500,6 +1013,20 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
        { "AIF1 DA0L", NULL, "RST AIF1" },
        { "AIF1 DA0R", NULL, "RST AIF1" },
 
+       { "CLK AIF2", NULL, "AIF2CLK" },
+       { "CLK AIF2", NULL, "SYSCLK" },
+       { "RST AIF2", NULL, "CLK AIF2" },
+       { "AIF2 ADCL", NULL, "RST AIF2" },
+       { "AIF2 ADCR", NULL, "RST AIF2" },
+       { "AIF2 DACL", NULL, "RST AIF2" },
+       { "AIF2 DACR", NULL, "RST AIF2" },
+
+       { "CLK AIF3", NULL, "AIF1CLK" },
+       { "CLK AIF3", NULL, "SYSCLK" },
+       { "RST AIF3", NULL, "CLK AIF3" },
+       { "AIF3 ADC", NULL, "RST AIF3" },
+       { "AIF3 DAC", NULL, "RST AIF3" },
+
        { "CLK ADC", NULL, "SYSCLK" },
        { "RST ADC", NULL, "CLK ADC" },
        { "ADC", NULL, "RST ADC" },
@@ -516,6 +1043,11 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
        { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
        { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
 
+       { "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
+       { "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
+
+       { "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
+
        /* AIF "ADC" Mono/Stereo Mux Routes */
        { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
        { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
@@ -531,12 +1063,51 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
        { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
        { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
 
+       { "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
+       { "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
+       { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+       { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+       { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+       { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+       { "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
+       { "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
+       { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+       { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+       { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+       { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+       /* AIF "ADC" Output Mux Routes */
+       { "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
+       { "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
+
        /* AIF "ADC" Mixer Routes */
        { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
+       { "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
        { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+       { "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
        { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
+       { "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
        { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+       { "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
+
+       { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
+       { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
+       { "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
+
+       { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
+       { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
+       { "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
+
+       /* AIF "DAC" Input Mux Routes */
+       { "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+       { "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
+       { "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
+
+       { "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
+       { "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
+       { "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
 
        /* AIF "DAC" Mono/Stereo Mux Routes */
        { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
@@ -553,15 +1124,31 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
        { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
        { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
 
+       { "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
+       { "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
+       { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
+       { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
+       { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
+       { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
+       { "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
+       { "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
+       { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
+       { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
+       { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
+       { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
        /* DAC Output Routes */
        { "DACL", NULL, "DACL Mixer" },
        { "DACR", NULL, "DACR Mixer" },
 
        /* DAC Mixer Routes */
        { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
+       { "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
        { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
        { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
+       { "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
        { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
@@ -621,37 +1208,12 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
                           BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
                           SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
 
+       /* Program the default sample rate. */
+       sun8i_codec_update_sample_rate(scodec);
+
        return 0;
 }
 
-static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
-       .hw_params = sun8i_codec_hw_params,
-       .set_fmt = sun8i_set_fmt,
-};
-
-static struct snd_soc_dai_driver sun8i_codec_dai = {
-       .name = "sun8i",
-       /* playback capabilities */
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       /* capture capabilities */
-       .capture = {
-               .stream_name = "Capture",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-               .sig_bits = 24,
-       },
-       /* pcm operations */
-       .ops = &sun8i_codec_dai_ops,
-};
-
 static const struct snd_soc_component_driver sun8i_soc_component = {
        .dapm_widgets           = sun8i_codec_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(sun8i_codec_dapm_widgets),
@@ -659,7 +1221,6 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
        .num_dapm_routes        = ARRAY_SIZE(sun8i_codec_dapm_routes),
        .probe                  = sun8i_codec_component_probe,
        .idle_bias_on           = 1,
-       .use_pmdown_time        = 1,
        .endianness             = 1,
        .non_legacy_dai_naming  = 1,
 };
@@ -714,7 +1275,8 @@ static int sun8i_codec_probe(struct platform_device *pdev)
        }
 
        ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
-                                    &sun8i_codec_dai, 1);
+                                             sun8i_codec_dais,
+                                             ARRAY_SIZE(sun8i_codec_dais));
        if (ret) {
                dev_err(&pdev->dev, "Failed to register codec\n");
                goto err_suspend;
index 3d91bd3..a62cc87 100644 (file)
@@ -39,7 +39,6 @@ config SND_SOC_TEGRA20_I2S
 config SND_SOC_TEGRA20_SPDIF
        tristate "Tegra20 SPDIF interface"
        depends on SND_SOC_TEGRA
-       default m
        help
          Say Y or M if you want to add support for the Tegra20 SPDIF interface.
          You will also need to select the individual machine drivers to support
index 0cbe31e..7d9948f 100644 (file)
@@ -310,7 +310,7 @@ static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
@@ -326,7 +326,7 @@ static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
@@ -339,7 +339,7 @@ static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static const struct regmap_config tegra186_dspk_regmap = {
index a661f40..ead2c99 100644 (file)
@@ -322,7 +322,7 @@ static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
@@ -338,7 +338,7 @@ static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
@@ -353,7 +353,7 @@ static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static const struct regmap_config tegra210_dmic_regmap_config = {
index a383bd5..ca31ec9 100644 (file)
@@ -662,7 +662,7 @@ static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
@@ -682,7 +682,7 @@ static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -701,7 +701,7 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
                return true;
        default:
                return false;
-       };
+       }
 }
 
 static const struct regmap_config tegra210_i2s_regmap_config = {
index 8661877..0a0efd2 100644 (file)
@@ -203,8 +203,8 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_card(card);
        if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
+               dev_err_probe(&pdev->dev, ret,
+                             "snd_soc_register_card failed\n");
                goto err_put_cpu_of_node;
        }
 
index 9d8e164..00c1970 100644 (file)
@@ -247,11 +247,9 @@ static int tegra_max98090_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "snd_soc_register_card failed\n");
 
        return 0;
 }
index c73bd23..9afba37 100644 (file)
@@ -193,11 +193,9 @@ static int tegra_rt5640_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "snd_soc_register_card failed\n");
 
        return 0;
 }
index 7504507..d30f8b6 100644 (file)
@@ -268,8 +268,8 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_card(card);
        if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
+               dev_err_probe(&pdev->dev, ret,
+                             "snd_soc_register_card failed\n");
                goto err_put_cpu_of_node;
        }
 
index e1dc8e7..8853321 100644 (file)
@@ -154,8 +154,8 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_card(card);
        if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
+               dev_err_probe(&pdev->dev, ret,
+                             "snd_soc_register_card failed\n");
                goto err_put_cpu_of_node;
        }
 
index fa41fa3..efd7938 100644 (file)
@@ -156,11 +156,9 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "snd_soc_register_card failed\n");
 
        return 0;
 }
index ef6652a..e4863fa 100644 (file)
@@ -352,11 +352,9 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret) {
-               dev_err(&pdev->dev, "devm_snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "snd_soc_register_card failed\n");
 
        return 0;
 }
index 726edfa..4f09a17 100644 (file)
@@ -117,8 +117,8 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_card(card);
        if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
+               dev_err_probe(&pdev->dev, ret,
+                             "snd_soc_register_card failed\n");
                goto codec_unregister;
        }
 
index baae4cc..6c1cc3d 100644 (file)
@@ -144,11 +144,9 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev)
                return ret;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "snd_soc_register_card failed\n");
 
        return 0;
 }
index 9775393..698d7bc 100644 (file)
@@ -26,6 +26,7 @@ config SND_SOC_DAVINCI_ASP
 
 config SND_SOC_DAVINCI_MCASP
        tristate "Multichannel Audio Serial Port (McASP) support"
+       depends on COMMON_CLK
        select SND_SOC_TI_EDMA_PCM
        select SND_SOC_TI_SDMA_PCM
        select SND_SOC_TI_UDMA_PCM
@@ -47,7 +48,7 @@ config SND_SOC_DAVINCI_VCIF
 
 config SND_SOC_OMAP_DMIC
        tristate "Digital Microphone Module (DMIC) support"
-       depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+       depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST && COMMON_CLK
        select SND_SOC_TI_SDMA_PCM
        help
          Say Y or M here if you want to have support for DMIC IP found in
@@ -55,7 +56,7 @@ config SND_SOC_OMAP_DMIC
 
 config SND_SOC_OMAP_MCBSP
        tristate "Multichannel Buffered Serial Port (McBSP) support"
-       depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST
+       depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST && COMMON_CLK
        select SND_SOC_TI_SDMA_PCM
        help
          Say Y or M here if you want to have support for McBSP IP found in
@@ -99,7 +100,7 @@ config SND_SOC_OMAP3_PANDORA
 
 config SND_SOC_OMAP3_TWL4030
        tristate "SoC Audio support for OMAP3 based boards with twl4030 codec"
-       depends on ARCH_OMAP3 || COMPILE_TEST
+       depends on ARCH_OMAP3 || COMPILE_TEST && COMMON_CLK
        depends on TWL4030_CORE
        select SND_SOC_OMAP_MCBSP
        select SND_SOC_TWL4030
@@ -221,7 +222,7 @@ config SND_SOC_DM365_VOICE_CODEC_MODULE
 
 config SND_SOC_J721E_EVM
        tristate "SoC Audio support for j721e EVM"
-       depends on ARCH_K3 || COMPILE_TEST
+       depends on ARCH_K3 || COMPILE_TEST && COMMON_CLK
        depends on I2C
        select SND_SOC_PCM3168A_I2C
        select SND_SOC_DAVINCI_MCASP
index 105e56a..b043a00 100644 (file)
@@ -46,8 +46,7 @@ static void evm_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_card_drvdata_davinci *drvdata =
                snd_soc_card_get_drvdata(soc_card);
 
-       if (drvdata->mclk)
-               clk_disable_unprepare(drvdata->mclk);
+       clk_disable_unprepare(drvdata->mclk);
 }
 
 static int evm_hw_params(struct snd_pcm_substream *substream,
index dd34504..6dca518 100644 (file)
@@ -747,7 +747,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id davinci_i2s_match[] = {
+static const struct of_device_id davinci_i2s_match[] __maybe_unused = {
        { .compatible = "ti,da850-mcbsp" },
        {},
 };
index 2d85cc4..6247ec3 100644 (file)
@@ -76,12 +76,16 @@ struct davinci_mcasp_ruledata {
 
 struct davinci_mcasp {
        struct snd_dmaengine_dai_dma_data dma_data[2];
+       struct davinci_mcasp_pdata *pdata;
        void __iomem *base;
        u32 fifo_base;
        struct device *dev;
        struct snd_pcm_substream *substreams[2];
        unsigned int dai_fmt;
 
+       /* Audio can not be enabled due to missing parameter(s) */
+       bool    missing_audio_param;
+
        /* McASP specific data */
        int     tdm_slots;
        u32     tdm_mask[2];
@@ -94,7 +98,6 @@ struct davinci_mcasp {
        u8      bclk_div;
        int     streams;
        u32     irq_request[2];
-       int     dma_request[2];
 
        int     sysclk_freq;
        bool    bclk_master;
@@ -1748,48 +1751,58 @@ err1:
        return ret;
 }
 
-static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
-                                               struct platform_device *pdev)
+static bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp)
 {
+#ifdef CONFIG_OF_GPIO
+       if (mcasp->dev->of_node &&
+           of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
+               return true;
+#endif
+
+       return false;
+}
+
+static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp,
+                                   struct platform_device *pdev)
+{
+       const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev);
        struct device_node *np = pdev->dev.of_node;
        struct davinci_mcasp_pdata *pdata = NULL;
-       const struct of_device_id *match =
-                       of_match_device(mcasp_dt_ids, &pdev->dev);
-       struct of_phandle_args dma_spec;
-
        const u32 *of_serial_dir32;
        u32 val;
-       int i, ret = 0;
+       int i;
 
        if (pdev->dev.platform_data) {
                pdata = pdev->dev.platform_data;
                pdata->dismod = DISMOD_LOW;
-               return pdata;
+               goto out;
        } else if (match) {
                pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
                                     GFP_KERNEL);
                if (!pdata)
-                       return NULL;
+                       return -ENOMEM;
        } else {
-               /* control shouldn't reach here. something is wrong */
-               ret = -EINVAL;
-               goto nodata;
+               dev_err(&pdev->dev, "No compatible match found\n");
+               return -EINVAL;
        }
 
-       ret = of_property_read_u32(np, "op-mode", &val);
-       if (ret >= 0)
+       if (of_property_read_u32(np, "op-mode", &val) == 0) {
                pdata->op_mode = val;
+       } else {
+               mcasp->missing_audio_param = true;
+               goto out;
+       }
 
-       ret = of_property_read_u32(np, "tdm-slots", &val);
-       if (ret >= 0) {
+       if (of_property_read_u32(np, "tdm-slots", &val) == 0) {
                if (val < 2 || val > 32) {
-                       dev_err(&pdev->dev,
-                               "tdm-slots must be in rage [2-32]\n");
-                       ret = -EINVAL;
-                       goto nodata;
+                       dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n");
+                       return -EINVAL;
                }
 
                pdata->tdm_slots = val;
+       } else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) {
+               mcasp->missing_audio_param = true;
+               goto out;
        }
 
        of_serial_dir32 = of_get_property(np, "serial-dir", &val);
@@ -1798,61 +1811,29 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
                u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
                                                 (sizeof(*of_serial_dir) * val),
                                                 GFP_KERNEL);
-               if (!of_serial_dir) {
-                       ret = -ENOMEM;
-                       goto nodata;
-               }
+               if (!of_serial_dir)
+                       return -ENOMEM;
 
                for (i = 0; i < val; i++)
                        of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
 
                pdata->num_serializer = val;
                pdata->serial_dir = of_serial_dir;
+       } else {
+               mcasp->missing_audio_param = true;
+               goto out;
        }
 
-       ret = of_property_match_string(np, "dma-names", "tx");
-       if (ret < 0)
-               goto nodata;
-
-       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-                                        &dma_spec);
-       if (ret < 0)
-               goto nodata;
-
-       pdata->tx_dma_channel = dma_spec.args[0];
-
-       /* RX is not valid in DIT mode */
-       if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               ret = of_property_match_string(np, "dma-names", "rx");
-               if (ret < 0)
-                       goto nodata;
-
-               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-                                                &dma_spec);
-               if (ret < 0)
-                       goto nodata;
-
-               pdata->rx_dma_channel = dma_spec.args[0];
-       }
-
-       ret = of_property_read_u32(np, "tx-num-evt", &val);
-       if (ret >= 0)
+       if (of_property_read_u32(np, "tx-num-evt", &val) == 0)
                pdata->txnumevt = val;
 
-       ret = of_property_read_u32(np, "rx-num-evt", &val);
-       if (ret >= 0)
+       if (of_property_read_u32(np, "rx-num-evt", &val) == 0)
                pdata->rxnumevt = val;
 
-       ret = of_property_read_u32(np, "sram-size-playback", &val);
-       if (ret >= 0)
-               pdata->sram_size_playback = val;
-
-       ret = of_property_read_u32(np, "sram-size-capture", &val);
-       if (ret >= 0)
-               pdata->sram_size_capture = val;
+       if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0)
+               mcasp->auxclk_fs_ratio = val;
 
-       ret = of_property_read_u32(np, "dismod", &val);
-       if (ret >= 0) {
+       if (of_property_read_u32(np, "dismod", &val) == 0) {
                if (val == 0 || val == 2 || val == 3) {
                        pdata->dismod = DISMOD_VAL(val);
                } else {
@@ -1863,15 +1844,50 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
                pdata->dismod = DISMOD_LOW;
        }
 
-       return  pdata;
+out:
+       mcasp->pdata = pdata;
+
+       if (mcasp->missing_audio_param) {
+               if (davinci_mcasp_have_gpiochip(mcasp)) {
+                       dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n");
+                       return 0;
+               }
 
-nodata:
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Error populating platform data, err %d\n",
-                       ret);
-               pdata = NULL;
+               dev_err(&pdev->dev, "Insufficient DT parameter(s)\n");
+               return -ENODEV;
        }
-       return  pdata;
+
+       mcasp->op_mode = pdata->op_mode;
+       /* sanity check for tdm slots parameter */
+       if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
+               if (pdata->tdm_slots < 2) {
+                       dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
+                                pdata->tdm_slots);
+                       mcasp->tdm_slots = 2;
+               } else if (pdata->tdm_slots > 32) {
+                       dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
+                                pdata->tdm_slots);
+                       mcasp->tdm_slots = 32;
+               } else {
+                       mcasp->tdm_slots = pdata->tdm_slots;
+               }
+       }
+
+       mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM
+       mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
+                                               mcasp->num_serializer, sizeof(u32),
+                                               GFP_KERNEL);
+       if (!mcasp->context.xrsr_regs)
+               return -ENOMEM;
+#endif
+       mcasp->serial_dir = pdata->serial_dir;
+       mcasp->version = pdata->version;
+       mcasp->txnumevt = pdata->txnumevt;
+       mcasp->rxnumevt = pdata->rxnumevt;
+       mcasp->dismod = pdata->dismod;
+
+       return 0;
 }
 
 enum {
@@ -2090,7 +2106,7 @@ static const struct gpio_chip davinci_mcasp_template_chip = {
 
 static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
 {
-       if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
+       if (!davinci_mcasp_have_gpiochip(mcasp))
                return 0;
 
        mcasp->gpio_chip = davinci_mcasp_template_chip;
@@ -2110,30 +2126,12 @@ static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
 }
 #endif /* CONFIG_GPIOLIB */
 
-static int davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp)
-{
-       struct device_node *np = mcasp->dev->of_node;
-       int ret;
-       u32 val;
-
-       if (!np)
-               return 0;
-
-       ret = of_property_read_u32(np, "auxclk-fs-ratio", &val);
-       if (ret >= 0)
-               mcasp->auxclk_fs_ratio = val;
-
-       return 0;
-}
-
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
        struct snd_dmaengine_dai_dma_data *dma_data;
-       struct resource *mem, *res, *dat;
-       struct davinci_mcasp_pdata *pdata;
+       struct resource *mem, *dat;
        struct davinci_mcasp *mcasp;
        char *irq_name;
-       int *dma;
        int irq;
        int ret;
 
@@ -2147,12 +2145,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (!mcasp)
                return  -ENOMEM;
 
-       pdata = davinci_mcasp_set_pdata_from_of(pdev);
-       if (!pdata) {
-               dev_err(&pdev->dev, "no platform data\n");
-               return -EINVAL;
-       }
-
        mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
        if (!mem) {
                dev_warn(&pdev->dev,
@@ -2168,44 +2160,25 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (IS_ERR(mcasp->base))
                return PTR_ERR(mcasp->base);
 
+       dev_set_drvdata(&pdev->dev, mcasp);
        pm_runtime_enable(&pdev->dev);
 
-       mcasp->op_mode = pdata->op_mode;
-       /* sanity check for tdm slots parameter */
-       if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
-               if (pdata->tdm_slots < 2) {
-                       dev_err(&pdev->dev, "invalid tdm slots: %d\n",
-                               pdata->tdm_slots);
-                       mcasp->tdm_slots = 2;
-               } else if (pdata->tdm_slots > 32) {
-                       dev_err(&pdev->dev, "invalid tdm slots: %d\n",
-                               pdata->tdm_slots);
-                       mcasp->tdm_slots = 32;
-               } else {
-                       mcasp->tdm_slots = pdata->tdm_slots;
-               }
-       }
-
-       mcasp->num_serializer = pdata->num_serializer;
-#ifdef CONFIG_PM
-       mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
-                                       mcasp->num_serializer, sizeof(u32),
-                                       GFP_KERNEL);
-       if (!mcasp->context.xrsr_regs) {
-               ret = -ENOMEM;
+       mcasp->dev = &pdev->dev;
+       ret = davinci_mcasp_get_config(mcasp, pdev);
+       if (ret)
                goto err;
-       }
-#endif
-       mcasp->serial_dir = pdata->serial_dir;
-       mcasp->version = pdata->version;
-       mcasp->txnumevt = pdata->txnumevt;
-       mcasp->rxnumevt = pdata->rxnumevt;
-       mcasp->dismod = pdata->dismod;
 
-       mcasp->dev = &pdev->dev;
+       /* All PINS as McASP */
+       pm_runtime_get_sync(mcasp->dev);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+       pm_runtime_put(mcasp->dev);
 
-       irq = platform_get_irq_byname(pdev, "common");
-       if (irq >= 0) {
+       /* Skip audio related setup code if the configuration is not adequat */
+       if (mcasp->missing_audio_param)
+               goto no_audio;
+
+       irq = platform_get_irq_byname_optional(pdev, "common");
+       if (irq > 0) {
                irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
                                          dev_name(&pdev->dev));
                if (!irq_name) {
@@ -2225,8 +2198,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
        }
 
-       irq = platform_get_irq_byname(pdev, "rx");
-       if (irq >= 0) {
+       irq = platform_get_irq_byname_optional(pdev, "rx");
+       if (irq > 0) {
                irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
                                          dev_name(&pdev->dev));
                if (!irq_name) {
@@ -2244,8 +2217,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
        }
 
-       irq = platform_get_irq_byname(pdev, "tx");
-       if (irq >= 0) {
+       irq = platform_get_irq_byname_optional(pdev, "tx");
+       if (irq > 0) {
                irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
                                          dev_name(&pdev->dev));
                if (!irq_name) {
@@ -2268,45 +2241,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->dat_port = true;
 
        dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_data->filter_data = "tx";
        if (dat)
                dma_data->addr = dat->start;
        else
-               dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata);
-
-       dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (res)
-               *dma = res->start;
-       else
-               *dma = pdata->tx_dma_channel;
+               dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
 
-       /* dmaengine filter data for DT and non-DT boot */
-       if (pdev->dev.of_node)
-               dma_data->filter_data = "tx";
-       else
-               dma_data->filter_data = dma;
 
        /* RX is not valid in DIT mode */
        if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
                dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+               dma_data->filter_data = "rx";
                if (dat)
                        dma_data->addr = dat->start;
                else
                        dma_data->addr =
-                               mem->start + davinci_mcasp_rxdma_offset(pdata);
-
-               dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (res)
-                       *dma = res->start;
-               else
-                       *dma = pdata->rx_dma_channel;
-
-               /* dmaengine filter data for DT and non-DT boot */
-               if (pdev->dev.of_node)
-                       dma_data->filter_data = "rx";
-               else
-                       dma_data->filter_data = dma;
+                               mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
        }
 
        if (mcasp->version < MCASP_VERSION_3) {
@@ -2346,26 +2296,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       dev_set_drvdata(&pdev->dev, mcasp);
-
        mcasp_reparent_fck(pdev);
 
-       /* All PINS as McASP */
-       pm_runtime_get_sync(mcasp->dev);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
-       pm_runtime_put(mcasp->dev);
-
-       ret = davinci_mcasp_init_gpiochip(mcasp);
-       if (ret)
-               goto err;
-
-       ret = davinci_mcasp_get_dt_params(mcasp);
-       if (ret)
-               return -EINVAL;
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                       &davinci_mcasp_component,
-                                       &davinci_mcasp_dai[pdata->op_mode], 1);
+       ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
+                                             &davinci_mcasp_dai[mcasp->op_mode], 1);
 
        if (ret != 0)
                goto err;
@@ -2392,8 +2326,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                goto err;
        }
 
-       return 0;
+no_audio:
+       ret = davinci_mcasp_init_gpiochip(mcasp);
+       if (ret) {
+               dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret);
+               goto err;
+       }
 
+       return 0;
 err:
        pm_runtime_disable(&pdev->dev);
        return ret;
index 8b44f8d..7b3cf5d 100644 (file)
@@ -372,7 +372,7 @@ static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
        .addr_ext  = 1,
 };
 
-static const struct of_device_id uniphier_aio_of_match[] = {
+static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
        {
                .compatible = "socionext,uniphier-ld11-aio",
                .data = &uniphier_aio_ld11_spec,
index a1d05fe..899904f 100644 (file)
@@ -282,7 +282,7 @@ static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = {
        .addr_ext  = 0,
 };
 
-static const struct of_device_id uniphier_aio_of_match[] = {
+static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
        {
                .compatible = "socionext,uniphier-pxs2-aio",
                .data = &uniphier_aio_pxs2_spec,
index d27e9ca..96343d1 100644 (file)
@@ -551,7 +551,7 @@ static int evea_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id evea_of_match[] = {
+static const struct of_device_id evea_of_match[] __maybe_unused = {
        { .compatible = "socionext,uniphier-evea", },
        {}
 };