diff --git a/Documentation/devicetree/bindings/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt
deleted file mode 100644
index ae5f7f057dc3104185d319bd401899cafa09b4c0..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/ak4104.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-AK4104 S/PDIF transmitter
-
-This device supports SPI mode only.
-
-Required properties:
-
-  - compatible : "asahi-kasei,ak4104"
-
-  - reg : The chip select number on the SPI bus
-
-  - vdd-supply : A regulator node, providing 2.7V - 3.6V
-
-Optional properties:
-
-  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
-		  deasserted before communication to the device starts.
-
-Example:
-
-spdif: ak4104@0 {
-	compatible = "asahi-kasei,ak4104";
-	reg = <0>;
-	spi-max-frequency = <5000000>;
-	vdd-supply = <&vdd_3v3_reg>;
-};
diff --git a/Documentation/devicetree/bindings/sound/ak4554.txt b/Documentation/devicetree/bindings/sound/ak4554.txt
deleted file mode 100644
index 934fa02754b38878a9b7cd110f63287cade24252..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/ak4554.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-AK4554 ADC/DAC
-
-Required properties:
-
-  - compatible : "asahi-kasei,ak4554"
-
-Example:
-
-ak4554-adc-dac {
-	compatible = "asahi-kasei,ak4554";
-};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt
deleted file mode 100644
index 4e8cd7eb7cec458225bb765315e0a0983a0633fa..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-* Amlogic HDMI Tx control glue
-
-Required properties:
-- compatible: "amlogic,g12a-tohdmitx" or
-	      "amlogic,sm1-tohdmitx"
-- reg: physical base address of the controller and length of memory
-       mapped region.
-- #sound-dai-cells: should be 1.
-- resets: phandle to the dedicated reset line of the hdmitx glue.
-
-Example on the S905X2 SoC:
-
-tohdmitx: audio-controller@744 {
-	compatible = "amlogic,g12a-tohdmitx";
-	reg = <0x0 0x744 0x0 0x4>;
-	#sound-dai-cells = <1>;
-	resets = <&clkc_audio AUD_RESET_TOHDMITX>;
-};
-
-Example of an 'amlogic,axg-sound-card':
-
-sound {
-	compatible = "amlogic,axg-sound-card";
-
-[...]
-
-	dai-link-x {
-		sound-dai = <&tdmif_a>;
-		dai-format = "i2s";
-		dai-tdm-slot-tx-mask-0 = <1 1>;
-
-		codec-0 {
-			sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>;
-		};
-
-		codec-1 {
-			sound-dai = <&external_dac>;
-		};
-	};
-
-	dai-link-y {
-		sound-dai = <&tdmif_c>;
-		dai-format = "i2s";
-		dai-tdm-slot-tx-mask-0 = <1 1>;
-
-		codec {
-			sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>;
-		};
-	};
-
-	dai-link-z {
-		sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
-
-		codec {
-			sound-dai = <&hdmi_tx>;
-		};
-	};
-};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b4b78475c5b8c3796925fbc806374e7574c65b27
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/amlogic,g12a-tohdmitx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic G12a HDMI TX Control Glue
+
+maintainers:
+  - Jerome Brunet <jbrunet@baylibre.com>
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  $nodename:
+    pattern: "^audio-controller@.*"
+
+  compatible:
+    oneOf:
+      - items:
+          - const: amlogic,g12a-tohdmitx
+      - items:
+          - enum:
+              - amlogic,sm1-tohdmitx
+          - const: amlogic,g12a-tohdmitx
+
+  reg:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - resets
+  - "#sound-dai-cells"
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
+
+    tohdmitx: audio-controller@744 {
+        compatible = "amlogic,g12a-tohdmitx";
+        reg = <0x744 0x4>;
+        resets = <&clkc_audio AUD_RESET_TOHDMITX>;
+        #sound-dai-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
index d4277d342e699ac4ab483f8fedb5e48421e17a33..0ecdaf7190e9f12ac527fb77f6cd30118ae672c3 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
@@ -23,7 +23,6 @@ properties:
 
   audio-widgets:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    minItems: 2
     description: |-
       A list off component DAPM widget. Each entry is a pair of strings,
       the first being the widget type, the second being the widget name
diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..86f6061d3c50182c073fe4383bfca8dcd35fda01
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4104.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4104.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AK4104 S/PDIF transmitter
+
+allOf:
+  - $ref: dai-common.yaml#
+
+maintainers:
+  - Daniel Mack <github@zonque.org>
+  - Xiaxi Shen <shenxiaxi26@gmail.com>
+
+properties:
+  compatible:
+    const: asahi-kasei,ak4104
+
+  reg:
+    description: Chip select number on the SPI bus 
+    maxItems: 1
+
+  vdd-supply:
+    description: A regulator node providing between 2.7V and 3.6V.
+
+  reset-gpios:
+    maxItems: 1
+    description: Optional GPIO spec for the reset pin, deasserted 
+                  before communication starts.
+    
+required:
+  - compatible
+  - reg
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        codec@0 {
+            compatible = "asahi-kasei,ak4104";
+            reg = <0>;
+            vdd-supply = <&vdd_3v3_reg>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/ak4375.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml
similarity index 94%
rename from Documentation/devicetree/bindings/sound/ak4375.yaml
rename to Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml
index 587598e122c6ed3d09cdd352584bfd7ecba62f10..bc07fcba535bfd06f7ce45e44dcc885ca1a0907a 100644
--- a/Documentation/devicetree/bindings/sound/ak4375.yaml
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/ak4375.yaml#
+$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4375.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: AK4375 DAC and headphones amplifier
diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c77d85df239e117b31d469e96bfd92e653fae8be
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4554.yaml
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4554.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AK4554 sound codec
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+  - Liam Girdwood <lgirdwood@gmail.com>
+  - Mark Brown <broonie@kernel.org>
+
+properties:
+  compatible:
+    const: asahi-kasei,ak4554
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    codec {
+        compatible = "asahi-kasei,ak4554";
+    };
diff --git a/Documentation/devicetree/bindings/sound/ak4613.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml
similarity index 94%
rename from Documentation/devicetree/bindings/sound/ak4613.yaml
rename to Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml
index 75e13414d6eb18654c91e63f84e5d601cbe17ae9..b49a6cff9f1f7affde5f5016b2760df2381e1736 100644
--- a/Documentation/devicetree/bindings/sound/ak4613.yaml
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/ak4613.yaml#
+$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4613.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: AK4613 I2C transmitter
diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d412531ef9a2ba8b84fe27fc23db93dbbcc0e092
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4619.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AK4619 I2C transmitter
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+  - Khanh Le <khanh.le.xr@renesas.com>
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: asahi-kasei,ak4619
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: mclk
+
+  "#sound-dai-cells":
+    const: 0
+
+  port:
+    $ref: audio-graph-port.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        codec@10 {
+            compatible = "asahi-kasei,ak4619";
+            reg = <0x10>;
+
+            clocks = <&rcar_sound>;
+            clock-names = "mclk";
+
+            #sound-dai-cells = <0>;
+            port {
+                 ak4619_endpoint: endpoint {
+                       remote-endpoint = <&rsnd_endpoint>;
+                  };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/ak4642.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml
similarity index 94%
rename from Documentation/devicetree/bindings/sound/ak4642.yaml
rename to Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml
index 437fe5d7cae1464c254761514678e1ad429f9fd9..fc03f0373a1a1db9839c0922c12e7c02b054f86a 100644
--- a/Documentation/devicetree/bindings/sound/ak4642.yaml
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/ak4642.yaml#
+$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4642.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: AK4642 I2C transmitter
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml b/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml
index d3ce4de449d51303476d12e29a74c814409a5ea0..f943f90d8b150af11c47caf3512c2ab61cd0fc89 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml
+++ b/Documentation/devicetree/bindings/sound/audio-graph-card2.yaml
@@ -23,6 +23,11 @@ properties:
       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
+  aux-devs:
+    description: |
+      List of phandles pointing to auxiliary devices, such
+      as amplifiers, to be added to the sound card.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
   multi:
     type: object
     description: Multi-CPU/Codec node
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
index 28b27e7e45de6beb5037d6e7e3d616e3d4188294..d1cbfc5edd3ac30fd8affddff4458ed2d34bc603 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
+++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
@@ -25,6 +25,15 @@ definitions:
       capture-only:
         description: port connection used only for capture
         $ref: /schemas/types.yaml#/definitions/flag
+      link-trigger-order:
+        description: trigger order for both start/stop
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+      link-trigger-order-start:
+        description: trigger order for start
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+      link-trigger-order-stop:
+        description: trigger order for stop
+        $ref: /schemas/types.yaml#/definitions/uint32-array
 
   endpoint-base:
     allOf:
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..336e11773694285d0acaf956fe49c5bef32776e4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cirrus,cs4270.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic CS4270 audio CODEC
+
+maintainers:
+  - patches@opensource.cirrus.com
+
+description:
+  The CS4270 is a stereo audio codec. The driver for this device currently only
+  supports I2C.
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: cirrus,cs4270
+
+  reg:
+    maxItems: 1
+
+  '#sound-dai-cells':
+    const: 0
+
+  reset-gpios:
+    description:
+      This pin will be deasserted before communication to the codec starts.
+    maxItems: 1
+
+  va-supply:
+    description: Analog power supply.
+
+  vd-supply:
+    description: Digital power supply.
+
+  vlc-supply:
+    description: Serial Control Port power supply.
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      codec@48 {
+          compatible = "cirrus,cs4270";
+          reg = <0x48>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..725b47e82062a2e1185bdc6ff044414de27220c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cirrus,cs42xx8.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic CS42448/CS42888 audio CODEC
+
+maintainers:
+  - patches@opensource.cirrus.com
+
+properties:
+  compatible:
+    enum:
+      - cirrus,cs42448
+      - cirrus,cs42888
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+
+  clock-names:
+    const: mclk
+
+  VA-supply:
+    description: Analog power supply.
+
+  VD-supply:
+    description: Digital power supply.
+
+  VLC-supply:
+    description: Control port power supply
+
+  VLS-supply:
+    description: Serial port interface power supply.
+
+  reset-gpios:
+    description: This pin is connected to the chip's RESET pin.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: cirrus,cs42888
+then:
+  required:
+    - VA-supply
+    - VD-supply
+    - VLC-supply
+    - VLS-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      codec@48 {
+          compatible = "cirrus,cs42888";
+          reg = <0x48>;
+          clocks = <&codec_mclk 0>;
+          clock-names = "mclk";
+          VA-supply = <&reg_audio>;
+          VD-supply = <&reg_audio>;
+          VLS-supply = <&reg_audio>;
+          VLC-supply = <&reg_audio>;
+          reset-gpios = <&gpio 1>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9582eb8eb418bc9c1b47406dca8a19b80ee9c600
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cirrus,cs530x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic cs530x family of audio ADCs
+
+maintainers:
+  - Paul Handrigan <paulha@opensource.cirrus.com>
+  - patches@opensource.cirrus.com
+
+description:
+  The CS530X devices are a family of high performance audio ADCs.
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - cirrus,cs5302
+      - cirrus,cs5304
+      - cirrus,cs5308
+
+  reg:
+    maxItems: 1
+
+  '#sound-dai-cells':
+    const: 1
+
+  reset-gpios:
+    maxItems: 1
+
+  vdd-a-supply:
+    description: Analog power supply
+
+  vdd-io-supply:
+    description: Digital IO power supply
+
+  cirrus,in-hiz-pin12:
+    description:
+      Sets input channels one and two to high impedance.
+    type: boolean
+
+  cirrus,in-hiz-pin34:
+    description:
+      Sets input channels three and four to high impedance.
+    type: boolean
+
+  cirrus,in-hiz-pin56:
+    description:
+      Sets input channels five and six to high impedance.
+    type: boolean
+
+  cirrus,in-hiz-pin78:
+    description:
+      Sets input channels seven and eight to high impedance.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cs5304: adc@48 {
+            compatible = "cirrus,cs5304";
+            reg = <0x48>;
+            #sound-dai-cells = <1>;
+            reset-gpios = <&gpio 110 GPIO_ACTIVE_LOW>;
+            vdd-a-supply = <&vreg>;
+            vdd-io-supply = <&vreg>;
+            cirrus,in-hiz-pin34;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt
deleted file mode 100644
index c33770ec4c3c726a750c8e5a6b978e5202906149..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/cs4270.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-CS4270 audio CODEC
-
-The driver for this device currently only supports I2C.
-
-Required properties:
-
-  - compatible : "cirrus,cs4270"
-
-  - reg : the I2C address of the device for I2C
-
-Optional properties:
-
-  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
-		  deasserted before communication to the codec starts.
-
-Example:
-
-codec: cs4270@48 {
-	compatible = "cirrus,cs4270";
-	reg = <0x48>;
-};
diff --git a/Documentation/devicetree/bindings/sound/cs42xx8.txt b/Documentation/devicetree/bindings/sound/cs42xx8.txt
deleted file mode 100644
index bbfe39347c206e791268ffdbd0d2fe22a3ea8092..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/cs42xx8.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-CS42448/CS42888 audio CODEC
-
-Required properties:
-
-  - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
-
-  - reg : the I2C address of the device for I2C
-
-  - clocks : a list of phandles + clock-specifiers, one for each entry in
-    clock-names
-
-  - clock-names : must contain "mclk"
-
-  - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
-    as covered in Documentation/devicetree/bindings/regulator/regulator.txt
-
-Optional properties:
-
-  - reset-gpios : a GPIO spec to define which pin is connected to the chip's
-    !RESET pin
-
-Example:
-
-cs42888: codec@48 {
-	compatible = "cirrus,cs42888";
-	reg = <0x48>;
-	clocks = <&codec_mclk 0>;
-	clock-names = "mclk";
-	VA-supply = <&reg_audio>;
-	VD-supply = <&reg_audio>;
-	VLS-supply = <&reg_audio>;
-	VLC-supply = <&reg_audio>;
-	reset-gpios = <&pca9557_b 1 GPIO_ACTIVE_LOW>;
-};
diff --git a/Documentation/devicetree/bindings/sound/everest,es7134.txt b/Documentation/devicetree/bindings/sound/everest,es7134.txt
deleted file mode 100644
index 091666069bde1e6d885a05346499fc0e651c7d34..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/everest,es7134.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-ES7134 i2s DA converter
-
-Required properties:
-- compatible : "everest,es7134" or
-               "everest,es7144" or
-	       "everest,es7154"
-- VDD-supply : regulator phandle for the VDD supply
-- PVDD-supply: regulator phandle for the PVDD supply for the es7154
-
-Example:
-
-i2s_codec: external-codec {
-	compatible = "everest,es7134";
-	VDD-supply = <&vcc_5v>;
-};
diff --git a/Documentation/devicetree/bindings/sound/everest,es71x4.yaml b/Documentation/devicetree/bindings/sound/everest,es71x4.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fd1b328122282ad82039bd6160be1ee9cb4a22a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/everest,es71x4.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/everest,es71x4.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Everest ES7134/7144/7154 2 channels I2S analog to digital converter
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+
+properties:
+  compatible:
+    enum:
+      - everest,es7134
+      - everest,es7144
+      - everest,es7154
+
+  VDD-supply: true
+  PVDD-supply: true
+
+  '#sound-dai-cells':
+    const: 0
+
+required:
+  - compatible
+  - VDD-supply
+
+allOf:
+  - $ref: dai-common.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - everest,es7134
+              - everest,es7144
+    then:
+      properties:
+        PVDD-supply: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - everest,es7154
+    then:
+      required:
+        - PVDD-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+   codec {
+       compatible = "everest,es7134";
+       #sound-dai-cells = <0>;
+       VDD-supply = <&vdd_supply>;
+   };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/everest,es7241.txt b/Documentation/devicetree/bindings/sound/everest,es7241.txt
deleted file mode 100644
index 28f82cf4959f41dae1bace4c00e23c1ebebd838b..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/everest,es7241.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-ES7241 i2s AD converter
-
-Required properties:
-- compatible : "everest,es7241"
-- VDDP-supply: regulator phandle for the VDDA supply
-- VDDA-supply: regulator phandle for the VDDP supply
-- VDDD-supply: regulator phandle for the VDDD supply
-
-Optional properties:
-- reset-gpios: gpio connected to the reset pin
-- m0-gpios   : gpio connected to the m0 pin
-- m1-gpios   : gpio connected to the m1 pin
-- everest,sdout-pull-down:
-   Format used by the serial interface is controlled by pulling
-   the sdout. If the sdout is pulled down, leftj format is used.
-   If this property is not provided, sdout is assumed to pulled
-   up and i2s format is used
-
-Example:
-
-linein: audio-codec@2 {
-	#sound-dai-cells = <0>;
-	compatible = "everest,es7241";
-	VDDA-supply = <&vcc_3v3>;
-	VDDP-supply = <&vcc_3v3>;
-	VDDD-supply = <&vcc_3v3>;
-	reset-gpios = <&gpio GPIOH_42>;
-};
diff --git a/Documentation/devicetree/bindings/sound/everest,es7241.yaml b/Documentation/devicetree/bindings/sound/everest,es7241.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f179af758730811cb765f87ac8fb1236dd0f3433
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/everest,es7241.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/everest,es7241.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Everest ES7241 2 channels I2S analog to digital converter
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+
+properties:
+  compatible:
+    enum:
+      - everest,es7241
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to the reset pin
+
+  m0-gpios:
+    maxItems: 1
+    description: GPIO connected to the m0 pin
+
+  m1-gpios:
+    maxItems: 1
+    description: GPIO connected to the m0 pin
+
+  everest,sdout-pull-down:
+    type: boolean
+    description:
+      Format used by the serial interface is controlled by pulling
+      the sdout. If the sdout is pulled down, leftj format is used.
+      If this property is not provided, sdout is assumed to pulled
+      up and i2s format is used
+
+  VDDP-supply: true
+  VDDA-supply: true
+  VDDD-supply: true
+
+  '#sound-dai-cells':
+    const: 0
+
+required:
+  - compatible
+  - VDDP-supply
+  - VDDA-supply
+  - VDDD-supply
+
+allOf:
+  - $ref: dai-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+   #include <dt-bindings/gpio/gpio.h>
+   codec {
+       compatible = "everest,es7241";
+       #sound-dai-cells = <0>;
+       reset-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+       VDDP-supply = <&vddp_supply>;
+       VDDA-supply = <&vdda_supply>;
+       VDDD-supply = <&vddd_supply>;
+   };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml
index b6079b3c440d54566321b47df8afdef2b738b745..214f135b7777f346c4ab168ef278abcd1687c908 100644
--- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml
+++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml
@@ -4,18 +4,21 @@
 $id: http://devicetree.org/schemas/sound/everest,es8316.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Everest ES8316 audio CODEC
+title: Everest ES8311 and ES8316 audio CODECs
 
 maintainers:
   - Daniel Drake <drake@endlessm.com>
   - Katsuhiro Suzuki <katsuhiro@katsuster.net>
+  - Matteo Martelli <matteomartelli3@gmail.com>
 
 allOf:
   - $ref: dai-common.yaml#
 
 properties:
   compatible:
-    const: everest,es8316
+    enum:
+      - everest,es8311
+      - everest,es8316
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml
deleted file mode 100644
index 5fc543d02ecb415ba9817117691cfa4ee7f6a4af..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml
+++ /dev/null
@@ -1,66 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/sound/fsl,imx-audio-spdif.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Freescale i.MX audio complex with S/PDIF transceiver
-
-maintainers:
-  - Shengjiu Wang <shengjiu.wang@nxp.com>
-
-properties:
-  compatible:
-    oneOf:
-      - items:
-          - enum:
-              - fsl,imx-sabreauto-spdif
-              - fsl,imx6sx-sdb-spdif
-          - const: fsl,imx-audio-spdif
-      - enum:
-          - fsl,imx-audio-spdif
-
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
-  spdif-controller:
-    $ref: /schemas/types.yaml#/definitions/phandle
-    description: The phandle of the i.MX S/PDIF controller
-
-  spdif-out:
-    type: boolean
-    description:
-      If present, the transmitting function of S/PDIF will be enabled,
-      indicating there's a physical S/PDIF out connector or jack on the
-      board or it's connecting to some other IP block, such as an HDMI
-      encoder or display-controller.
-
-  spdif-in:
-    type: boolean
-    description:
-      If present, the receiving function of S/PDIF will be enabled,
-      indicating there is a physical S/PDIF in connector/jack on the board.
-
-required:
-  - compatible
-  - model
-  - spdif-controller
-
-anyOf:
-  - required:
-      - spdif-in
-  - required:
-      - spdif-out
-
-additionalProperties: false
-
-examples:
-  - |
-    sound-spdif {
-        compatible = "fsl,imx-audio-spdif";
-        model = "imx-spdif";
-        spdif-controller = <&spdif>;
-        spdif-out;
-        spdif-in;
-    };
diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml
index 8b33353a80ca7e101f6e62fe4fa20fdff68d50d2..030ccc173130a4cc044ef0e335059fd164bda7ad 100644
--- a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml
@@ -23,6 +23,8 @@ properties:
       - fsl,imx8qm-mqs
       - fsl,imx8qxp-mqs
       - fsl,imx93-mqs
+      - fsl,imx95-aonmix-mqs
+      - fsl,imx95-netcmix-mqs
 
   clocks:
     minItems: 1
diff --git a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
index b522ed7dcc51bf33b832c092811fa2e8cdb9615e..a23e49198c3736bf0d53f2798c68dd11ed922ba1 100644
--- a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
@@ -12,7 +12,9 @@ maintainers:
 description: |
   The QMC audio is an ASoC component which uses QMC (QUICC Multichannel
   Controller) channels to transfer the audio data.
-  It provides as many DAI as the number of QMC channel used.
+  It provides several DAIs. For each DAI, the DAI is working in interleaved mode
+  if only one QMC channel is used by the DAI or it is working in non-interleaved
+  mode if several QMC channels are used by the DAI.
 
 allOf:
   - $ref: dai-common.yaml#
@@ -45,12 +47,19 @@ patternProperties:
       fsl,qmc-chan:
         $ref: /schemas/types.yaml#/definitions/phandle-array
         items:
-          - items:
-              - description: phandle to QMC node
-              - description: Channel number
+          items:
+            - description: phandle to QMC node
+            - description: Channel number
+        minItems: 1
         description:
-          Should be a phandle/number pair. The phandle to QMC node and the QMC
-          channel to use for this DAI.
+          Should be a phandle/number pair list. The list of phandle to QMC node
+          and the QMC channel pair to use for this DAI.
+          If only one phandle/number pair is provided, this DAI works in
+          interleaved mode, i.e. audio channels for this DAI are interleaved in
+          the QMC channel. If more than one pair is provided, this DAI works
+          in non-interleave mode. In that case the first audio channel uses the
+          the first QMC channel, the second audio channel uses the second QMC
+          channel, etc...
 
     required:
       - reg
@@ -79,6 +88,11 @@ examples:
             reg = <17>;
             fsl,qmc-chan = <&qmc 17>;
         };
+        dai@18 {
+            reg = <18>;
+            /* Non-interleaved mode */
+            fsl,qmc-chan = <&qmc 18>, <&qmc 19>;
+        };
     };
 
     sound {
@@ -115,4 +129,19 @@ examples:
                 dai-tdm-slot-rx-mask = <0 0 1 0 1 0 1 0 1>;
             };
         };
+        simple-audio-card,dai-link@2 {
+            reg = <2>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 18>;
+            };
+            codec {
+                sound-dai = <&codec3>;
+                dai-tdm-slot-num = <2>;
+                dai-tdm-slot-width = <8>;
+                /* TS 9, 10 */
+                dai-tdm-slot-tx-mask = <0 0 0 0 0 0 0 0 0 1 1>;
+                dai-tdm-slot-rx-mask = <0 0 0 0 0 0 0 0 0 1 1>;
+            };
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
index 188f38baddec31b0132cc9699d49d3288be2585b..3d5d435c765b4944af559474d4663e48cb764595 100644
--- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
@@ -29,6 +29,7 @@ properties:
       - fsl,imx8mp-rpmsg-audio
       - fsl,imx8ulp-rpmsg-audio
       - fsl,imx93-rpmsg-audio
+      - fsl,imx95-rpmsg-audio
 
   clocks:
     items:
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.yaml b/Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml
similarity index 97%
rename from Documentation/devicetree/bindings/sound/sgtl5000.yaml
rename to Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml
index 1353c051488faeb1d4417a206f17e8ebc8f8fbba..c6ab1ca16763ba1b6cf6e1a5b6cdb9d8d201a1fe 100644
--- a/Documentation/devicetree/bindings/sound/sgtl5000.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/sgtl5000.yaml#
+$id: http://devicetree.org/schemas/sound/fsl,sgtl5000.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Freescale SGTL5000 Stereo Codec
diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
index 0eb0c1ba8710dc14984c489696c2949cda680867..5e2801014221e07f80669b8dee44896062feca08 100644
--- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
@@ -22,6 +22,7 @@ properties:
     enum:
       - fsl,imx8mp-xcvr
       - fsl,imx93-xcvr
+      - fsl,imx95-xcvr
 
   reg:
     items:
@@ -41,6 +42,7 @@ properties:
     items:
       - description: WAKEUPMIX Audio XCVR Interrupt 1
       - description: WAKEUPMIX Audio XCVR Interrupt 2
+      - description: SPDIF wakeup interrupt from PHY
     minItems: 1
 
   clocks:
@@ -49,6 +51,9 @@ properties:
       - description: PHY clock
       - description: SPBA clock
       - description: PLL clock
+      - description: PLL clock source for 8kHz series
+      - description: PLL clock source for 11kHz series
+    minItems: 4
 
   clock-names:
     items:
@@ -56,6 +61,9 @@ properties:
       - const: phy
       - const: spba
       - const: pll_ipg
+      - const: pll8k
+      - const: pll11k
+    minItems: 4
 
   dmas:
     items:
@@ -79,15 +87,25 @@ required:
   - clock-names
   - dmas
   - dma-names
-  - resets
 
 allOf:
+  - $ref: dai-common.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: fsl,imx8mp-xcvr
+    then:
+      required:
+        - resets
+
   - if:
       properties:
         compatible:
           contains:
             enum:
               - fsl,imx93-xcvr
+              - fsl,imx95-xcvr
     then:
       properties:
         interrupts:
@@ -96,9 +114,24 @@ allOf:
     else:
       properties:
         interrupts:
-          maxItems: 1
+          minItems: 3
+          maxItems: 3
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8mp-xcvr
+              - fsl,imx93-xcvr
+    then:
+      properties:
+        clocks:
+          maxItems: 4
+        clock-names:
+          maxItems: 4
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -113,7 +146,9 @@ examples:
                  <0x30cc0c00 0x080>,
                  <0x30cc0e00 0x080>;
            reg-names = "ram", "regs", "rxfifo", "txfifo";
-           interrupts = <0x0 128 IRQ_TYPE_LEVEL_HIGH>;
+           interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                        <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+                        <GIC_SPI 146 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>,
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml b/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml
index 9922664d5cccaa50a5c0b79ab2a903f00fe4cdb5..92aa47ec72c7b78e3f44d84d1c059ed718ba6090 100644
--- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml
@@ -65,6 +65,11 @@ properties:
               - fsl,imx-audio-sgtl5000
               - fsl,imx-audio-wm8960
               - fsl,imx-audio-wm8962
+      - items:
+          - enum:
+              - fsl,imx-sabreauto-spdif
+              - fsl,imx6sx-sdb-spdif
+          - const: fsl,imx-audio-spdif
       - items:
           - enum:
               - fsl,imx-audio-ac97
@@ -81,6 +86,7 @@ properties:
               - fsl,imx-audio-wm8960
               - fsl,imx-audio-wm8962
               - fsl,imx-audio-wm8958
+              - fsl,imx-audio-spdif
 
   model:
     $ref: /schemas/types.yaml#/definitions/string
@@ -93,8 +99,15 @@ properties:
       need to add ASRC support via DPCM.
 
   audio-codec:
-    $ref: /schemas/types.yaml#/definitions/phandle
-    description: The phandle of an audio codec
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      The phandle of an audio codec.
+      With "fsl,imx-audio-spdif", either SPDIF audio codec spdif_transmitter,
+      spdif_receiver or both.
+    minItems: 1
+    maxItems: 2
+    items:
+      maxItems: 1
 
   audio-cpu:
     $ref: /schemas/types.yaml#/definitions/phandle
@@ -150,8 +163,10 @@ properties:
     description: dai-link uses bit clock inversion.
 
   mclk-id:
-    $ref: /schemas/types.yaml#/definitions/uint32
-    description: main clock id, specific for each card configuration.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Main clock id for each codec, specific for each card configuration.
+    minItems: 1
+    maxItems: 2
 
   mux-int-port:
     $ref: /schemas/types.yaml#/definitions/uint32
@@ -167,6 +182,27 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle
     description: The phandle of an CPU DAI controller
 
+  spdif-controller:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    deprecated: true
+    description: The phandle of an S/PDIF CPU DAI controller.
+
+  spdif-out:
+    type: boolean
+    deprecated: true
+    description: |
+      If present, the transmitting function of S/PDIF will be enabled,
+      indicating there's a physical S/PDIF out connector or jack on the
+      board or it's connecting to some other IP block, such as an HDMI
+      encoder or display-controller.
+
+  spdif-in:
+    type: boolean
+    deprecated: true
+    description: |
+      If present, the receiving function of S/PDIF will be enabled,
+      indicating there is a physical S/PDIF in connector/jack on the board.
+
 required:
   - compatible
   - model
@@ -195,3 +231,12 @@ examples:
              "AIN2L", "Line In Jack",
              "AIN2R", "Line In Jack";
     };
+
+  - |
+    sound-spdif-asrc {
+        compatible = "fsl,imx-audio-spdif";
+        model = "spdif-asrc-audio";
+        audio-cpu = <&spdif>;
+        audio-asrc = <&easrc>;
+        audio-codec = <&spdifdit>, <&spdifdir>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml b/Documentation/devicetree/bindings/sound/linux,spdif.yaml
similarity index 75%
rename from Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml
rename to Documentation/devicetree/bindings/sound/linux,spdif.yaml
index fe5f0756af2f461029b6bbb84cf402c1105d4abb..0f4893e11ec44b173f801431b0682d1767b79dc9 100644
--- a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml
+++ b/Documentation/devicetree/bindings/sound/linux,spdif.yaml
@@ -1,10 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/linux,spdif-dit.yaml#
+$id: http://devicetree.org/schemas/sound/linux,spdif.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Dummy SPDIF Transmitter
+title: Dummy SPDIF Transmitter/Receiver
 
 maintainers:
   - Mark Brown <broonie@kernel.org>
@@ -14,7 +14,9 @@ allOf:
 
 properties:
   compatible:
-    const: linux,spdif-dit
+    enum:
+      - linux,spdif-dit
+      - linux,spdif-dir
 
   "#sound-dai-cells":
     const: 0
diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.txt b/Documentation/devicetree/bindings/sound/maxim,max98088.txt
deleted file mode 100644
index da764d91331903d4985c73bb1e28edb793004436..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/maxim,max98088.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-MAX98088 audio CODEC
-
-This device supports I2C only.
-
-Required properties:
-
-- compatible: "maxim,max98088" or "maxim,max98089".
-- reg: The I2C address of the device.
-
-Optional properties:
-
-- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section
-  "consumer" for more information.
-- clock-names: must be set to "mclk"
-
-Example:
-
-max98089: codec@10 {
-	compatible = "maxim,max98089";
-	reg = <0x10>;
-	clocks = <&clks IMX6QDL_CLK_CKO2>;
-	clock-names = "mclk";
-};
diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.yaml b/Documentation/devicetree/bindings/sound/maxim,max98088.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e4a2967e1e8180d9a9980afc3e306aae7ec24a58
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/maxim,max98088.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/maxim,max98088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MAX98088 audio CODEC
+
+maintainers:
+  - Abdulrasaq Lawani <abdulrasaqolawani@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - maxim,max98088
+      - maxim,max98089
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: master clock
+
+  clock-names:
+    items:
+      - const: mclk
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        audio-codec@10 {
+            compatible = "maxim,max98089";
+            reg = <0x10>;
+            clocks = <&clks 0>;
+            clock-names = "mclk";
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/zl38060.yaml b/Documentation/devicetree/bindings/sound/mscc,zl38060.yaml
similarity index 96%
rename from Documentation/devicetree/bindings/sound/zl38060.yaml
rename to Documentation/devicetree/bindings/sound/mscc,zl38060.yaml
index 8bd201e573aa0d95c7eeffa48667e845f4193a88..994313fd12b27caf5302c5510251f44038f6c91c 100644
--- a/Documentation/devicetree/bindings/sound/zl38060.yaml
+++ b/Documentation/devicetree/bindings/sound/mscc,zl38060.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/zl38060.yaml#
+$id: http://devicetree.org/schemas/sound/mscc,zl38060.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: ZL38060 Connected Home Audio Processor from Microsemi.
diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml
index 3dbf438c38410e5979d48a4d9137acdb7f7d8a1c..232dc16a94a38f00b1d01d18f5b8910b65475a59 100644
--- a/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml
+++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml
@@ -23,6 +23,14 @@ properties:
   '#sound-dai-cells':
     const: 0
 
+  clocks:
+    items:
+      - description: The phandle of the master clock to the CODEC
+
+  clock-names:
+    items:
+      - const: mclk
+
   interrupts:
     maxItems: 1
 
diff --git a/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml b/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..40a0877a8aba8215ebc5c0d6c25c6a8f2d7c3b54
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nxp,lpc3220-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP LPC32XX I2S Controller
+
+description:
+  The I2S controller in LPC32XX SoCs, ASoC DAI.
+
+maintainers:
+  - J.M.B. Downing <jonathan.downing@nautel.com>
+  - Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - nxp,lpc3220-i2s
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: input clock of the peripheral.
+
+  dmas:
+    items:
+      - description: RX DMA Channel
+      - description: TX DMA Channel
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  "#sound-dai-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - dmas
+  - dma-names
+  - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/lpc32xx-clock.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2s@20094000 {
+      compatible = "nxp,lpc3220-i2s";
+      reg = <0x20094000 0x1000>;
+      interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&clk LPC32XX_CLK_I2S0>;
+      dmas = <&dma 0 1>, <&dma 13 1>;
+      dma-names = "rx", "tx";
+      #sound-dai-cells = <0>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
deleted file mode 100644
index ff98a0cb5b3f242d512fdcb1f80893e29cedbf91..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-* Texas Instruments OMAP4+ McPDM
-
-Required properties:
-- compatible: "ti,omap4-mcpdm"
-- reg: Register location and size as an array:
-       <MPU access base address, size>,
-       <L3 interconnect address, size>;
-- interrupts: Interrupt number for McPDM
-- ti,hwmods: Name of the hwmod associated to the McPDM
-- clocks:  phandle for the pdmclk provider, likely <&twl6040>
-- clock-names: Must be "pdmclk"
-
-Example:
-
-mcpdm: mcpdm@40132000 {
-	compatible = "ti,omap4-mcpdm";
-	reg = <0x40132000 0x7f>, /* MPU private access */
-	      <0x49032000 0x7f>; /* L3 Interconnect */
-	interrupts = <0 112 0x4>;
-	interrupt-parent = <&gic>;
-	ti,hwmods = "mcpdm";
-};
-
-In board DTS file the pdmclk needs to be added:
-
-&mcpdm {
-	clocks = <&twl6040>;
-	clock-names = "pdmclk";
-	status = "okay";
-};
diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt
index 77006a4aec4ad5c88f2f020a758c3f63328470f4..47878a6df60872bf7e789e70bccc1bc4041e490b 100644
--- a/Documentation/devicetree/bindings/sound/pcm512x.txt
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -6,7 +6,7 @@ on the board). The TAS575x devices only support I2C.
 Required properties:
 
   - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141",
-                 "ti,pcm5142", "ti,tas5754" or "ti,tas5756"
+                 "ti,pcm5142", "ti,pcm5242", "ti,tas5754" or "ti,tas5756"
 
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8096.txt b/Documentation/devicetree/bindings/sound/qcom,apq8096.txt
deleted file mode 100644
index e1b9fa8a5bf8f4e9e2bb6aee0b5aeba174751865..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/qcom,apq8096.txt
+++ /dev/null
@@ -1,128 +0,0 @@
-* Qualcomm Technologies APQ8096 ASoC sound card driver
-
-This binding describes the APQ8096 sound card, which uses qdsp for audio.
-
-- compatible:
-	Usage: required
-	Value type: <stringlist>
-	Definition: must be "qcom,apq8096-sndcard"
-
-- audio-routing:
-	Usage: Optional
-	Value type: <stringlist>
-	Definition:  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:
-		  Valid names include:
-
-		Board Connectors:
-			"Headphone Left"
-			"Headphone Right"
-			"Earphone"
-			"Line Out1"
-			"Line Out2"
-			"Line Out3"
-			"Line Out4"
-			"Analog Mic1"
-			"Analog Mic2"
-			"Analog Mic3"
-			"Analog Mic4"
-			"Analog Mic5"
-			"Analog Mic6"
-			"Digital Mic2"
-			"Digital Mic3"
-
-		Audio pins and MicBias on WCD9335 Codec:
-			"MIC_BIAS1"
-			"MIC_BIAS2"
-			"MIC_BIAS3"
-			"MIC_BIAS4"
-			"AMIC1"
-			"AMIC2"
-			"AMIC3"
-			"AMIC4"
-			"AMIC5"
-			"AMIC6"
-			"AMIC6"
-			"DMIC1"
-			"DMIC2"
-			"DMIC3"
-
-- model:
-	Usage: required
-	Value type: <stringlist>
-	Definition: The user-visible name of this sound card.
-
-- aux-devs
-	Usage: optional
-	Value type: <array of phandles>
-	Definition: A list of phandles for auxiliary devices (e.g. analog
-		    amplifiers) that do not appear directly within the DAI
-		    links. Should be connected to another audio component
-		    using "audio-routing".
-
-= dailinks
-Each subnode of sndcard represents either a dailink, and subnodes of each
-dailinks would be cpu/codec/platform dais.
-
-- link-name:
-	Usage: required
-	Value type: <string>
-	Definition: User friendly name for dai link
-
-= CPU, PLATFORM, CODEC dais subnodes
-- cpu:
-	Usage: required
-	Value type: <subnode>
-	Definition: cpu dai sub-node
-
-- codec:
-	Usage: Optional
-	Value type: <subnode>
-	Definition: codec dai sub-node
-
-- platform:
-	Usage: Optional
-	Value type: <subnode>
-	Definition: platform dai sub-node
-
-- sound-dai:
-	Usage: required
-	Value type: <phandle with arguments>
-	Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node.
-
-Obsolete:
-	qcom,model: String for soundcard name (Use model instead)
-	qcom,audio-routing: A list of the connections between audio components.
-			    (Use audio-routing instead)
-
-Example:
-
-audio {
-	compatible = "qcom,apq8096-sndcard";
-	model = "DB820c";
-
-	mm1-dai-link {
-		link-name = "MultiMedia1";
-		cpu {
-			sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
-		};
-	};
-
-	hdmi-dai-link {
-		link-name = "HDMI Playback";
-		cpu {
-			sound-dai = <&q6afe HDMI_RX>;
-		};
-
-		platform {
-			sound-dai = <&q6adm>;
-		};
-
-		codec {
-			sound-dai = <&hdmi 0>;
-		};
-	};
-};
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a899c4e7c1c9190b449c850ed2b6900ea2df45cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,msm8916-wcd-digital-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm MSM8916 WCD Digital Audio Codec
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+  The digital WCD audio codec found on Qualcomm MSM8916 LPASS.
+
+properties:
+  compatible:
+    const: qcom,msm8916-wcd-digital-codec
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: ahbix-clk
+      - const: mclk
+
+  '#sound-dai-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#sound-dai-cells'
+
+allOf:
+  - $ref: dai-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-msm8916.h>
+    audio-codec@771c000 {
+        compatible = "qcom,msm8916-wcd-digital-codec";
+        reg = <0x0771c000 0x400>;
+        clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>,
+                 <&gcc GCC_CODEC_DIGCODEC_CLK>;
+        clock-names = "ahbix-clk", "mclk";
+        #sound-dai-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt
deleted file mode 100644
index 1c8e4cb2517662f1eeff74ab5771e59200ae56d1..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-msm8916 digital audio CODEC
-
-## Bindings for codec core in lpass:
-
-Required properties
- - compatible = "qcom,msm8916-wcd-digital-codec";
- - reg: address space for lpass codec.
- - clocks: Handle to mclk and ahbclk
- - clock-names: should be "mclk", "ahbix-clk".
-
-Example:
-
-audio-codec@771c000{
-	compatible = "qcom,msm8916-wcd-digital-codec";
-	reg = <0x0771c000 0x400>;
-	clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>,
-		 <&gcc GCC_CODEC_DIGCODEC_CLK>;
-	clock-names = "ahbix-clk", "mclk";
-	#sound-dai-cells = <1>;
-};
diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
index b2e15ebbd1bc9864a1a23caff42b5c2e37e496fa..c9076dcd44c1168ea76212a5a420b3ac88380c6c 100644
--- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
@@ -28,6 +28,7 @@ properties:
           - const: qcom,sm8450-sndcard
       - enum:
           - qcom,apq8016-sbc-sndcard
+          - qcom,apq8096-sndcard
           - qcom,msm8916-qdsp6-sndcard
           - qcom,qcm6490-idp-sndcard
           - qcom,qcs6490-rb3gen2-sndcard
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d3cf8f59cb232617c9d3acbc7caa4dc31c4bb92f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd937x-sdw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SoundWire Slave devices on WCD9370/WCD9375
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description: |
+  Qualcomm WCD9370/WCD9375 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices. This bindings is for the
+  slave devices.
+
+properties:
+  compatible:
+    const: sdw20217010a00
+
+  reg:
+    maxItems: 1
+
+  qcom,tx-port-mapping:
+    description: |
+      Specifies static port mapping between device and host tx ports.
+      In the order of the device port index which are adc1_port, adc23_port,
+      dmic03_mbhc_port, dmic46_port.
+      Supports maximum 4 tx soundwire ports.
+
+      WCD9370 TX Port 1 (ADC1)               <=> SWR2 Port 2
+      WCD9370 TX Port 2 (ADC2, 3)            <=> SWR2 Port 2
+      WCD9370 TX Port 3 (DMIC0,1,2,3 & MBHC) <=> SWR2 Port 3
+      WCD9370 TX Port 4 (DMIC4,5,6,7)        <=> SWR2 Port 4
+
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 4
+    maxItems: 4
+    items:
+      enum: [1, 2, 3, 4]
+
+  qcom,rx-port-mapping:
+    description: |
+      Specifies static port mapping between device and host rx ports.
+      In the order of device port index which are hph_port, clsh_port,
+      comp_port, lo_port, dsd port.
+      Supports maximum 5 rx soundwire ports.
+
+      WCD9370 RX Port 1 (HPH_L/R)       <==>    SWR1 Port 1 (HPH_L/R)
+      WCD9370 RX Port 2 (CLSH)          <==>    SWR1 Port 2 (CLSH)
+      WCD9370 RX Port 3 (COMP_L/R)      <==>    SWR1 Port 3 (COMP_L/R)
+      WCD9370 RX Port 4 (LO)            <==>    SWR1 Port 4 (LO)
+      WCD9370 RX Port 5 (DSD_L/R)       <==>    SWR1 Port 5 (DSD)
+
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 5
+    maxItems: 5
+    items:
+      enum: [1, 2, 3, 4, 5]
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    soundwire@3210000 {
+        reg = <0x03210000 0x2000>;
+        #address-cells = <2>;
+        #size-cells = <0>;
+        wcd937x_rx: codec@0,4 {
+            compatible = "sdw20217010a00";
+            reg = <0 4>;
+            qcom,rx-port-mapping = <1 2 3 4 5>;
+        };
+    };
+
+    soundwire@3230000 {
+        reg = <0x03230000 0x2000>;
+        #address-cells = <2>;
+        #size-cells = <0>;
+        wcd937x_tx: codec@0,3 {
+            compatible = "sdw20217010a00";
+            reg = <0 3>;
+            qcom,tx-port-mapping = <2 2 3 4>;
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..de397d879acc2e6e95e740cd4a2139bc88ff4c98
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd937x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm WCD9370/WCD9375 Audio Codec
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+  Qualcomm WCD9370/WCD9375 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices.
+
+allOf:
+  - $ref: dai-common.yaml#
+  - $ref: qcom,wcd93xx-common.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: qcom,wcd9370-codec
+      - items:
+          - const: qcom,wcd9375-codec
+          - const: qcom,wcd9370-codec
+
+  vdd-px-supply:
+    description: A reference to the 1.8V I/O supply
+
+required:
+  - compatible
+  - vdd-px-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    codec {
+        compatible = "qcom,wcd9370-codec";
+        pinctrl-names = "default", "sleep";
+        pinctrl-0 = <&wcd_reset_n>;
+        pinctrl-1 = <&wcd_reset_n_sleep>;
+        reset-gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>;
+        vdd-buck-supply = <&vreg_l17b_1p8>;
+        vdd-rxtx-supply = <&vreg_l18b_1p8>;
+        vdd-px-supply = <&vreg_l18b_1p8>;
+        vdd-mic-bias-supply = <&vreg_bob>;
+        qcom,micbias1-microvolt = <1800000>;
+        qcom,micbias2-microvolt = <1800000>;
+        qcom,micbias3-microvolt = <1800000>;
+        qcom,micbias4-microvolt = <1800000>;
+        qcom,rx-device = <&wcd937x_rx>;
+        qcom,tx-device = <&wcd937x_tx>;
+        #sound-dai-cells = <1>;
+    };
+
+    /* ... */
+
+    soundwire@3210000 {
+        reg = <0x03210000 0x2000>;
+        #address-cells = <2>;
+        #size-cells = <0>;
+        wcd937x_rx: codec@0,4 {
+            compatible = "sdw20217010a00";
+            reg = <0 4>;
+            qcom,rx-port-mapping = <1 2 3 4 5>;
+        };
+    };
+
+    soundwire@3230000 {
+        reg = <0x03230000 0x2000>;
+        #address-cells = <2>;
+        #size-cells = <0>;
+        wcd937x_tx: codec@0,3 {
+            compatible = "sdw20217010a00";
+            reg = <0 3>;
+            qcom,tx-port-mapping = <1 2 3 4>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
index 8e462cdf0018f376b074ac188c8b7b142f167d22..14d312f9c345e643aa874a6e1f09c4f8040c272e 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
@@ -32,6 +32,14 @@ properties:
   vdd-supply:
     description: VDD Supply for the Codec
 
+  qcom,port-mapping:
+    description: |
+      Specifies static port mapping between slave and master ports.
+      In the order of slave port index.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 4
+    maxItems: 4
+
   '#thermal-sensor-cells':
     const: 0
 
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml
index 22798d22d981b270602882732dcd1e72d62c3023..83e0360301e1d2d1df717599a8111a8af1604ed0 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml
@@ -32,6 +32,14 @@ properties:
     description: Powerdown/Shutdown line to use (pin SD_N)
     maxItems: 1
 
+  qcom,port-mapping:
+    description: |
+      Specifies static port mapping between slave and master ports.
+      In the order of slave port index.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 6
+    maxItems: 6
+
   '#sound-dai-cells':
     const: 0
 
diff --git a/Documentation/devicetree/bindings/sound/rt1019.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1019.yaml
similarity index 90%
rename from Documentation/devicetree/bindings/sound/rt1019.yaml
rename to Documentation/devicetree/bindings/sound/realtek,rt1019.yaml
index 3d5a91a942f4798d1e2141f77f4d54a069537c6d..adf5e38f4dbc389cba1de36501edf4f04e5efd43 100644
--- a/Documentation/devicetree/bindings/sound/rt1019.yaml
+++ b/Documentation/devicetree/bindings/sound/realtek,rt1019.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/rt1019.yaml#
+$id: http://devicetree.org/schemas/sound/realtek,rt1019.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: RT1019 Mono Class-D Audio Amplifier
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5514.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5514.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7fbf7739c3719262defd2d37423d771848d1cef0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5514.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/realtek,rt5514.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RT5514 audio CODEC
+
+maintainers:
+  - Animesh Agarwal <animeshagarwal28@gmail.com>
+
+description: |
+  This device supports both I2C and SPI.
+
+  Pins on the device (for linking into audio routes) for I2C:
+    * DMIC1L
+    * DMIC1R
+    * DMIC2L
+    * DMIC2R
+    * AMICL
+    * AMICR
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: realtek,rt5514
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Master clock to the CODEC
+
+  clock-names:
+    items:
+      - const: mclk
+
+  interrupts:
+    maxItems: 1
+    description: The interrupt number to the cpu.
+
+  realtek,dmic-init-delay-ms:
+    description: Set the DMIC initial delay (ms) to wait it ready for I2C.
+
+  spi-max-frequency: true
+
+  wakeup-source:
+    type: boolean
+    description: Flag to indicate this device can wake system (suspend/resume).
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        codec@57 {
+            compatible = "realtek,rt5514";
+            reg = <0x57>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5631.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5631.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..747a731c44c99d88e7634caf68e0677709b8f9fc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5631.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/realtek,rt5631.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ALC5631/RT5631 audio CODEC
+
+maintainers:
+  - Animesh Agarwal <animeshagarwal28@gmail.com>
+
+description: |
+  This device supports I2C only.
+
+  Pins on the device (for linking into audio routes):
+      * SPK_OUT_R_P
+      * SPK_OUT_R_N
+      * SPK_OUT_L_P
+      * SPK_OUT_L_N
+      * HP_OUT_L
+      * HP_OUT_R
+      * AUX_OUT2_LP
+      * AUX_OUT2_RN
+      * AUX_OUT1_LP
+      * AUX_OUT1_RN
+      * AUX_IN_L_JD
+      * AUX_IN_R_JD
+      * MONO_IN_P
+      * MONO_IN_N
+      * MIC1_P
+      * MIC1_N
+      * MIC2_P
+      * MIC2_N
+      * MONO_OUT_P
+      * MONO_OUT_N
+      * MICBIAS1
+      * MICBIAS2
+
+properties:
+  compatible:
+    enum:
+      - realtek,alc5631
+      - realtek,rt5631
+
+  reg:
+    maxItems: 1
+
+  port:
+    $ref: audio-graph-port.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        codec@1a {
+            compatible = "realtek,alc5631";
+            reg = <0x1a>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5645.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5645.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..13f09f1bc8003a7bb048bcc6253f755849de0b8a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5645.yaml
@@ -0,0 +1,131 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/realtek,rt5645.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RT5650/RT5645 audio CODEC
+
+maintainers:
+  - Animesh Agarwal <animeshagarwal28@gmail.com>
+
+description: |
+  This device supports I2C only.
+
+  Pins on the device (for linking into audio routes) for RT5645/RT5650:
+    * DMIC L1
+    * DMIC R1
+    * DMIC L2
+    * DMIC R2
+    * IN1P
+    * IN1N
+    * IN2P
+    * IN2N
+    * Haptic Generator
+    * HPOL
+    * HPOR
+    * LOUTL
+    * LOUTR
+    * PDM1L
+    * PDM1R
+    * SPOL
+    * SPOR
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - realtek,rt5645
+      - realtek,rt5650
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+    description: The CODEC's interrupt output.
+
+  avdd-supply:
+    description: Power supply for AVDD, providing 1.8V.
+
+  cpvdd-supply:
+    description: Power supply for CPVDD, providing 3.5V.
+
+  hp-detect-gpios:
+    description: 
+      A GPIO spec for the external headphone detect pin. If jd-mode = 0, we
+      will get the JD status by getting the value of hp-detect-gpios.
+    maxItems: 1
+
+  cbj-sleeve-gpios:
+    description:
+      A GPIO spec to control the external combo jack circuit to tie the
+      sleeve/ring2 contacts to the ground or floating. It could avoid some
+      electric noise from the active speaker jacks.
+    maxItems: 1
+
+  realtek,in2-differential:
+    description:
+      Indicate MIC2 input are differential, rather than single-ended.
+    type: boolean
+
+  realtek,dmic1-data-pin:
+    description: Specify which pin to be used as DMIC1 data pin.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # dmic1 is not used
+      - 1 # using IN2P pin as dmic1 data pin
+      - 2 # using GPIO6 pin as dmic1 data pin
+      - 3 # using GPIO10 pin as dmic1 data pin
+      - 4 # using GPIO12 pin as dmic1 data pin
+
+  realtek,dmic2-data-pin:
+    description: Specify which pin to be used as DMIC2 data pin.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # dmic2 is not used
+      - 1 # using IN2N pin as dmic2 data pin
+      - 2 # using GPIO5 pin as dmic2 data pin
+      - 3 # using GPIO11 pin as dmic2 data pin
+
+  realtek,jd-mode:
+    description: The JD mode of rt5645/rt5650.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # rt5645/rt5650 JD function is not used
+      - 1 # Mode-0 (VDD=3.3V), two port jack detection
+      - 2 # Mode-1 (VDD=3.3V), one port jack detection
+      - 3 # Mode-2 (VDD=1.8V), one port jack detection
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - avdd-supply
+  - cpvdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        codec@1a {
+            compatible = "realtek,rt5650";
+            reg = <0x1a>;
+            hp-detect-gpios = <&gpio 19 0>;
+            cbj-sleeve-gpios = <&gpio 20 0>;
+            interrupt-parent = <&gpio>;
+            interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+            avdd-supply = <&avdd_reg>;
+            cpvdd-supply = <&cpvdd_supply>;
+            realtek,jd-mode = <3>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5659.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5659.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1100ffd9a7c0f821a5fe003d6ac748327b8ce4a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5659.yaml
@@ -0,0 +1,129 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/realtek,rt5659.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RT5659/RT5658 audio CODEC
+
+maintainers:
+  - Animesh Agarwal <animeshagarwal28@gmail.com>
+
+description: |
+  This device supports I2C only.
+
+  Pins on the device (for linking into audio routes) for RT5659/RT5658:
+    * DMIC L1
+    * DMIC R1
+    * DMIC L2
+    * DMIC R2
+    * IN1P
+    * IN1N
+    * IN2P
+    * IN2N
+    * IN3P
+    * IN3N
+    * IN4P
+    * IN4N
+    * HPOL
+    * HPOR
+    * SPOL
+    * SPOR
+    * LOUTL
+    * LOUTR
+    * MONOOUT
+    * PDML
+    * PDMR
+    * SPDIF
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - realtek,rt5659
+      - realtek,rt5658
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: mclk
+
+  realtek,dmic1-data-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # dmic1 is not used
+      - 1 # using IN2N pin as dmic1 data pin
+      - 2 # using GPIO5 pin as dmic1 data pin
+      - 3 # using GPIO9 pin as dmic1 data pin
+      - 4 # using GPIO11 pin as dmic1 data pin
+    description: Specify which pin to be used as DMIC1 data pin.
+    default: 0
+
+  realtek,dmic2-data-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # dmic2 is not used
+      - 1 # using IN2P pin as dmic2 data pin
+      - 2 # using GPIO6 pin as dmic2 data pin
+      - 3 # using GPIO10 pin as dmic2 data pin
+      - 4 # using GPIO12 pin as dmic2 data pin
+    description: Specify which pin to be used as DMIC2 data pin.
+    default: 0
+
+  realtek,jd-src:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # No JD is used
+      - 1 # using JD3 as JD source
+      - 2 # JD source for Intel HDA header
+    description: Specify which JD source be used.
+    default: 0
+
+  realtek,ldo1-en-gpios:
+    maxItems: 1
+    description: CODEC's LDO1_EN pin.
+
+  realtek,reset-gpios:
+    maxItems: 1
+    description: CODEC's RESET pin.
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+  port:
+    $ref: audio-graph-port.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        codec@1b {
+            compatible = "realtek,rt5659";
+            reg = <0x1b>;
+            interrupt-parent = <&gpio>;
+            interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
+            realtek,ldo1-en-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9ce23e58e5ea1bd125d0800feb8a5e5924c10487
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml
@@ -0,0 +1,135 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/realtek,rt5677.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RT5677 audio CODEC
+
+maintainers:
+  - Animesh Agarwal <animeshagarwal28@gmail.com>
+
+description: |
+  This device supports I2C only.
+
+  Pins on the device (for linking into audio routes):
+    * IN1P
+    * IN1N
+    * IN2P
+    * IN2N
+    * MICBIAS1
+    * DMIC1
+    * DMIC2
+    * DMIC3
+    * DMIC4
+    * LOUT1
+    * LOUT2
+    * LOUT3
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: realtek,rt5677
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 2
+
+  realtek,pow-ldo2-gpio:
+    maxItems: 1
+    description: CODEC's POW_LDO2 pin.
+
+  realtek,reset-gpio:
+    maxItems: 1
+    description: CODEC's RESET pin. Active low.
+
+  realtek,gpio-config:
+    description: |
+      Array of six 8bit elements that configures GPIO.
+      0 - floating (reset value)
+      1 - pull down
+      2 - pull up
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 6
+    maxItems: 6
+    items:
+      maximum: 2
+
+  realtek,jd1-gpio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # OFF
+      - 1 # GPIO1 for jd1.
+      - 2 # GPIO2 for jd1.
+      - 3 # GPIO3 for jd1.
+    description: Configures GPIO Mic Jack detection 1.
+
+  realtek,jd2-gpio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # OFF
+      - 1 # GPIO4 for jd2.
+      - 2 # GPIO5 for jd2.
+      - 3 # GPIO6 for jd2.
+    description: Configures GPIO Mic Jack detection 2.
+
+  realtek,jd3-gpio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # OFF
+      - 1 # GPIO4 for jd3.
+      - 2 # GPIO5 for jd3.
+      - 3 # GPIO6 for jd3.
+    description: Configures GPIO Mic Jack detection 3.
+
+patternProperties:
+  '^realtek,in[1-2]-differential$':
+    type: boolean
+    description: Indicate MIC1/2 input are differential, rather than
+      single-ended.
+
+  '^realtek,lout[1-3]-differential$':
+    type: boolean
+    description: Indicate LOUT1/2/3 outputs are differential, rather than
+      single-ended.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - gpio-controller
+  - '#gpio-cells'
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        codec@2c {
+            compatible = "realtek,rt5677";
+            reg = <0x2c>;
+            interrupt-parent = <&gpio>;
+            interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
+            gpio-controller;
+            #gpio-cells = <2>;
+            realtek,pow-ldo2-gpio = <&gpio 3 GPIO_ACTIVE_HIGH>;
+            realtek,reset-gpio = <&gpio 3 GPIO_ACTIVE_LOW>;
+            realtek,in1-differential;
+            realtek,gpio-config = <0 0 0 0 0 2>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/rt5514.txt b/Documentation/devicetree/bindings/sound/rt5514.txt
deleted file mode 100644
index d2cc171f22f2aedd918ad75df8bb2ca6daa51bd4..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/rt5514.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-RT5514 audio CODEC
-
-This device supports both I2C and SPI.
-
-Required properties:
-
-- compatible : "realtek,rt5514".
-
-- reg : the I2C address of the device for I2C, the chip select
-        number for SPI.
-
-Optional properties:
-
-- clocks: The phandle of the master clock to the CODEC
-- clock-names: Should be "mclk"
-
-- interrupts: The interrupt number to the cpu. The interrupt specifier format
-	      depends on the interrupt controller.
-
-- realtek,dmic-init-delay-ms
-  Set the DMIC initial delay (ms) to wait it ready for I2C.
-
-Pins on the device (for linking into audio routes) for I2C:
-
-  * DMIC1L
-  * DMIC1R
-  * DMIC2L
-  * DMIC2R
-  * AMICL
-  * AMICR
-
-Example:
-
-rt5514: codec@57 {
-	compatible = "realtek,rt5514";
-	reg = <0x57>;
-};
diff --git a/Documentation/devicetree/bindings/sound/rt5631.txt b/Documentation/devicetree/bindings/sound/rt5631.txt
deleted file mode 100644
index 56bc85232c49d79dd7579c32c25976fc49364fda..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/rt5631.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-ALC5631/RT5631 audio CODEC
-
-This device supports I2C only.
-
-Required properties:
-
-  - compatible : "realtek,alc5631" or "realtek,rt5631"
-
-  - reg : the I2C address of the device.
-
-Pins on the device (for linking into audio routes):
-
-  * SPK_OUT_R_P
-  * SPK_OUT_R_N
-  * SPK_OUT_L_P
-  * SPK_OUT_L_N
-  * HP_OUT_L
-  * HP_OUT_R
-  * AUX_OUT2_LP
-  * AUX_OUT2_RN
-  * AUX_OUT1_LP
-  * AUX_OUT1_RN
-  * AUX_IN_L_JD
-  * AUX_IN_R_JD
-  * MONO_IN_P
-  * MONO_IN_N
-  * MIC1_P
-  * MIC1_N
-  * MIC2_P
-  * MIC2_N
-  * MONO_OUT_P
-  * MONO_OUT_N
-  * MICBIAS1
-  * MICBIAS2
-
-Example:
-
-alc5631: audio-codec@1a {
-	compatible = "realtek,alc5631";
-	reg = <0x1a>;
-};
-
-or
-
-rt5631: audio-codec@1a {
-	compatible = "realtek,rt5631";
-	reg = <0x1a>;
-};
diff --git a/Documentation/devicetree/bindings/sound/rt5645.txt b/Documentation/devicetree/bindings/sound/rt5645.txt
deleted file mode 100644
index c1fa379f5f3ea1388ed9e54ea8fef66d4645d673..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/rt5645.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-RT5650/RT5645 audio CODEC
-
-This device supports I2C only.
-
-Required properties:
-
-- compatible : One of "realtek,rt5645" or "realtek,rt5650".
-
-- reg : The I2C address of the device.
-
-- interrupts : The CODEC's interrupt output.
-
-- avdd-supply: Power supply for AVDD, providing 1.8V.
-
-- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
-
-Optional properties:
-
-- hp-detect-gpios:
-  a GPIO spec for the external headphone detect pin. If jd-mode = 0,
-  we will get the JD status by getting the value of hp-detect-gpios.
-
-- cbj-sleeve-gpios:
-  a GPIO spec to control the external combo jack circuit to tie the sleeve/ring2
-  contacts to the ground or floating. It could avoid some electric noise from the
-  active speaker jacks.
-
-- realtek,in2-differential
-  Boolean. Indicate MIC2 input are differential, rather than single-ended.
-
-- realtek,dmic1-data-pin
-  0: dmic1 is not used
-  1: using IN2P pin as dmic1 data pin
-  2: using GPIO6 pin as dmic1 data pin
-  3: using GPIO10 pin as dmic1 data pin
-  4: using GPIO12 pin as dmic1 data pin
-
-- realtek,dmic2-data-pin
-  0: dmic2 is not used
-  1: using IN2N pin as dmic2 data pin
-  2: using GPIO5 pin as dmic2 data pin
-  3: using GPIO11 pin as dmic2 data pin
-
--- realtek,jd-mode : The JD mode of rt5645/rt5650
-   0 : rt5645/rt5650 JD function is not used
-   1 : Mode-0 (VDD=3.3V), two port jack detection
-   2 : Mode-1 (VDD=3.3V), one port jack detection
-   3 : Mode-2 (VDD=1.8V), one port jack detection
-
-Pins on the device (for linking into audio routes) for RT5645/RT5650:
-
-  * DMIC L1
-  * DMIC R1
-  * DMIC L2
-  * DMIC R2
-  * IN1P
-  * IN1N
-  * IN2P
-  * IN2N
-  * Haptic Generator
-  * HPOL
-  * HPOR
-  * LOUTL
-  * LOUTR
-  * PDM1L
-  * PDM1R
-  * SPOL
-  * SPOR
-
-Example:
-
-codec: rt5650@1a {
-	compatible = "realtek,rt5650";
-	reg = <0x1a>;
-	hp-detect-gpios = <&gpio 19 0>;
-	cbj-sleeve-gpios = <&gpio 20 0>;
-	interrupt-parent = <&gpio>;
-	interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
-	realtek,dmic-en = "true";
-	realtek,en-jd-func = "true";
-	realtek,jd-mode = <3>;
-};
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
deleted file mode 100644
index 8f3f62c0226a845bd2b617a3fe3766eadc068f2c..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/rt5659.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-RT5659/RT5658 audio CODEC
-
-This device supports I2C only.
-
-Required properties:
-
-- compatible : One of "realtek,rt5659" or "realtek,rt5658".
-
-- reg : The I2C address of the device.
-
-- interrupts : The CODEC's interrupt output.
-
-Optional properties:
-
-- clocks: The phandle of the master clock to the CODEC
-- clock-names: Should be "mclk"
-
-- realtek,in1-differential
-- realtek,in3-differential
-- realtek,in4-differential
-  Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended.
-
-- realtek,dmic1-data-pin
-  0: dmic1 is not used
-  1: using IN2N pin as dmic1 data pin
-  2: using GPIO5 pin as dmic1 data pin
-  3: using GPIO9 pin as dmic1 data pin
-  4: using GPIO11 pin as dmic1 data pin
-
-- realtek,dmic2-data-pin
-  0: dmic2 is not used
-  1: using IN2P pin as dmic2 data pin
-  2: using GPIO6 pin as dmic2 data pin
-  3: using GPIO10 pin as dmic2 data pin
-  4: using GPIO12 pin as dmic2 data pin
-
-- realtek,jd-src
-  0: No JD is used
-  1: using JD3 as JD source
-  2: JD source for Intel HDA header
-
-- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
-- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin.
-
-- sound-name-prefix: Please refer to dai-common.yaml
-
-- ports: A Codec may have a single or multiple I2S interfaces. These
-  interfaces on Codec side can be described under 'ports' or 'port'.
-  When the SoC or host device is connected to multiple interfaces of
-  the Codec, the connectivity can be described using 'ports' property.
-  If a single interface is used, then 'port' can be used. The usage
-  depends on the platform or board design.
-  Please refer to Documentation/devicetree/bindings/graph.txt
-
-Pins on the device (for linking into audio routes) for RT5659/RT5658:
-
-  * DMIC L1
-  * DMIC R1
-  * DMIC L2
-  * DMIC R2
-  * IN1P
-  * IN1N
-  * IN2P
-  * IN2N
-  * IN3P
-  * IN3N
-  * IN4P
-  * IN4N
-  * HPOL
-  * HPOR
-  * SPOL
-  * SPOR
-  * LOUTL
-  * LOUTR
-  * MONOOUT
-  * PDML
-  * PDMR
-  * SPDIF
-
-Example:
-
-rt5659 {
-	compatible = "realtek,rt5659";
-	reg = <0x1b>;
-	interrupt-parent = <&gpio>;
-	interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_HIGH>;
-	realtek,ldo1-en-gpios =
-		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
-};
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
deleted file mode 100644
index da2430099181262b46607b921d141cc20ae48036..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/rt5677.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-RT5677 audio CODEC
-
-This device supports I2C only.
-
-Required properties:
-
-- compatible : "realtek,rt5677".
-
-- reg : The I2C address of the device.
-
-- interrupts : The CODEC's interrupt output.
-
-- gpio-controller : Indicates this device is a GPIO controller.
-
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
-
-Optional properties:
-
-- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
-- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low.
-
-- realtek,in1-differential
-- realtek,in2-differential
-- realtek,lout1-differential
-- realtek,lout2-differential
-- realtek,lout3-differential
-  Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
-  rather than single-ended.
-
-- realtek,gpio-config
-  Array of six 8bit elements that configures GPIO.
-    0 - floating (reset value)
-    1 - pull down
-    2 - pull up
-
-- realtek,jd1-gpio
-  Configures GPIO Mic Jack detection 1.
-  Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively.
-
-- realtek,jd2-gpio
-- realtek,jd3-gpio
-  Configures GPIO Mic Jack detection 2 and 3.
-  Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively.
-
-Pins on the device (for linking into audio routes):
-
-  * IN1P
-  * IN1N
-  * IN2P
-  * IN2N
-  * MICBIAS1
-  * DMIC1
-  * DMIC2
-  * DMIC3
-  * DMIC4
-  * LOUT1
-  * LOUT2
-  * LOUT3
-
-Example:
-
-rt5677 {
-	compatible = "realtek,rt5677";
-	reg = <0x2c>;
-	interrupt-parent = <&gpio>;
-	interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_HIGH>;
-
-	gpio-controller;
-	#gpio-cells = <2>;
-
-	realtek,pow-ldo2-gpio =
-		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
-	realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
-	realtek,in1-differential = "true";
-	realtek,gpio-config = /bits/ 8  <0 0 0 0 0 2>;   /* pull up GPIO6 */
-	realtek,jd2-gpio = <3>;  /* Enables Jack detection for GPIO6 */
-};
diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml
index 6ec80f529d84778449b4a0a576be4b6f8a6fdd6a..69ddfd4afdcdf2cc62e294da3f65eadf109d3a94 100644
--- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml
+++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml
@@ -53,6 +53,9 @@ properties:
   submic-bias-supply:
     description: Supply for the micbias on the Sub microphone
 
+  headset-mic-bias-supply:
+    description: Supply for the micbias on the Headset microphone
+
   fm-sel-gpios:
     maxItems: 1
     description: GPIO pin for FM selection
@@ -61,6 +64,36 @@ properties:
     maxItems: 1
     description: GPIO pin for line out selection
 
+  headset-detect-gpios:
+    maxItems: 1
+    description: GPIO for detection of headset insertion
+
+  headset-key-gpios:
+    maxItems: 1
+    description: GPIO for detection of headset key press
+
+  io-channels:
+    maxItems: 1
+    description: IO channel to read micbias voltage for headset detection
+
+  io-channel-names:
+    const: headset-detect
+
+  samsung,headset-4pole-threshold-microvolt:
+    minItems: 2
+    maxItems: 2
+    description:
+      Array containing minimum and maximum IO channel value for 4-pole
+      (with microphone/button) headsets. If the IO channel value is
+      outside of this range, a 3-pole headset is assumed.
+
+  samsung,headset-button-threshold-microvolt:
+    minItems: 3
+    maxItems: 3
+    description: |
+      Array of minimum (inclusive) IO channel values for headset button
+      detection, in order: "Media", "Volume Up" and "Volume Down".
+
 required:
   - compatible
   - cpu
diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
index 9f319caf3db7494a4739393f43dd6af02d581d32..194ac1d4f4f5f40a9bc44e8cd0acbf2eab708365 100644
--- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml
@@ -24,6 +24,11 @@ properties:
     description: |
       GPIOs used to select the input line.
 
+  state-labels:
+    description: State of input line. default is "Input 1", "Input 2"
+    $ref: /schemas/types.yaml#/definitions/string-array
+    maxItems: 2
+
   sound-name-prefix: true
 
 required:
@@ -37,4 +42,5 @@ examples:
     mux {
         compatible = "simple-audio-mux";
         mux-gpios = <&gpio 3 0>;
+        state-labels = "Label_A", "Label_B";
     };
diff --git a/Documentation/devicetree/bindings/sound/spdif-receiver.txt b/Documentation/devicetree/bindings/sound/spdif-receiver.txt
deleted file mode 100644
index 80f807bf8a1d1f068b0e19c187b79b6fa5365bd3..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/spdif-receiver.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Device-Tree bindings for dummy spdif receiver
-
-Required properties:
-	- compatible: should be "linux,spdif-dir".
-
-Example node:
-
-	codec: spdif-receiver {
-		compatible = "linux,spdif-dir";
-	};
diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt
deleted file mode 100644
index 1addc75989d56744caabecf37c5b3f43f2d7792c..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/tas571x.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers
-
-The codec is controlled through an I2C interface.  It also has two other
-signals that can be wired up to GPIOs: reset (strongly recommended), and
-powerdown (optional).
-
-Required properties:
-
-- compatible: should be one of the following:
-  - "ti,tas5707"
-  - "ti,tas5711",
-  - "ti,tas5717",
-  - "ti,tas5719",
-  - "ti,tas5721"
-  - "ti,tas5733"
-- reg: The I2C address of the device
-- #sound-dai-cells: must be equal to 0
-
-Optional properties:
-
-- reset-gpios: GPIO specifier for the TAS571x's active low reset line
-- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line
-- clocks: clock phandle for the MCLK input
-- clock-names: should be "mclk"
-- AVDD-supply: regulator phandle for the AVDD supply (all chips)
-- DVDD-supply: regulator phandle for the DVDD supply (all chips)
-- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719)
-- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719)
-- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719)
-- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711)
-- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
-- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
-- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
-- DRVDD-supply: regulator phandle for the DRVDD supply (5721)
-- PVDD-supply: regulator phandle for the PVDD supply (5721)
-
-Example:
-
-	tas5717: audio-codec@2a {
-		compatible = "ti,tas5717";
-		reg = <0x2a>;
-		#sound-dai-cells = <0>;
-
-		reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
-		pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
-
-		clocks = <&clk_core CLK_I2S>;
-		clock-names = "mclk";
-	};
diff --git a/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml b/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cdea0a00826a1b42cc803a77453853d0dba528c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,omap4-mcpdm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OMAP McPDM
+
+maintainers:
+  - Misael Lopez Cruz <misael.lopez@ti.com>
+
+description:
+  OMAP ALSA SoC DAI driver using McPDM port used by TWL6040
+
+properties:
+  compatible:
+    const: ti,omap4-mcpdm
+
+  reg:
+    items:
+      - description: MPU access base address
+      - description: L3 interconnect address
+
+  reg-names:
+    items:
+      - const: mpu
+      - const: dma
+
+  interrupts:
+    maxItems: 1
+
+  dmas:
+    maxItems: 2
+
+  dma-names:
+    items:
+      - const: up_link
+      - const: dn_link
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: pdmclk
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - dmas
+  - dma-names
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    mcpdm@0 {
+      compatible = "ti,omap4-mcpdm";
+      reg = <0x0 0x7f>, /* MPU private access */
+            <0x49032000 0x7f>; /* L3 Interconnect */
+      reg-names = "mpu", "dma";
+      interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-parent = <&gic>;
+      dmas = <&sdma 65>, <&sdma 66>;
+      dma-names = "up_link", "dn_link";
+      clocks = <&twl6040>;
+      clock-names = "pdmclk";
+    };
diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/ti,tas2562.yaml
similarity index 97%
rename from Documentation/devicetree/bindings/sound/tas2562.yaml
rename to Documentation/devicetree/bindings/sound/ti,tas2562.yaml
index d28c102c0ce7f0fe94577e45b54daa7496331e7f..8bc3b0c7531e0af1a0b1e273e525cc99f721b18b 100644
--- a/Documentation/devicetree/bindings/sound/tas2562.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas2562.yaml
@@ -2,7 +2,7 @@
 # Copyright (C) 2019 Texas Instruments Incorporated
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/tas2562.yaml#
+$id: http://devicetree.org/schemas/sound/ti,tas2562.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Texas Instruments TAS2562 Smart PA
diff --git a/Documentation/devicetree/bindings/sound/tas2770.yaml b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml
similarity index 97%
rename from Documentation/devicetree/bindings/sound/tas2770.yaml
rename to Documentation/devicetree/bindings/sound/ti,tas2770.yaml
index be2536e8c4403a84a67a02212dcb118ac489fabf..362c2e6154f0ec187ef0247906d67a1ee2e6edbf 100644
--- a/Documentation/devicetree/bindings/sound/tas2770.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml
@@ -2,7 +2,7 @@
 # Copyright (C) 2019-20 Texas Instruments Incorporated
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/tas2770.yaml#
+$id: http://devicetree.org/schemas/sound/ti,tas2770.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Texas Instruments TAS2770 Smart PA
diff --git a/Documentation/devicetree/bindings/sound/tas27xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas27xx.yaml
similarity index 97%
rename from Documentation/devicetree/bindings/sound/tas27xx.yaml
rename to Documentation/devicetree/bindings/sound/ti,tas27xx.yaml
index f2d878f6f4959c3be4e8295836eeb0ca88e701cd..530bc3937847ff26140399c54869c8cc209d832c 100644
--- a/Documentation/devicetree/bindings/sound/tas27xx.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas27xx.yaml
@@ -2,7 +2,7 @@
 # Copyright (C) 2020-2022 Texas Instruments Incorporated
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/tas27xx.yaml#
+$id: http://devicetree.org/schemas/sound/ti,tas27xx.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Texas Instruments TAS2764/TAS2780 Smart PA
diff --git a/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2f917238db95360916063b7a5b41c026262384d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,tas57xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+
+properties:
+  compatible:
+    enum:
+      - ti,tas5707
+      - ti,tas5711
+      - ti,tas5717
+      - ti,tas5719
+      - ti,tas5721
+      - ti,tas5733
+
+  reg:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO for the active low reset line
+
+  pdn-gpios:
+    maxItems: 1
+    description: GPIO for the active low powerdown line
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: mclk
+
+  AVDD-supply: true
+  DVDD-supply: true
+  HPVDD-supply: true
+  PVDD_AB-supply: true
+  PVDD_CD-supply: true
+  PVDD_A-supply: true
+  PVDD_B-supply: true
+  PVDD_C-supply: true
+  PVDD_D-supply: true
+  DRVDD-supply: true
+  PVDD-supply: true
+
+  '#sound-dai-cells':
+    const: 0
+
+  port:
+    $ref: audio-graph-port.yaml#
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - '#sound-dai-cells'
+
+allOf:
+  - $ref: dai-common.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - ti,tas5717
+              - ti,tas5719
+    then:
+      properties:
+        PVDD_A-supply: false
+        PVDD_B-supply: false
+        PVDD_C-supply: false
+        PVDD_D-supply: false
+        DRVDD-supply: false
+        PVDD-supply: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - ti,tas5711
+    then:
+      properties:
+        HPVDD-supply: false
+        PVDD_AB-supply: false
+        PVDD_CD-supply: false
+        DRVDD-supply: false
+        PVDD-supply: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - ti,tas5721
+    then:
+      properties:
+        HPVDD-supply: false
+        PVDD_AB-supply: false
+        PVDD_CD-supply: false
+        PVDD_A-supply: false
+        PVDD_B-supply: false
+        PVDD_C-supply: false
+        PVDD_D-supply: false
+
+unevaluatedProperties: false
+
+examples:
+  - |
+   i2c {
+     #address-cells = <1>;
+     #size-cells = <0>;
+
+     codec@2a {
+       compatible = "ti,tas5717";
+       reg = <0x2a>;
+       #sound-dai-cells = <0>;
+       reset-gpios = <&gpio1 15 0>;
+       pdn-gpios = <&gpio1 15 0>;
+       AVDD-supply = <&avdd_supply>;
+       DVDD-supply = <&dvdd_supply>;
+       HPVDD-supply = <&hpvdd_supply>;
+       PVDD_AB-supply = <&pvdd_ab_supply>;
+       PVDD_CD-supply = <&pvdd_cd_supply>;
+     };
+   };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/tas5805m.yaml b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml
similarity index 95%
rename from Documentation/devicetree/bindings/sound/tas5805m.yaml
rename to Documentation/devicetree/bindings/sound/ti,tas5805m.yaml
index 12c41974274e7f52752956fb34c1278d2a392722..c2c2835a9e1dbd8c684d1bdd676da5b0e36a81e3 100644
--- a/Documentation/devicetree/bindings/sound/tas5805m.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/tas5805m.yaml#
+$id: http://devicetree.org/schemas/sound/ti,tas5805m.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: TAS5805M audio amplifier
diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml
index ede14ca2c07a1227bd158c7c737aef7695385fff..66b76656229fccc3c9eb319313470a7ec61270b8 100644
--- a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml
@@ -58,8 +58,8 @@ properties:
     description: |
       Configuration for DMDIN/GPIO1 pin.
 
-      When ADC3XXX_GPIO_GPO is configured, this causes corresponding the
-      ALSA control "GPIOx Output" to appear, as a switch control.
+      When ADC3XXX_GPIO_GPO is selected, the pin may be controlled via the
+      GPIO framework, as pin number 0 on the device.
 
   ti,dmclk-gpio2:
     $ref: /schemas/types.yaml#/definitions/uint32
@@ -76,12 +76,32 @@ properties:
     description: |
       Configuration for DMCLK/GPIO2 pin.
 
-      When ADC3XXX_GPIO_GPO is configured, this causes corresponding the
-      ALSA control "GPIOx Output" to appear, as a switch control.
+      When ADC3XXX_GPIO_GPO is selected, the pin may be controlled via the
+      GPIO framework, as pin number 1 on the device.
 
       Note that there is currently no support for reading the GPIO pins as
       inputs.
 
+  ti,micbias1-gpo:
+    type: boolean
+    description: |
+      When set, the MICBIAS1 pin may be controlled via the GPIO framework,
+      as pin number 3 on the device.
+
+      In this mode, when the pin is activated, it will be set to the voltage
+      specified by the ti,micbias1-vg property. When deactivated, the pin will
+      float.
+
+  ti,micbias2-gpo:
+    type: boolean
+    description: |
+      When set, the MICBIAS2 pin may be controlled via the GPIO framework,
+      as pin number 4 on the device.
+
+      In this mode, when the pin is activated, it will be set to the voltage
+      specified by the ti,micbias2-vg property. When deactivated, the pin will
+      float.
+
   ti,micbias1-vg:
     $ref: /schemas/types.yaml#/definitions/uint32
     enum:
@@ -104,6 +124,10 @@ properties:
     description: |
       Mic bias voltage output on MICBIAS2 pin
 
+dependencies:
+  ti,micbias1-gpo: ['ti,micbias1-vg']
+  ti,micbias2-gpo: ['ti,micbias2-vg']
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
similarity index 99%
rename from Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
rename to Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
index f3274bcc4c05e5966202c54e601a4fae8e1e78a7..876fa97bfbcdd3b9450aa6ff57de42f1faed350d 100644
--- a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
@@ -2,7 +2,7 @@
 # Copyright (C) 2019 Texas Instruments Incorporated
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/tlv320adcx140.yaml#
+$id: http://devicetree.org/schemas/sound/ti,tlv320adcx140.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Texas Instruments TLV320ADCX140 Quad Channel Analog-to-Digital Converter
diff --git a/Documentation/devicetree/bindings/sound/wm8750.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8750.yaml
similarity index 92%
rename from Documentation/devicetree/bindings/sound/wm8750.yaml
rename to Documentation/devicetree/bindings/sound/wlf,wm8750.yaml
index 24246ac7bbdfd02266668551c788a1a105b1012b..96859e38315b1a85a5bb3238875ec75e775d50aa 100644
--- a/Documentation/devicetree/bindings/sound/wm8750.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8750.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/sound/wm8750.yaml#
+$id: http://devicetree.org/schemas/sound/wlf,wm8750.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: WM8750 and WM8987 audio CODECs
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8782.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8782.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d0bbdc9f9ced8a8b172fa311bbbf5a346cbc44b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8782.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8782.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wolfson Microelectromics WM8782 audio CODEC
+
+maintainers:
+  - patches@opensource.cirrus.com
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: wlf,wm8782
+
+  Vdda-supply:
+    description: Regulator for the analog power supply (2.7V - 5.5V)
+
+  Vdd-supply:
+    description: Regulator for the digital power supply (2.7V - 3.6V)
+
+  wlf,fsampen:
+    description: FSAMPEN pin value, 0 for low, 1 for high, 2 for disconnected.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1, 2]
+
+  "#sound-dai-cells":
+    const: 0
+
+required:
+  - compatible
+  - Vdda-supply
+  - Vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    wm8782: codec {
+        compatible = "wlf,wm8782";
+        Vdda-supply = <&vdda_supply>;
+        Vdd-supply = <&vdd_supply>;
+        wlf,fsampen = <2>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8804.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8804.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3c060179f06efd1baba1c189374863a8e2cf27f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8804.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8804.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: WM8804 audio codec
+
+description: |
+  This device supports both I2C and SPI (configured with pin strapping on the
+  board).
+
+maintainers:
+  - patches@opensource.cirrus.com
+
+properties:
+  compatible:
+    const: wlf,wm8804
+
+  reg:
+    description:
+      The I2C address of the device for I2C, the chip select number for SPI.
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 0
+
+  PVDD-supply:
+    description: PLL core supply
+
+  DVDD-supply:
+    description: Digital core supply
+
+  wlf,reset-gpio:
+    description: A GPIO specifier for the GPIO controlling the reset pin.
+    maxItems: 1
+
+required:
+  - reg
+  - compatible
+  - PVDD-supply
+  - DVDD-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        codec@1a {
+            compatible = "wlf,wm8804";
+            reg = <0x1a>;
+            PVDD-supply = <&pvdd_reg>;
+            DVDD-supply = <&dvdd_reg>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/wm8782.txt b/Documentation/devicetree/bindings/sound/wm8782.txt
deleted file mode 100644
index 1a28f3280972387e858ad2879574d2560ea659a2..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/wm8782.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-WM8782 stereo ADC
-
-This device does not have any control interface or reset pins.
-
-Required properties:
-
- - compatible  : "wlf,wm8782"
- - Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V)
- - Vdd-supply  : phandle to a regulator for the digital power supply (2.7V - 3.6V)
-
-Optional properties:
-
- - wlf,fsampen:
-   FSAMPEN pin value, 0 for low, 1 for high, 2 for disconnected.
-   Defaults to 0 if left unspecified.
-
-Example:
-
-wm8782: stereo-adc {
-	compatible = "wlf,wm8782";
-	Vdda-supply = <&vdda_supply>;
-	Vdd-supply = <&vdd_supply>;
-	wlf,fsampen = <2>; /* 192KHz */
-};
diff --git a/Documentation/devicetree/bindings/sound/wm8804.txt b/Documentation/devicetree/bindings/sound/wm8804.txt
deleted file mode 100644
index 2c1641c17a91efc97c0a6194724da559849721cb..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/wm8804.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-WM8804 audio CODEC
-
-This device supports both I2C and SPI (configured with pin strapping
-on the board).
-
-Required properties:
-
-  - compatible : "wlf,wm8804"
-
-  - reg : the I2C address of the device for I2C, the chip select
-          number for SPI.
-
-  - PVDD-supply, DVDD-supply : Power supplies for the device, as covered
-    in Documentation/devicetree/bindings/regulator/regulator.txt
-
-Optional properties:
-
-  - wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin
-
-Example:
-
-wm8804: codec@1a {
-	compatible = "wlf,wm8804";
-	reg = <0x1a>;
-};
diff --git a/MAINTAINERS b/MAINTAINERS
index 661833e652bd5fe6cd21b2bf5cef2ed46bf10c6e..4a096207f8b472375c57c50688f53a9e5041087e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9028,6 +9028,16 @@ S:	Maintained
 F:	sound/soc/fsl/fsl*
 F:	sound/soc/fsl/imx*
 
+FREESCALE SOC LPC32XX SOUND DRIVERS
+M:	J.M.B. Downing <jonathan.downing@nautel.com>
+M:	Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
+R:	Vladimir Zapolskiy <vz@mleia.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml
+F:	sound/soc/fsl/lpc3xxx-*
+
 FREESCALE SOC SOUND QMC DRIVER
 M:	Herve Codina <herve.codina@bootlin.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -16400,7 +16410,7 @@ NXP SGTL5000 DRIVER
 M:	Fabio Estevam <festevam@gmail.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Maintained
-F:	Documentation/devicetree/bindings/sound/sgtl5000.yaml
+F:	Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml
 F:	sound/soc/codecs/sgtl5000*
 
 NXP SJA1105 ETHERNET SWITCH DRIVER
@@ -22442,13 +22452,13 @@ M:	Baojun Xu <baojun.xu@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Maintained
 F:	Documentation/devicetree/bindings/sound/tas2552.txt
-F:	Documentation/devicetree/bindings/sound/tas2562.yaml
-F:	Documentation/devicetree/bindings/sound/tas2770.yaml
-F:	Documentation/devicetree/bindings/sound/tas27xx.yaml
+F:	Documentation/devicetree/bindings/sound/ti,tas2562.yaml
+F:	Documentation/devicetree/bindings/sound/ti,tas2770.yaml
+F:	Documentation/devicetree/bindings/sound/ti,tas27xx.yaml
 F:	Documentation/devicetree/bindings/sound/ti,pcm1681.yaml
 F:	Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
 F:	Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
-F:	Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
+F:	Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
 F:	Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
 F:	Documentation/devicetree/bindings/sound/tpa6130a2.txt
 F:	include/sound/tas2*.h
@@ -25221,6 +25231,12 @@ F:	mm/zpool.c
 F:	mm/zswap.c
 F:	tools/testing/selftests/cgroup/test_zswap.c
 
+SENARYTECH AUDIO CODEC DRIVER
+M:	bo liu <bo.liu@senarytech.com>
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
+F:	sound/pci/hda/patch_senarytech.c
+
 THE REST
 M:	Linus Torvalds <torvalds@linux-foundation.org>
 L:	linux-kernel@vger.kernel.org
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index b7c271ddf9c0b13f697f991477c635ada2a0f99e..333ef55476a30fed3ac75fdb550d3f8afba8e79f 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -318,7 +318,6 @@ CONFIG_SND_IMX_SOC=y
 CONFIG_SND_SOC_EUKREA_TLV320=y
 CONFIG_SND_SOC_IMX_ES8328=y
 CONFIG_SND_SOC_IMX_SGTL5000=y
-CONFIG_SND_SOC_IMX_SPDIF=y
 CONFIG_SND_SOC_FSL_ASOC_CARD=y
 CONFIG_SND_SOC_AC97_CODEC=y
 CONFIG_SND_SOC_CS42XX8_I2C=y
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ef2235838c441e76898bcc3787a30547b7ed777e..7d32fca649965ad280ac514b89af38261381d325 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -951,7 +951,6 @@ CONFIG_SND_SOC_FSL_MICFIL=m
 CONFIG_SND_SOC_FSL_EASRC=m
 CONFIG_SND_IMX_SOC=m
 CONFIG_SND_SOC_IMX_SGTL5000=m
-CONFIG_SND_SOC_IMX_SPDIF=m
 CONFIG_SND_SOC_FSL_ASOC_CARD=m
 CONFIG_SND_SOC_IMX_AUDMIX=m
 CONFIG_SND_SOC_MT8183=m
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 202234ba54bd93989aed1d43fb152e78ed1797b1..ae93842822733e1358652905976efedd111fa76d 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -277,15 +277,25 @@ acpi_evaluate_integer(acpi_handle handle,
 
 EXPORT_SYMBOL(acpi_evaluate_integer);
 
-int acpi_get_local_address(acpi_handle handle, u32 *addr)
+int acpi_get_local_u64_address(acpi_handle handle, u64 *addr)
 {
-	unsigned long long adr;
 	acpi_status status;
 
-	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, addr);
 	if (ACPI_FAILURE(status))
 		return -ENODATA;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_get_local_u64_address);
+
+int acpi_get_local_address(acpi_handle handle, u32 *addr)
+{
+	u64 adr;
+	int ret;
 
+	ret = acpi_get_local_u64_address(handle, &adr);
+	if (ret < 0)
+		return ret;
 	*addr = (u32)adr;
 	return 0;
 }
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index 42c9cd0ebfb78a2ff35e255f5ff00b081fd3d546..419220fa42fd7e66077b1642a94ed2ceea4a1fad 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -12,6 +12,7 @@
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/minmax.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/seq_file.h>
@@ -802,6 +803,9 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
 
 	lockdep_assert_held(&ctl->dsp->pwr_lock);
 
+	if (ctl->flags && !(ctl->flags & WMFW_CTL_FLAG_WRITEABLE))
+		return -EPERM;
+
 	if (len + off * sizeof(u32) > ctl->len)
 		return -EINVAL;
 
@@ -1053,7 +1057,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp,
 
 	ctl->fw_name = dsp->fw_name;
 	ctl->alg_region = *alg_region;
-	if (subname && dsp->fw_ver >= 2) {
+	if (subname && dsp->wmfw_ver >= 2) {
 		ctl->subname_len = subname_len;
 		ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname);
 		if (!ctl->subname) {
@@ -1180,7 +1184,7 @@ static int cs_dsp_coeff_parse_alg(struct cs_dsp *dsp,
 
 	raw = (const struct wmfw_adsp_alg_data *)region->data;
 
-	switch (dsp->fw_ver) {
+	switch (dsp->wmfw_ver) {
 	case 0:
 	case 1:
 		if (sizeof(*raw) > data_len)
@@ -1257,7 +1261,7 @@ static int cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp,
 	blk->offset = le16_to_cpu(raw->hdr.offset);
 	blk->mem_type = le16_to_cpu(raw->hdr.type);
 
-	switch (dsp->fw_ver) {
+	switch (dsp->wmfw_ver) {
 	case 0:
 	case 1:
 		if (sizeof(*raw) > (data_len - pos))
@@ -1476,7 +1480,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 	const struct wmfw_region *region;
 	const struct cs_dsp_region *mem;
 	const char *region_name;
-	char *text = NULL;
 	struct cs_dsp_buf *buf;
 	unsigned int reg;
 	int regions = 0;
@@ -1505,8 +1508,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 		goto out_fw;
 	}
 
-	cs_dsp_info(dsp, "Firmware version: %d\n", header->ver);
-	dsp->fw_ver = header->ver;
+	dsp->wmfw_ver = header->ver;
 
 	if (header->core != dsp->type) {
 		cs_dsp_err(dsp, "%s: invalid core %d != %d\n",
@@ -1529,8 +1531,8 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 		goto out_fw;
 	}
 
-	cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file,
-		   le64_to_cpu(footer->timestamp));
+	cs_dsp_info(dsp, "%s: format %d timestamp %#llx\n", file, header->ver,
+		    le64_to_cpu(footer->timestamp));
 
 	while (pos < firmware->size) {
 		/* Is there enough data for a complete block header? */
@@ -1548,15 +1550,15 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 
 		region_name = "Unknown";
 		reg = 0;
-		text = NULL;
 		offset = le32_to_cpu(region->offset) & 0xffffff;
 		type = be32_to_cpu(region->type) & 0xff;
 
 		switch (type) {
+		case WMFW_INFO_TEXT:
 		case WMFW_NAME_TEXT:
-			region_name = "Firmware name";
-			text = kzalloc(le32_to_cpu(region->len) + 1,
-				       GFP_KERNEL);
+			region_name = "Info/Name";
+			cs_dsp_info(dsp, "%s: %.*s\n", file,
+				    min(le32_to_cpu(region->len), 100), region->data);
 			break;
 		case WMFW_ALGORITHM_DATA:
 			region_name = "Algorithm";
@@ -1564,11 +1566,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 			if (ret != 0)
 				goto out_fw;
 			break;
-		case WMFW_INFO_TEXT:
-			region_name = "Information";
-			text = kzalloc(le32_to_cpu(region->len) + 1,
-				       GFP_KERNEL);
-			break;
 		case WMFW_ABSOLUTE:
 			region_name = "Absolute";
 			reg = offset;
@@ -1602,13 +1599,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 			   regions, le32_to_cpu(region->len), offset,
 			   region_name);
 
-		if (text) {
-			memcpy(text, region->data, le32_to_cpu(region->len));
-			cs_dsp_info(dsp, "%s: %s\n", file, text);
-			kfree(text);
-			text = NULL;
-		}
-
 		if (reg) {
 			buf = cs_dsp_buf_alloc(region->data,
 					       le32_to_cpu(region->len),
@@ -1650,7 +1640,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 out_fw:
 	regmap_async_complete(regmap);
 	cs_dsp_buf_free(&buf_list);
-	kfree(text);
 
 	if (ret == -EOVERFLOW)
 		cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@@ -1799,7 +1788,7 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp,
 
 	list_add_tail(&alg_region->list, &dsp->alg_regions);
 
-	if (dsp->fw_ver > 0)
+	if (dsp->wmfw_ver > 0)
 		cs_dsp_ctl_fixup_base(dsp, alg_region);
 
 	return alg_region;
@@ -1922,7 +1911,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp)
 			ret = PTR_ERR(alg_region);
 			goto out;
 		}
-		if (dsp->fw_ver == 0) {
+		if (dsp->wmfw_ver == 0) {
 			if (i + 1 < n_algs) {
 				len = be32_to_cpu(adsp1_alg[i + 1].dm);
 				len -= be32_to_cpu(adsp1_alg[i].dm);
@@ -1944,7 +1933,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp)
 			ret = PTR_ERR(alg_region);
 			goto out;
 		}
-		if (dsp->fw_ver == 0) {
+		if (dsp->wmfw_ver == 0) {
 			if (i + 1 < n_algs) {
 				len = be32_to_cpu(adsp1_alg[i + 1].zm);
 				len -= be32_to_cpu(adsp1_alg[i].zm);
@@ -2035,7 +2024,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
 			ret = PTR_ERR(alg_region);
 			goto out;
 		}
-		if (dsp->fw_ver == 0) {
+		if (dsp->wmfw_ver == 0) {
 			if (i + 1 < n_algs) {
 				len = be32_to_cpu(adsp2_alg[i + 1].xm);
 				len -= be32_to_cpu(adsp2_alg[i].xm);
@@ -2057,7 +2046,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
 			ret = PTR_ERR(alg_region);
 			goto out;
 		}
-		if (dsp->fw_ver == 0) {
+		if (dsp->wmfw_ver == 0) {
 			if (i + 1 < n_algs) {
 				len = be32_to_cpu(adsp2_alg[i + 1].ym);
 				len -= be32_to_cpu(adsp2_alg[i].ym);
@@ -2079,7 +2068,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
 			ret = PTR_ERR(alg_region);
 			goto out;
 		}
-		if (dsp->fw_ver == 0) {
+		if (dsp->wmfw_ver == 0) {
 			if (i + 1 < n_algs) {
 				len = be32_to_cpu(adsp2_alg[i + 1].zm);
 				len -= be32_to_cpu(adsp2_alg[i].zm);
@@ -2183,7 +2172,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 	struct cs_dsp_alg_region *alg_region;
 	const char *region_name;
 	int ret, pos, blocks, type, offset, reg, version;
-	char *text = NULL;
 	struct cs_dsp_buf *buf;
 
 	if (!firmware)
@@ -2252,7 +2240,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 		region_name = "Unknown";
 		switch (type) {
 		case (WMFW_NAME_TEXT << 8):
-			text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL);
+			cs_dsp_info(dsp, "%s: %.*s\n", dsp->fw_name,
+				    min(le32_to_cpu(blk->len), 100), blk->data);
 			break;
 		case (WMFW_INFO_TEXT << 8):
 		case (WMFW_METADATA << 8):
@@ -2324,13 +2313,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 			break;
 		}
 
-		if (text) {
-			memcpy(text, blk->data, le32_to_cpu(blk->len));
-			cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text);
-			kfree(text);
-			text = NULL;
-		}
-
 		if (reg) {
 			buf = cs_dsp_buf_alloc(blk->data,
 					       le32_to_cpu(blk->len),
@@ -2370,7 +2352,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 out_fw:
 	regmap_async_complete(regmap);
 	cs_dsp_buf_free(&buf_list);
-	kfree(text);
 
 	if (ret == -EOVERFLOW)
 		cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@@ -2437,8 +2418,8 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP);
  * Return: Zero for success, a negative number on error.
  */
 int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
-			  const struct firmware *wmfw_firmware, char *wmfw_filename,
-			  const struct firmware *coeff_firmware, char *coeff_filename,
+			  const struct firmware *wmfw_firmware, const char *wmfw_filename,
+			  const struct firmware *coeff_firmware, const char *coeff_filename,
 			  const char *fw_name)
 {
 	unsigned int val;
@@ -2731,8 +2712,8 @@ static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp)
  * Return: Zero for success, a negative number on error.
  */
 int cs_dsp_power_up(struct cs_dsp *dsp,
-		    const struct firmware *wmfw_firmware, char *wmfw_filename,
-		    const struct firmware *coeff_firmware, char *coeff_filename,
+		    const struct firmware *wmfw_firmware, const char *wmfw_filename,
+		    const struct firmware *coeff_firmware, const char *coeff_filename,
 		    const char *fw_name)
 {
 	int ret;
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
index f498db9abe35f09c9e49cdb0aac306467e7ab37f..76bb496305a0e0a241c3f2acf088b94478128b4f 100644
--- a/drivers/soc/fsl/qe/qmc.c
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -1777,13 +1777,28 @@ static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsign
 	return qmc_chan;
 }
 
-struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name)
+int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name)
+{
+	int count;
+
+	/* phandles are fixed args phandles with one arg */
+	count = of_count_phandle_with_args(np, phandles_name, NULL);
+	if (count < 0)
+		return count;
+
+	return count / 2;
+}
+EXPORT_SYMBOL(qmc_chan_count_phandles);
+
+struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np,
+					       const char *phandles_name,
+					       int index)
 {
 	struct of_phandle_args out_args;
 	struct qmc_chan *qmc_chan;
 	int ret;
 
-	ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0,
+	ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index,
 					       &out_args);
 	if (ret < 0)
 		return ERR_PTR(ret);
@@ -1797,7 +1812,7 @@ struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phan
 	of_node_put(out_args.np);
 	return qmc_chan;
 }
-EXPORT_SYMBOL(qmc_chan_get_byphandle);
+EXPORT_SYMBOL(qmc_chan_get_byphandles_index);
 
 struct qmc_chan *qmc_chan_get_bychild(struct device_node *np)
 {
@@ -1827,9 +1842,10 @@ static void devm_qmc_chan_release(struct device *dev, void *res)
 	qmc_chan_put(*qmc_chan);
 }
 
-struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
-					     struct device_node *np,
-					     const char *phandle_name)
+struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev,
+						    struct device_node *np,
+						    const char *phandles_name,
+						    int index)
 {
 	struct qmc_chan *qmc_chan;
 	struct qmc_chan **dr;
@@ -1838,7 +1854,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
 	if (!dr)
 		return ERR_PTR(-ENOMEM);
 
-	qmc_chan = qmc_chan_get_byphandle(np, phandle_name);
+	qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index);
 	if (!IS_ERR(qmc_chan)) {
 		*dr = qmc_chan;
 		devres_add(dev, dr);
@@ -1848,7 +1864,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
 
 	return qmc_chan;
 }
-EXPORT_SYMBOL(devm_qmc_chan_get_byphandle);
+EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index);
 
 struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev,
 					   struct device_node *np)
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index 9963b92eb50536d5e44b36409023fe95a6c5475f..f1a4df6cfebd9c2143f04abe83c935e7110c3cf9 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -97,18 +97,13 @@ static bool find_slave(struct sdw_bus *bus,
 		       struct acpi_device *adev,
 		       struct sdw_slave_id *id)
 {
-	u64 addr;
 	unsigned int link_id;
-	acpi_status status;
-
-	status = acpi_evaluate_integer(adev->handle,
-				       METHOD_NAME__ADR, NULL, &addr);
+	u64 addr;
+	int ret;
 
-	if (ACPI_FAILURE(status)) {
-		dev_err(bus->dev, "_ADR resolution failed: %x\n",
-			status);
+	ret = acpi_get_local_u64_address(adev->handle, &addr);
+	if (ret < 0)
 		return false;
-	}
 
 	if (bus->ops->override_adr)
 		addr = bus->ops->override_adr(bus, addr);
diff --git a/include/dt-bindings/sound/audio-graph.h b/include/dt-bindings/sound/audio-graph.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdb70c6b7332f4c3161b107e74c734c435e7d46c
--- /dev/null
+++ b/include/dt-bindings/sound/audio-graph.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * audio-graph.h
+ *
+ * Copyright (c) 2024 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ */
+#ifndef __AUDIO_GRAPH_H
+#define __AUDIO_GRAPH_H
+
+/*
+ * used in
+ *	link-trigger-order
+ *	link-trigger-order-start
+ *	link-trigger-order-stop
+ *
+ * default is
+ *	link-trigger-order = <SND_SOC_TRIGGER_LINK
+ *			      SND_SOC_TRIGGER_COMPONENT
+ *			      SND_SOC_TRIGGER_DAI>;
+ */
+#define SND_SOC_TRIGGER_LINK		0
+#define SND_SOC_TRIGGER_COMPONENT	1
+#define SND_SOC_TRIGGER_DAI		2
+#define SND_SOC_TRIGGER_SIZE		3	/* shoud be last */
+
+#endif /* __AUDIO_GRAPH_H */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 170f5f8b0563c95d85d6d22e27a71e58041525ea..e93059f71c7185ad7c0677415c3cb6bd33cb7bc8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -759,6 +759,7 @@ static inline u64 acpi_arch_get_root_pointer(void)
 }
 #endif
 
+int acpi_get_local_u64_address(acpi_handle handle, u64 *addr);
 int acpi_get_local_address(acpi_handle handle, u32 *addr);
 const char *acpi_get_subsystem_id(acpi_handle handle);
 
diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h
index c28a6b9c3b2db954ae20a9e4f78aecd2c2015bd2..7cae703b3137cf1c80efaf3840edd3f206b91033 100644
--- a/include/linux/firmware/cirrus/cs_dsp.h
+++ b/include/linux/firmware/cirrus/cs_dsp.h
@@ -177,7 +177,7 @@ struct cs_dsp {
 	const struct cs_dsp_region *mem;
 	int num_mems;
 
-	int fw_ver;
+	int wmfw_ver;
 
 	bool booted;
 	bool running;
@@ -223,13 +223,13 @@ int cs_dsp_adsp2_init(struct cs_dsp *dsp);
 int cs_dsp_halo_init(struct cs_dsp *dsp);
 
 int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
-			  const struct firmware *wmfw_firmware, char *wmfw_filename,
-			  const struct firmware *coeff_firmware, char *coeff_filename,
+			  const struct firmware *wmfw_firmware, const char *wmfw_filename,
+			  const struct firmware *coeff_firmware, const char *coeff_filename,
 			  const char *fw_name);
 void cs_dsp_adsp1_power_down(struct cs_dsp *dsp);
 int cs_dsp_power_up(struct cs_dsp *dsp,
-		    const struct firmware *wmfw_firmware, char *wmfw_filename,
-		    const struct firmware *coeff_firmware, char *coeff_filename,
+		    const struct firmware *wmfw_firmware, const char *wmfw_filename,
+		    const struct firmware *coeff_firmware, const char *coeff_filename,
 		    const char *fw_name);
 void cs_dsp_power_down(struct cs_dsp *dsp);
 int cs_dsp_run(struct cs_dsp *dsp);
diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h
index 5b1d16fa3f568cf9f0cb462ed1a3c41890e53371..6e86799a7dc43a6b83750b4e89ba536e10f50e13 100644
--- a/include/linux/firmware/mediatek/mtk-adsp-ipc.h
+++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h
@@ -40,7 +40,7 @@ struct mtk_adsp_chan {
 struct mtk_adsp_ipc {
 	struct mtk_adsp_chan chans[MTK_ADSP_MBOX_NUM];
 	struct device *dev;
-	struct mtk_adsp_ipc_ops *ops;
+	const struct mtk_adsp_ipc_ops *ops;
 	void *private_data;
 };
 
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 76a8f2d6bd645140a2076b44c87e0f20d3e3cb47..e388c8b1cbc2769a9bc8c25f524393489fb72fc9 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -3116,6 +3116,7 @@
 #define PCI_DEVICE_ID_INTEL_HDA_LNL_P	0xa828
 #define PCI_DEVICE_ID_INTEL_S21152BB	0xb152
 #define PCI_DEVICE_ID_INTEL_HDA_BMG	0xe2f7
+#define PCI_DEVICE_ID_INTEL_HDA_PTL	0xe428
 #define PCI_DEVICE_ID_INTEL_HDA_CML_R	0xf0c8
 #define PCI_DEVICE_ID_INTEL_HDA_RKL_S	0xf1c8
 
diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h
index 2a333fc1ea818296e96f0c5fbd4c34cfa803b63f..294e42ea8d4c5088f4d1ee6b568ab6568182ac44 100644
--- a/include/soc/fsl/qe/qmc.h
+++ b/include/soc/fsl/qe/qmc.h
@@ -16,11 +16,32 @@ struct device_node;
 struct device;
 struct qmc_chan;
 
-struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name);
+int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name);
+
+struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np,
+					       const char *phandles_name,
+					       int index);
+struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev,
+						    struct device_node *np,
+						    const char *phandles_name,
+						    int index);
+
+static inline struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np,
+						      const char *phandle_name)
+{
+	return qmc_chan_get_byphandles_index(np, phandle_name, 0);
+}
+
+static inline struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
+							   struct device_node *np,
+							   const char *phandle_name)
+{
+	return devm_qmc_chan_get_byphandles_index(dev, np, phandle_name, 0);
+}
+
 struct qmc_chan *qmc_chan_get_bychild(struct device_node *np);
 void qmc_chan_put(struct qmc_chan *chan);
-struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, struct device_node *np,
-					     const char *phandle_name);
+
 struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np);
 
 enum qmc_mode {
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index bb70782d15d06e06d8eac58c2bae649b36a03efd..43c6a9ef8d9f1991c263316942cccbb4b5e88d43 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -896,8 +896,8 @@ int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap);
 int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap);
 int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid);
 int cs35l41_set_channels(struct device *dev, struct regmap *reg,
-			 unsigned int tx_num, unsigned int *tx_slot,
-			 unsigned int rx_num, unsigned int *rx_slot);
+			 unsigned int tx_num, const unsigned int *tx_slot,
+			 unsigned int rx_num, const unsigned int *rx_slot);
 int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg);
 void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp);
 int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 1a3c6f66f6205597cb46b3c7cc826802fc35c740..a6aa112e57416ce04b4e9ada51b39b52a2e8de68 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -80,9 +80,7 @@
 #define CS35L56_DSP1_AHBM_WINDOW_DEBUG_1		0x25E2044
 #define CS35L56_DSP1_XMEM_UNPACKED24_0			0x2800000
 #define CS35L56_DSP1_FW_VER				0x2800010
-#define CS35L56_DSP1_HALO_STATE_A1			0x2801E58
 #define CS35L56_DSP1_HALO_STATE				0x28021E0
-#define CS35L56_DSP1_PM_CUR_STATE_A1			0x2804000
 #define CS35L56_DSP1_PM_CUR_STATE			0x2804308
 #define CS35L56_DSP1_XMEM_UNPACKED24_8191		0x2807FFC
 #define CS35L56_DSP1_CORE_BASE				0x2B80000
@@ -209,7 +207,7 @@
 
 /* CS35L56_MAIN_RENDER_USER_VOLUME */
 #define CS35L56_MAIN_RENDER_USER_VOLUME_MIN		-400
-#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX		400
+#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX		48
 #define CS35L56_MAIN_RENDER_USER_VOLUME_MASK		0x0000FFC0
 #define CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT		6
 #define CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT		9
@@ -267,13 +265,18 @@ struct cs35l56_base {
 	bool fw_patched;
 	bool secured;
 	bool can_hibernate;
-	bool fw_owns_asp1;
 	bool cal_data_valid;
 	s8 cal_index;
 	struct cirrus_amp_cal_data cal_data;
 	struct gpio_desc *reset_gpio;
 };
 
+/* Temporary to avoid a build break with the HDA driver */
+static inline int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
+{
+	return 0;
+}
+
 extern struct regmap_config cs35l56_regmap_i2c;
 extern struct regmap_config cs35l56_regmap_spi;
 extern struct regmap_config cs35l56_regmap_sdw;
@@ -284,8 +287,6 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
 extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
 
 int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
-int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base);
-int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base);
 int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
 int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
 int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 3edd7a7346daaaf30ddb44e1151d8caae8371a64..ac8f3aef92052384000844dd5077e86034d2d360 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -93,6 +93,7 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO	2
 /* 3 is absent slot. */
 #define SNDRV_PCM_IOCTL1_FIFO_SIZE	4
+#define SNDRV_PCM_IOCTL1_SYNC_ID	5
 
 #define SNDRV_PCM_TRIGGER_STOP		0
 #define SNDRV_PCM_TRIGGER_START		1
@@ -401,7 +402,7 @@ struct snd_pcm_runtime {
 	snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
 	snd_pcm_uframes_t silence_filled; /* already filled part of silence area */
 
-	union snd_pcm_sync_id sync;	/* hardware synchronization ID */
+	bool std_sync_id;		/* hardware synchronization - standard per card ID */
 
 	/* -- mmap -- */
 	struct snd_pcm_mmap_status *status;
@@ -1155,7 +1156,18 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int
 
 void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
 		     const struct snd_pcm_ops *ops);
-void snd_pcm_set_sync(struct snd_pcm_substream *substream);
+void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
+			       const unsigned char *id, unsigned int len);
+/**
+ * snd_pcm_set_sync - set the PCM sync id
+ * @substream: the pcm substream
+ *
+ * Use the default PCM sync identifier for the specific card.
+ */
+static inline void snd_pcm_set_sync(struct snd_pcm_substream *substream)
+{
+	substream->runtime->std_sync_id = true;
+}
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 		      unsigned int cmd, void *arg);                      
 void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream);
diff --git a/include/sound/rt1318.h b/include/sound/rt1318.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe6bff06036c1bc7b5ee6d1a9a9fe8cf4afc6de2
--- /dev/null
+++ b/include/sound/rt1318.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/sound/rt1318.h -- Platform data for RT1318
+ *
+ * Copyright 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __LINUX_SND_RT1318_H
+#define __LINUX_SND_RT1318_H
+
+struct rt1318_platform_data {
+	unsigned int init_r0_l;
+	unsigned int init_r0_r;
+};
+
+#endif
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index ad67957b7b48ccee86e89b80be4fa68e622182ea..3360d9eab068d5f9ea4ae7e4dcd8da6a3234d068 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -174,6 +174,8 @@ void simple_util_parse_convert(struct device_node *np, char *prefix,
 			       struct simple_util_data *data);
 bool simple_util_is_convert_required(const struct simple_util_data *data);
 
+int simple_util_get_sample_fmt(struct simple_util_data *data);
+
 int simple_util_parse_routing(struct snd_soc_card *card,
 				      char *prefix);
 int simple_util_parse_widgets(struct snd_soc_card *card,
@@ -195,8 +197,12 @@ int graph_util_is_ports0(struct device_node *port);
 int graph_util_parse_dai(struct device *dev, struct device_node *ep,
 			 struct snd_soc_dai_link_component *dlc, int *is_single_link);
 
-int graph_util_parse_link_direction(struct device_node *np,
+void graph_util_parse_link_direction(struct device_node *np,
 				    bool *is_playback_only, bool *is_capture_only);
+void graph_util_parse_trigger_order(struct simple_util_priv *priv,
+				    struct device_node *np,
+				    enum snd_soc_trigger_order *trigger_start,
+				    enum snd_soc_trigger_order *trigger_stop);
 
 #ifdef DEBUG
 static inline void simple_util_debug_dai(struct simple_util_priv *priv,
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index adcd8719d3435aafb6555a5d2f684f5d37966310..bbb72ad4c951827a880ac8c1f793717271230817 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -180,16 +180,16 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
 int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
 
 /* Digital Audio interface formatting */
-int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd);
-u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority);
+int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd);
+u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority);
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
 
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
 
 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
-	unsigned int tx_num, unsigned int *tx_slot,
-	unsigned int rx_num, unsigned int *rx_slot);
+	unsigned int tx_num, const unsigned int *tx_slot,
+	unsigned int rx_num, const unsigned int *rx_slot);
 
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 
@@ -198,11 +198,11 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
 			     int direction);
 
 
-int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai,
 		unsigned int *tx_num, unsigned int *tx_slot,
 		unsigned int *rx_num, unsigned int *rx_slot);
 
-int snd_soc_dai_is_dummy(struct snd_soc_dai *dai);
+int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai);
 
 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
 			  struct snd_pcm_substream *substream,
@@ -218,7 +218,7 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai);
 void snd_soc_dai_resume(struct snd_soc_dai *dai);
 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
 			     struct snd_soc_pcm_runtime *rtd, int num);
-bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream);
+bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream);
 void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link);
 void snd_soc_dai_action(struct snd_soc_dai *dai,
 			int stream, int action);
@@ -232,7 +232,7 @@ static inline void snd_soc_dai_deactivate(struct snd_soc_dai *dai,
 {
 	snd_soc_dai_action(dai, stream, -1);
 }
-int snd_soc_dai_active(struct snd_soc_dai *dai);
+int snd_soc_dai_active(const struct snd_soc_dai *dai);
 
 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);
@@ -271,7 +271,7 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
 				   struct snd_compr_stream *cstream,
 				   struct snd_compr_metadata *metadata);
 
-const char *snd_soc_dai_name_get(struct snd_soc_dai *dai);
+const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai);
 
 struct snd_soc_dai_ops {
 	/* DAI driver callbacks */
@@ -305,9 +305,9 @@ struct snd_soc_dai_ops {
 		unsigned int tx_mask, unsigned int rx_mask,
 		int slots, int slot_width);
 	int (*set_channel_map)(struct snd_soc_dai *dai,
-		unsigned int tx_num, unsigned int *tx_slot,
-		unsigned int rx_num, unsigned int *rx_slot);
-	int (*get_channel_map)(struct snd_soc_dai *dai,
+		unsigned int tx_num, const unsigned int *tx_slot,
+		unsigned int rx_num, const unsigned int *rx_slot);
+	int (*get_channel_map)(const struct snd_soc_dai *dai,
 			unsigned int *tx_num, unsigned int *tx_slot,
 			unsigned int *rx_num, unsigned int *rx_slot);
 	int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
@@ -361,7 +361,7 @@ struct snd_soc_dai_ops {
 	 * see
 	 *	snd_soc_dai_get_fmt()
 	 */
-	u64 *auto_selectable_formats;
+	const u64 *auto_selectable_formats;
 	int num_auto_selectable_formats;
 
 	/* probe ordering - for components with runtime dependencies */
@@ -413,7 +413,7 @@ struct snd_soc_dai_driver {
 	unsigned int id;
 	unsigned int base;
 	struct snd_soc_dobj dobj;
-	struct of_phandle_args *dai_args;
+	const struct of_phandle_args *dai_args;
 
 	/* ops */
 	const struct snd_soc_dai_ops *ops;
@@ -473,7 +473,7 @@ struct snd_soc_dai {
 	unsigned int probed:1;
 };
 
-static inline struct snd_soc_pcm_stream *
+static inline const struct snd_soc_pcm_stream *
 snd_soc_dai_get_pcm_stream(const struct snd_soc_dai *dai, int stream)
 {
 	return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -518,7 +518,8 @@ static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, void *play
 	snd_soc_dai_dma_data_set_capture(dai,  capture);
 }
 
-static inline unsigned int snd_soc_dai_tdm_mask_get(struct snd_soc_dai *dai, int stream)
+static inline unsigned int snd_soc_dai_tdm_mask_get(const struct snd_soc_dai *dai,
+						    int stream)
 {
 	return dai->stream[stream].tdm_mask;
 }
@@ -529,7 +530,8 @@ static inline void snd_soc_dai_tdm_mask_set(struct snd_soc_dai *dai, int stream,
 	dai->stream[stream].tdm_mask = tdm_mask;
 }
 
-static inline unsigned int snd_soc_dai_stream_active(struct snd_soc_dai *dai, int stream)
+static inline unsigned int snd_soc_dai_stream_active(const struct snd_soc_dai *dai,
+						     int stream)
 {
 	/* see snd_soc_dai_action() for setup */
 	return dai->stream[stream].active;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 667ecd4daa68b0b905df81060a76499fc3300825..12cd7b5a2202e0cc4548c3ce1579e9e2d4cca092 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -457,7 +457,7 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
 int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *uncontrol);
 int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
-	const struct snd_soc_dapm_widget *widget, int num);
+	const struct snd_soc_dapm_widget *widget, unsigned int num);
 struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 		const struct snd_soc_dapm_widget *widget);
 struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
index f055c6917f6c9b3f48e0f8cb1b5299ee2bc40e8e..1eedd203ac29904c6cd76decda273e2515a75577 100644
--- a/include/sound/soc-topology.h
+++ b/include/sound/soc-topology.h
@@ -178,7 +178,7 @@ 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);
+	const 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 */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 33671437ee896ee694f8880eba1b007f5ab16c28..a8e66bbf932b333447abce2bd053cca2436c8f57 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -534,10 +534,10 @@ static inline int snd_soc_set_dmi_name(struct snd_soc_card *card,
 
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
-int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
+int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params);
 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots);
-int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
-int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params,
+int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *parms);
+int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params,
 			       int tdm_width, int tdm_slots, int slot_multiple);
 
 /* set runtime hw params */
@@ -675,7 +675,7 @@ struct snd_soc_dai_link_component {
 	const char *name;
 	struct device_node *of_node;
 	const char *dai_name;
-	struct of_phandle_args *dai_args;
+	const struct of_phandle_args *dai_args;
 };
 
 /*
@@ -837,7 +837,8 @@ struct snd_soc_dai_link {
 #endif
 };
 
-static inline int snd_soc_link_num_ch_map(struct snd_soc_dai_link *link) {
+static inline int snd_soc_link_num_ch_map(const struct snd_soc_dai_link *link)
+{
 	return max(link->num_cpus, link->num_codecs);
 }
 
@@ -1299,7 +1300,7 @@ struct soc_enum {
 #endif
 };
 
-static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
+static inline bool snd_soc_volsw_is_stereo(const struct soc_mixer_control *mc)
 {
 	if (mc->reg == mc->rreg && mc->shift == mc->rshift)
 		return false;
@@ -1311,7 +1312,7 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
 	return true;
 }
 
-static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e,
+static inline unsigned int snd_soc_enum_val_to_item(const struct soc_enum *e,
 	unsigned int val)
 {
 	unsigned int i;
@@ -1326,7 +1327,7 @@ static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e,
 	return 0;
 }
 
-static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e,
+static inline unsigned int snd_soc_enum_item_to_val(const struct soc_enum *e,
 	unsigned int item)
 {
 	if (!e->values)
@@ -1401,7 +1402,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
 	snd_soc_daifmt_clock_provider_from_bitmap(			\
 		snd_soc_daifmt_parse_clock_provider_as_bitmap(np, prefix))
 
-int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream);
+int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream);
 int snd_soc_get_dlc(const struct of_phandle_args *args,
 		    struct snd_soc_dai_link_component *dlc);
 int snd_soc_of_get_dlc(struct device_node *of_node,
diff --git a/include/sound/sof.h b/include/sound/sof.h
index ec6c30d54592aecbd3cbf0a60e2420d8de8cb7d2..64fd5504cb2b63eb05e1896cb17b693f7113282f 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -173,5 +173,6 @@ struct sof_dev_desc {
 
 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd);
 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd);
+int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd);
 
 #endif
diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h
index 7fba7ea26a4b07a953f618489316a5c1a5f20f60..3cda9da14f6d1dc88992b8622a723b276c031915 100644
--- a/include/sound/tas2781-dsp.h
+++ b/include/sound/tas2781-dsp.h
@@ -117,10 +117,17 @@ struct tasdevice_fw {
 	struct device *dev;
 };
 
-enum tasdevice_dsp_fw_state {
-	TASDEVICE_DSP_FW_NONE = 0,
+enum tasdevice_fw_state {
+	/* Driver in startup mode, not load any firmware. */
 	TASDEVICE_DSP_FW_PENDING,
+	/* DSP firmware in the system, but parsing error. */
 	TASDEVICE_DSP_FW_FAIL,
+	/*
+	 * Only RCA (Reconfigurable Architecture) firmware load
+	 * successfully.
+	 */
+	TASDEVICE_RCA_FW_OK,
+	/* Both RCA and DSP firmware load successfully. */
 	TASDEVICE_DSP_FW_ALL_OK,
 };
 
diff --git a/include/sound/tas2781-tlv.h b/include/sound/tas2781-tlv.h
index 1dc59005d241fbe683fb98d62d86e8c04f3708eb..99c41bfc7827e4e5d9bf9d9a7fe548481bebbf5c 100644
--- a/include/sound/tas2781-tlv.h
+++ b/include/sound/tas2781-tlv.h
@@ -2,7 +2,7 @@
 //
 // ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
 //
-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
 // https://www.ti.com
 //
 // The TAS2781 driver implements a flexible and configurable
@@ -17,5 +17,265 @@
 
 static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0);
 static const DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1);
 
+/* pow(10, db/20) * pow(2,30) */
+static const unsigned char tas2563_dvc_table[][4] = {
+	{ 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */
+	{ 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */
+	{ 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */
+	{ 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */
+	{ 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */
+	{ 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */
+	{ 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */
+	{ 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */
+	{ 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */
+	{ 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */
+	{ 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */
+	{ 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */
+	{ 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */
+	{ 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */
+	{ 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */
+	{ 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */
+	{ 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */
+	{ 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */
+	{ 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */
+	{ 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */
+	{ 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */
+	{ 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */
+	{ 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */
+	{ 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */
+	{ 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */
+	{ 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */
+	{ 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */
+	{ 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */
+	{ 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */
+	{ 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */
+	{ 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */
+	{ 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */
+	{ 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */
+	{ 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */
+	{ 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */
+	{ 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */
+	{ 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */
+	{ 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */
+	{ 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */
+	{ 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */
+	{ 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */
+	{ 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */
+	{ 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */
+	{ 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */
+	{ 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */
+	{ 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */
+	{ 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */
+	{ 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */
+	{ 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */
+	{ 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */
+	{ 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */
+	{ 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */
+	{ 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */
+	{ 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */
+	{ 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */
+	{ 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */
+	{ 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */
+	{ 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */
+	{ 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */
+	{ 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */
+	{ 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */
+	{ 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */
+	{ 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */
+	{ 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */
+	{ 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */
+	{ 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */
+	{ 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */
+	{ 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */
+	{ 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */
+	{ 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */
+	{ 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */
+	{ 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */
+	{ 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */
+	{ 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */
+	{ 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */
+	{ 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */
+	{ 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */
+	{ 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */
+	{ 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */
+	{ 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */
+	{ 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */
+	{ 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */
+	{ 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */
+	{ 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */
+	{ 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */
+	{ 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */
+	{ 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */
+	{ 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */
+	{ 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */
+	{ 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */
+	{ 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */
+	{ 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */
+	{ 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */
+	{ 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */
+	{ 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */
+	{ 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */
+	{ 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */
+	{ 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */
+	{ 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */
+	{ 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */
+	{ 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */
+	{ 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */
+	{ 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */
+	{ 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */
+	{ 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */
+	{ 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */
+	{ 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */
+	{ 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */
+	{ 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */
+	{ 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */
+	{ 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */
+	{ 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */
+	{ 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */
+	{ 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */
+	{ 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */
+	{ 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */
+	{ 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */
+	{ 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */
+	{ 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */
+	{ 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */
+	{ 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */
+	{ 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */
+	{ 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */
+	{ 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */
+	{ 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */
+	{ 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */
+	{ 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */
+	{ 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */
+	{ 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */
+	{ 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */
+	{ 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */
+	{ 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */
+	{ 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */
+	{ 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */
+	{ 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */
+	{ 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */
+	{ 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */
+	{ 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */
+	{ 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */
+	{ 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */
+	{ 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */
+	{ 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */
+	{ 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */
+	{ 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */
+	{ 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */
+	{ 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */
+	{ 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */
+	{ 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */
+	{ 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */
+	{ 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */
+	{ 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */
+	{ 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */
+	{ 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */
+	{ 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */
+	{ 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */
+	{ 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */
+	{ 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */
+	{ 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */
+	{ 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */
+	{ 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */
+	{ 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */
+	{ 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */
+	{ 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */
+	{ 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */
+	{ 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */
+	{ 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */
+	{ 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */
+	{ 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */
+	{ 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */
+	{ 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */
+	{ 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */
+	{ 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */
+	{ 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */
+	{ 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */
+	{ 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */
+	{ 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */
+	{ 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */
+	{ 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */
+	{ 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */
+	{ 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */
+	{ 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */
+	{ 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */
+	{ 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */
+	{ 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */
+	{ 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */
+	{ 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */
+	{ 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */
+	{ 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */
+	{ 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */
+	{ 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */
+	{ 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */
+	{ 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */
+	{ 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */
+	{ 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */
+	{ 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */
+	{ 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */
+	{ 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */
+	{ 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */
+	{ 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */
+	{ 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */
+	{ 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */
+	{ 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */
+	{ 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */
+	{ 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */
+	{ 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */
+	{ 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */
+	{ 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */
+	{ 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */
+	{ 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */
+	{ 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */
+	{ 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */
+	{ 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */
+	{ 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */
+	{ 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */
+	{ 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */
+	{ 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */
+	{ 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */
+	{ 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */
+	{ 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */
+	{ 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */
+	{ 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */
+	{ 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */
+	{ 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */
+	{ 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */
+	{ 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */
+	{ 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */
+	{ 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */
+	{ 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */
+	{ 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */
+	{ 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */
+	{ 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */
+	{ 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */
+	{ 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */
+	{ 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */
+	{ 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */
+	{ 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */
+	{ 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */
+	{ 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */
+	{ 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */
+	{ 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */
+	{ 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */
+	{ 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */
+	{ 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */
+	{ 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */
+	{ 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */
+	{ 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */
+	{ 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */
+	{ 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */
+	{ 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */
+	{ 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */
+	{ 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */
+	{ 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */
+	{ 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */
+	{ 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */
+	{ 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */
+	{ 0XFF, 0XFF, 0XFF, 0XFF }, /* 6.0db */
+};
 #endif
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index 99ca3e401fd1fe36422a77a71eb87c26bbdaeacf..18161d02a96f7c7c3d23c3a6e67874322177db6c 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -2,7 +2,7 @@
 //
 // ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
 //
-// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
 // https://www.ti.com
 //
 // The TAS2563/TAS2781 driver implements a flexible and configurable
@@ -43,13 +43,14 @@
 					(page * 128)) + reg)
 
 /*Software Reset */
-#define TAS2781_REG_SWRESET		TASDEVICE_REG(0x0, 0X0, 0x01)
-#define TAS2781_REG_SWRESET_RESET	BIT(0)
+#define TASDEVICE_REG_SWRESET		TASDEVICE_REG(0x0, 0X0, 0x01)
+#define TASDEVICE_REG_SWRESET_RESET	BIT(0)
 
 /*I2C Checksum */
 #define TASDEVICE_I2CChecksum		TASDEVICE_REG(0x0, 0x0, 0x7E)
 
 /* Volume control */
+#define TAS2563_DVC_LVL			TASDEVICE_REG(0x00, 0x02, 0x0C)
 #define TAS2781_DVC_LVL			TASDEVICE_REG(0x0, 0x0, 0x1A)
 #define TAS2781_AMP_LEVEL		TASDEVICE_REG(0x0, 0x0, 0x03)
 #define TAS2781_AMP_LEVEL_MASK		GENMASK(5, 1)
@@ -108,6 +109,7 @@ struct tasdevice_priv {
 	unsigned char coef_binaryname[64];
 	unsigned char rca_binaryname[64];
 	unsigned char dev_name[32];
+	const char *name_prefix;
 	unsigned char ndev;
 	unsigned int magic_num;
 	unsigned int chip_id;
@@ -139,7 +141,7 @@ struct tasdevice_priv {
 	void (*apply_calibration)(struct tasdevice_priv *tas_priv);
 };
 
-void tas2781_reset(struct tasdevice_priv *tas_dev);
+void tasdevice_reset(struct tasdevice_priv *tas_dev);
 int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
 	struct module *module,
 	void (*cont)(const struct firmware *fw, void *context));
diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h
index c85fdd8895d844c9c02d2d419d49878b94b8ff86..39b37edcf81316b678158eca3e2572b22e5d7f84 100644
--- a/include/uapi/sound/asequencer.h
+++ b/include/uapi/sound/asequencer.h
@@ -10,7 +10,7 @@
 #include <sound/asound.h>
 
 /** version of the sequencer */
-#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3)
+#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 4)
 
 /**
  * definition of sequencer event types
@@ -523,11 +523,12 @@ struct snd_seq_queue_status {
 /* queue tempo */
 struct snd_seq_queue_tempo {
 	int queue;			/* sequencer queue */
-	unsigned int tempo;		/* current tempo, us/tick */
+	unsigned int tempo;		/* current tempo, us/tick (or different time-base below) */
 	int ppq;			/* time resolution, ticks/quarter */
 	unsigned int skew_value;	/* queue skew */
 	unsigned int skew_base;		/* queue skew base */
-	char reserved[24];		/* for the future */
+	unsigned short tempo_base;	/* tempo base in nsec unit; either 10 or 1000 */
+	char reserved[22];		/* for the future */
 };
 
 
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 628d46a0da92eb0393dd592a38e987d08dcf6db0..8bf7e8a0eb6f03a8026e07f1968568fb099e7c9f 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 17)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 18)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -334,7 +334,7 @@ union snd_pcm_sync_id {
 	unsigned char id[16];
 	unsigned short id16[8];
 	unsigned int id32[4];
-};
+} __attribute__((deprecated));
 
 struct snd_pcm_info {
 	unsigned int device;		/* RO/WR (control): device number */
@@ -348,7 +348,7 @@ struct snd_pcm_info {
 	int dev_subclass;		/* SNDRV_PCM_SUBCLASS_* */
 	unsigned int subdevices_count;
 	unsigned int subdevices_avail;
-	union snd_pcm_sync_id sync;	/* hardware synchronization ID */
+	unsigned char pad1[16];		/* was: hardware synchronization ID */
 	unsigned char reserved[64];	/* reserved for future... */
 };
 
@@ -420,7 +420,8 @@ struct snd_pcm_hw_params {
 	unsigned int rate_num;		/* R: rate numerator */
 	unsigned int rate_den;		/* R: rate denominator */
 	snd_pcm_uframes_t fifo_size;	/* R: chip FIFO size in frames */
-	unsigned char reserved[64];	/* reserved for future */
+	unsigned char sync[16];		/* R: synchronization ID (perfect sync - one clock source) */
+	unsigned char reserved[48];	/* reserved for future */
 };
 
 enum {
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index cc62980cfa6e287127f19eb441690d39c0bd414c..014b3bfe32374880a5f0cbdcc2763c24ba47b5c7 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -89,6 +89,7 @@ snd_rawmidi_ops
 snd_soc_component_driver
 snd_soc_dai_ops
 snd_soc_ops
+snd_soc_tplg_ops
 soc_pcmcia_socket_ops
 stacktrace_ops
 sysfs_ops
diff --git a/sound/core/control.c b/sound/core/control.c
index fb0c60044f7b3b1a4a8fd478cf68306a9443ef5d..f64a555f404f0af1952d583a481345e6974e6d0d 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -604,6 +604,7 @@ static inline int snd_ctl_remove_locked(struct snd_card *card,
  *
  * Removes the control from the card and then releases the instance.
  * You don't need to call snd_ctl_free_one().
+ * Passing NULL to @kcontrol argument is allowed as noop.
  *
  * Return: 0 if successful, or a negative error code on failure.
  *
@@ -611,6 +612,8 @@ static inline int snd_ctl_remove_locked(struct snd_card *card,
  */
 int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
+	if (!kcontrol)
+		return 0;
 	guard(rwsem_write)(&card->controls_rwsem);
 	return snd_ctl_remove_locked(card, kcontrol);
 }
@@ -1480,12 +1483,16 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
 static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	int change;
+	int err, change;
 	struct user_element *ue = kcontrol->private_data;
 	unsigned int size = ue->elem_data_size;
 	char *dst = ue->elem_data +
 			snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
 
+	err = sanity_check_input_values(ue->card, ucontrol, &ue->info, false);
+	if (err < 0)
+		return err;
+
 	change = memcmp(&ucontrol->value, dst, size) != 0;
 	if (change)
 		memcpy(dst, &ucontrol->value, size);
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index cc5db93b9132cebfb1d7f341ec806af6a6b06e7a..b134a51b3fd587830c011180d967b46fe2b96fb4 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -352,20 +352,19 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
 int snd_dmaengine_pcm_sync_stop(struct snd_pcm_substream *substream)
 {
 	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	struct dma_tx_state state;
+	enum dma_status status;
 
-	dmaengine_synchronize(prtd->dma_chan);
+	status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+	if (status != DMA_PAUSED)
+		dmaengine_synchronize(prtd->dma_chan);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_sync_stop);
 
-/**
- * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
- * @substream: PCM substream
- *
- * Return: 0 on success, a negative error code otherwise
- */
-int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
+static void __snd_dmaengine_pcm_close(struct snd_pcm_substream *substream,
+				      bool release_channel)
 {
 	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
 	struct dma_tx_state state;
@@ -376,8 +375,20 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
 		dmaengine_terminate_async(prtd->dma_chan);
 
 	dmaengine_synchronize(prtd->dma_chan);
+	if (release_channel)
+		dma_release_channel(prtd->dma_chan);
 	kfree(prtd);
+}
 
+/**
+ * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
+ * @substream: PCM substream
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
+{
+	__snd_dmaengine_pcm_close(substream, false);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
@@ -393,18 +404,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
  */
 int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
 {
-	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-	struct dma_tx_state state;
-	enum dma_status status;
-
-	status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
-	if (status == DMA_PAUSED)
-		dmaengine_terminate_async(prtd->dma_chan);
-
-	dmaengine_synchronize(prtd->dma_chan);
-	dma_release_channel(prtd->dma_chan);
-	kfree(prtd);
-
+	__snd_dmaengine_pcm_close(substream, true);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 6f73b3c2c205ee201552fb4fb1b2efbc6a63b1d0..6e7905749c4a3b60be131622309a9d308a5aa499 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -516,21 +516,38 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
 EXPORT_SYMBOL(snd_pcm_set_ops);
 
 /**
- * snd_pcm_set_sync - set the PCM sync id
+ * snd_pcm_set_sync_per_card - set the PCM sync id with card number
  * @substream: the pcm substream
+ * @params: modified hardware parameters
+ * @id: identifier (max 12 bytes)
+ * @len: identifier length (max 12 bytes)
  *
- * Sets the PCM sync identifier for the card.
+ * Sets the PCM sync identifier for the card with zero padding.
+ *
+ * User space or any user should use this 16-byte identifier for a comparison only
+ * to check if two IDs are similar or different. Special case is the identifier
+ * containing only zeros. Interpretation for this combination is - empty (not set).
+ * The contents of the identifier should not be interpreted in any other way.
+ *
+ * The synchronization ID must be unique per clock source (usually one sound card,
+ * but multiple soundcard may use one PCM word clock source which means that they
+ * are fully synchronized).
+ *
+ * This routine composes this ID using card number in first four bytes and
+ * 12-byte additional ID. When other ID composition is used (e.g. for multiple
+ * sound cards), make sure that the composition does not clash with this
+ * composition scheme.
  */
-void snd_pcm_set_sync(struct snd_pcm_substream *substream)
+void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       const unsigned char *id, unsigned int len)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	
-	runtime->sync.id32[0] = substream->pcm->card->number;
-	runtime->sync.id32[1] = -1;
-	runtime->sync.id32[2] = -1;
-	runtime->sync.id32[3] = -1;
+	*(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
+	len = min(12, len);
+	memcpy(params->sync + 4, id, len);
+	memset(params->sync + 4 + len, 0, 12 - len);
 }
-EXPORT_SYMBOL(snd_pcm_set_sync);
+EXPORT_SYMBOL_GPL(snd_pcm_set_sync_per_card);
 
 /*
  *  Standard ioctl routine
@@ -1810,6 +1827,18 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream,
+				     void *arg)
+{
+	static const unsigned char id[12] = { 0xff, 0xff, 0xff, 0xff,
+					      0xff, 0xff, 0xff, 0xff,
+					      0xff, 0xff, 0xff, 0xff };
+
+	if (substream->runtime->std_sync_id)
+		snd_pcm_set_sync_per_card(substream, arg, id, sizeof(id));
+	return 0;
+}
+
 /**
  * snd_pcm_lib_ioctl - a generic PCM ioctl callback
  * @substream: the pcm substream instance
@@ -1831,6 +1860,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 		return snd_pcm_lib_ioctl_channel_info(substream, arg);
 	case SNDRV_PCM_IOCTL1_FIFO_SIZE:
 		return snd_pcm_lib_ioctl_fifo_size(substream, arg);
+	case SNDRV_PCM_IOCTL1_SYNC_ID:
+		return snd_pcm_lib_ioctl_sync_id(substream, arg);
 	}
 	return -ENXIO;
 }
@@ -2556,6 +2587,7 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
 	struct snd_kcontrol_new knew = {
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
 		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE |
 			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
 		.info = pcm_chmap_ctl_info,
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c152ccf32214fc9712bfb1aa2bf5d4281581a2a7..4057f9f10aeec250ae9b50f168f2c096f6c77e71 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -533,6 +533,12 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
 					  SNDRV_PCM_INFO_MMAP_VALID);
 	}
 
+	err = snd_pcm_ops_ioctl(substream,
+				SNDRV_PCM_IOCTL1_SYNC_ID,
+				params);
+	if (err < 0)
+		return err;
+
 	return 0;
 }
 
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 42a7051410501826b4b0716cd1ef3009da5c3e90..8c4ee5066afe5b7f9077d957435a3b6e06dd6fce 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1718,6 +1718,8 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
 	tempo->ppq = tmr->ppq;
 	tempo->skew_value = tmr->skew;
 	tempo->skew_base = tmr->skew_base;
+	if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 4))
+		tempo->tempo_base = tmr->tempo_base;
 	queuefree(queue);
 
 	return 0;
@@ -1739,6 +1741,8 @@ static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
 	struct snd_seq_queue_tempo *tempo = arg;
 	int result;
 
+	if (client->user_pversion < SNDRV_PROTOCOL_VERSION(1, 0, 4))
+		tempo->tempo_base = 0;
 	result = snd_seq_set_queue_tempo(client->number, tempo);
 	return result < 0 ? result : 0;
 }
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 500ee6b19c717746af1b3f723d4e667825813b33..5df26788dda418ebf9bffc1d289cbaa1fab790b0 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -460,7 +460,8 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client,
 		return -EPERM;
 	}
 
-	result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq);
+	result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq,
+					     info->tempo_base);
 	if (result >= 0 && info->skew_base > 0)
 		result = snd_seq_timer_set_skew(q->timer, info->skew_value,
 						info->skew_base);
@@ -724,7 +725,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
 
 		tmr = q->timer;
 		if (tmr->tempo)
-			bpm = 60000000 / tmr->tempo;
+			bpm = (60000 * tmr->tempo_base) / tmr->tempo;
 		else
 			bpm = 0;
 
@@ -741,6 +742,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
 		snd_iprintf(buffer, "timer state        : %s\n", tmr->running ? "Running" : "Stopped");
 		snd_iprintf(buffer, "timer PPQ          : %d\n", tmr->ppq);
 		snd_iprintf(buffer, "current tempo      : %d\n", tmr->tempo);
+		snd_iprintf(buffer, "tempo base         : %d ns\n", tmr->tempo_base);
 		snd_iprintf(buffer, "current BPM        : %d\n", bpm);
 		snd_iprintf(buffer, "current time       : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec);
 		snd_iprintf(buffer, "current tick       : %d\n", tmr->tick.cur_tick);
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index ad2b97e2762d998c140eabf2a783340c8ed02e5a..c9f0392ac7f156cc6bfeb1f70721baa3f9193bd7 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -20,14 +20,17 @@
 
 static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
 {
-	if (tmr->tempo < 1000000)
-		tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
+	unsigned int threshold =
+		tmr->tempo_base == 1000 ? 1000000 : 10000;
+
+	if (tmr->tempo < threshold)
+		tmr->tick.resolution = (tmr->tempo * tmr->tempo_base) / tmr->ppq;
 	else {
 		/* might overflow.. */
 		unsigned int s;
 		s = tmr->tempo % tmr->ppq;
-		s = (s * 1000) / tmr->ppq;
-		tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
+		s = (s * tmr->tempo_base) / tmr->ppq;
+		tmr->tick.resolution = (tmr->tempo / tmr->ppq) * tmr->tempo_base;
 		tmr->tick.resolution += s;
 	}
 	if (tmr->tick.resolution <= 0)
@@ -79,6 +82,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
 	/* setup defaults */
 	tmr->ppq = 96;		/* 96 PPQ */
 	tmr->tempo = 500000;	/* 120 BPM */
+	tmr->tempo_base = 1000;	/* 1us */
 	snd_seq_timer_set_tick_resolution(tmr);
 	tmr->running = 0;
 
@@ -164,8 +168,9 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
 	return 0;
 }
 
-/* set current tempo and ppq in a shot */
-int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
+/* set current tempo, ppq and base in a shot */
+int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
+				unsigned int tempo_base)
 {
 	int changed;
 
@@ -173,6 +178,9 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
 		return -EINVAL;
 	if (tempo <= 0 || ppq <= 0)
 		return -EINVAL;
+	/* allow only 10ns or 1us tempo base for now */
+	if (tempo_base && tempo_base != 10 && tempo_base != 1000)
+		return -EINVAL;
 	guard(spinlock_irqsave)(&tmr->lock);
 	if (tmr->running && (ppq != tmr->ppq)) {
 		/* refuse to change ppq on running timers */
@@ -183,6 +191,7 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
 	changed = (tempo != tmr->tempo) || (ppq != tmr->ppq);
 	tmr->tempo = tempo;
 	tmr->ppq = ppq;
+	tmr->tempo_base = tempo_base ? tempo_base : 1000;
 	if (changed)
 		snd_seq_timer_set_tick_resolution(tmr);
 	return 0;
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h
index 4bec57df8158caf81e6cdba3248d7e252bd34643..3b906064bde1befccbd4e5755ad409d1a60f6b3a 100644
--- a/sound/core/seq/seq_timer.h
+++ b/sound/core/seq/seq_timer.h
@@ -36,6 +36,7 @@ struct snd_seq_timer {
 
 	unsigned int skew;
 	unsigned int skew_base;
+	unsigned int tempo_base;
 
 	struct timespec64	last_update;	 /* time of last clock update, used for interpolation */
 
@@ -116,7 +117,8 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr);
 int snd_seq_timer_start(struct snd_seq_timer *tmr);
 int snd_seq_timer_continue(struct snd_seq_timer *tmr);
 int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo);
-int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq);
+int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
+				unsigned int tempo_base);
 int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
 int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
 int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
index c627d72f7fe2029579a9bc41cfea5fdcbe02ee70..9cdfbeae3ed59816a0feb059b01f8641da04dacc 100644
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -28,6 +28,7 @@ struct seq_ump_group {
 	int group;			/* group index (0-based) */
 	unsigned int dir_bits;		/* directions */
 	bool active;			/* activeness */
+	bool valid;			/* valid group (referred by blocks) */
 	char name[64];			/* seq port name */
 };
 
@@ -210,6 +211,13 @@ static void fill_port_info(struct snd_seq_port_info *port,
 		sprintf(port->name, "Group %d", group->group + 1);
 }
 
+/* skip non-existing group for static blocks */
+static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *group)
+{
+	return !group->valid &&
+		(client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS);
+}
+
 /* create a new sequencer port per UMP group */
 static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
 {
@@ -217,6 +225,9 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
 	struct snd_seq_port_info *port __free(kfree) = NULL;
 	struct snd_seq_port_callback pcallbacks;
 
+	if (skip_group(client, group))
+		return 0;
+
 	port = kzalloc(sizeof(*port), GFP_KERNEL);
 	if (!port)
 		return -ENOMEM;
@@ -250,6 +261,9 @@ static void update_port_infos(struct seq_ump_client *client)
 		return;
 
 	for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
+		if (skip_group(client, &client->groups[i]))
+			continue;
+
 		old->addr.client = client->seq_client;
 		old->addr.port = i;
 		err = snd_seq_kernel_client_ctl(client->seq_client,
@@ -284,6 +298,7 @@ static void update_group_attrs(struct seq_ump_client *client)
 		group->dir_bits = 0;
 		group->active = 0;
 		group->group = i;
+		group->valid = false;
 	}
 
 	list_for_each_entry(fb, &client->ump->block_list, list) {
@@ -291,6 +306,7 @@ static void update_group_attrs(struct seq_ump_client *client)
 			break;
 		group = &client->groups[fb->info.first_group];
 		for (i = 0; i < fb->info.num_groups; i++, group++) {
+			group->valid = true;
 			if (fb->info.active)
 				group->active = 1;
 			switch (fb->info.direction) {
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 04a57f7be6ea42ae2891b70cf85f0b7048389665..c657659b236c4245077afe0479dd6b10f6892456 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -198,6 +198,12 @@ static int follower_put(struct snd_kcontrol *kcontrol,
 	err = follower_init(follower);
 	if (err < 0)
 		return err;
+	for (ch = 0; ch < follower->info.count; ch++) {
+		if (ucontrol->value.integer.value[ch] < follower->info.min_val ||
+		    ucontrol->value.integer.value[ch] > follower->info.max_val)
+			return -EINVAL;
+	}
+
 	for (ch = 0; ch < follower->info.count; ch++) {
 		if (follower->vals[ch] != ucontrol->value.integer.value[ch]) {
 			changed = 1;
@@ -365,6 +371,8 @@ static int master_put(struct snd_kcontrol *kcontrol,
 	new_val = ucontrol->value.integer.value[0];
 	if (new_val == old_val)
 		return 0;
+	if (new_val < master->info.min_val || new_val > master->info.max_val)
+		return -EINVAL;
 
 	err = sync_followers(master, old_val, new_val);
 	if (err < 0)
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 068c16e52dffafe637ae1faab4303796cacd9d36..3fbb9793dcfcedebb8b91697a08e1c764daa4e08 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -665,6 +665,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = {
 	{ 0x19e5, "Huawei" },
 	{ 0x1aec, "Wolfson Microelectronics" },
 	{ 0x1af4, "QEMU" },
+	{ 0x1fa8, "Senarytech" },
 	{ 0x434d, "C-Media" },
 	{ 0x8086, "Intel" },
 	{ 0x8384, "SigmaTel" },
diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c
index 5d8e1d944b0afb2128c8770583f947eb3d3df85e..7b276047f85a7d2849803eafb0f282378dab2a45 100644
--- a/sound/hda/hdmi_chmap.c
+++ b/sound/hda/hdmi_chmap.c
@@ -753,6 +753,20 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+/* a simple sanity check for input values to chmap kcontrol */
+static int chmap_value_check(struct hdac_chmap *hchmap,
+			     const struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+
+	for (i = 0; i < hchmap->channels_max; i++) {
+		if (ucontrol->value.integer.value[i] < 0 ||
+		    ucontrol->value.integer.value[i] > SNDRV_CHMAP_LAST)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
@@ -764,6 +778,10 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 	unsigned char chmap[8], per_pin_chmap[8];
 	int i, err, ca, prepared = 0;
 
+	err = chmap_value_check(hchmap, ucontrol);
+	if (err < 0)
+		return err;
+
 	/* No monitor is connected in dyn_pcm_assign.
 	 * It's invalid to setup the chmap
 	 */
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index 478d2b50c571de4a10a21f8bc504a03da2f07e5b..913880b090657fa71c00dae5332cbf3bc3dfa2cf 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -543,6 +543,15 @@ static const struct config_entry config_table[] = {
 		.device = PCI_DEVICE_ID_INTEL_HDA_LNL_P,
 	},
 #endif
+
+	/* Panther Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_PANTHERLAKE)
+	{
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+		.device = PCI_DEVICE_ID_INTEL_HDA_PTL,
+	},
+#endif
+
 };
 
 static const struct config_entry *snd_intel_dsp_find_config
diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c
index d7417a40392b2dc02647ff3ffb0802cfada6fa35..f3b2a610df23272bf2cf8a3e22886ab566d39683 100644
--- a/sound/hda/intel-sdw-acpi.c
+++ b/sound/hda/intel-sdw-acpi.c
@@ -125,11 +125,11 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
 				     void *cdata, void **return_value)
 {
 	struct sdw_intel_acpi_info *info = cdata;
-	acpi_status status;
 	u64 adr;
+	int ret;
 
-	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-	if (ACPI_FAILURE(status))
+	ret = acpi_get_local_u64_address(handle, &adr);
+	if (ret < 0)
 		return AE_OK; /* keep going */
 
 	if (!acpi_fetch_acpi_dev(handle)) {
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index a6405772d5370266a916a80a76615371b65cd45a..af478c36ce5b1fbf42871cfa0eaf05c01976d176 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -1039,10 +1039,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
 	return 0;
 
 __error:
-	for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
-		if (emu->controls[i])
-			snd_ctl_remove(card, emu->controls[i]);
-	}
+	for (i = 0; i < EMU8000_NUM_CONTROLS; i++)
+		snd_ctl_remove(card, emu->controls[i]);
 	return err;
 }
 
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 8d8357019719974e0fe47a61eb984ad5c3fc415f..fdb992733bde1051202d56736a25913b600af40f 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -1080,14 +1080,10 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
 
 	card = p->chip->card;	
 	
-	if (p->qsound_switch) {
-		snd_ctl_remove(card, p->qsound_switch);
-		p->qsound_switch = NULL;
-	}
-	if (p->qsound_space) {
-		snd_ctl_remove(card, p->qsound_space);
-		p->qsound_space = NULL;
-	}
+	snd_ctl_remove(card, p->qsound_switch);
+	p->qsound_switch = NULL;
+	snd_ctl_remove(card, p->qsound_space);
+	p->qsound_space = NULL;
 
 	/* cancel pending transfer of QSound parameters */
 	spin_lock_irqsave (&p->q_lock, flags);
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index e7f097cae574e63a3af636cee8fda50f29428a16..a9a75891f1da4716d0df1568a10a8fe9f36e2d57 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -174,11 +174,6 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
 	if (err < 0)
                 return err;
 
-	runtime->sync.id32[0] = substream->pcm->card->number;
-	runtime->sync.id32[1] = 'P';
-	runtime->sync.id32[2] = 16;
-	runtime->sync.id32[3] = 'V';
-
 	return 0;
 }
 
@@ -226,6 +221,17 @@ static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream)
 	return snd_p16v_pcm_open_capture_channel(substream, 0);
 }
 
+static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream,
+				       unsigned int cmd, void *arg)
+{
+	if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) {
+		static const unsigned char id[4] = { 'P', '1', '6', 'V' };
+		snd_pcm_set_sync_per_card(substream, arg, id, 4);
+		return 0;
+	}
+	return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
 /* prepare playback callback */
 static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
 {
@@ -531,6 +537,7 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream)
 static const struct snd_pcm_ops snd_p16v_playback_front_ops = {
 	.open =        snd_p16v_pcm_open_playback_front,
 	.close =       snd_p16v_pcm_close_playback,
+	.ioctl =       snd_p16v_pcm_ioctl_playback,
 	.prepare =     snd_p16v_pcm_prepare_playback,
 	.trigger =     snd_p16v_pcm_trigger_playback,
 	.pointer =     snd_p16v_pcm_pointer_playback,
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index a3cf0725fc43b0d210cc149e8bc11af7edbce74e..bb15a0248250cc42844e5fa08811ff774178937e 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -294,6 +294,17 @@ config SND_HDA_CODEC_CONEXANT
 comment "Set to Y if you want auto-loading the codec driver"
 	depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
 
+config SND_HDA_CODEC_SENARYTECH
+	tristate "Build Senarytech HD-audio codec support"
+	select SND_HDA_GENERIC
+	select SND_HDA_GENERIC_LEDS
+	help
+	  Say Y or M here to include Senarytech HD-audio codec support in
+	  snd-hda-intel driver, such as SN6186.
+
+comment "Set to Y if you want auto-loading the codec driver"
+	depends on SND_HDA=y && SND_HDA_CODEC_SENARYTECH=m
+
 config SND_HDA_CODEC_CA0110
 	tristate "Build Creative CA0110-IBG codec support"
 	select SND_HDA_GENERIC
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 058ca0a289e4d2192631b1730dfdb4f123b6f2cf..80210f845df212197be3ff31bd0277cac928e192 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -24,6 +24,7 @@ snd-hda-codec-cs8409-y :=	patch_cs8409.o patch_cs8409-tables.o
 snd-hda-codec-ca0110-y :=	patch_ca0110.o
 snd-hda-codec-ca0132-y :=	patch_ca0132.o
 snd-hda-codec-conexant-y :=	patch_conexant.o
+snd-hda-codec-senarytech-y :=patch_senarytech.o
 snd-hda-codec-via-y :=		patch_via.o
 snd-hda-codec-hdmi-y :=		patch_hdmi.o hda_eld.o
 
@@ -55,6 +56,7 @@ obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
 obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
 obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
 obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
+obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
 obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
 obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
 
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 031703f010be5b25aee4f124915862a4b1af77dc..4b411ed8c3fe0e794a86c13f33351cb7be27b2b1 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -1419,27 +1419,29 @@ static void cs35l41_acpi_device_notify(acpi_handle handle, u32 event, struct dev
 static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
 {
 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-	struct hda_component *comps = master_data;
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
 	unsigned int sleep_flags;
 	int ret = 0;
 
-	if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS)
+	comp = hda_component_from_index(parent, cs35l41->index);
+	if (!comp)
 		return -EINVAL;
 
-	comps = &comps[cs35l41->index];
-	if (comps->dev)
+	if (comp->dev)
 		return -EBUSY;
 
 	pm_runtime_get_sync(dev);
 
 	mutex_lock(&cs35l41->fw_mutex);
 
-	comps->dev = dev;
+	comp->dev = dev;
+	cs35l41->codec = parent->codec;
 	if (!cs35l41->acpi_subsystem_id)
 		cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x",
-						       comps->codec->core.subsystem_id);
-	cs35l41->codec = comps->codec;
-	strscpy(comps->name, dev_name(dev), sizeof(comps->name));
+						       cs35l41->codec->core.subsystem_id);
+
+	strscpy(comp->name, dev_name(dev), sizeof(comp->name));
 
 	cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT;
 
@@ -1454,13 +1456,13 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
 
 	ret = cs35l41_create_controls(cs35l41);
 
-	comps->playback_hook = cs35l41_hda_playback_hook;
-	comps->pre_playback_hook = cs35l41_hda_pre_playback_hook;
-	comps->post_playback_hook = cs35l41_hda_post_playback_hook;
-	comps->acpi_notify = cs35l41_acpi_device_notify;
-	comps->adev = cs35l41->dacpi;
+	comp->playback_hook = cs35l41_hda_playback_hook;
+	comp->pre_playback_hook = cs35l41_hda_pre_playback_hook;
+	comp->post_playback_hook = cs35l41_hda_post_playback_hook;
+	comp->acpi_notify = cs35l41_acpi_device_notify;
+	comp->adev = cs35l41->dacpi;
 
-	comps->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comps->adev),
+	comp->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comp->adev),
 		CS35L41_DSM_GET_MUTE);
 
 	cs35l41->mute_override = cs35l41_get_acpi_mute_state(cs35l41,
@@ -1469,7 +1471,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
 	mutex_unlock(&cs35l41->fw_mutex);
 
 	sleep_flags = lock_system_sleep();
-	if (!device_link_add(&comps->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS))
+	if (!device_link_add(&cs35l41->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS))
 		dev_warn(dev, "Unable to create device link\n");
 	unlock_system_sleep(sleep_flags);
 
@@ -1489,14 +1491,19 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
 static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
 {
 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-	struct hda_component *comps = master_data;
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
 	unsigned int sleep_flags;
 
-	if (comps[cs35l41->index].dev == dev) {
-		memset(&comps[cs35l41->index], 0, sizeof(*comps));
+	comp = hda_component_from_index(parent, cs35l41->index);
+	if (!comp)
+		return;
+
+	if (comp->dev == dev) {
 		sleep_flags = lock_system_sleep();
 		device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev);
 		unlock_system_sleep(sleep_flags);
+		memset(comp, 0, sizeof(*comp));
 	}
 }
 
@@ -1746,38 +1753,14 @@ int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int
 	return speaker_id;
 }
 
-static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
+int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id)
 {
 	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
 	u32 values[HDA_MAX_COMPONENTS];
-	struct acpi_device *adev;
-	struct device *physdev;
-	struct spi_device *spi;
-	const char *sub;
 	char *property;
 	size_t nval;
 	int i, ret;
 
-	adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
-	if (!adev) {
-		dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
-		return -ENODEV;
-	}
-
-	cs35l41->dacpi = adev;
-	physdev = get_device(acpi_get_first_physical_node(adev));
-
-	sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
-	if (IS_ERR(sub))
-		sub = NULL;
-	cs35l41->acpi_subsystem_id = sub;
-
-	ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
-	if (!ret) {
-		dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
-		goto out;
-	}
-
 	property = "cirrus,dev-index";
 	ret = device_property_count_u32(physdev, property);
 	if (ret <= 0)
@@ -1809,8 +1792,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
 	/* To use the same release code for all laptop variants we can't use devm_ version of
 	 * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
 	 */
-	cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index,
-						     GPIOD_OUT_LOW, "cs35l41-reset");
+	cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
+						     cs35l41->index, GPIOD_OUT_LOW,
+						     "cs35l41-reset");
 
 	property = "cirrus,speaker-position";
 	ret = device_property_read_u32_array(physdev, property, values, nval);
@@ -1866,6 +1850,51 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
 		hw_cfg->bst_type = CS35L41_EXT_BOOST;
 
 	hw_cfg->valid = true;
+
+	return 0;
+err:
+	dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
+	hw_cfg->valid = false;
+	hw_cfg->gpio1.valid = false;
+	hw_cfg->gpio2.valid = false;
+	acpi_dev_put(cs35l41->dacpi);
+
+	return ret;
+}
+
+static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
+{
+	struct acpi_device *adev;
+	struct device *physdev;
+	struct spi_device *spi;
+	const char *sub;
+	int ret;
+
+	adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+	if (!adev) {
+		dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
+		return -ENODEV;
+	}
+
+	cs35l41->dacpi = adev;
+	physdev = get_device(acpi_get_first_physical_node(adev));
+
+	sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+	if (IS_ERR(sub))
+		sub = NULL;
+	cs35l41->acpi_subsystem_id = sub;
+
+	ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
+	if (!ret) {
+		dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
+		goto out;
+	}
+
+	ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id);
+	if (ret) {
+		put_device(physdev);
+		return ret;
+	}
 out:
 	put_device(physdev);
 
@@ -1881,16 +1910,6 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
 	}
 
 	return 0;
-
-err:
-	dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
-	hw_cfg->valid = false;
-	hw_cfg->gpio1.valid = false;
-	hw_cfg->gpio2.valid = false;
-	acpi_dev_put(cs35l41->dacpi);
-	put_device(physdev);
-
-	return ret;
 }
 
 int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h
index b0bebb7784623052a63349f7f6d1301f37792952..c730b335158944f4aef86cfc3da60b90752d08af 100644
--- a/sound/pci/hda/cs35l41_hda.h
+++ b/sound/pci/hda/cs35l41_hda.h
@@ -104,5 +104,6 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
 		      struct regmap *regmap, enum control_bus control_bus);
 void cs35l41_hda_remove(struct device *dev);
 int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id);
+int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id);
 
 #endif /*__CS35L41_HDA_H__*/
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
index 80c816922f788a151d89f8685149494d4f76603b..61d2314834e7b1da13c9b6189891cb35c6c8a2d2 100644
--- a/sound/pci/hda/cs35l41_hda_property.c
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -428,6 +428,20 @@ static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *phy
 	return 0;
 }
 
+static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+				    const char *hid)
+{
+	int ret;
+
+	ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2);
+	if (ret) {
+		dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
+		return ret;
+	}
+
+	return cs35l41_hda_parse_acpi(cs35l41, physdev, id);
+}
+
 struct cs35l41_prop_model {
 	const char *hid;
 	const char *ssid;
@@ -501,6 +515,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
 	{ "CSC3551", "104317F3", generic_dsd_config },
 	{ "CSC3551", "10431863", generic_dsd_config },
 	{ "CSC3551", "104318D3", generic_dsd_config },
+	{ "CSC3551", "10431A63", missing_speaker_id_gpio2 },
 	{ "CSC3551", "10431A83", generic_dsd_config },
 	{ "CSC3551", "10431B93", generic_dsd_config },
 	{ "CSC3551", "10431C9F", generic_dsd_config },
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c
index e134ede6c5aa54d98454467222c863005533801c..96d3f13c5abf9f24636294a8262b54b579e08269 100644
--- a/sound/pci/hda/cs35l56_hda.c
+++ b/sound/pci/hda/cs35l56_hda.c
@@ -50,11 +50,19 @@ static const struct reg_sequence cs35l56_hda_dai_config[] = {
 
 };
 
+static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56)
+{
+	/* Wait for patching to complete */
+	flush_work(&cs35l56->dsp_work);
+}
+
 static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
 {
 	unsigned int val;
 	int ret;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	pm_runtime_get_sync(cs35l56->base.dev);
 	ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);
 	if (ret == 0) {
@@ -180,6 +188,8 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
 	unsigned int reg_val;
 	int i;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
 	reg_val &= CS35L56_ASP_TXn_SRC_MASK;
 
@@ -203,6 +213,8 @@ static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
 	if (item >= CS35L56_NUM_INPUT_SRC)
 		return -EINVAL;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
 				 CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
 				 &changed);
@@ -227,6 +239,8 @@ static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
 	unsigned int pos;
 	int ret;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos);
 	if (ret)
 		return ret;
@@ -248,6 +262,8 @@ static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
 	    (pos > CS35L56_MAIN_POSTURE_MAX))
 		return -EINVAL;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	ret = regmap_update_bits_check(cs35l56->base.regmap,
 				       CS35L56_MAIN_POSTURE_NUMBER,
 				       CS35L56_MAIN_POSTURE_MASK,
@@ -291,6 +307,8 @@ static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,
 	int vol;
 	int ret;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol);
 
 	if (ret)
@@ -323,6 +341,8 @@ static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,
 	raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<
 		  CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+
 	ret = regmap_update_bits_check(cs35l56->base.regmap,
 				       CS35L56_MAIN_RENDER_USER_VOLUME,
 				       CS35L56_MAIN_RENDER_USER_VOLUME_MASK,
@@ -539,8 +559,9 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw
 	kfree(coeff_filename);
 }
 
-static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56)
+static void cs35l56_hda_create_dsp_controls_work(struct work_struct *work)
 {
+	struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, control_work);
 	struct hda_cs_dsp_ctl_info info;
 
 	info.device_name = cs35l56->amp_name;
@@ -566,7 +587,7 @@ static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
 		dev_info(cs35l56->base.dev, "Calibration applied\n");
 }
 
-static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
+static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
 {
 	const struct firmware *coeff_firmware = NULL;
 	const struct firmware *wmfw_firmware = NULL;
@@ -574,15 +595,34 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
 	char *wmfw_filename = NULL;
 	unsigned int preloaded_fw_ver;
 	bool firmware_missing;
-	int ret = 0;
+	bool add_dsp_controls_required = false;
+	int ret;
+
+	/*
+	 * control_work must be flushed before proceeding, but we can't do that
+	 * here as it would create a deadlock on controls_rwsem so it must be
+	 * performed before queuing dsp_work.
+	 */
+	WARN_ON_ONCE(work_busy(&cs35l56->control_work));
 
-	/* Prepare for a new DSP power-up */
+	/*
+	 * Prepare for a new DSP power-up. If the DSP has had firmware
+	 * downloaded previously then it needs to be powered down so that it
+	 * can be updated and if hadn't been patched before then the controls
+	 * will need to be added once firmware download succeeds.
+	 */
 	if (cs35l56->base.fw_patched)
 		cs_dsp_power_down(&cs35l56->cs_dsp);
+	else
+		add_dsp_controls_required = true;
 
 	cs35l56->base.fw_patched = false;
 
-	pm_runtime_get_sync(cs35l56->base.dev);
+	ret = pm_runtime_resume_and_get(cs35l56->base.dev);
+	if (ret < 0) {
+		dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret);
+		return;
+	}
 
 	/*
 	 * The firmware can only be upgraded if it is currently running
@@ -606,7 +646,6 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
 	 */
 	if (!coeff_firmware && firmware_missing) {
 		dev_err(cs35l56->base.dev, ".bin file required but not found\n");
-		ret = -ENOENT;
 		goto err_fw_release;
 	}
 
@@ -659,6 +698,15 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
 			  CS35L56_FIRMWARE_MISSING);
 	cs35l56->base.fw_patched = true;
 
+	/*
+	 * Adding controls is deferred to prevent a lock inversion - ALSA takes
+	 * the controls_rwsem when adding a control, the get() / put()
+	 * functions of a control are called holding controls_rwsem and those
+	 * that depend on running firmware wait for dsp_work() to complete.
+	 */
+	if (add_dsp_controls_required)
+		queue_work(system_long_wq, &cs35l56->control_work);
+
 	ret = cs_dsp_run(&cs35l56->cs_dsp);
 	if (ret)
 		dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
@@ -678,34 +726,37 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
 					   coeff_firmware, coeff_filename);
 err_pm_put:
 	pm_runtime_put(cs35l56->base.dev);
+}
 
-	return ret;
+static void cs35l56_hda_dsp_work(struct work_struct *work)
+{
+	struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work);
+
+	cs35l56_hda_fw_load(cs35l56);
 }
 
 static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
 {
 	struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-	struct hda_component *comps = master_data;
-	int ret;
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
 
-	if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS)
+	comp = hda_component_from_index(parent, cs35l56->index);
+	if (!comp)
 		return -EINVAL;
 
-	comps = &comps[cs35l56->index];
-	if (comps->dev)
+	if (comp->dev)
 		return -EBUSY;
 
-	comps->dev = dev;
-	cs35l56->codec = comps->codec;
-	strscpy(comps->name, dev_name(dev), sizeof(comps->name));
-	comps->playback_hook = cs35l56_hda_playback_hook;
+	comp->dev = dev;
+	cs35l56->codec = parent->codec;
+	strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+	comp->playback_hook = cs35l56_hda_playback_hook;
 
-	ret = cs35l56_hda_fw_load(cs35l56);
-	if (ret)
-		return ret;
+	flush_work(&cs35l56->control_work);
+	queue_work(system_long_wq, &cs35l56->dsp_work);
 
 	cs35l56_hda_create_controls(cs35l56);
-	cs35l56_hda_add_dsp_controls(cs35l56);
 
 #if IS_ENABLED(CONFIG_SND_DEBUG)
 	cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);
@@ -720,7 +771,11 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas
 static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)
 {
 	struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-	struct hda_component *comps = master_data;
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
+
+	cancel_work_sync(&cs35l56->dsp_work);
+	cancel_work_sync(&cs35l56->control_work);
 
 	cs35l56_hda_remove_controls(cs35l56);
 
@@ -732,8 +787,9 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *
 	if (cs35l56->base.fw_patched)
 		cs_dsp_power_down(&cs35l56->cs_dsp);
 
-	if (comps[cs35l56->index].dev == dev)
-		memset(&comps[cs35l56->index], 0, sizeof(*comps));
+	comp = hda_component_from_index(parent, cs35l56->index);
+	if (comp && (comp->dev == dev))
+		memset(comp, 0, sizeof(*comp));
 
 	cs35l56->codec = NULL;
 
@@ -749,6 +805,9 @@ static int cs35l56_hda_system_suspend(struct device *dev)
 {
 	struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
 
+	cs35l56_hda_wait_dsp_ready(cs35l56);
+	flush_work(&cs35l56->control_work);
+
 	if (cs35l56->playing)
 		cs35l56_hda_pause(cs35l56);
 
@@ -847,11 +906,8 @@ static int cs35l56_hda_system_resume(struct device *dev)
 
 	ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
 	dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
-	if (ret > 0) {
-		ret = cs35l56_hda_fw_load(cs35l56);
-		if (ret)
-			return ret;
-	}
+	if (ret > 0)
+		queue_work(system_long_wq, &cs35l56->dsp_work);
 
 	if (cs35l56->playing)
 		cs35l56_hda_play(cs35l56);
@@ -969,6 +1025,9 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
 	mutex_init(&cs35l56->base.irq_lock);
 	dev_set_drvdata(cs35l56->base.dev, cs35l56);
 
+	INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work);
+	INIT_WORK(&cs35l56->control_work, cs35l56_hda_create_dsp_controls_work);
+
 	ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
 	if (ret)
 		goto err;
diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h
index 464e4aa63cd1b18c380571031a6148733eb4edb4..c40d159507c26d51568aabdd75b6c37facceebbe 100644
--- a/sound/pci/hda/cs35l56_hda.h
+++ b/sound/pci/hda/cs35l56_hda.h
@@ -14,6 +14,7 @@
 #include <linux/firmware/cirrus/cs_dsp.h>
 #include <linux/firmware/cirrus/wmfw.h>
 #include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
 #include <sound/cs35l56.h>
 
 struct dentry;
@@ -21,6 +22,8 @@ struct dentry;
 struct cs35l56_hda {
 	struct cs35l56_base base;
 	struct hda_codec *codec;
+	struct work_struct dsp_work;
+	struct work_struct control_work;
 
 	int index;
 	const char *system_name;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 325e8f0b99a82911f8509490de7b725a44f7e3b5..3dd1bda0c5c69ef4be01b9e40d3d08124f30792e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1496,7 +1496,7 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
 	/* ofs = 0: raw max value */
 	maxval = get_amp_max_value(codec, nid, dir, 0);
 	if (val > maxval)
-		val = maxval;
+		return -EINVAL;
 	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
 					HDA_AMP_VOLMASK, val);
 }
@@ -1547,13 +1547,21 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
 	unsigned int ofs = get_amp_offset(kcontrol);
 	long *valp = ucontrol->value.integer.value;
 	int change = 0;
+	int err;
 
 	if (chs & 1) {
-		change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
+		err = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
+		if (err < 0)
+			return err;
+		change |= err;
 		valp++;
 	}
-	if (chs & 2)
-		change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
+	if (chs & 2) {
+		err = update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
+		if (err < 0)
+			return err;
+		change |= err;
+	}
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
@@ -2149,15 +2157,20 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
 	int change = 0;
 
 	if (chs & 1) {
+		if (*valp < 0 || *valp > 1)
+			return -EINVAL;
 		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
 						  HDA_AMP_MUTE,
 						  *valp ? 0 : HDA_AMP_MUTE);
 		valp++;
 	}
-	if (chs & 2)
+	if (chs & 2) {
+		if (*valp < 0 || *valp > 1)
+			return -EINVAL;
 		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
 						   HDA_AMP_MUTE,
 						   *valp ? 0 : HDA_AMP_MUTE);
+	}
 	hda_call_check_power_status(codec, nid);
 	return change;
 }
diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c
index d02589014a3fa6305a80e3420c67b1a0fc53b193..7b19cb38b4e025a363435595d2d8ca03ba86cf02 100644
--- a/sound/pci/hda/hda_component.c
+++ b/sound/pci/hda/hda_component.c
@@ -15,35 +15,41 @@
 #include "hda_local.h"
 
 #ifdef CONFIG_ACPI
-void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps,
+void hda_component_acpi_device_notify(struct hda_component_parent *parent,
 				      acpi_handle handle, u32 event, void *data)
 {
+	struct hda_component *comp;
 	int i;
 
-	for (i = 0; i < num_comps; i++) {
-		if (comps[i].dev && comps[i].acpi_notify)
-			comps[i].acpi_notify(acpi_device_handle(comps[i].adev), event,
-					     comps[i].dev);
+	mutex_lock(&parent->mutex);
+	for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+		comp = hda_component_from_index(parent, i);
+		if (comp->dev && comp->acpi_notify)
+			comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev);
 	}
+	mutex_unlock(&parent->mutex);
 }
 EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT);
 
 int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
-						  struct hda_component *comps, int num_comps,
+						  struct hda_component_parent *parent,
 						  acpi_notify_handler handler, void *data)
 {
 	bool support_notifications = false;
 	struct acpi_device *adev;
+	struct hda_component *comp;
 	int ret;
 	int i;
 
-	adev = comps[0].adev;
+	adev = parent->comps[0].adev;
 	if (!acpi_device_handle(adev))
 		return 0;
 
-	for (i = 0; i < num_comps; i++)
+	for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+		comp = hda_component_from_index(parent, i);
 		support_notifications = support_notifications ||
-			comps[i].acpi_notifications_supported;
+			comp->acpi_notifications_supported;
+	}
 
 	if (support_notifications) {
 		ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
@@ -61,13 +67,13 @@ int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
 EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT);
 
 void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
-						     struct hda_component *comps,
+						     struct hda_component_parent *parent,
 						     acpi_notify_handler handler)
 {
 	struct acpi_device *adev;
 	int ret;
 
-	adev = comps[0].adev;
+	adev = parent->comps[0].adev;
 	if (!acpi_device_handle(adev))
 		return;
 
@@ -78,22 +84,28 @@ void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
 EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT);
 #endif /* ifdef CONFIG_ACPI */
 
-void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, int action)
+void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action)
 {
+	struct hda_component *comp;
 	int i;
 
-	for (i = 0; i < num_comps; i++) {
-		if (comps[i].dev && comps[i].pre_playback_hook)
-			comps[i].pre_playback_hook(comps[i].dev, action);
+	mutex_lock(&parent->mutex);
+	for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+		comp = hda_component_from_index(parent, i);
+		if (comp->dev && comp->pre_playback_hook)
+			comp->pre_playback_hook(comp->dev, action);
 	}
-	for (i = 0; i < num_comps; i++) {
-		if (comps[i].dev && comps[i].playback_hook)
-			comps[i].playback_hook(comps[i].dev, action);
+	for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+		comp = hda_component_from_index(parent, i);
+		if (comp->dev && comp->playback_hook)
+			comp->playback_hook(comp->dev, action);
 	}
-	for (i = 0; i < num_comps; i++) {
-		if (comps[i].dev && comps[i].post_playback_hook)
-			comps[i].post_playback_hook(comps[i].dev, action);
+	for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+		comp = hda_component_from_index(parent, i);
+		if (comp->dev && comp->post_playback_hook)
+			comp->post_playback_hook(comp->dev, action);
 	}
+	mutex_unlock(&parent->mutex);
 }
 EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT);
 
@@ -124,22 +136,25 @@ static int hda_comp_match_dev_name(struct device *dev, void *data)
 }
 
 int hda_component_manager_bind(struct hda_codec *cdc,
-			       struct hda_component *comps, int count)
+			       struct hda_component_parent *parent)
 {
-	int i;
+	int ret;
 
-	/* Init shared data */
-	for (i = 0; i < count; ++i) {
-		memset(&comps[i], 0, sizeof(comps[i]));
-		comps[i].codec = cdc;
-	}
+	/* Init shared and component specific data */
+	memset(parent, 0, sizeof(*parent));
+	mutex_init(&parent->mutex);
+	parent->codec = cdc;
+
+	mutex_lock(&parent->mutex);
+	ret = component_bind_all(hda_codec_dev(cdc), parent);
+	mutex_unlock(&parent->mutex);
 
-	return component_bind_all(hda_codec_dev(cdc), comps);
+	return ret;
 }
 EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT);
 
 int hda_component_manager_init(struct hda_codec *cdc,
-			       struct hda_component *comps, int count,
+			       struct hda_component_parent *parent, int count,
 			       const char *bus, const char *hid,
 			       const char *match_str,
 			       const struct component_master_ops *ops)
diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h
index c70b3de68ab2063c2807af0771f34646b136a107..9f786608144c0f74f7cbedcfe6038da4309c8fac 100644
--- a/sound/pci/hda/hda_component.h
+++ b/sound/pci/hda/hda_component.h
@@ -11,6 +11,7 @@
 
 #include <linux/acpi.h>
 #include <linux/component.h>
+#include <linux/mutex.h>
 #include <sound/hda_codec.h>
 
 #define HDA_MAX_COMPONENTS	4
@@ -19,7 +20,6 @@
 struct hda_component {
 	struct device *dev;
 	char name[HDA_MAX_NAME_SIZE];
-	struct hda_codec *codec;
 	struct acpi_device *adev;
 	bool acpi_notifications_supported;
 	void (*acpi_notify)(acpi_handle handle, u32 event, struct device *dev);
@@ -28,18 +28,23 @@ struct hda_component {
 	void (*post_playback_hook)(struct device *dev, int action);
 };
 
+struct hda_component_parent {
+	struct mutex mutex;
+	struct hda_codec *codec;
+	struct hda_component comps[HDA_MAX_COMPONENTS];
+};
+
 #ifdef CONFIG_ACPI
-void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps,
+void hda_component_acpi_device_notify(struct hda_component_parent *parent,
 				      acpi_handle handle, u32 event, void *data);
 int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
-						  struct hda_component *comps, int num_comps,
+						  struct hda_component_parent *parent,
 						  acpi_notify_handler handler, void *data);
 void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
-						     struct hda_component *comps,
+						     struct hda_component_parent *parent,
 						     acpi_notify_handler handler);
 #else
-static inline void hda_component_acpi_device_notify(struct hda_component *comps,
-						    int num_comps,
+static inline void hda_component_acpi_device_notify(struct hda_component_parent *parent,
 						    acpi_handle handle,
 						    u32 event,
 						    void *data)
@@ -47,8 +52,7 @@ static inline void hda_component_acpi_device_notify(struct hda_component *comps,
 }
 
 static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
-								struct hda_component *comps,
-								int num_comps,
+								struct hda_component_parent *parent,
 								acpi_notify_handler handler,
 								void *data)
 
@@ -57,17 +61,16 @@ static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec
 }
 
 static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
-								   struct hda_component *comps,
+								   struct hda_component_parent *parent,
 								   acpi_notify_handler handler)
 {
 }
 #endif /* ifdef CONFIG_ACPI */
 
-void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps,
-					 int action);
+void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action);
 
 int hda_component_manager_init(struct hda_codec *cdc,
-			       struct hda_component *comps, int count,
+			       struct hda_component_parent *parent, int count,
 			       const char *bus, const char *hid,
 			       const char *match_str,
 			       const struct component_master_ops *ops);
@@ -75,13 +78,26 @@ int hda_component_manager_init(struct hda_codec *cdc,
 void hda_component_manager_free(struct hda_codec *cdc,
 				const struct component_master_ops *ops);
 
-int hda_component_manager_bind(struct hda_codec *cdc,
-			       struct hda_component *comps, int count);
+int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent);
+
+static inline struct hda_component *hda_component_from_index(struct hda_component_parent *parent,
+							     int index)
+{
+	if (!parent)
+		return NULL;
+
+	if (index < 0 || index >= ARRAY_SIZE(parent->comps))
+		return NULL;
+
+	return &parent->comps[index];
+}
 
 static inline void hda_component_manager_unbind(struct hda_codec *cdc,
-					       struct hda_component *comps)
+						struct hda_component_parent *parent)
 {
-	component_unbind_all(hda_codec_dev(cdc), comps);
+	mutex_lock(&parent->mutex);
+	component_unbind_all(hda_codec_dev(cdc), parent);
+	mutex_unlock(&parent->mutex);
 }
 
 #endif /* ifndef __HDA_COMPONENT_H__ */
diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c
index e6e876998e7131962b30110fd5b1205fb80e5c67..deb74c2470829ff6014fcef26be56e8b292bd620 100644
--- a/sound/pci/hda/hda_cs_dsp_ctl.c
+++ b/sound/pci/hda/hda_cs_dsp_ctl.c
@@ -207,7 +207,7 @@ void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
 	struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv;
 
 	/* ctl and kctl may already have been removed by ALSA private_free */
-	if (ctl && ctl->kctl)
+	if (ctl)
 		snd_ctl_remove(ctl->card, ctl->kctl);
 }
 EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 3500108f6ba37535a490bdd075d876a6846b7b44..b33602e64d174c8af1bf196ee5b0ce90668f9681 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2495,6 +2495,8 @@ static const struct pci_device_id azx_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
 	/* Arrow Lake */
 	{ PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+	/* Panther Lake */
+	{ PCI_DEVICE_DATA(INTEL, HDA_PTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
 	/* Apollolake (Broxton-P) */
 	{ PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
 	/* Gemini-Lake */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 766f0b1d3e9d6e6b93df2a007fedf01c2b8804fc..c3a86a99f8c6d8f6a0f7b3df809f117082e68514 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -131,7 +131,7 @@ struct alc_spec {
 	u8 alc_mute_keycode_map[1];
 
 	/* component binding */
-	struct hda_component comps[HDA_MAX_COMPONENTS];
+	struct hda_component_parent comps;
 };
 
 /*
@@ -6793,8 +6793,7 @@ static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
 
 	codec_info(cdc, "ACPI Notification %d\n", event);
 
-	hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps),
-					 handle, event, data);
+	hda_component_acpi_device_notify(&spec->comps, handle, event, data);
 }
 
 static int comp_bind(struct device *dev)
@@ -6803,12 +6802,12 @@ static int comp_bind(struct device *dev)
 	struct alc_spec *spec = cdc->spec;
 	int ret;
 
-	ret = hda_component_manager_bind(cdc, spec->comps, ARRAY_SIZE(spec->comps));
+	ret = hda_component_manager_bind(cdc, &spec->comps);
 	if (ret)
 		return ret;
 
 	return hda_component_manager_bind_acpi_notifications(cdc,
-							     spec->comps, ARRAY_SIZE(spec->comps),
+							     &spec->comps,
 							     comp_acpi_device_notify, cdc);
 }
 
@@ -6817,8 +6816,8 @@ static void comp_unbind(struct device *dev)
 	struct hda_codec *cdc = dev_to_hda_codec(dev);
 	struct alc_spec *spec = cdc->spec;
 
-	hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify);
-	hda_component_manager_unbind(cdc, spec->comps);
+	hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify);
+	hda_component_manager_unbind(cdc, &spec->comps);
 }
 
 static const struct component_master_ops comp_master_ops = {
@@ -6831,7 +6830,7 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_
 {
 	struct alc_spec *spec = cdc->spec;
 
-	hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action);
+	hda_component_manager_playback_hook(&spec->comps, action);
 }
 
 static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
@@ -6842,7 +6841,7 @@ static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bu
 
 	switch (action) {
 	case HDA_FIXUP_ACT_PRE_PROBE:
-		ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid,
+		ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid,
 						 match_str, &comp_master_ops);
 		if (ret)
 			return;
@@ -10384,6 +10383,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
 	SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
 	SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
+	SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
 	SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
 	SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
@@ -10398,6 +10398,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP),
 	SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
 	SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP),
+	SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP),
 	SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP),
 	SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
 	SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
@@ -10539,6 +10540,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
 	SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
+	SND_PCI_QUIRK(0x17aa, 0x2326, "Hera2", ALC287_FIXUP_TAS2781_I2C),
 	SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
 	SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
 	SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
diff --git a/sound/pci/hda/patch_senarytech.c b/sound/pci/hda/patch_senarytech.c
new file mode 100644
index 0000000000000000000000000000000000000000..0691996fa971c895d9d55230285fba39b372cfeb
--- /dev/null
+++ b/sound/pci/hda/patch_senarytech.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Senary HDA audio codec
+ *
+ * Initially based on sound/pci/hda/patch_conexant.c
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "hda_generic.h"
+
+struct senary_spec {
+	struct hda_gen_spec gen;
+
+	/* extra EAPD pins */
+	unsigned int num_eapds;
+	hda_nid_t eapds[4];
+	hda_nid_t mute_led_eapd;
+
+	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+	int mute_led_polarity;
+	unsigned int gpio_led;
+	unsigned int gpio_mute_led_mask;
+	unsigned int gpio_mic_led_mask;
+};
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new senary_beep_mixer[] = {
+	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+};
+
+static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid,
+			int idx, int dir)
+{
+	struct snd_kcontrol_new *knew;
+	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+	int i;
+
+	spec->gen.beep_nid = nid;
+	for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) {
+		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+					    &senary_beep_mixer[i]);
+		if (!knew)
+			return -ENOMEM;
+		knew->private_value = beep_amp;
+	}
+	return 0;
+}
+
+static int senary_auto_parse_beep(struct hda_codec *codec)
+{
+	struct senary_spec *spec = codec->spec;
+	hda_nid_t nid;
+
+	for_each_hda_codec_node(nid, codec)
+		if ((get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) &&
+			(get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_AMP_OVRD)))
+			return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+	return 0;
+}
+#else
+#define senary_auto_parse_beep(codec)	0
+#endif
+
+/* parse EAPDs */
+static void senary_auto_parse_eapd(struct hda_codec *codec)
+{
+	struct senary_spec *spec = codec->spec;
+	hda_nid_t nid;
+
+	for_each_hda_codec_node(nid, codec) {
+		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+			continue;
+		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+			continue;
+		spec->eapds[spec->num_eapds++] = nid;
+		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+			break;
+	}
+}
+
+static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+			      const hda_nid_t *pins, bool on)
+{
+	int i;
+
+	for (i = 0; i < num_pins; i++) {
+		if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+			snd_hda_codec_write(codec, pins[i], 0,
+					    AC_VERB_SET_EAPD_BTLENABLE,
+					    on ? 0x02 : 0);
+	}
+}
+
+/* turn on/off EAPD according to Master switch */
+static void senary_auto_vmaster_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	struct senary_spec *spec = codec->spec;
+
+	senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
+}
+
+static void senary_init_gpio_led(struct hda_codec *codec)
+{
+	struct senary_spec *spec = codec->spec;
+	unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
+
+	if (mask) {
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+				    mask);
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+				    mask);
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+	}
+}
+
+static int senary_auto_init(struct hda_codec *codec)
+{
+	snd_hda_gen_init(codec);
+	senary_init_gpio_led(codec);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+	return 0;
+}
+
+static void senary_auto_shutdown(struct hda_codec *codec)
+{
+	struct senary_spec *spec = codec->spec;
+
+	/* Turn the problematic codec into D3 to avoid spurious noises
+	 * from the internal speaker during (and after) reboot
+	 */
+	senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
+}
+
+static void senary_auto_free(struct hda_codec *codec)
+{
+	senary_auto_shutdown(codec);
+	snd_hda_gen_free(codec);
+}
+
+static int senary_auto_suspend(struct hda_codec *codec)
+{
+	senary_auto_shutdown(codec);
+	return 0;
+}
+
+static const struct hda_codec_ops senary_auto_patch_ops = {
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = senary_auto_init,
+	.free = senary_auto_free,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = senary_auto_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+};
+
+static int patch_senary_auto(struct hda_codec *codec)
+{
+	struct senary_spec *spec;
+	int err;
+
+	codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	snd_hda_gen_spec_init(&spec->gen);
+	codec->spec = spec;
+	codec->patch_ops = senary_auto_patch_ops;
+
+	senary_auto_parse_eapd(codec);
+	spec->gen.own_eapd_ctl = 1;
+
+	if (!spec->gen.vmaster_mute.hook)
+		spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
+				       spec->parse_flags);
+	if (err < 0)
+		goto error;
+
+	err = senary_auto_parse_beep(codec);
+	if (err < 0)
+		goto error;
+
+	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+	if (err < 0)
+		goto error;
+
+	/* Some laptops with Senary chips show stalls in S3 resume,
+	 * which falls into the single-cmd mode.
+	 * Better to make reset, then.
+	 */
+	if (!codec->bus->core.sync_write) {
+		codec_info(codec,
+			   "Enable sync_write for stable communication\n");
+		codec->bus->core.sync_write = 1;
+		codec->bus->allow_bus_reset = 1;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	senary_auto_free(codec);
+	return err;
+}
+
+/*
+ */
+
+static const struct hda_device_id snd_hda_id_senary[] = {
+	HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Senarytech HD-audio codec");
+
+static struct hda_codec_driver senary_driver = {
+	.id = snd_hda_id_senary,
+};
+
+module_hda_codec_driver(senary_driver);
diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c
index fdee6592c502d0528b25c642c7fab37f31decf2d..49bd7097d8928aa11ffa53ee22748bd1a304d893 100644
--- a/sound/pci/hda/tas2781_hda_i2c.c
+++ b/sound/pci/hda/tas2781_hda_i2c.c
@@ -597,18 +597,13 @@ static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
 {
 	struct hda_codec *codec = tas_hda->priv->codec;
 
-	if (tas_hda->dsp_prog_ctl)
-		snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
-
-	if (tas_hda->dsp_conf_ctl)
-		snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
+	snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
+	snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
 
 	for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
-		if (tas_hda->snd_ctls[i])
-			snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
+		snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
 
-	if (tas_hda->prof_ctl)
-		snd_ctl_remove(codec->card, tas_hda->prof_ctl);
+	snd_ctl_remove(codec->card, tas_hda->prof_ctl);
 }
 
 static void tasdev_fw_ready(const struct firmware *fmw, void *context)
@@ -706,20 +701,20 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
 	void *master_data)
 {
 	struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-	struct hda_component *comps = master_data;
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
 	struct hda_codec *codec;
 	unsigned int subid;
 	int ret;
 
-	if (!comps || tas_hda->priv->index < 0 ||
-		tas_hda->priv->index >= HDA_MAX_COMPONENTS)
+	comp = hda_component_from_index(parent, tas_hda->priv->index);
+	if (!comp)
 		return -EINVAL;
 
-	comps = &comps[tas_hda->priv->index];
-	if (comps->dev)
+	if (comp->dev)
 		return -EBUSY;
 
-	codec = comps->codec;
+	codec = parent->codec;
 	subid = codec->core.subsystem_id >> 16;
 
 	switch (subid) {
@@ -733,13 +728,13 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
 
 	pm_runtime_get_sync(dev);
 
-	comps->dev = dev;
+	comp->dev = dev;
 
-	strscpy(comps->name, dev_name(dev), sizeof(comps->name));
+	strscpy(comp->name, dev_name(dev), sizeof(comp->name));
 
 	ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);
 	if (!ret)
-		comps->playback_hook = tas2781_hda_playback_hook;
+		comp->playback_hook = tas2781_hda_playback_hook;
 
 	pm_runtime_mark_last_busy(dev);
 	pm_runtime_put_autosuspend(dev);
@@ -751,13 +746,14 @@ static void tas2781_hda_unbind(struct device *dev,
 	struct device *master, void *master_data)
 {
 	struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-	struct hda_component *comps = master_data;
-	comps = &comps[tas_hda->priv->index];
-
-	if (comps->dev == dev) {
-		comps->dev = NULL;
-		memset(comps->name, 0, sizeof(comps->name));
-		comps->playback_hook = NULL;
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
+
+	comp = hda_component_from_index(parent, tas_hda->priv->index);
+	if (comp && (comp->dev == dev)) {
+		comp->dev = NULL;
+		memset(comp->name, 0, sizeof(comp->name));
+		comp->playback_hook = NULL;
 	}
 
 	tas2781_hda_remove_controls(tas_hda);
@@ -834,7 +830,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
 	pm_runtime_set_active(tas_hda->dev);
 	pm_runtime_enable(tas_hda->dev);
 
-	tas2781_reset(tas_hda->priv);
+	tasdevice_reset(tas_hda->priv);
 
 	ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);
 	if (ret) {
@@ -929,7 +925,7 @@ static int tas2781_system_resume(struct device *dev)
 		tas_hda->priv->tasdevice[i].cur_prog = -1;
 		tas_hda->priv->tasdevice[i].cur_conf = -1;
 	}
-	tas2781_reset(tas_hda->priv);
+	tasdevice_reset(tas_hda->priv);
 	tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
 
 	/* If calibrated data occurs error, dsp will still work with default
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index dfc1fc9b701d989d4487e771dfdadd1bd506b35d..2894d041b2f5480b5f6216c17ab4ca1d9d72a501 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -80,8 +80,8 @@ static void keywest_remove(struct i2c_client *client)
 
 
 static const struct i2c_device_id keywest_i2c_id[] = {
-	{ "MAC,tas3004", 0 },		/* instantiated by i2c-powermac */
-	{ "keywest", 0 },		/* instantiated by us if needed */
+	{ "MAC,tas3004" },	/* instantiated by i2c-powermac */
+	{ "keywest" },		/* instantiated by us if needed */
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, keywest_i2c_id);
diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c
index e079b3218c6f472c3ac84f467c3df74909f609e5..3756b8bef17bc6ed660339aa815376a5cbdce99b 100644
--- a/sound/soc/amd/acp-es8336.c
+++ b/sound/soc/amd/acp-es8336.c
@@ -203,8 +203,10 @@ static int st_es8336_late_probe(struct snd_soc_card *card)
 
 	codec_dev = acpi_get_first_physical_node(adev);
 	acpi_dev_put(adev);
-	if (!codec_dev)
+	if (!codec_dev) {
 		dev_err(card->dev, "can not find codec dev\n");
+		return -ENODEV;
+	}
 
 	ret = devm_acpi_dev_add_driver_gpios(codec_dev, acpi_es8336_gpios);
 	if (ret)
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index ef12f97ddc69ecefdd0863f80980b4522efaed41..97258b4cf89b0d9fd59b49eb9755a34e28d479fe 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -369,12 +369,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
 		}
 		writel(period_bytes, adata->acp_base + water_val);
 		writel(buf_size, adata->acp_base + buf_reg);
+		if (rsrc->soc_mclk)
+			acp_set_i2s_clk(adata, dai->driver->id);
 		val = readl(adata->acp_base + reg_val);
 		val = val | BIT(0);
 		writel(val, adata->acp_base + reg_val);
 		writel(1, adata->acp_base + ier_val);
-		if (rsrc->soc_mclk)
-			acp_set_i2s_clk(adata, dai->driver->id);
 		return 0;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -584,21 +584,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
 	return 0;
 }
 
-static int acp_i2s_probe(struct snd_soc_dai *dai)
-{
-	struct device *dev = dai->component->dev;
-	struct acp_dev_data *adata = dev_get_drvdata(dev);
-
-	if (!adata->acp_base) {
-		dev_err(dev, "I2S base is NULL\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
-	.probe		= acp_i2s_probe,
 	.startup	= acp_i2s_startup,
 	.hw_params	= acp_i2s_hwparams,
 	.prepare	= acp_i2s_prepare,
@@ -608,5 +594,6 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
 };
 EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
 
+MODULE_DESCRIPTION("AMD ACP Audio I2S controller");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
index 3be7c6d55a6f8ec5d06e117b9f78f2984433f3c1..4422cec81e3c4d351c5589ca451655f8b31b1ccd 100644
--- a/sound/soc/amd/acp/acp-legacy-common.c
+++ b/sound/soc/amd/acp/acp-legacy-common.c
@@ -475,4 +475,5 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
 }
 EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON);
 
+MODULE_DESCRIPTION("AMD ACP legacy common features");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index 777b5a78d8a9ef1a1ab1c0b1026c0c34d83d6b58..b0304b813cadce354d7b3e62d65107a47454744f 100644
--- a/sound/soc/amd/acp/acp-pci.c
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -249,6 +249,7 @@ static struct pci_driver snd_amd_acp_pci_driver = {
 };
 module_pci_driver(snd_amd_acp_pci_driver);
 
+MODULE_DESCRIPTION("AMD ACP common PCI support");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
 MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c
index f754bf79b5e3f7e210952f21a5049dc32d6d849f..bb79269c2fc1c242138ee310ee52af0defaeb106 100644
--- a/sound/soc/amd/acp/acp-pdm.c
+++ b/sound/soc/amd/acp/acp-pdm.c
@@ -178,5 +178,6 @@ const struct snd_soc_dai_ops acp_dmic_dai_ops = {
 };
 EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, SND_SOC_ACP_COMMON);
 
+MODULE_DESCRIPTION("AMD ACP Audio PDM controller");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c
index aaac8aa744cb0655ede3437ab93b1505d1e97f38..4f409cd09c11cda12794fdb84d42a486937846c1 100644
--- a/sound/soc/amd/acp/acp-platform.c
+++ b/sound/soc/amd/acp/acp-platform.c
@@ -197,6 +197,20 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
 	else
 		runtime->hw = acp_pcm_hardware_capture;
 
+	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE);
+	if (ret) {
+		dev_err(component->dev, "set hw constraint HW_PARAM_PERIOD_BYTES failed\n");
+		kfree(stream);
+		return ret;
+	}
+
+	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, DMA_SIZE);
+	if (ret) {
+		dev_err(component->dev, "set hw constraint HW_PARAM_BUFFER_BYTES failed\n");
+		kfree(stream);
+		return ret;
+	}
+
 	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0) {
 		dev_err(component->dev, "set integer constraint failed\n");
diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c
index 158f819f8da4ae208549f1ca1d5d0fc0785578d3..e19981c7d65aa7e5db9236b0fd8e6d11ae091131 100644
--- a/sound/soc/amd/acp/acp-rembrandt.c
+++ b/sound/soc/amd/acp/acp-rembrandt.c
@@ -39,8 +39,6 @@ static struct acp_resource rsrc = {
 	.irqp_used = 1,
 	.soc_mclk = true,
 	.irq_reg_offset = 0x1a00,
-	.i2s_pin_cfg_offset = 0x1440,
-	.i2s_mode = 0x0a,
 	.scratch_reg_offset = 0x12800,
 	.sram_pte_offset = 0x03802800,
 };
@@ -231,12 +229,13 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
 	adata->rsrc = &rsrc;
 	adata->platform = REMBRANDT;
 	adata->flag = chip->flag;
+	adata->is_i2s_config = chip->is_i2s_config;
 	adata->machines = snd_soc_acpi_amd_rmb_acp_machines;
 	acp_machine_select(adata);
 
 	dev_set_drvdata(dev, adata);
 
-	if (chip->flag != FLAG_AMD_LEGACY_ONLY_DMIC) {
+	if (chip->is_i2s_config && rsrc.soc_mclk) {
 		ret = acp6x_master_clock_generate(dev);
 		if (ret)
 			return ret;
@@ -269,7 +268,7 @@ static int __maybe_unused rmb_pcm_resume(struct device *dev)
 	snd_pcm_uframes_t buf_in_frames;
 	u64 buf_size;
 
-	if (adata->flag != FLAG_AMD_LEGACY_ONLY_DMIC)
+	if (adata->is_i2s_config && adata->rsrc->soc_mclk)
 		acp6x_master_clock_generate(dev);
 
 	spin_lock(&adata->acp_lock);
diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c
index b0e181c9a733a5f1a243763829d6c10fbc90f751..db835ed7c20847af9a5ad730b6b4d2acb12677a8 100644
--- a/sound/soc/amd/acp/acp-renoir.c
+++ b/sound/soc/amd/acp/acp-renoir.c
@@ -32,8 +32,6 @@ static struct acp_resource rsrc = {
 	.no_of_ctrls = 1,
 	.irqp_used = 0,
 	.irq_reg_offset = 0x1800,
-	.i2s_pin_cfg_offset = 0x1400,
-	.i2s_mode = 0x04,
 	.scratch_reg_offset = 0x12800,
 	.sram_pte_offset = 0x02052800,
 };
diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c
index 4d342441a6506f4f7bd4f03c10f110321a95c0a1..f340920b328919069f9408a47edd805742c7e6d0 100644
--- a/sound/soc/amd/acp/acp63.c
+++ b/sound/soc/amd/acp/acp63.c
@@ -55,8 +55,6 @@ static struct acp_resource rsrc = {
 	.irqp_used = 1,
 	.soc_mclk = true,
 	.irq_reg_offset = 0x1a00,
-	.i2s_pin_cfg_offset = 0x1440,
-	.i2s_mode = 0x0a,
 	.scratch_reg_offset = 0x12800,
 	.sram_pte_offset = 0x03802800,
 };
@@ -241,11 +239,12 @@ static int acp63_audio_probe(struct platform_device *pdev)
 	adata->rsrc = &rsrc;
 	adata->platform = ACP63;
 	adata->flag = chip->flag;
+	adata->is_i2s_config = chip->is_i2s_config;
 	adata->machines = snd_soc_acpi_amd_acp63_acp_machines;
 	acp_machine_select(adata);
 	dev_set_drvdata(dev, adata);
 
-	if (chip->flag != FLAG_AMD_LEGACY_ONLY_DMIC) {
+	if (chip->is_i2s_config && rsrc.soc_mclk) {
 		ret = acp63_i2s_master_clock_generate(adata);
 		if (ret)
 			return ret;
@@ -278,7 +277,7 @@ static int __maybe_unused acp63_pcm_resume(struct device *dev)
 	snd_pcm_uframes_t buf_in_frames;
 	u64 buf_size;
 
-	if (adata->flag != FLAG_AMD_LEGACY_ONLY_DMIC)
+	if (adata->is_i2s_config && adata->rsrc->soc_mclk)
 		acp63_i2s_master_clock_generate(adata);
 
 	spin_lock(&adata->acp_lock);
diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c
index 0d7cdd4017e5c18fa7717870ea22add1d71c2620..a2cbdcca431324778a2f516bef6ec249c4e8a127 100644
--- a/sound/soc/amd/acp/acp70.c
+++ b/sound/soc/amd/acp/acp70.c
@@ -31,8 +31,6 @@ static struct acp_resource rsrc = {
 	.irqp_used = 1,
 	.soc_mclk = true,
 	.irq_reg_offset = 0x1a00,
-	.i2s_pin_cfg_offset = 0x1440,
-	.i2s_mode = 0x0a,
 	.scratch_reg_offset = 0x12800,
 	.sram_pte_offset = 0x03802800,
 };
diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h
index d75b4eb34de8d3614e7b7925c708a1cdfc387ab4..87a4813783f911718bdb43814cda0d786f6691a4 100644
--- a/sound/soc/amd/acp/amd.h
+++ b/sound/soc/amd/acp/amd.h
@@ -162,8 +162,6 @@ struct acp_resource {
 	int irqp_used;
 	bool soc_mclk;
 	u32 irq_reg_offset;
-	u32 i2s_pin_cfg_offset;
-	int i2s_mode;
 	u64 scratch_reg_offset;
 	u64 sram_pte_offset;
 };
@@ -175,6 +173,7 @@ struct acp_dev_data {
 	unsigned int i2s_irq;
 
 	bool tdm_mode;
+	bool is_i2s_config;
 	/* SOC specific dais */
 	struct snd_soc_dai_driver *dai_driver;
 	int num_dai;
diff --git a/sound/soc/amd/ps/ps-mach.c b/sound/soc/amd/ps/ps-mach.c
index e675b8f569eb3099095022b80b69b74aa9aafb6f..ff8ad036b077a84fb62438b12b5c74c881fe5fe8 100644
--- a/sound/soc/amd/ps/ps-mach.c
+++ b/sound/soc/amd/ps/ps-mach.c
@@ -75,5 +75,6 @@ static struct platform_driver acp63_mach_driver = {
 module_platform_driver(acp63_mach_driver);
 
 MODULE_AUTHOR("Syed.SabaKareem@amd.com");
+MODULE_DESCRIPTION("AMD Pink Sardine support for DMIC");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/renoir/acp3x-rn.c b/sound/soc/amd/renoir/acp3x-rn.c
index 5d979a7b77fbe028ffee3afcb445f6f55fbbc56f..3249f74a0197af5388ea961c6213e3aa945be6ba 100644
--- a/sound/soc/amd/renoir/acp3x-rn.c
+++ b/sound/soc/amd/renoir/acp3x-rn.c
@@ -72,5 +72,6 @@ static struct platform_driver acp_mach_driver = {
 module_platform_driver(acp_mach_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD Renoir support for DMIC");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 4e3a8ce690a458b57954289ac6f6cbe96e4174a7..f54466ed8e3eef757b6d917a33607d95435675ef 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -511,5 +511,6 @@ static struct platform_driver acp6x_mach_driver = {
 module_platform_driver(acp6x_mach_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD Yellow Carp support for DMIC");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 91b502f8cc3f8a53d329daf78b2e64a665b6608d..b5e6d0a986c8e9cabbe7451f5b792d12275c732c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -45,6 +45,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_AK4535
 	imply SND_SOC_AK4554
 	imply SND_SOC_AK4613
+	imply SND_SOC_AK4619
 	imply SND_SOC_AK4641
 	imply SND_SOC_AK4642
 	imply SND_SOC_AK4671
@@ -100,6 +101,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_CS47L90
 	imply SND_SOC_CS47L92
 	imply SND_SOC_CS53L30
+	imply SND_SOC_CS530X_I2C
 	imply SND_SOC_CX20442
 	imply SND_SOC_CX2072X
 	imply SND_SOC_DA7210
@@ -222,7 +224,9 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_RT722_SDCA_SDW
 	imply SND_SOC_RT1308_SDW
 	imply SND_SOC_RT1316_SDW
+	imply SND_SOC_RT1318
 	imply SND_SOC_RT1318_SDW
+	imply SND_SOC_RT1320_SDW
 	imply SND_SOC_RT9120
 	imply SND_SOC_RTQ9128
 	imply SND_SOC_SDW_MOCKUP
@@ -279,6 +283,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_UDA1380
 	imply SND_SOC_WCD9335
 	imply SND_SOC_WCD934X
+	imply SND_SOC_WCD937X_SDW
 	imply SND_SOC_WCD938X_SDW
 	imply SND_SOC_WCD939X_SDW
 	imply SND_SOC_LPASS_MACRO_COMMON
@@ -597,6 +602,10 @@ config SND_SOC_AK4613
 	tristate "AKM AK4613 CODEC"
 	depends on I2C
 
+config SND_SOC_AK4619
+        tristate "AKM AK4619 CODEC"
+        depends on I2C
+
 config SND_SOC_AK4641
 	tristate
 	depends on I2C
@@ -1008,6 +1017,19 @@ config SND_SOC_CS53L30
 	tristate "Cirrus Logic CS53L30 CODEC"
 	depends on I2C
 
+config SND_SOC_CS530X
+	tristate
+
+config SND_SOC_CS530X_I2C
+	tristate "Cirrus Logic CS530x ADCs (I2C)"
+	depends on I2C
+	select REGMAP
+	select REGMAP_I2C
+	select SND_SOC_CS530X
+	help
+	  Enable support for Cirrus Logic CS530X ADCs
+	  with I2C control.
+
 config SND_SOC_CX20442
 	tristate
 	depends on TTY
@@ -1112,6 +1134,10 @@ config SND_SOC_ES83XX_DSM_COMMON
 	depends on ACPI
 	tristate
 
+config SND_SOC_ES8311
+	tristate "Everest Semi ES8311 CODEC"
+	depends on I2C
+
 config SND_SOC_ES8316
 	tristate "Everest Semi ES8316 CODEC"
 	depends on I2C
@@ -1581,11 +1607,21 @@ config SND_SOC_RT1316_SDW
 	depends on SOUNDWIRE
 	select REGMAP_SOUNDWIRE
 
+config SND_SOC_RT1318
+	tristate
+	depends on I2C
+
 config SND_SOC_RT1318_SDW
 	tristate "Realtek RT1318 Codec - SDW"
 	depends on SOUNDWIRE
 	select REGMAP_SOUNDWIRE
 
+config SND_SOC_RT1320_SDW
+	tristate "Realtek RT1320 Codec - SDW"
+	depends on SOUNDWIRE
+	select REGMAP_SOUNDWIRE
+	select REGMAP_SOUNDWIRE_MBQ
+
 config SND_SOC_RT5514
 	tristate
 	depends on I2C
@@ -2111,6 +2147,25 @@ config SND_SOC_WCD934X
 	  The WCD9340/9341 is a audio codec IC Integrated in
 	  Qualcomm SoCs like SDM845.
 
+config SND_SOC_WCD937X
+	depends on SND_SOC_WCD937X_SDW
+	tristate
+	depends on SOUNDWIRE || !SOUNDWIRE
+	select SND_SOC_WCD_CLASSH
+
+config SND_SOC_WCD937X_SDW
+	tristate "WCD9370/WCD9375 Codec - SDW"
+	select SND_SOC_WCD937X
+	select SND_SOC_WCD_MBHC
+	select REGMAP_IRQ
+	depends on SOUNDWIRE
+	select REGMAP_SOUNDWIRE
+	help
+	  The WCD9370/9375 is an audio codec IC used with SoCs
+	  like SC7280 or QCM6490 chipsets, and it connected
+	  via soundwire.
+	  To compile this codec driver say Y or m.
+
 config SND_SOC_WCD938X
 	depends on SND_SOC_WCD938X_SDW
 	tristate
@@ -2513,6 +2568,7 @@ config SND_SOC_LPASS_MACRO_COMMON
 config SND_SOC_LPASS_WSA_MACRO
 	depends on COMMON_CLK
 	select REGMAP_MMIO
+	select SND_SOC_LPASS_MACRO_COMMON
 	tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
 
 config SND_SOC_LPASS_VA_MACRO
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3afd7c16c95968c3eb78394b80b34dc4b249abca..622e360f00866b7b371128fef11168c45db5e142 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-ak4458-y := ak4458.o
 snd-soc-ak4535-y := ak4535.o
 snd-soc-ak4554-y := ak4554.o
 snd-soc-ak4613-y := ak4613.o
+snd-soc-ak4619-y := ak4619.o
 snd-soc-ak4641-y := ak4641.o
 snd-soc-ak4642-y := ak4642.o
 snd-soc-ak4671-y := ak4671.o
@@ -108,6 +109,8 @@ snd-soc-cs47l85-y := cs47l85.o
 snd-soc-cs47l90-y := cs47l90.o
 snd-soc-cs47l92-y := cs47l92.o
 snd-soc-cs53l30-y := cs53l30.o
+snd-soc-cs530x-y := cs530x.o
+snd-soc-cs530x-i2c-y := cs530x-i2c.o
 snd-soc-cx20442-y := cx20442.o
 snd-soc-cx2072x-y := cx2072x.o
 snd-soc-da7210-y := da7210.o
@@ -120,6 +123,7 @@ snd-soc-dmic-y := dmic.o
 snd-soc-es7134-y := es7134.o
 snd-soc-es7241-y := es7241.o
 snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
+snd-soc-es8311-y := es8311.o
 snd-soc-es8316-y := es8316.o
 snd-soc-es8326-y := es8326.o
 snd-soc-es8328-y := es8328.o
@@ -222,7 +226,9 @@ snd-soc-rt1305-y := rt1305.o
 snd-soc-rt1308-y := rt1308.o
 snd-soc-rt1308-sdw-y := rt1308-sdw.o
 snd-soc-rt1316-sdw-y := rt1316-sdw.o
+snd-soc-rt1318-y := rt1318.o
 snd-soc-rt1318-sdw-y := rt1318-sdw.o
+snd-soc-rt1320-sdw-y := rt1320-sdw.o
 snd-soc-rt274-y := rt274.o
 snd-soc-rt286-y := rt286.o
 snd-soc-rt298-y := rt298.o
@@ -317,6 +323,8 @@ snd-soc-wcd-classh-y := wcd-clsh-v2.o
 snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o
 snd-soc-wcd9335-y := wcd9335.o
 snd-soc-wcd934x-y := wcd934x.o
+snd-soc-wcd937x-objs := wcd937x.o
+snd-soc-wcd937x-sdw-objs := wcd937x-sdw.o
 snd-soc-wcd938x-y := wcd938x.o
 snd-soc-wcd938x-sdw-y := wcd938x-sdw.o
 snd-soc-wcd939x-y := wcd939x.o
@@ -436,6 +444,7 @@ obj-$(CONFIG_SND_SOC_AK4458)	+= snd-soc-ak4458.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4554)	+= snd-soc-ak4554.o
 obj-$(CONFIG_SND_SOC_AK4613)	+= snd-soc-ak4613.o
+obj-$(CONFIG_SND_SOC_AK4619)	+= snd-soc-ak4619.o
 obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
@@ -506,6 +515,8 @@ obj-$(CONFIG_SND_SOC_CS47L85)	+= snd-soc-cs47l85.o
 obj-$(CONFIG_SND_SOC_CS47L90)	+= snd-soc-cs47l90.o
 obj-$(CONFIG_SND_SOC_CS47L92)	+= snd-soc-cs47l92.o
 obj-$(CONFIG_SND_SOC_CS53L30)	+= snd-soc-cs53l30.o
+obj-$(CONFIG_SND_SOC_CS530X)	+= snd-soc-cs530x.o
+obj-$(CONFIG_SND_SOC_CS530X_I2C)	+= snd-soc-cs530x-i2c.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_CX2072X)	+= snd-soc-cx2072x.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
@@ -518,6 +529,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON)    += snd-soc-es83xx-dsm-common.o
+obj-$(CONFIG_SND_SOC_ES8311)    += snd-soc-es8311.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
 obj-$(CONFIG_SND_SOC_ES8326)    += snd-soc-es8326.o
 obj-$(CONFIG_SND_SOC_ES8328)	+= snd-soc-es8328.o
@@ -615,7 +627,9 @@ obj-$(CONFIG_SND_SOC_RT1305)	+= snd-soc-rt1305.o
 obj-$(CONFIG_SND_SOC_RT1308)	+= snd-soc-rt1308.o
 obj-$(CONFIG_SND_SOC_RT1308_SDW)	+= snd-soc-rt1308-sdw.o
 obj-$(CONFIG_SND_SOC_RT1316_SDW)	+= snd-soc-rt1316-sdw.o
+obj-$(CONFIG_SND_SOC_RT1318)	+= snd-soc-rt1318.o
 obj-$(CONFIG_SND_SOC_RT1318_SDW)	+= snd-soc-rt1318-sdw.o
+obj-$(CONFIG_SND_SOC_RT1320_SDW)	+= snd-soc-rt1320-sdw.o
 obj-$(CONFIG_SND_SOC_RT274)	+= snd-soc-rt274.o
 obj-$(CONFIG_SND_SOC_RT286)	+= snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT298)	+= snd-soc-rt298.o
@@ -712,6 +726,11 @@ obj-$(CONFIG_SND_SOC_WCD_CLASSH)	+= snd-soc-wcd-classh.o
 obj-$(CONFIG_SND_SOC_WCD_MBHC)	+= snd-soc-wcd-mbhc.o
 obj-$(CONFIG_SND_SOC_WCD9335)	+= snd-soc-wcd9335.o
 obj-$(CONFIG_SND_SOC_WCD934X)	+= snd-soc-wcd934x.o
+obj-$(CONFIG_SND_SOC_WCD937X)	+= snd-soc-wcd937x.o
+ifdef CONFIG_SND_SOC_WCD937X_SDW
+# avoid link failure by forcing sdw code built-in when needed
+obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x-sdw.o
+endif
 obj-$(CONFIG_SND_SOC_WCD938X)	+= snd-soc-wcd938x.o
 ifdef CONFIG_SND_SOC_WCD938X_SDW
 # avoid link failure by forcing sdw code built-in when needed
diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c
index a663d37e57760ff19fe798f949c1e94aff20a281..abc4764697a5330a52ee7e2324d70f2771f4c061 100644
--- a/sound/soc/codecs/adau7118.c
+++ b/sound/soc/codecs/adau7118.c
@@ -121,8 +121,10 @@ static const struct snd_soc_dapm_widget adau7118_widgets[] = {
 };
 
 static int adau7118_set_channel_map(struct snd_soc_dai *dai,
-				    unsigned int tx_num, unsigned int *tx_slot,
-				    unsigned int rx_num, unsigned int *rx_slot)
+				    unsigned int tx_num,
+				    const unsigned int *tx_slot,
+				    unsigned int rx_num,
+				    const unsigned int *rx_slot)
 {
 	struct adau7118_data *st =
 		snd_soc_component_get_drvdata(dai->component);
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index 9a43235e6a11d09dbd60dffdad6bf29f404bd774..23e868e4e3fba2c7e885b39260f8e40105255ae9 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -9,7 +9,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 73cf482f104f1afc645a295881d35faa15615480..d472d9952628795531ea59984893fb457a0bd9a1 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -10,7 +10,6 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
@@ -46,7 +45,6 @@ struct ak4458_priv {
 	const struct ak4458_drvdata *drvdata;
 	struct device *dev;
 	struct regmap *regmap;
-	struct gpio_desc *reset_gpiod;
 	struct reset_control *reset;
 	struct gpio_desc *mute_gpiod;
 	int digfil;	/* SSLOW, SD, SLOW bits */
@@ -632,10 +630,7 @@ static struct snd_soc_dai_driver ak4497_dai = {
 
 static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
 {
-	if (ak4458->reset_gpiod) {
-		gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
-		usleep_range(1000, 2000);
-	} else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+	if (!IS_ERR_OR_NULL(ak4458->reset)) {
 		if (active)
 			reset_control_assert(ak4458->reset);
 		else
@@ -759,11 +754,6 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
 	if (IS_ERR(ak4458->reset))
 		return PTR_ERR(ak4458->reset);
 
-	ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
-						      GPIOD_OUT_LOW);
-	if (IS_ERR(ak4458->reset_gpiod))
-		return PTR_ERR(ak4458->reset_gpiod);
-
 	ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute",
 						     GPIOD_OUT_LOW);
 	if (IS_ERR(ak4458->mute_gpiod))
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 73fb35560e5149ec595623a9181d072ccd53468c..551738abd1a5821c444bd56ff838a58d44da7611 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -753,7 +753,7 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
  *	SND_SOC_DAIFMT_CBC_CFC
  *	SND_SOC_DAIFMT_CBP_CFP
  */
-static u64 ak4613_dai_formats =
+static const u64 ak4613_dai_formats =
 	SND_SOC_POSSIBLE_DAIFMT_I2S	|
 	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
 
diff --git a/sound/soc/codecs/ak4619.c b/sound/soc/codecs/ak4619.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f2442482f72546ee288c5d499d152b0823f3f95
--- /dev/null
+++ b/sound/soc/codecs/ak4619.c
@@ -0,0 +1,912 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ak4619.c -- Asahi Kasei ALSA SoC Audio driver
+ *
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ * Khanh Le <khanh.le.xr@renesas.com>
+ *
+ * Based on ak4613.c by Kuninori Morimoto
+ * Based on da7213.c by Adam Thomson
+ * Based on ak4641.c by Harald Welte
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+/*
+ * Registers
+ */
+
+#define PWR_MGMT	0x00	/* Power Management */
+#define AU_IFF1		0x01	/* Audio I/F Format */
+#define AU_IFF2		0x02	/* Audio I/F Format (Extended) */
+#define SYS_CLK		0x03	/* System Clock Setting */
+#define MIC_AMP1	0x04	/* MIC AMP Gain 1 */
+#define MIC_AMP2	0x05	/* MIC AMP Gain 2 */
+#define LADC1		0x06	/* ADC1 Lch Digital Volume */
+#define RADC1		0x07	/* ADC1 Rch Digital Volume */
+#define LADC2		0x08	/* ADC2 Lch Digital Volume */
+#define RADC2		0x09	/* ADC2 Rch Digital Volume */
+#define ADC_DF		0x0a	/* ADC Digital Filter Setting */
+#define ADC_AI		0x0b	/* ADC Analog Input Setting */
+#define ADC_MHPF	0x0D	/* ADC Mute & HPF Control */
+#define LDAC1		0x0E	/* DAC1 Lch Digital Volume */
+#define RDAC1		0x0F	/* DAC1 Rch Digital Volume */
+#define LDAC2		0x10	/* DAC2 Lch Digital Volume */
+#define RDAC2		0x11	/* DAC2 Rch Digital Volume */
+#define DAC_IS		0x12	/* DAC Input Select Setting */
+#define DAC_DEMP	0x13	/* DAC De-Emphasis Setting */
+#define DAC_MF		0x14	/* DAC Mute & Filter Setting */
+
+/*
+ * Bit fields
+ */
+
+/* Power Management */
+#define PMAD2		BIT(5)
+#define PMAD1		BIT(4)
+#define PMDA2		BIT(2)
+#define PMDA1		BIT(1)
+#define RSTN		BIT(0)
+
+/* Audio_I/F Format */
+#define DCF_STEREO_I2S	(0x0 << 4)
+#define DCF_STEREO_MSB	(0x5 << 4)
+#define DCF_PCM_SF	(0x6 << 4)
+#define DCF_PCM_LF	(0x7 << 4)
+#define DSL_32		(0x3 << 2)
+#define DCF_MASK	(0x7 << 4)
+#define DSL_MASK	(0x3 << 2)
+#define BCKP		BIT(1)
+
+/* Audio_I/F Format (Extended) */
+#define DIDL_24		(0x0 << 2)
+#define DIDL_20		(0x1 << 2)
+#define DIDL_16		(0x2 << 2)
+#define DIDL_32		(0x3 << 2)
+#define DODL_24		(0x0 << 0)
+#define DODL_20		(0x1 << 0)
+#define DODL_16		(0x2 << 0)
+#define DIDL_MASK	(0x3 << 2)
+#define DODL_MASK	(0x3 << 0)
+#define SLOT            BIT(4)
+
+/* System Clock Setting */
+#define FS_MASK		0x7
+
+/* MIC AMP Gain */
+#define MGNL_SHIFT	4
+#define MGNR_SHIFT	0
+#define MGN_MAX		0xB
+
+/* ADC Digital Volume */
+#define VOLAD_SHIFT	0
+#define VOLAD_MAX	0xFF
+
+/* ADC Digital Filter Setting */
+#define AD1SL_SHIFT	0
+#define AD2SL_SHIFT	4
+
+/* Analog Input Select */
+#define AD1LSEL_SHIFT	6
+#define AD1RSEL_SHIFT	4
+#define AD2LSEL_SHIFT	2
+#define AD2RSEL_SHIFT	0
+
+/* ADC Mute & HPF Control */
+#define ATSPAD_SHIFT	7
+#define AD1MUTE_SHIFT	5
+#define AD2MUTE_SHIFT	6
+#define AD1MUTE_MAX	1
+#define AD2MUTE_MAX	1
+#define AD1MUTE_EN	BIT(5)
+#define AD2MUTE_EN	BIT(6)
+#define AD1HPFN_SHIFT	1
+#define AD1HPFN_MAX	1
+#define AD2HPFN_SHIFT	2
+#define AD2HPFN_MAX	1
+
+/* DAC Digital Volume */
+#define VOLDA_SHIFT	0
+#define VOLDA_MAX	0xFF
+
+/* DAC Input Select Setting */
+#define DAC1SEL_SHIFT	0
+#define DAC2SEL_SHIFT	2
+
+/* DAC De-Emphasis Setting */
+#define DEM1_32000	(0x3 << 0)
+#define DEM1_44100	(0x0 << 0)
+#define DEM1_48000	(0x2 << 0)
+#define DEM1_OFF	(0x1 << 0)
+#define DEM2_32000	(0x3 << 2)
+#define DEM2_44100	(0x0 << 2)
+#define DEM2_48000	(0x2 << 2)
+#define DEM2_OFF	(0x1 << 2)
+#define DEM1_MASK	(0x3 << 0)
+#define DEM2_MASK	(0x3 << 2)
+#define DEM1_SHIFT	0
+#define DEM2_SHIFT	2
+
+/* DAC Mute & Filter Setting */
+#define DA1MUTE_SHIFT	4
+#define DA1MUTE_MAX	1
+#define DA2MUTE_SHIFT	5
+#define DA2MUTE_MAX	1
+#define DA1MUTE_EN	BIT(4)
+#define DA2MUTE_EN	BIT(5)
+#define ATSPDA_SHIFT	7
+#define DA1SL_SHIFT	0
+#define DA2SL_SHIFT	2
+
+/* Codec private data */
+struct ak4619_priv {
+	struct regmap *regmap;
+	struct snd_pcm_hw_constraint_list constraint;
+	int deemph_en;
+	unsigned int playback_rate;
+	unsigned int sysclk;
+};
+
+/*
+ * DAC Volume
+ *
+ * max : 0x00 : +12.0 dB
+ *	( 0.5 dB step )
+ * min : 0xFE : -115.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -11550, 50, 1);
+
+/*
+ * MIC Volume
+ *
+ * max : 0x0B : +27.0 dB
+ *	( 3 dB step )
+ * min: 0x00 : -6.0 dB
+ */
+static const DECLARE_TLV_DB_SCALE(mic_tlv, -600, 300, 0);
+
+/*
+ * ADC Volume
+ *
+ * max : 0x00 : +24.0 dB
+ *	( 0.5 dB step )
+ * min : 0xFE : -103.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1);
+
+/* ADC & DAC Volume Level Transition Time select */
+static const char * const ak4619_vol_trans_txt[] = {
+	"4/fs", "16/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_vol_trans, ADC_MHPF, ATSPAD_SHIFT, ak4619_vol_trans_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_vol_trans, DAC_MF,   ATSPDA_SHIFT, ak4619_vol_trans_txt);
+
+/* ADC Digital Filter select */
+static const char * const ak4619_adc_digi_fil_txt[] = {
+	"Sharp Roll-Off Filter",
+	"Slow Roll-Off Filter",
+	"Short Delay Sharp Roll-Off Filter",
+	"Short Delay Slow Roll-Off Filter",
+	"Voice Filter"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_1_digi_fil, ADC_DF, AD1SL_SHIFT, ak4619_adc_digi_fil_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_2_digi_fil, ADC_DF, AD2SL_SHIFT, ak4619_adc_digi_fil_txt);
+
+/* DAC De-Emphasis Filter select */
+static const char * const ak4619_dac_de_emp_txt[] = {
+	"44.1kHz", "OFF", "48kHz", "32kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_de_emp, DAC_DEMP, DEM1_SHIFT, ak4619_dac_de_emp_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_de_emp, DAC_DEMP, DEM2_SHIFT, ak4619_dac_de_emp_txt);
+
+/* DAC Digital Filter select */
+static const char * const ak4619_dac_digi_fil_txt[] = {
+	"Sharp Roll-Off Filter",
+	"Slow Roll-Off Filter",
+	"Short Delay Sharp Roll-Off Filter",
+	"Short Delay Slow Roll-Off Filter"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_digi_fil, DAC_MF, DA1SL_SHIFT, ak4619_dac_digi_fil_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_digi_fil, DAC_MF, DA2SL_SHIFT, ak4619_dac_digi_fil_txt);
+
+/*
+ * Control functions
+ */
+
+static void ak4619_set_deemph(struct snd_soc_component *component)
+{
+	struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+	u8 dem = 0;
+
+	if (!ak4619->deemph_en)
+		return;
+
+	switch (ak4619->playback_rate) {
+	case 32000:
+		dem |= DEM1_32000 | DEM2_32000;
+		break;
+	case 44100:
+		dem |= DEM1_44100 | DEM2_44100;
+		break;
+	case 48000:
+		dem |= DEM1_48000 | DEM2_48000;
+		break;
+	default:
+		dem |= DEM1_OFF | DEM2_OFF;
+		break;
+	}
+	snd_soc_component_update_bits(component, DAC_DEMP, DEM1_MASK | DEM2_MASK, dem);
+}
+
+static int ak4619_put_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+	int deemph_en = ucontrol->value.integer.value[0];
+	int ret = 0;
+
+	switch (deemph_en) {
+	case 0:
+	case 1:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ak4619->deemph_en != deemph_en)
+		ret = 1; /* The value changed */
+
+	ak4619->deemph_en = deemph_en;
+	ak4619_set_deemph(component);
+
+	return ret;
+}
+
+static int ak4619_get_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = ak4619->deemph_en;
+
+	return 0;
+};
+
+/*
+ * KControls
+ */
+static const struct snd_kcontrol_new ak4619_snd_controls[] = {
+
+	/* Volume controls */
+	SOC_DOUBLE_R_TLV("DAC 1 Volume", LDAC1, RDAC1, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC 2 Volume", LDAC2, RDAC2, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("ADC 1 Volume", LADC1, RADC1, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv),
+	SOC_DOUBLE_R_TLV("ADC 2 Volume", LADC2, RADC2, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv),
+
+	SOC_DOUBLE_TLV("Mic 1 Volume", MIC_AMP1, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv),
+	SOC_DOUBLE_TLV("Mic 2 Volume", MIC_AMP2, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv),
+
+	/* Volume Level Transition Time controls */
+	SOC_ENUM("ADC Volume Level Transition Time", ak4619_adc_vol_trans),
+	SOC_ENUM("DAC Volume Level Transition Time", ak4619_dac_vol_trans),
+
+	/* Mute controls */
+	SOC_SINGLE("DAC 1 Switch", DAC_MF, DA1MUTE_SHIFT, DA1MUTE_MAX, 1),
+	SOC_SINGLE("DAC 2 Switch", DAC_MF, DA2MUTE_SHIFT, DA2MUTE_MAX, 1),
+
+	SOC_SINGLE("ADC 1 Switch", ADC_MHPF, AD1MUTE_SHIFT, AD1MUTE_MAX, 1),
+	SOC_SINGLE("ADC 2 Switch", ADC_MHPF, AD2MUTE_SHIFT, AD2MUTE_MAX, 1),
+
+	/* Filter controls */
+	SOC_ENUM("ADC 1 Digital Filter", ak4619_adc_1_digi_fil),
+	SOC_ENUM("ADC 2 Digital Filter", ak4619_adc_2_digi_fil),
+
+	SOC_SINGLE("ADC 1 HPF", ADC_MHPF, AD1HPFN_SHIFT, AD1HPFN_MAX, 1),
+	SOC_SINGLE("ADC 2 HPF", ADC_MHPF, AD2HPFN_SHIFT, AD2HPFN_MAX, 1),
+
+	SOC_ENUM("DAC 1 De-Emphasis Filter", ak4619_dac_1_de_emp),
+	SOC_ENUM("DAC 2 De-Emphasis Filter", ak4619_dac_2_de_emp),
+
+	SOC_ENUM("DAC 1 Digital Filter", ak4619_dac_1_digi_fil),
+	SOC_ENUM("DAC 2 Digital Filter", ak4619_dac_2_digi_fil),
+
+	SOC_SINGLE_BOOL_EXT("Playback De-Emphasis Switch", 0, ak4619_get_deemph, ak4619_put_deemph),
+};
+
+/*
+ * DAPM
+ */
+
+/* Analog input mode */
+static const char * const ak4619_analog_in_txt[] = {
+	"Differential", "Single-Ended1", "Single-Ended2", "Pseudo Differential"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_left_in,  ADC_AI, AD1LSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_right_in, ADC_AI, AD1RSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_left_in,  ADC_AI, AD2LSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_right_in, ADC_AI, AD2RSEL_SHIFT, ak4619_analog_in_txt);
+
+static const struct snd_kcontrol_new ak4619_ad_1_left_in_mux =
+	SOC_DAPM_ENUM("Analog Input 1 Left MUX",  ak4619_ad_1_left_in);
+static const struct snd_kcontrol_new ak4619_ad_1_right_in_mux =
+	SOC_DAPM_ENUM("Analog Input 1 Right MUX", ak4619_ad_1_right_in);
+static const struct snd_kcontrol_new ak4619_ad_2_left_in_mux =
+	SOC_DAPM_ENUM("Analog Input 2 Left MUX",  ak4619_ad_2_left_in);
+static const struct snd_kcontrol_new ak4619_ad_2_right_in_mux =
+	SOC_DAPM_ENUM("Analog Input 2 Right MUX", ak4619_ad_2_right_in);
+
+/* DAC source mux */
+static const char * const ak4619_dac_in_txt[] = {
+	"SDIN1", "SDIN2", "SDOUT1", "SDOUT2"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_in, DAC_IS, DAC1SEL_SHIFT, ak4619_dac_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_in, DAC_IS, DAC2SEL_SHIFT, ak4619_dac_in_txt);
+
+static const struct snd_kcontrol_new ak4619_dac_1_in_mux =
+	SOC_DAPM_ENUM("DAC 1 Source MUX", ak4619_dac_1_in);
+static const struct snd_kcontrol_new ak4619_dac_2_in_mux =
+	SOC_DAPM_ENUM("DAC 2 Source MUX", ak4619_dac_2_in);
+
+static const struct snd_soc_dapm_widget ak4619_dapm_widgets[] = {
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC1", NULL, PWR_MGMT, 1, 0),
+	SND_SOC_DAPM_DAC("DAC2", NULL, PWR_MGMT, 2, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1", NULL, PWR_MGMT, 4, 0),
+	SND_SOC_DAPM_ADC("ADC2", NULL, PWR_MGMT, 5, 0),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("AOUT1L"),
+	SND_SOC_DAPM_OUTPUT("AOUT2L"),
+
+	SND_SOC_DAPM_OUTPUT("AOUT1R"),
+	SND_SOC_DAPM_OUTPUT("AOUT2R"),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN4L"),
+	SND_SOC_DAPM_INPUT("AIN5L"),
+
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("AIN4R"),
+	SND_SOC_DAPM_INPUT("AIN5R"),
+
+	SND_SOC_DAPM_INPUT("MIC1L"),
+	SND_SOC_DAPM_INPUT("MIC1R"),
+	SND_SOC_DAPM_INPUT("MIC2L"),
+	SND_SOC_DAPM_INPUT("MIC2R"),
+
+	/* DAI */
+	SND_SOC_DAPM_AIF_IN("SDIN1",  "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SDIN2",  "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SDOUT1", "Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SDOUT2", "Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* MUXs for Mic PGA source selection */
+	SND_SOC_DAPM_MUX("Analog Input 1 Left MUX",  SND_SOC_NOPM, 0, 0, &ak4619_ad_1_left_in_mux),
+	SND_SOC_DAPM_MUX("Analog Input 1 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_right_in_mux),
+	SND_SOC_DAPM_MUX("Analog Input 2 Left MUX",  SND_SOC_NOPM, 0, 0, &ak4619_ad_2_left_in_mux),
+	SND_SOC_DAPM_MUX("Analog Input 2 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_right_in_mux),
+
+	/* MUXs for DAC source selection */
+	SND_SOC_DAPM_MUX("DAC 1 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_1_in_mux),
+	SND_SOC_DAPM_MUX("DAC 2 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_2_in_mux),
+};
+
+static const struct snd_soc_dapm_route ak4619_intercon[] = {
+	/* Dest       Connecting Widget    Source */
+
+	/* Output path */
+	{"AOUT1L", NULL, "DAC1"},
+	{"AOUT2L", NULL, "DAC2"},
+
+	{"AOUT1R", NULL, "DAC1"},
+	{"AOUT2R", NULL, "DAC2"},
+
+	{"DAC1", NULL, "DAC 1 Source MUX"},
+	{"DAC2", NULL, "DAC 2 Source MUX"},
+
+	{"DAC 1 Source MUX", "SDIN1",  "SDIN1"},
+	{"DAC 1 Source MUX", "SDIN2",  "SDIN2"},
+	{"DAC 1 Source MUX", "SDOUT1", "SDOUT1"},
+	{"DAC 1 Source MUX", "SDOUT2", "SDOUT2"},
+
+	{"DAC 2 Source MUX", "SDIN1",  "SDIN1"},
+	{"DAC 2 Source MUX", "SDIN2",  "SDIN2"},
+	{"DAC 2 Source MUX", "SDOUT1", "SDOUT1"},
+	{"DAC 2 Source MUX", "SDOUT2", "SDOUT2"},
+
+	/* Input path */
+	{"SDOUT1", NULL, "ADC1"},
+	{"SDOUT2", NULL, "ADC2"},
+
+	{"ADC1", NULL, "Analog Input 1 Left MUX"},
+	{"ADC1", NULL, "Analog Input 1 Right MUX"},
+
+	{"ADC2", NULL, "Analog Input 2 Left MUX"},
+	{"ADC2", NULL, "Analog Input 2 Right MUX"},
+
+	{"Analog Input 1 Left MUX", "Differential",		"MIC1L"},
+	{"Analog Input 1 Left MUX", "Single-Ended1",		"MIC1L"},
+	{"Analog Input 1 Left MUX", "Single-Ended2",		"MIC1L"},
+	{"Analog Input 1 Left MUX", "Pseudo Differential",	"MIC1L"},
+
+	{"Analog Input 1 Right MUX", "Differential",		"MIC1R"},
+	{"Analog Input 1 Right MUX", "Single-Ended1",		"MIC1R"},
+	{"Analog Input 1 Right MUX", "Single-Ended2",		"MIC1R"},
+	{"Analog Input 1 Right MUX", "Pseudo Differential",	"MIC1R"},
+
+	{"Analog Input 2 Left MUX", "Differential",		"MIC2L"},
+	{"Analog Input 2 Left MUX", "Single-Ended1",		"MIC2L"},
+	{"Analog Input 2 Left MUX", "Single-Ended2",		"MIC2L"},
+	{"Analog Input 2 Left MUX", "Pseudo Differential",	"MIC2L"},
+
+	{"Analog Input 2 Right MUX", "Differential",		"MIC2R"},
+	{"Analog Input 2 Right MUX", "Single-Ended1",		"MIC2R"},
+	{"Analog Input 2 Right MUX", "Single-Ended2",		"MIC2R"},
+	{"Analog Input 2 Right MUX", "Pseudo Differential",	"MIC2R"},
+
+	{"MIC1L", NULL, "AIN1L"},
+	{"MIC1L", NULL, "AIN2L"},
+
+	{"MIC1R", NULL, "AIN1R"},
+	{"MIC1R", NULL, "AIN2R"},
+
+	{"MIC2L", NULL, "AIN4L"},
+	{"MIC2L", NULL, "AIN5L"},
+
+	{"MIC2R", NULL, "AIN4R"},
+	{"MIC2R", NULL, "AIN5R"},
+};
+
+static const struct reg_default ak4619_reg_defaults[] = {
+	{ PWR_MGMT,	0x00 },
+	{ AU_IFF1,	0x0C },
+	{ AU_IFF2,	0x0C },
+	{ SYS_CLK,	0x00 },
+	{ MIC_AMP1,	0x22 },
+	{ MIC_AMP2,	0x22 },
+	{ LADC1,	0x30 },
+	{ RADC1,	0x30 },
+	{ LADC2,	0x30 },
+	{ RADC2,	0x30 },
+	{ ADC_DF,	0x00 },
+	{ ADC_AI,	0x00 },
+	{ ADC_MHPF,	0x00 },
+	{ LDAC1,	0x18 },
+	{ RDAC1,	0x18 },
+	{ LDAC2,	0x18 },
+	{ RDAC2,	0x18 },
+	{ DAC_IS,	0x04 },
+	{ DAC_DEMP,	0x05 },
+	{ DAC_MF,	0x0A },
+};
+
+static int ak4619_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	u8 pwr_ctrl = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		pwr_ctrl |= RSTN;
+		fallthrough;
+	case SND_SOC_BIAS_PREPARE:
+		pwr_ctrl |= PMAD1 | PMAD2 | PMDA1 | PMDA2;
+		fallthrough;
+	case SND_SOC_BIAS_STANDBY:
+	case SND_SOC_BIAS_OFF:
+	default:
+		break;
+	}
+
+	snd_soc_component_write(component, PWR_MGMT, pwr_ctrl);
+
+	return 0;
+}
+
+static int ak4619_dai_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 ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+	unsigned int width;
+	unsigned int rate;
+	unsigned int fs;
+	bool is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u8 dai_ctrl = 0;
+	u8 clk_mode = 0;
+
+	width = params_width(params);
+	switch (width) {
+	case 16:
+		dai_ctrl |= is_play ? DIDL_16 : DODL_16;
+		break;
+	case 20:
+		dai_ctrl |= is_play ? DIDL_20 : DODL_20;
+		break;
+	case 24:
+		dai_ctrl |= is_play ? DIDL_24 : DODL_24;
+		break;
+	case 32:
+		if (is_play)
+			dai_ctrl |= DIDL_32;
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rate = params_rate(params);
+	if (rate)
+		fs = ak4619->sysclk / rate;
+	else
+		return -EINVAL;
+
+	switch (rate) {
+	case  8000:
+	case 11025:
+	case 12000:
+	case 16000:
+	case 22050:
+	case 24000:
+	case 32000:
+	case 44100:
+	case 48000:
+		switch (fs) {
+		case 256:
+			clk_mode |= (0x0 << 0);
+			break;
+		case 384:
+			clk_mode |= (0x2 << 0);
+			break;
+		case 512:
+			clk_mode |= (0x3 << 0);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case 64000:
+	case 88200:
+	case 96000:
+		if (fs == 256)
+			clk_mode |= (0x1 << 0);
+		else
+			return -EINVAL;
+		break;
+	case 176400:
+	case 192000:
+		if (fs == 128)
+			clk_mode |= (0x4 << 0);
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, SYS_CLK, FS_MASK, clk_mode);
+	snd_soc_component_update_bits(component, AU_IFF2,
+				      is_play ? DIDL_MASK : DODL_MASK, dai_ctrl);
+
+	if (is_play) {
+		ak4619->playback_rate = rate;
+		ak4619_set_deemph(component);
+	}
+
+	return 0;
+}
+
+static int ak4619_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 dai_fmt1 = 0;
+	u8 dai_fmt2 = 0;
+
+	/* Set clock normal/inverted */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		dai_fmt1 |= BCKP;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+	case SND_SOC_DAIFMT_IB_IF:
+	default:
+		return -EINVAL;
+	}
+
+	/* Only Stereo modes are supported */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dai_fmt1 |= DCF_STEREO_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dai_fmt1 |= DCF_STEREO_MSB;
+		break;
+	case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
+		dai_fmt1 |= DCF_PCM_SF;
+		dai_fmt2 |= SLOT;
+		break;
+	case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+		dai_fmt1 |= DCF_PCM_LF;
+		dai_fmt2 |= SLOT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Only slave mode is support */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default only 64 BICK per LRCLK is supported */
+	dai_fmt1 |= DSL_32;
+
+	snd_soc_component_update_bits(component, AU_IFF1, DCF_MASK |
+					DSL_MASK | BCKP, dai_fmt1);
+	snd_soc_component_update_bits(component, AU_IFF2, SLOT, dai_fmt2);
+
+	return 0;
+}
+
+static int ak4619_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+	ak4619->sysclk = freq;
+
+	return 0;
+}
+
+static int ak4619_dai_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+	struct snd_soc_component *component = dai->component;
+
+	snd_soc_component_update_bits(component, DAC_MF, DA1MUTE_EN, mute ? DA1MUTE_EN : 0);
+	snd_soc_component_update_bits(component, DAC_MF, DA2MUTE_EN, mute ? DA2MUTE_EN : 0);
+
+	return 0;
+}
+
+static void ak4619_hw_constraints(struct ak4619_priv *ak4619,
+				  struct snd_pcm_runtime *runtime)
+{
+	struct snd_pcm_hw_constraint_list *constraint = &ak4619->constraint;
+	int ak4619_rate_mask = 0;
+	unsigned int fs;
+	int i;
+	static const unsigned int ak4619_sr[] = {
+		  8000,
+		 11025,
+		 12000,
+		 16000,
+		 22050,
+		 24000,
+		 32000,
+		 44100,
+		 48000,
+		 64000,
+		 88200,
+		 96000,
+		176400,
+		192000,
+	};
+
+	/*
+	 *	[8kHz - 48kHz]		: 256fs, 384fs or 512fs
+	 *	[64kHz - 96kHz]		: 256fs
+	 *	[176.4kHz, 192kHz]	: 128fs
+	 */
+
+	for (i = 0; i < ARRAY_SIZE(ak4619_sr); i++) {
+		fs = ak4619->sysclk / ak4619_sr[i];
+
+		switch (fs) {
+		case 512:
+		case 384:
+		case 256:
+			ak4619_rate_mask |= (1 << i);
+			break;
+		case 128:
+			switch (i) {
+			case (ARRAY_SIZE(ak4619_sr) - 1):
+			case (ARRAY_SIZE(ak4619_sr) - 2):
+				ak4619_rate_mask |= (1 << i);
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	constraint->list	= ak4619_sr;
+	constraint->mask	= ak4619_rate_mask;
+	constraint->count	= ARRAY_SIZE(ak4619_sr);
+
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, constraint);
+};
+
+#define PLAYBACK_MODE	0
+#define CAPTURE_MODE	1
+
+static int ak4619_dai_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+	ak4619_hw_constraints(ak4619, substream->runtime);
+
+	return 0;
+}
+
+static u64 ak4619_dai_formats[] = {
+	/*
+	 * Select below from Sound Card, not here
+	 *	SND_SOC_DAIFMT_CBC_CFC
+	 *	SND_SOC_DAIFMT_CBP_CFP
+	 */
+
+	/* First Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J,
+
+	/* Second Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
+static const struct snd_soc_dai_ops ak4619_dai_ops = {
+	.startup			= ak4619_dai_startup,
+	.set_sysclk			= ak4619_dai_set_sysclk,
+	.set_fmt			= ak4619_dai_set_fmt,
+	.hw_params			= ak4619_dai_hw_params,
+	.mute_stream			= ak4619_dai_mute,
+	.auto_selectable_formats	= ak4619_dai_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(ak4619_dai_formats),
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4619 = {
+	.set_bias_level		= ak4619_set_bias_level,
+	.controls		= ak4619_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4619_snd_controls),
+	.dapm_widgets		= ak4619_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4619_dapm_widgets),
+	.dapm_routes		= ak4619_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4619_intercon),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+};
+
+static const struct regmap_config ak4619_regmap_cfg = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 0x14,
+	.reg_defaults		= ak4619_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(ak4619_reg_defaults),
+	.cache_type		= REGCACHE_MAPLE,
+};
+
+static const struct of_device_id ak4619_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4619",	.data = &ak4619_regmap_cfg },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ak4619_of_match);
+
+static const struct i2c_device_id ak4619_i2c_id[] = {
+	{ "ak4619", (kernel_ulong_t)&ak4619_regmap_cfg },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4619_i2c_id);
+
+#define AK4619_RATES	SNDRV_PCM_RATE_8000_192000
+
+#define AK4619_DAC_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S20_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE |\
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AK4619_ADC_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S20_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver ak4619_dai = {
+	.name = "ak4619-hifi",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= AK4619_RATES,
+		.formats	= AK4619_DAC_FORMATS,
+	},
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= AK4619_RATES,
+		.formats	= AK4619_ADC_FORMATS,
+	},
+	.ops			= &ak4619_dai_ops,
+	.symmetric_rate		= 1,
+};
+
+static int ak4619_i2c_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct ak4619_priv *ak4619;
+	int ret;
+
+	ak4619 = devm_kzalloc(dev, sizeof(*ak4619), GFP_KERNEL);
+	if (!ak4619)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ak4619);
+
+	ak4619->regmap = devm_regmap_init_i2c(i2c, &ak4619_regmap_cfg);
+	if (IS_ERR(ak4619->regmap)) {
+		ret = PTR_ERR(ak4619->regmap);
+		dev_err(dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_ak4619,
+				      &ak4619_dai, 1);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register ak4619 component: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct i2c_driver ak4619_i2c_driver = {
+	.driver = {
+		.name = "ak4619-codec",
+		.of_match_table = ak4619_of_match,
+	},
+	.probe		= ak4619_i2c_probe,
+	.id_table	= ak4619_i2c_id,
+};
+module_i2c_driver(ak4619_i2c_driver);
+
+MODULE_DESCRIPTION("SoC AK4619 driver");
+MODULE_AUTHOR("Khanh Le <khanh.le.xr@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c
index 1e8e1effc2afea10ef8b37bf29a45293ce045d9c..588e48044c13c8aeadf0039a767a22d1fcc9c0b2 100644
--- a/sound/soc/codecs/audio-iio-aux.c
+++ b/sound/soc/codecs/audio-iio-aux.c
@@ -6,6 +6,7 @@
 //
 // Author: Herve Codina <herve.codina@bootlin.com>
 
+#include <linux/cleanup.h>
 #include <linux/iio/consumer.h>
 #include <linux/minmax.h>
 #include <linux/mod_devicetable.h>
@@ -131,33 +132,27 @@ static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
 				   struct audio_iio_aux_chan *chan)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
-	char *output_name;
-	char *input_name;
-	char *pga_name;
 	int ret;
 
-	input_name = kasprintf(GFP_KERNEL, "%s IN", chan->name);
+	/* Allocated names are not needed afterwards (duplicated in ASoC internals) */
+	char *input_name __free(kfree) = kasprintf(GFP_KERNEL, "%s IN", chan->name);
 	if (!input_name)
 		return -ENOMEM;
 
-	output_name = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
-	if (!output_name) {
-		ret = -ENOMEM;
-		goto out_free_input_name;
-	}
+	char *output_name __free(kfree) = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
+	if (!output_name)
+		return -ENOMEM;
 
-	pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
-	if (!pga_name) {
-		ret = -ENOMEM;
-		goto out_free_output_name;
-	}
+	char *pga_name __free(kfree) = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
+	if (!pga_name)
+		return -ENOMEM;
 
 	widgets[0] = SND_SOC_DAPM_INPUT(input_name);
 	widgets[1] = SND_SOC_DAPM_OUTPUT(output_name);
 	widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0);
 	ret = snd_soc_dapm_new_controls(dapm, widgets, 3);
 	if (ret)
-		goto out_free_pga_name;
+		return ret;
 
 	routes[0].sink = pga_name;
 	routes[0].control = NULL;
@@ -165,17 +160,8 @@ static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
 	routes[1].sink = output_name;
 	routes[1].control = NULL;
 	routes[1].source = pga_name;
-	ret = snd_soc_dapm_add_routes(dapm, routes, 2);
-
-	/* Allocated names are no more needed (duplicated in ASoC internals) */
 
-out_free_pga_name:
-	kfree(pga_name);
-out_free_output_name:
-	kfree(output_name);
-out_free_input_name:
-	kfree(input_name);
-	return ret;
+	return snd_soc_dapm_add_routes(dapm, routes, 2);
 }
 
 static int audio_iio_aux_component_probe(struct snd_soc_component *component)
@@ -244,8 +230,6 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
 	struct audio_iio_aux_chan *iio_aux_chan;
 	struct device *dev = &pdev->dev;
 	struct audio_iio_aux *iio_aux;
-	const char **names;
-	u32 *invert_ranges;
 	int count;
 	int ret;
 	int i;
@@ -262,22 +246,22 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
 
 	iio_aux->num_chans = count;
 
-	names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL);
+	const char **names __free(kfree) = kcalloc(iio_aux->num_chans,
+						   sizeof(*names),
+						   GFP_KERNEL);
 	if (!names)
 		return -ENOMEM;
 
-	invert_ranges = kcalloc(iio_aux->num_chans, sizeof(*invert_ranges), GFP_KERNEL);
-	if (!invert_ranges) {
-		ret = -ENOMEM;
-		goto out_free_names;
-	}
+	u32 *invert_ranges __free(kfree) = kcalloc(iio_aux->num_chans,
+						   sizeof(*invert_ranges),
+						   GFP_KERNEL);
+	if (!invert_ranges)
+		return -ENOMEM;
 
 	ret = device_property_read_string_array(dev, "io-channel-names",
 						names, iio_aux->num_chans);
-	if (ret < 0) {
-		dev_err_probe(dev, ret, "failed to read io-channel-names\n");
-		goto out_free_invert_ranges;
-	}
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to read io-channel-names\n");
 
 	/*
 	 * snd-control-invert-range is optional and can contain fewer items
@@ -288,10 +272,8 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
 		count = min_t(unsigned int, count, iio_aux->num_chans);
 		ret = device_property_read_u32_array(dev, "snd-control-invert-range",
 						     invert_ranges, count);
-		if (ret < 0) {
-			dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
-			goto out_free_invert_ranges;
-		}
+		if (ret < 0)
+			return dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
 	}
 
 	for (i = 0; i < iio_aux->num_chans; i++) {
@@ -300,23 +282,16 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
 		iio_aux_chan->is_invert_range = invert_ranges[i];
 
 		iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name);
-		if (IS_ERR(iio_aux_chan->iio_chan)) {
-			ret = PTR_ERR(iio_aux_chan->iio_chan);
-			dev_err_probe(dev, ret, "get IIO channel '%s' failed\n",
-				      iio_aux_chan->name);
-			goto out_free_invert_ranges;
-		}
+		if (IS_ERR(iio_aux_chan->iio_chan))
+			return dev_err_probe(dev, PTR_ERR(iio_aux_chan->iio_chan),
+					     "get IIO channel '%s' failed\n",
+					     iio_aux_chan->name);
 	}
 
 	platform_set_drvdata(pdev, iio_aux);
 
-	ret = devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
-					      NULL, 0);
-out_free_invert_ranges:
-	kfree(invert_ranges);
-out_free_names:
-	kfree(names);
-	return ret;
+	return devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
+					       NULL, 0);
 }
 
 static const struct of_device_id audio_iio_aux_ids[] = {
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c
index 79521ff440018a0e08741cec0113f1eb1a2fccf7..110009616966acbbfb04fa9d2bedfe30e7cbd698 100644
--- a/sound/soc/codecs/aw87390.c
+++ b/sound/soc/codecs/aw87390.c
@@ -445,7 +445,7 @@ static int aw87390_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id aw87390_i2c_id[] = {
-	{ AW87390_I2C_NAME, 0 },
+	{ AW87390_I2C_NAME },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id);
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index a78ceedd033445791286eb56387bdf1fa6b56a9a..fb99871578c5a99dab9c4d852d27cd1c547a60b6 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -1266,7 +1266,7 @@ static int aw88261_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id aw88261_i2c_id[] = {
-	{ AW88261_I2C_NAME, 0 },
+	{ AW88261_I2C_NAME },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id);
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index 3c459a67ad0c981d8e3d4252efaf9ddefec9e9b0..aea44a199b98ee6e3e30917ba7dac65a4e7b0f98 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -8,9 +8,9 @@
 // Author: Weidong Wang <wangweidong.a@awinic.com>
 //
 
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/firmware.h>
-#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "aw88395.h"
@@ -560,7 +560,7 @@ static int aw88395_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id aw88395_i2c_id[] = {
-	{ AW88395_I2C_NAME, 0 },
+	{ AW88395_I2C_NAME },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aw88395_i2c_id);
diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c
index f25f6e0d4428cb17b43e3d525d195d484cb0d6cb..769ca32a5c8efab45d4e0f64512315ba03af87bf 100644
--- a/sound/soc/codecs/aw88395/aw88395_lib.c
+++ b/sound/soc/codecs/aw88395/aw88395_lib.c
@@ -7,6 +7,7 @@
 // Author: Bruce zhao <zhaolei@awinic.com>
 //
 
+#include <linux/cleanup.h>
 #include <linux/crc8.h>
 #include <linux/i2c.h>
 #include "aw88395_lib.h"
@@ -361,11 +362,11 @@ static int aw_dev_parse_raw_dsp_fw(unsigned char *data,	unsigned int data_len,
 static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *data,
 				unsigned int data_len, struct aw_prof_desc *prof_desc)
 {
-	struct aw_bin *aw_bin;
 	int ret;
 	int i;
 
-	aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(struct aw_bin), GFP_KERNEL);
+	struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(struct aw_bin),
+						     GFP_KERNEL);
 	if (!aw_bin)
 		return -ENOMEM;
 
@@ -375,7 +376,7 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
 	ret = aw_parsing_bin_file(aw_dev, aw_bin);
 	if (ret < 0) {
 		dev_err(aw_dev->dev, "parse bin failed");
-		goto parse_bin_failed;
+		return ret;
 	}
 
 	for (i = 0; i < aw_bin->all_bin_parse_num; i++) {
@@ -387,10 +388,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
 					data + aw_bin->header_info[i].valid_data_addr;
 			break;
 		case DATA_TYPE_DSP_REG:
-			if (aw_bin->header_info[i].valid_data_len & 0x01) {
-				ret = -EINVAL;
-				goto parse_bin_failed;
-			}
+			if (aw_bin->header_info[i].valid_data_len & 0x01)
+				return -EINVAL;
 
 			swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),
 					aw_bin->header_info[i].valid_data_len >> 1);
@@ -402,10 +401,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
 			break;
 		case DATA_TYPE_DSP_FW:
 		case DATA_TYPE_SOC_APP:
-			if (aw_bin->header_info[i].valid_data_len & 0x01) {
-				ret = -EINVAL;
-				goto parse_bin_failed;
-			}
+			if (aw_bin->header_info[i].valid_data_len & 0x01)
+				return -EINVAL;
 
 			swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),
 					aw_bin->header_info[i].valid_data_len >> 1);
@@ -422,20 +419,17 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
 		}
 	}
 	prof_desc->prof_st = AW88395_PROFILE_OK;
-	ret =  0;
 
-parse_bin_failed:
-	devm_kfree(aw_dev->dev, aw_bin);
-	return ret;
+	return 0;
 }
 
 static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
 			uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc)
 {
-	struct aw_bin *aw_bin;
 	int ret;
 
-	aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL);
+	struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(*aw_bin),
+						      GFP_KERNEL);
 	if (!aw_bin)
 		return -ENOMEM;
 
@@ -445,14 +439,13 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
 	ret = aw_parsing_bin_file(aw_dev, aw_bin);
 	if (ret < 0) {
 		dev_err(aw_dev->dev, "parse bin failed");
-		goto parse_bin_failed;
+		return ret;
 	}
 
 	if ((aw_bin->all_bin_parse_num != 1) ||
 		(aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
 		dev_err(aw_dev->dev, "bin num or type error");
-		ret = -EINVAL;
-		goto parse_bin_failed;
+		return -EINVAL;
 	}
 
 	prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =
@@ -461,15 +454,7 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
 				aw_bin->header_info[0].valid_data_len;
 	prof_desc->prof_st = AW88395_PROFILE_OK;
 
-	devm_kfree(aw_dev->dev, aw_bin);
-	aw_bin = NULL;
-
 	return 0;
-
-parse_bin_failed:
-	devm_kfree(aw_dev->dev, aw_bin);
-	aw_bin = NULL;
-	return ret;
 }
 
 static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr,
@@ -678,21 +663,21 @@ static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev,
 static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
 		struct aw_cfg_hdr *prof_hdr)
 {
-	struct aw_all_prof_info *all_prof_info;
 	int ret;
 
-	all_prof_info = devm_kzalloc(aw_dev->dev, sizeof(struct aw_all_prof_info), GFP_KERNEL);
+	struct aw_all_prof_info *all_prof_info __free(kfree) = kzalloc(sizeof(*all_prof_info),
+								       GFP_KERNEL);
 	if (!all_prof_info)
 		return -ENOMEM;
 
 	ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, all_prof_info);
 	if (ret < 0) {
-		goto exit;
+		return ret;
 	} else if (ret == AW88395_DEV_TYPE_NONE) {
 		dev_dbg(aw_dev->dev, "get dev type num is 0, parse default dev");
 		ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, all_prof_info);
 		if (ret < 0)
-			goto exit;
+			return ret;
 	}
 
 	switch (aw_dev->prof_data_type) {
@@ -710,8 +695,6 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
 	if (!ret)
 		aw_dev->prof_info.prof_name_list = profile_name;
 
-exit:
-	devm_kfree(aw_dev->dev, all_prof_info);
 	return ret;
 }
 
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index 9fcb805bf97135ccb491072db2016b82f4b18bf6..8dc2b8aa6832d5f8a75e31f335bcba0b61b72ab5 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -8,9 +8,9 @@
 //
 
 #include <linux/crc32.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/firmware.h>
-#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "aw88399.h"
@@ -1892,7 +1892,7 @@ static int aw88399_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id aw88399_i2c_id[] = {
-	{ AW88399_I2C_NAME, 0 },
+	{ AW88399_I2C_NAME },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aw88399_i2c_id);
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 4c517231d765e14673617e7956acc507a249bb8c..e63a518e3b8e04ecf4d57c6fad7625f10af32147 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -787,7 +787,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = {
 	.endianness		= 1,
 };
 
-static struct regmap_config cs35l34_regmap = {
+static const struct regmap_config cs35l34_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index c39b3cfe95741262c4b015ec6dab09f647771598..7a01b1d9fc9d70c4697d640fea71500bcdad6225 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1086,7 +1086,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = {
 	.endianness		= 1,
 };
 
-static struct regmap_config cs35l35_regmap = {
+static const struct regmap_config cs35l35_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index bc79990615e8047b7470e847700e24c29b474577..cbea79bd89808ab4addbd426f8e498f33b3332ce 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -1300,7 +1300,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = {
 	.endianness		= 1,
 };
 
-static struct regmap_config cs35l36_regmap = {
+static const struct regmap_config cs35l36_regmap = {
 	.reg_bits = 32,
 	.val_bits = 32,
 	.reg_stride = 4,
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index e9993a39f7d0a3f30eaf4a26265ed5242f07745b..1702f26049d37ee15c1d6db7055c8b2f12bd11f1 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -936,8 +936,8 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign
 EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch);
 
 int cs35l41_set_channels(struct device *dev, struct regmap *reg,
-			 unsigned int tx_num, unsigned int *tx_slot,
-			 unsigned int rx_num, unsigned int *rx_slot)
+			 unsigned int tx_num, const unsigned int *tx_slot,
+			 unsigned int rx_num, const unsigned int *rx_slot)
 {
 	unsigned int val, mask;
 	int i;
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index cb25c33cc9b9541ea250f8047988d29f58216551..1688c2c688f06b387e4be0eac61f422d621dbd03 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -673,7 +673,8 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
 };
 
 static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n,
-				   unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot)
+				   const unsigned int *tx_slot,
+				   unsigned int rx_n, const unsigned int *rx_slot)
 {
 	struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component);
 
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 70ff55c1517fe02d2a75e7d683e58edcb01947d0..fc03bb7ecae136b99fccc2efb332f05c4c1124fd 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -271,7 +271,6 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
 	prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT);
 	prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT);
 	prop->paging_support = true;
-	prop->clk_stop_mode1 = false;
 	prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
 	prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF;
 
@@ -317,79 +316,6 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
 	return 0;
 }
 
-static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
-				   struct sdw_slave *peripheral)
-{
-	unsigned int curr_scale_reg, next_scale_reg;
-	int curr_scale, next_scale, ret;
-
-	if (!cs35l56->base.init_done)
-		return 0;
-
-	if (peripheral->bus->params.curr_bank) {
-		curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
-		next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
-	} else {
-		curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
-		next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
-	}
-
-	/*
-	 * Current clock scale value must be different to new value.
-	 * Modify current to guarantee this. If next still has the dummy
-	 * value we wrote when it was current, the core code has not set
-	 * a new scale so restore its original good value
-	 */
-	curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg);
-	if (curr_scale < 0) {
-		dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale);
-		return curr_scale;
-	}
-
-	next_scale = sdw_read_no_pm(peripheral, next_scale_reg);
-	if (next_scale < 0) {
-		dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale);
-		return next_scale;
-	}
-
-	if (next_scale == CS35L56_SDW_INVALID_BUS_SCALE) {
-		next_scale = cs35l56->old_sdw_clock_scale;
-		ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale);
-		if (ret < 0) {
-			dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n",
-				ret);
-			return ret;
-		}
-	}
-
-	cs35l56->old_sdw_clock_scale = curr_scale;
-	ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE);
-	if (ret < 0) {
-		dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret);
-		return ret;
-	}
-
-	dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale);
-
-	return 0;
-}
-
-static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
-				  struct sdw_bus_params *params)
-{
-	struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
-	int sclk;
-
-	sclk = params->curr_dr_freq / 2;
-	dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n",
-		__func__, sclk, params->col, params->row);
-
-	if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev < 0xb0))
-		return cs35l56_a1_kick_divider(cs35l56, peripheral);
-
-	return 0;
-}
-
 static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
 					       enum sdw_clk_stop_mode mode,
 					       enum sdw_clk_stop_type type)
@@ -405,7 +331,6 @@ static const struct sdw_slave_ops cs35l56_sdw_ops = {
 	.read_prop = cs35l56_sdw_read_prop,
 	.interrupt_callback = cs35l56_sdw_interrupt,
 	.update_status = cs35l56_sdw_update_status,
-	.bus_config = cs35l56_sdw_bus_config,
 #ifdef DEBUG
 	.clk_stop = cs35l56_sdw_clk_stop,
 #endif
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 30497152e02a74784aa441f8247a5cba71068b51..e7e8d617da94e4931062f00db7bd386f14694ddf 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -20,6 +20,18 @@ static const struct reg_sequence cs35l56_patch[] = {
 	 * Firmware can change these to non-defaults to satisfy SDCA.
 	 * Ensure that they are at known defaults.
 	 */
+	{ CS35L56_ASP1_ENABLES1,		0x00000000 },
+	{ CS35L56_ASP1_CONTROL1,		0x00000028 },
+	{ CS35L56_ASP1_CONTROL2,		0x18180200 },
+	{ CS35L56_ASP1_CONTROL3,		0x00000002 },
+	{ CS35L56_ASP1_FRAME_CONTROL1,		0x03020100 },
+	{ CS35L56_ASP1_FRAME_CONTROL5,		0x00020100 },
+	{ CS35L56_ASP1_DATA_CONTROL1,		0x00000018 },
+	{ CS35L56_ASP1_DATA_CONTROL5,		0x00000018 },
+	{ CS35L56_ASP1TX1_INPUT,		0x00000000 },
+	{ CS35L56_ASP1TX2_INPUT,		0x00000000 },
+	{ CS35L56_ASP1TX3_INPUT,		0x00000000 },
+	{ CS35L56_ASP1TX4_INPUT,		0x00000000 },
 	{ CS35L56_SWIRE_DP3_CH1_INPUT,		0x00000018 },
 	{ CS35L56_SWIRE_DP3_CH2_INPUT,		0x00000019 },
 	{ CS35L56_SWIRE_DP3_CH3_INPUT,		0x00000029 },
@@ -41,12 +53,18 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
 static const struct reg_default cs35l56_reg_defaults[] = {
 	/* no defaults for OTP_MEM - first read populates cache */
 
-	/*
-	 * No defaults for ASP1 control or ASP1TX mixer. See
-	 * cs35l56_populate_asp1_register_defaults() and
-	 * cs35l56_sync_asp1_mixer_widgets_with_firmware().
-	 */
-
+	{ CS35L56_ASP1_ENABLES1,		0x00000000 },
+	{ CS35L56_ASP1_CONTROL1,		0x00000028 },
+	{ CS35L56_ASP1_CONTROL2,		0x18180200 },
+	{ CS35L56_ASP1_CONTROL3,		0x00000002 },
+	{ CS35L56_ASP1_FRAME_CONTROL1,		0x03020100 },
+	{ CS35L56_ASP1_FRAME_CONTROL5,		0x00020100 },
+	{ CS35L56_ASP1_DATA_CONTROL1,		0x00000018 },
+	{ CS35L56_ASP1_DATA_CONTROL5,		0x00000018 },
+	{ CS35L56_ASP1TX1_INPUT,		0x00000000 },
+	{ CS35L56_ASP1TX2_INPUT,		0x00000000 },
+	{ CS35L56_ASP1TX3_INPUT,		0x00000000 },
+	{ CS35L56_ASP1TX4_INPUT,		0x00000000 },
 	{ CS35L56_SWIRE_DP3_CH1_INPUT,		0x00000018 },
 	{ CS35L56_SWIRE_DP3_CH2_INPUT,		0x00000019 },
 	{ CS35L56_SWIRE_DP3_CH3_INPUT,		0x00000029 },
@@ -206,77 +224,6 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
 	}
 }
 
-static const struct reg_sequence cs35l56_asp1_defaults[] = {
-	REG_SEQ0(CS35L56_ASP1_ENABLES1,		0x00000000),
-	REG_SEQ0(CS35L56_ASP1_CONTROL1,		0x00000028),
-	REG_SEQ0(CS35L56_ASP1_CONTROL2,		0x18180200),
-	REG_SEQ0(CS35L56_ASP1_CONTROL3,		0x00000002),
-	REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1,	0x03020100),
-	REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5,	0x00020100),
-	REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1,	0x00000018),
-	REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5,	0x00000018),
-	REG_SEQ0(CS35L56_ASP1TX1_INPUT,		0x00000000),
-	REG_SEQ0(CS35L56_ASP1TX2_INPUT,		0x00000000),
-	REG_SEQ0(CS35L56_ASP1TX3_INPUT,		0x00000000),
-	REG_SEQ0(CS35L56_ASP1TX4_INPUT,		0x00000000),
-};
-
-/*
- * The firmware can have control of the ASP so we don't provide regmap
- * with defaults for these registers, to prevent a regcache_sync() from
- * overwriting the firmware settings. But if the machine driver hooks up
- * the ASP it means the driver is taking control of the ASP, so then the
- * registers are populated with the defaults.
- */
-int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base)
-{
-	if (!cs35l56_base->fw_owns_asp1)
-		return 0;
-
-	cs35l56_base->fw_owns_asp1 = false;
-
-	return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults,
-				      ARRAY_SIZE(cs35l56_asp1_defaults));
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED);
-
-/*
- * The firmware boot sequence can overwrite the ASP1 config registers so that
- * they don't match regmap's view of their values. Rewrite the values from the
- * regmap cache into the hardware registers.
- */
-int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
-{
-	struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)];
-	int i, ret;
-
-	if (cs35l56_base->fw_owns_asp1)
-		return 0;
-
-	memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs));
-
-	/* Read current values from regmap cache into the write sequence */
-	for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) {
-		ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def);
-		if (ret)
-			goto err;
-	}
-
-	/* Write the values cache-bypassed so that they will be written to silicon */
-	ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs,
-					      ARRAY_SIZE(asp1_regs));
-	if (ret)
-		goto err;
-
-	return 0;
-
-err:
-	dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret);
-
-	return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED);
-
 int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
 {
 	unsigned int val;
@@ -298,19 +245,13 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);
 int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
 {
 	int ret;
-	unsigned int reg;
 	unsigned int val;
 
 	ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN);
 	if (ret)
 		return ret;
 
-	if (cs35l56_base->rev < CS35L56_REVID_B0)
-		reg = CS35L56_DSP1_PM_CUR_STATE_A1;
-	else
-		reg = CS35L56_DSP1_PM_CUR_STATE;
-
-	ret = regmap_read_poll_timeout(cs35l56_base->regmap,  reg,
+	ret = regmap_read_poll_timeout(cs35l56_base->regmap,  CS35L56_DSP1_PM_CUR_STATE,
 				       val, (val == CS35L56_HALO_STATE_SHUTDOWN),
 				       CS35L56_HALO_STATE_POLL_US,
 				       CS35L56_HALO_STATE_TIMEOUT_US);
@@ -323,15 +264,9 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED);
 
 int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
 {
-	unsigned int reg;
 	unsigned int val = 0;
 	int read_ret, poll_ret;
 
-	if (cs35l56_base->rev < CS35L56_REVID_B0)
-		reg = CS35L56_DSP1_HALO_STATE_A1;
-	else
-		reg = CS35L56_DSP1_HALO_STATE;
-
 	/*
 	 * The regmap must remain in cache-only until the chip has
 	 * booted, so use a bypassed read of the status register.
@@ -341,7 +276,7 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
 				     CS35L56_HALO_STATE_POLL_US,
 				     CS35L56_HALO_STATE_TIMEOUT_US,
 				     false,
-				     cs35l56_base->regmap, reg, &val);
+				     cs35l56_base->regmap, CS35L56_DSP1_HALO_STATE, &val);
 
 	if (poll_ret) {
 		dev_err(cs35l56_base->dev, "Firmware boot timed out(%d): HALO_STATE=%#x\n",
@@ -397,7 +332,7 @@ int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
 {
 	int ret;
 
-	if (!irq)
+	if (irq < 1)
 		return 0;
 
 	ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
@@ -779,11 +714,6 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
 	else
 		cs35l56_wait_control_port_ready();
 
-	/*
-	 * The HALO_STATE register is in different locations on Ax and B0
-	 * devices so the REVID needs to be determined before waiting for the
-	 * firmware to boot.
-	 */
 	ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_REVID, &revid);
 	if (ret < 0) {
 		dev_err(cs35l56_base->dev, "Get Revision ID failed\n");
@@ -857,9 +787,16 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
 int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base)
 {
 	struct gpio_descs *descs;
-	int speaker_id;
+	u32 speaker_id;
 	int i, ret;
 
+	/* Attempt to read the speaker type from a device property first */
+	ret = device_property_read_u32(cs35l56_base->dev, "cirrus,speaker-id", &speaker_id);
+	if (!ret) {
+		dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id);
+		return speaker_id;
+	}
+
 	/* Read the speaker type qualifier from the motherboard GPIOs */
 	descs = gpiod_get_array_optional(cs35l56_base->dev, "spk-id", GPIOD_IN);
 	if (!descs) {
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 758dfdf9d3eac7b7d8b94b672746c4599932fdbd..84c34f5b1a516d092e1ded727d3eb77c9f7f5b1e 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -63,131 +63,6 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol,
 	return snd_soc_put_volsw(kcontrol, ucontrol);
 }
 
-static const unsigned short cs35l56_asp1_mixer_regs[] = {
-	CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX2_INPUT,
-	CS35L56_ASP1TX3_INPUT, CS35L56_ASP1TX4_INPUT,
-};
-
-static const char * const cs35l56_asp1_mux_control_names[] = {
-	"ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source"
-};
-
-static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56)
-{
-	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
-	const char *prefix = cs35l56->component->name_prefix;
-	char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-	const char *name;
-	struct snd_kcontrol *kcontrol;
-	struct soc_enum *e;
-	unsigned int val[4];
-	int i, item, ret;
-
-	if (cs35l56->asp1_mixer_widgets_initialized)
-		return 0;
-
-	/*
-	 * Resume so we can read the registers from silicon if the regmap
-	 * cache has not yet been populated.
-	 */
-	ret = pm_runtime_resume_and_get(cs35l56->base.dev);
-	if (ret < 0)
-		return ret;
-
-	/* Wait for firmware download and reboot */
-	cs35l56_wait_dsp_ready(cs35l56);
-
-	ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT,
-			       val, ARRAY_SIZE(val));
-
-	pm_runtime_mark_last_busy(cs35l56->base.dev);
-	pm_runtime_put_autosuspend(cs35l56->base.dev);
-
-	if (ret) {
-		dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
-		return ret;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) {
-		name = cs35l56_asp1_mux_control_names[i];
-
-		if (prefix) {
-			snprintf(full_name, sizeof(full_name), "%s %s", prefix, name);
-			name = full_name;
-		}
-
-		kcontrol = snd_soc_card_get_kcontrol_locked(dapm->card, name);
-		if (!kcontrol) {
-			dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
-			continue;
-		}
-
-		e = (struct soc_enum *)kcontrol->private_value;
-		item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK);
-		snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
-	}
-
-	cs35l56->asp1_mixer_widgets_initialized = true;
-
-	return 0;
-}
-
-static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
-	struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
-	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	int index = e->shift_l;
-	unsigned int addr, val;
-	int ret;
-
-	ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
-	if (ret)
-		return ret;
-
-	addr = cs35l56_asp1_mixer_regs[index];
-	ret = regmap_read(cs35l56->base.regmap, addr, &val);
-	if (ret)
-		return ret;
-
-	val &= CS35L56_ASP_TXn_SRC_MASK;
-	ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
-
-	return 0;
-}
-
-static int cs35l56_dspwait_asp1tx_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 cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
-	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	int item = ucontrol->value.enumerated.item[0];
-	int index = e->shift_l;
-	unsigned int addr, val;
-	bool changed;
-	int ret;
-
-	ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
-	if (ret)
-		return ret;
-
-	addr = cs35l56_asp1_mixer_regs[index];
-	val = snd_soc_enum_item_to_val(e, item);
-
-	ret = regmap_update_bits_check(cs35l56->base.regmap, addr,
-				       CS35L56_ASP_TXn_SRC_MASK, val, &changed);
-	if (ret)
-		return ret;
-
-	if (changed)
-		snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
-
-	return changed;
-}
-
 static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
 
 static const struct snd_kcontrol_new cs35l56_controls[] = {
@@ -196,7 +71,11 @@ static const struct snd_kcontrol_new cs35l56_controls[] = {
 		       cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
 	SOC_SINGLE_S_EXT_TLV("Speaker Volume",
 			     CS35L56_MAIN_RENDER_USER_VOLUME,
-			     6, -400, 400, 9, 0,
+			     CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
+			     CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
+			     CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
+			     CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
+			     0,
 			     cs35l56_dspwait_get_volsw,
 			     cs35l56_dspwait_put_volsw,
 			     vol_tlv),
@@ -206,44 +85,40 @@ static const struct snd_kcontrol_new cs35l56_controls[] = {
 };
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
-				  SND_SOC_NOPM,
-				  0, 0,
+				  CS35L56_ASP1TX1_INPUT,
+				  0, CS35L56_ASP_TXn_SRC_MASK,
 				  cs35l56_tx_input_texts,
 				  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx1_mux =
-	SOC_DAPM_ENUM_EXT("ASP1TX1 SRC", cs35l56_asp1tx1_enum,
-			  cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+	SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum,
-				  SND_SOC_NOPM,
-				  1, 0,
+				  CS35L56_ASP1TX2_INPUT,
+				  0, CS35L56_ASP_TXn_SRC_MASK,
 				  cs35l56_tx_input_texts,
 				  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx2_mux =
-	SOC_DAPM_ENUM_EXT("ASP1TX2 SRC", cs35l56_asp1tx2_enum,
-			  cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+	SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum,
-				  SND_SOC_NOPM,
-				  2, 0,
+				  CS35L56_ASP1TX3_INPUT,
+				  0, CS35L56_ASP_TXn_SRC_MASK,
 				  cs35l56_tx_input_texts,
 				  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx3_mux =
-	SOC_DAPM_ENUM_EXT("ASP1TX3 SRC", cs35l56_asp1tx3_enum,
-			  cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+	SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum,
-				  SND_SOC_NOPM,
-				  3, 0,
+				  CS35L56_ASP1TX4_INPUT,
+				  0, CS35L56_ASP_TXn_SRC_MASK,
 				  cs35l56_tx_input_texts,
 				  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx4_mux =
-	SOC_DAPM_ENUM_EXT("ASP1TX4 SRC", cs35l56_asp1tx4_enum,
-			  cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+	SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum,
 				CS35L56_SWIRE_DP3_CH1_INPUT,
@@ -281,21 +156,6 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum,
 static const struct snd_kcontrol_new sdw1_tx4_mux =
 	SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum);
 
-static int cs35l56_asp1_cfg_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 cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		/* Override register values set by firmware boot */
-		return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
-	default:
-		return 0;
-	}
-}
-
 static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
@@ -332,9 +192,6 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
 	SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0),
 	SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0),
 
-	SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event,
-			    SND_SOC_DAPM_PRE_PMU),
-
 	SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event,
 			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -402,9 +259,6 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = {
 	{ "AMP", NULL, "VDD_B" },
 	{ "AMP", NULL, "VDD_AMP" },
 
-	{ "ASP1 Playback", NULL, "ASP1 CFG" },
-	{ "ASP1 Capture", NULL, "ASP1 CFG" },
-
 	{ "ASP1 Playback", NULL, "PLAY" },
 	{ "SDW1 Playback", NULL, "PLAY" },
 
@@ -455,14 +309,9 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
 {
 	struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
 	unsigned int val;
-	int ret;
 
 	dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);
 
-	ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
-	if (ret)
-		return ret;
-
 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
 	case SND_SOC_DAIFMT_CBC_CFC:
 		break;
@@ -536,11 +385,6 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
 					unsigned int rx_mask, int slots, int slot_width)
 {
 	struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
-	int ret;
-
-	ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
-	if (ret)
-		return ret;
 
 	if ((slots == 0) || (slot_width == 0)) {
 		dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
@@ -589,11 +433,6 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
 	struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int rate = params_rate(params);
 	u8 asp_width, asp_wl;
-	int ret;
-
-	ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
-	if (ret)
-		return ret;
 
 	asp_wl = params_width(params);
 	if (cs35l56->asp_slot_width)
@@ -650,11 +489,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
 				      int clk_id, unsigned int freq, int dir)
 {
 	struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
-	int freq_id, ret;
-
-	ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
-	if (ret)
-		return ret;
+	int freq_id;
 
 	if (freq == 0) {
 		cs35l56->sysclk_set = false;
@@ -1035,13 +870,6 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
 	debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
 	debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
 
-	/*
-	 * The widgets for the ASP1TX mixer can't be initialized
-	 * until the firmware has been downloaded and rebooted.
-	 */
-	regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT);
-	cs35l56->asp1_mixer_widgets_initialized = false;
-
 	queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
 
 	return 0;
@@ -1432,9 +1260,6 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
 	cs35l56->base.cal_index = -1;
 	cs35l56->speaker_id = -ENOENT;
 
-	/* Assume that the firmware owns ASP1 until we know different */
-	cs35l56->base.fw_owns_asp1 = true;
-
 	dev_set_drvdata(cs35l56->base.dev, cs35l56);
 
 	cs35l56_fill_supply_names(cs35l56->supplies);
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index b000e7365e4065eaffc3b3ea2aa2714b9acccdfd..8a987ec01507ec3a5b53c2a914303004e6d68282 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -51,8 +51,6 @@ struct cs35l56_private {
 	u8 asp_slot_count;
 	bool tdm_mode;
 	bool sysclk_set;
-	bool asp1_mixer_widgets_initialized;
-	u8 old_sdw_clock_scale;
 };
 
 extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..56659bf735db7c91a99a4bcd56e2caa005ceead9
--- /dev/null
+++ b/sound/soc/codecs/cs530x-i2c.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include "cs530x.h"
+
+static const struct of_device_id cs530x_of_match[] = {
+	{
+		.compatible = "cirrus,cs5302",
+		.data = (void *)CS5302,
+	}, {
+		.compatible = "cirrus,cs5304",
+		.data = (void *)CS5304,
+	}, {
+		.compatible = "cirrus,cs5308",
+		.data = (void *)CS5308,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cs530x_of_match);
+
+static const struct i2c_device_id cs530x_i2c_id[] = {
+	{ "cs5302", CS5302 },
+	{ "cs5304", CS5304 },
+	{ "cs5308", CS5308 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs530x_i2c_id);
+
+static int cs530x_i2c_probe(struct i2c_client *client)
+{
+	struct cs530x_priv *cs530x;
+
+	cs530x = devm_kzalloc(&client->dev, sizeof(*cs530x), GFP_KERNEL);
+	if (!cs530x)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, cs530x);
+
+	cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap);
+	if (IS_ERR(cs530x->regmap))
+		return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap),
+			      "Failed to allocate register map\n");
+
+	cs530x->devtype = (uintptr_t)i2c_get_match_data(client);
+	cs530x->dev = &client->dev;
+
+	return cs530x_probe(cs530x);
+}
+
+static struct i2c_driver cs530x_i2c_driver = {
+	.driver = {
+		.name = "cs530x",
+		.of_match_table = cs530x_of_match,
+	},
+	.probe = cs530x_i2c_probe,
+	.id_table = cs530x_i2c_id,
+};
+module_i2c_driver(cs530x_i2c_driver);
+
+MODULE_DESCRIPTION("I2C CS530X driver");
+MODULE_IMPORT_NS(SND_SOC_CS530X);
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paulha@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
new file mode 100644
index 0000000000000000000000000000000000000000..25a86a32e936679dcfd13d9428e47618ac60706f
--- /dev/null
+++ b/sound/soc/codecs/cs530x.c
@@ -0,0 +1,971 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <sound/core.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <sound/initval.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs530x.h"
+
+#define CS530X_MAX_ADC_CH	8
+#define CS530X_MIN_ADC_CH	2
+
+static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = {
+	"vdd-a",
+	"vdd-io",
+};
+
+static const struct reg_default cs530x_reg_defaults[] = {
+	{ CS530X_CLK_CFG_0, 0x30 },
+	{ CS530X_CLK_CFG_1, 0x0001 },
+	{ CS530X_CHIP_ENABLE, 0 },
+	{ CS530X_ASP_CFG, 0 },
+	{ CS530X_SIGNAL_PATH_CFG, 0 },
+	{ CS530X_IN_ENABLES, 0 },
+	{ CS530X_IN_RAMP_SUM, 0x0022 },
+	{ CS530X_IN_FILTER, 0 },
+	{ CS530X_IN_HIZ, 0 },
+	{ CS530X_IN_INV, 0 },
+	{ CS530X_IN_VOL_CTRL1_0, 0x8000 },
+	{ CS530X_IN_VOL_CTRL1_1, 0x8000 },
+	{ CS530X_IN_VOL_CTRL2_0, 0x8000 },
+	{ CS530X_IN_VOL_CTRL2_1, 0x8000 },
+	{ CS530X_IN_VOL_CTRL3_0, 0x8000 },
+	{ CS530X_IN_VOL_CTRL3_1, 0x8000 },
+	{ CS530X_IN_VOL_CTRL4_0, 0x8000 },
+	{ CS530X_IN_VOL_CTRL4_1, 0x8000 },
+	{ CS530X_PAD_FN, 0 },
+	{ CS530X_PAD_LVL, 0 },
+};
+
+static bool cs530x_read_and_write_regs(unsigned int reg)
+{
+	switch (reg) {
+	case CS530X_CLK_CFG_0:
+	case CS530X_CLK_CFG_1:
+	case CS530X_CHIP_ENABLE:
+	case CS530X_ASP_CFG:
+	case CS530X_SIGNAL_PATH_CFG:
+	case CS530X_IN_ENABLES:
+	case CS530X_IN_RAMP_SUM:
+	case CS530X_IN_FILTER:
+	case CS530X_IN_HIZ:
+	case CS530X_IN_INV:
+	case CS530X_IN_VOL_CTRL1_0:
+	case CS530X_IN_VOL_CTRL1_1:
+	case CS530X_IN_VOL_CTRL2_0:
+	case CS530X_IN_VOL_CTRL2_1:
+	case CS530X_IN_VOL_CTRL3_0:
+	case CS530X_IN_VOL_CTRL3_1:
+	case CS530X_IN_VOL_CTRL4_0:
+	case CS530X_IN_VOL_CTRL4_1:
+	case CS530X_PAD_FN:
+	case CS530X_PAD_LVL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs530x_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS530X_DEVID:
+	case CS530X_REVID:
+		return true;
+	default:
+		return cs530x_read_and_write_regs(reg);
+	}
+}
+
+static bool cs530x_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS530X_SW_RESET:
+	case CS530X_IN_VOL_CTRL5:
+		return true;
+	default:
+		return cs530x_read_and_write_regs(reg);
+	}
+}
+
+static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+	int ret;
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret)
+		goto volsw_err;
+
+	/* Write IN_VU bit for the volume change to take effect */
+	regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU);
+
+volsw_err:
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0);
+
+static const char * const cs530x_in_hpf_text[] = {
+	"Min Phase Slow Roll-off",
+	"Min Phase Fast Roll-off",
+	"Linear Phase Slow Roll-off",
+	"Linear Phase Fast Roll-off",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_hpf_enum, CS530X_IN_FILTER,
+			    CS530X_IN_FILTER_SHIFT,
+			    cs530x_in_hpf_text);
+
+static const char * const cs530x_in_4ch_sum_text[] = {
+	"None",
+	"Groups of 2",
+	"Groups of 4",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM,
+			    CS530X_IN_SUM_MODE_SHIFT,
+			    cs530x_in_4ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = {
+SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum),
+};
+
+static const char * const cs530x_in_8ch_sum_text[] = {
+	"None",
+	"Groups of 2",
+	"Groups of 4",
+	"Groups of 8",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM,
+			    CS530X_IN_SUM_MODE_SHIFT,
+			    cs530x_in_8ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = {
+SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum),
+};
+
+
+static const char * const cs530x_vol_ramp_text[] = {
+	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+	"15ms/6dB", "30ms/6dB",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM,
+			    CS530X_RAMP_RATE_INC_SHIFT,
+			    cs530x_vol_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM,
+			    CS530X_RAMP_RATE_DEC_SHIFT,
+			    cs530x_vol_ramp_text);
+
+static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = {
+SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_ENUM("IN HPF Select", cs530x_in_hpf_enum),
+SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum),
+SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum),
+
+SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = {
+SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = {
+SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1,
+		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0),
+};
+
+static int cs530x_adc_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		cs530x->adc_pairs_count++;
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+				 (w->shift * 2), CS530X_IN_MUTE);
+		regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+				 ((w->shift+1) * 2), CS530X_IN_MUTE);
+
+		cs530x->adc_pairs_count--;
+		if (!cs530x->adc_pairs_count) {
+			usleep_range(1000, 1100);
+			return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
+					    CS530X_IN_VU);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+			       (w->shift * 2), CS530X_IN_MUTE);
+		regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+			       ((w->shift+1) * 2), CS530X_IN_MUTE);
+		return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
+				    CS530X_IN_VU);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new adc12_ctrl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new adc34_ctrl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new adc56_ctrl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new adc78_ctrl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new in_hpf_ctrl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* General DAPM widgets for all devices */
+static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0),
+};
+
+/* ADC's Channels 1 and 2 plus generic ADC DAPM events */
+static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1"),
+SND_SOC_DAPM_INPUT("IN2"),
+SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0,
+		   cs530x_adc_event,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0),
+SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl),
+SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT,
+		    0, &in_hpf_ctrl),
+};
+
+/* ADC's Channels 3 and 4 */
+static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN3"),
+SND_SOC_DAPM_INPUT("IN4"),
+SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0,
+		   cs530x_adc_event,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0),
+SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl),
+};
+
+/* ADC's Channels 5 to 8 */
+static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN5"),
+SND_SOC_DAPM_INPUT("IN6"),
+SND_SOC_DAPM_INPUT("IN7"),
+SND_SOC_DAPM_INPUT("IN8"),
+SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0,
+		   cs530x_adc_event,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0),
+SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl),
+SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0,
+		   cs530x_adc_event,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0),
+SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl),
+};
+
+static const struct snd_soc_dapm_route adc_ch1_2_routes[] = {
+	{ "ADC1", NULL, "Global Enable" },
+	{ "ADC2", NULL, "Global Enable" },
+
+	{ "ADC12 Enable", "Switch", "IN1" },
+	{ "ADC12 Enable", "Switch", "IN2" },
+	{ "ADC1", NULL, "ADC12 Enable" },
+	{ "ADC2", NULL, "ADC12 Enable" },
+	{ "IN HPF", "Switch", "ADC1" },
+	{ "IN HPF", "Switch", "ADC2" },
+
+	{ "AIF Capture", NULL, "IN HPF" },
+	{ "AIF Capture", NULL, "ADC1" },
+	{ "AIF Capture", NULL, "ADC2" },
+};
+
+static const struct snd_soc_dapm_route adc_ch3_4_routes[] = {
+	{ "ADC3", NULL, "Global Enable" },
+	{ "ADC4", NULL, "Global Enable" },
+
+	{ "ADC34 Enable", "Switch", "IN3" },
+	{ "ADC34 Enable", "Switch", "IN4" },
+	{ "ADC3", NULL, "ADC34 Enable" },
+	{ "ADC4", NULL, "ADC34 Enable" },
+	{ "IN HPF", "Switch", "ADC3" },
+	{ "IN HPF", "Switch", "ADC4" },
+
+	{ "AIF Capture", NULL, "ADC3" },
+	{ "AIF Capture", NULL, "ADC4" },
+};
+
+static const struct snd_soc_dapm_route adc_ch5_8_routes[] = {
+	{ "ADC5", NULL, "Global Enable" },
+	{ "ADC6", NULL, "Global Enable" },
+	{ "ADC7", NULL, "Global Enable" },
+	{ "ADC8", NULL, "Global Enable" },
+
+	{ "ADC56 Enable", "Switch", "IN5" },
+	{ "ADC56 Enable", "Switch", "IN6" },
+	{ "ADC5", NULL, "ADC56 Enable" },
+	{ "ADC6", NULL, "ADC56 Enable" },
+	{ "IN HPF", "Switch", "ADC5" },
+	{ "IN HPF", "Switch", "ADC6" },
+
+	{ "AIF Capture", NULL, "ADC5" },
+	{ "AIF Capture", NULL, "ADC6" },
+
+	{ "ADC78 Enable", "Switch", "IN7" },
+	{ "ADC78 Enable", "Switch", "IN8" },
+	{ "ADC7", NULL, "ADC78 Enable" },
+	{ "ADC8", NULL, "ADC78 Enable" },
+	{ "IN HPF", "Switch", "ADC7" },
+	{ "IN HPF", "Switch", "ADC8" },
+
+	{ "AIF Capture", NULL, "ADC7" },
+	{ "AIF Capture", NULL, "ADC8" },
+};
+
+static void cs530x_add_12_adc_widgets(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_add_component_controls(component,
+				       cs530x_in_1_to_2_controls,
+				       ARRAY_SIZE(cs530x_in_1_to_2_controls));
+
+	snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets,
+				  ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes,
+				ARRAY_SIZE(adc_ch1_2_routes));
+}
+
+static void cs530x_add_34_adc_widgets(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_add_component_controls(component,
+				       cs530x_in_3_to_4_controls,
+				       ARRAY_SIZE(cs530x_in_3_to_4_controls));
+
+	snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets,
+				  ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes,
+				ARRAY_SIZE(adc_ch3_4_routes));
+}
+
+static int cs530x_set_bclk(struct snd_soc_component *component, const int freq)
+{
+	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+	unsigned int bclk_val;
+
+	switch (freq) {
+	case 2822400:
+	case 3072000:
+		bclk_val = CS530X_BCLK_2P822_3P072;
+		break;
+	case 5644800:
+	case 6144000:
+		bclk_val = CS530X_BCLK_5P6448_6P144;
+		break;
+	case 11289600:
+	case 12288000:
+		bclk_val = CS530X_BCLK_11P2896_12P288;
+		break;
+	case 22579200:
+	case 24576000:
+		bclk_val = CS530X_BCLK_24P5792_24P576;
+		break;
+	default:
+		dev_err(component->dev, "Invalid BCLK frequency %d\n", freq);
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "BCLK frequency is %d\n", freq);
+
+	return regmap_update_bits(regmap, CS530X_ASP_CFG,
+				  CS530X_ASP_BCLK_FREQ_MASK, bclk_val);
+}
+
+static int cs530x_set_pll_refclk(struct snd_soc_component *component,
+				  const unsigned int freq)
+{
+	struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = priv->regmap;
+	unsigned int refclk;
+
+	switch (freq) {
+	case 2822400:
+	case 3072000:
+		refclk = CS530X_REFCLK_2P822_3P072;
+		break;
+	case 5644800:
+	case 6144000:
+		refclk = CS530X_REFCLK_5P6448_6P144;
+		break;
+	case 11289600:
+	case 12288000:
+		refclk = CS530X_REFCLK_11P2896_12P288;
+		break;
+	case 22579200:
+	case 24576000:
+		refclk = CS530X_REFCLK_24P5792_24P576;
+		break;
+	default:
+		dev_err(component->dev, "Invalid PLL refclk %d\n", freq);
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+				  CS530X_PLL_REFCLK_FREQ_MASK, refclk);
+}
+
+static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+	int ret = 0, fs = params_rate(params), bclk;
+	unsigned int fs_val;
+
+
+	switch (fs) {
+	case 32000:
+		fs_val = CS530X_FS_32K;
+		break;
+	case 44100:
+	case 48000:
+		fs_val = CS530X_FS_48K_44P1K;
+		break;
+	case 88200:
+	case 96000:
+		fs_val = CS530X_FS_96K_88P2K;
+		break;
+	case 176400:
+	case 192000:
+		fs_val = CS530X_FS_192K_176P4K;
+		break;
+	case 356800:
+	case 384000:
+		fs_val = CS530X_FS_384K_356P8K;
+		break;
+	case 705600:
+	case 768000:
+		fs_val = CS530X_FS_768K_705P6K;
+		break;
+	default:
+		dev_err(component->dev, "Invalid sample rate %d\n", fs);
+		return -EINVAL;
+	}
+
+	cs530x->fs = fs;
+	regmap_update_bits(regmap, CS530X_CLK_CFG_1,
+			   CS530X_SAMPLE_RATE_MASK, fs_val);
+
+
+	if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+			     CS530X_TDM_EN_MASK)) {
+		dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
+			cs530x->tdm_slots, cs530x->tdm_width);
+		bclk = snd_soc_tdm_params_to_bclk(params,
+						  cs530x->tdm_width,
+						  cs530x->tdm_slots,
+						  1);
+	} else {
+		bclk = snd_soc_params_to_bclk(params);
+	}
+
+	if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0,
+			     CS530X_PLL_REFCLK_SRC_MASK)) {
+		ret = cs530x_set_pll_refclk(component, bclk);
+		if (ret)
+			return ret;
+	}
+
+	return cs530x_set_bclk(component, bclk);
+}
+
+static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = priv->regmap;
+	unsigned int asp_fmt, asp_cfg = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		asp_cfg = CS530X_ASP_PRIMARY;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		asp_fmt = CS530X_ASP_FMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		asp_fmt = CS530X_ASP_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		asp_fmt = CS530X_ASP_FMT_LJ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		asp_cfg |= CS530X_ASP_BCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(regmap, CS530X_ASP_CFG,
+			   CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV,
+			   asp_cfg);
+
+	return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+				  CS530X_ASP_FMT_MASK, asp_fmt);
+}
+
+static bool cs530x_check_mclk_freq(struct snd_soc_component *component,
+				   const unsigned int freq)
+{
+	switch (freq) {
+	case 24576000:
+	case 22579200:
+	case 12288000:
+	case 11289600:
+		return true;
+	default:
+		dev_err(component->dev, "Invalid MCLK %d\n", freq);
+		return false;
+	}
+}
+
+static int cs530x_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;
+	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+	unsigned int val;
+
+	switch (tx_mask) {
+	case CS530X_0_1_TDM_SLOT_MASK:
+	case CS530X_0_3_TDM_SLOT_MASK:
+	case CS530X_0_7_TDM_SLOT_MASK:
+		val = CS530X_0_7_TDM_SLOT_VAL;
+		break;
+	case CS530X_2_3_TDM_SLOT_MASK:
+		val = CS530X_2_3_TDM_SLOT_VAL;
+		break;
+	case CS530X_4_5_TDM_SLOT_MASK:
+	case CS530X_4_7_TDM_SLOT_MASK:
+		val = CS530X_4_7_TDM_SLOT_VAL;
+		break;
+	case CS530X_6_7_TDM_SLOT_MASK:
+		val = CS530X_6_7_TDM_SLOT_VAL;
+		break;
+	case CS530X_8_9_TDM_SLOT_MASK:
+	case CS530X_8_11_TDM_SLOT_MASK:
+	case CS530X_8_15_TDM_SLOT_MASK:
+		val = CS530X_8_15_TDM_SLOT_VAL;
+		break;
+	case CS530X_10_11_TDM_SLOT_MASK:
+		val = CS530X_10_11_TDM_SLOT_VAL;
+		break;
+	case CS530X_12_13_TDM_SLOT_MASK:
+	case CS530X_12_15_TDM_SLOT_MASK:
+		val = CS530X_12_15_TDM_SLOT_VAL;
+		break;
+	case CS530X_14_15_TDM_SLOT_MASK:
+		val = CS530X_14_15_TDM_SLOT_VAL;
+		break;
+	default:
+		dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask);
+		return -EINVAL;
+	}
+
+	cs530x->tdm_width = slot_width;
+	cs530x->tdm_slots = slots;
+
+	return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+				  CS530X_ASP_TDM_SLOT_MASK,
+				  val << CS530X_ASP_TDM_SLOT_SHIFT);
+}
+
+static const struct snd_soc_dai_ops cs530x_dai_ops = {
+	.set_fmt = cs530x_set_fmt,
+	.hw_params = cs530x_hw_params,
+	.set_tdm_slot = cs530x_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_driver cs530x_dai = {
+	.name = "cs530x-dai",
+	.capture = {
+		.stream_name = "AIF Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.ops = &cs530x_dai_ops,
+	.symmetric_rate = 1,
+	.symmetric_sample_bits = 1,
+};
+
+static int cs530x_set_pll(struct snd_soc_component *component, int pll_id,
+			   int source, unsigned int freq_in,
+			   unsigned int freq_out)
+{
+	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+	unsigned int sysclk_src;
+	int ret;
+
+	regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src);
+
+	/* Check if the source is the PLL  */
+	if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0)
+		return 0;
+
+	switch (source) {
+	case CS530X_PLL_SRC_MCLK:
+		if (!cs530x_check_mclk_freq(component, freq_in))
+			return -EINVAL;
+
+		ret = cs530x_set_pll_refclk(component, freq_in);
+		if (ret)
+			return ret;
+
+		break;
+	case CS530X_PLL_SRC_BCLK:
+		break;
+	default:
+		dev_err(component->dev, "Invalid PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+				  CS530X_PLL_REFCLK_SRC_MASK, source);
+}
+
+static int cs530x_component_probe(struct snd_soc_component *component)
+{
+	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int num_widgets;
+
+	snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets,
+				  ARRAY_SIZE(cs530x_gen_dapm_widgets));
+
+	switch (cs530x->devtype) {
+	case CS5302:
+		cs530x_add_12_adc_widgets(component);
+		break;
+	case CS5304:
+		cs530x_add_12_adc_widgets(component);
+		cs530x_add_34_adc_widgets(component);
+
+		num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls);
+		snd_soc_add_component_controls(component,
+					       cs530x_in_sum_4ch_controls,
+					       num_widgets);
+		break;
+
+	case CS5308:
+		cs530x_add_12_adc_widgets(component);
+		cs530x_add_34_adc_widgets(component);
+
+		num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls);
+		snd_soc_add_component_controls(component,
+					       cs530x_in_5_to_8_controls,
+					       num_widgets);
+
+		num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls);
+		snd_soc_add_component_controls(component,
+					       cs530x_in_sum_8ch_controls,
+					       num_widgets);
+
+		num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets);
+		snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets,
+					  num_widgets);
+
+		snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes,
+					ARRAY_SIZE(adc_ch5_8_routes));
+		break;
+	default:
+		dev_err(component->dev, "Invalid device type %d\n",
+			cs530x->devtype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
+				int source, unsigned int freq, int dir)
+{
+	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = cs530x->regmap;
+
+	switch (source) {
+	case CS530X_SYSCLK_SRC_MCLK:
+		if (freq != 24560000 && freq != 22572000) {
+			dev_err(component->dev, "Invalid MCLK source rate %d\n",
+				freq);
+			return -EINVAL;
+		}
+
+		cs530x->mclk_rate = freq;
+		break;
+	case CS530X_SYSCLK_SRC_PLL:
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+				  CS530X_SYSCLK_SRC_MASK,
+				  source << CS530X_SYSCLK_SRC_SHIFT);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs530x = {
+	.probe			= cs530x_component_probe,
+	.set_sysclk		= cs530x_set_sysclk,
+	.set_pll		= cs530x_set_pll,
+	.endianness		= 1,
+};
+
+const struct regmap_config cs530x_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = CS530X_MAX_REGISTER,
+	.readable_reg = cs530x_readable_register,
+	.writeable_reg = cs530x_writeable_register,
+
+	.cache_type = REGCACHE_MAPLE,
+	.reg_defaults = cs530x_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
+};
+EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X);
+
+static int cs530x_check_device_id(struct cs530x_priv *cs530x)
+{
+	struct device *dev = cs530x->dev;
+	unsigned int dev_id, rev;
+	int ret;
+
+	ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id);
+	if (ret)
+		return dev_err_probe(dev, ret, "Can't read device ID\n");
+
+	ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Can't read REV ID\n");
+
+	dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev);
+
+	switch (dev_id) {
+	case CS530X_2CH_ADC_DEV_ID:
+		cs530x->num_adcs = 2;
+		break;
+	case CS530X_4CH_ADC_DEV_ID:
+		cs530x->num_adcs = 4;
+		break;
+	case CS530X_8CH_ADC_DEV_ID:
+		cs530x->num_adcs = 8;
+		break;
+	default:
+		return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n",
+				     dev_id);
+	}
+
+	return 0;
+}
+
+static int cs530x_parse_device_properties(struct cs530x_priv *cs530x)
+{
+	struct regmap *regmap = cs530x->regmap;
+	struct device *dev = cs530x->dev;
+	unsigned int val = 0;
+
+	switch (cs530x->num_adcs) {
+	case 8:
+		if (device_property_read_bool(dev, "cirrus,in-hiz-pin78"))
+			val = CS530X_IN78_HIZ;
+
+		if (device_property_read_bool(dev, "cirrus,in-hiz-pin56"))
+			val |= CS530X_IN56_HIZ;
+
+		fallthrough;
+	case 4:
+		if (device_property_read_bool(dev, "cirrus,in-hiz-pin34"))
+			val |= CS530X_IN34_HIZ;
+
+		fallthrough;
+	case 2:
+		if (device_property_read_bool(dev, "cirrus,in-hiz-pin12"))
+			val |= CS530X_IN12_HIZ;
+
+		return regmap_set_bits(regmap, CS530X_IN_HIZ, val);
+	default:
+		return dev_err_probe(dev, -EINVAL,
+				     "Invalid number of adcs %d\n",
+				     cs530x->num_adcs);
+	}
+}
+
+int cs530x_probe(struct cs530x_priv *cs530x)
+{
+	struct device *dev = cs530x->dev;
+	int ret, i;
+
+	cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai,
+					sizeof(*(cs530x->dev_dai)),
+					GFP_KERNEL);
+	if (!cs530x->dev_dai)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++)
+		cs530x->supplies[i].supply = cs530x_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies),
+				      cs530x->supplies);
+	if (ret != 0)
+		return dev_err_probe(dev, ret, "Failed to request supplies");
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies),
+				    cs530x->supplies);
+	if (ret != 0)
+		return dev_err_probe(dev, ret, "Failed to enable supplies");
+
+	cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						      GPIOD_OUT_HIGH);
+	if (IS_ERR(cs530x->reset_gpio)) {
+		ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio),
+			      "Reset gpio not available\n");
+		goto err_regulator;
+	}
+
+	if (cs530x->reset_gpio) {
+		usleep_range(2000, 2100);
+		gpiod_set_value_cansleep(cs530x->reset_gpio, 0);
+	}
+
+	usleep_range(5000, 5100);
+	ret = cs530x_check_device_id(cs530x);
+	if (ret)
+		goto err_reset;
+
+	if (!cs530x->reset_gpio) {
+		ret = regmap_write(cs530x->regmap, CS530X_SW_RESET,
+				   CS530X_SW_RST_VAL);
+		if (ret) {
+			dev_err_probe(dev, ret, "Soft Reset Failed\n");
+			goto err_reset;
+		}
+	}
+
+	ret = cs530x_parse_device_properties(cs530x);
+	if (ret)
+		goto err_reset;
+
+	cs530x->dev_dai->capture.channels_max = cs530x->num_adcs;
+
+	ret = devm_snd_soc_register_component(dev,
+			&soc_component_dev_cs530x, cs530x->dev_dai, 1);
+	if (ret) {
+		dev_err_probe(dev, ret, "Can't register cs530x component\n");
+		goto err_reset;
+	}
+
+	return 0;
+
+err_reset:
+	gpiod_set_value_cansleep(cs530x->reset_gpio, 1);
+
+err_regulator:
+	regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies),
+			       cs530x->supplies);
+
+	return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X);
+
+MODULE_DESCRIPTION("CS530X CODEC Driver");
+MODULE_AUTHOR("Paul Handrigan <paulha@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h
new file mode 100644
index 0000000000000000000000000000000000000000..f473e33eb835960ecc4e448a8aca6c27cc51e72f
--- /dev/null
+++ b/sound/soc/codecs/cs530x.h
@@ -0,0 +1,223 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS530x CODEC driver internal data
+ *
+ * Copyright (C) 2023-2024 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef _CS530X_H
+#define _CS530X_H
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+/* Devices */
+#define CS530X_2CH_ADC_DEV_ID		 0x5302
+#define CS530X_4CH_ADC_DEV_ID		 0x5304
+#define CS530X_8CH_ADC_DEV_ID		 0x5308
+
+/* Registers */
+
+#define CS530X_DEVID			0x0000000
+#define CS530X_REVID			0x0000004
+#define CS530X_SW_RESET			0x0000022
+
+#define CS530X_CLK_CFG_0		0x0000040
+#define CS530X_CLK_CFG_1		0x0000042
+#define CS530X_CHIP_ENABLE		0x0000044
+#define CS530X_ASP_CFG			0x0000048
+#define CS530X_SIGNAL_PATH_CFG		0x0000050
+#define CS530X_IN_ENABLES		0x0000080
+#define CS530X_IN_RAMP_SUM		0x0000082
+#define CS530X_IN_FILTER		0x0000086
+#define CS530X_IN_HIZ			0x0000088
+#define CS530X_IN_INV			0x000008A
+#define CS530X_IN_VOL_CTRL1_0	        0x0000090
+#define CS530X_IN_VOL_CTRL1_1	        0x0000092
+#define CS530X_IN_VOL_CTRL2_0	        0x0000094
+#define CS530X_IN_VOL_CTRL2_1	        0x0000096
+#define CS530X_IN_VOL_CTRL3_0	        0x0000098
+#define CS530X_IN_VOL_CTRL3_1	        0x000009A
+#define CS530X_IN_VOL_CTRL4_0	        0x000009C
+#define CS530X_IN_VOL_CTRL4_1	        0x000009E
+#define CS530X_IN_VOL_CTRL5		0x00000A0
+
+#define CS530X_PAD_FN			0x0003D24
+#define CS530X_PAD_LVL			0x0003D28
+
+#define CS530X_MAX_REGISTER		CS530X_PAD_LVL
+
+/* Register Fields */
+
+/* REVID */
+#define CS530X_MTLREVID			GENMASK(3, 0)
+#define CS530X_AREVID			GENMASK(7, 4)
+
+/* SW_RESET */
+#define CS530X_SW_RST_SHIFT		8
+#define CS530X_SW_RST_VAL		(0x5A << CS530X_SW_RST_SHIFT)
+
+/* CLK_CFG_0 */
+#define CS530X_PLL_REFCLK_SRC_MASK	BIT(0)
+#define CS530X_PLL_REFCLK_FREQ_MASK	GENMASK(5, 4)
+#define CS530X_SYSCLK_SRC_MASK		BIT(12)
+#define CS530X_SYSCLK_SRC_SHIFT		12
+#define CS530X_REFCLK_2P822_3P072	0
+#define CS530X_REFCLK_5P6448_6P144	0x10
+#define CS530X_REFCLK_11P2896_12P288	0x20
+#define CS530X_REFCLK_24P5792_24P576	0x30
+
+/* CLK_CFG_1 */
+#define CS530X_SAMPLE_RATE_MASK		GENMASK(2, 0)
+#define CS530X_FS_32K			0
+#define CS530X_FS_48K_44P1K		1
+#define CS530X_FS_96K_88P2K		2
+#define CS530X_FS_192K_176P4K		3
+#define CS530X_FS_384K_356P8K		4
+#define CS530X_FS_768K_705P6K		5
+
+/* CHIP_ENABLE */
+#define CS530X_GLOBAL_EN		BIT(0)
+
+/* ASP_CFG */
+#define CS530X_ASP_BCLK_FREQ_MASK	GENMASK(1, 0)
+#define CS530X_ASP_PRIMARY		BIT(5)
+#define CS530X_ASP_BCLK_INV		BIT(6)
+#define CS530X_BCLK_2P822_3P072		0
+#define CS530X_BCLK_5P6448_6P144	1
+#define CS530X_BCLK_11P2896_12P288	2
+#define CS530X_BCLK_24P5792_24P576	3
+
+/* SIGNAL_PATH_CFG */
+#define CS530X_ASP_FMT_MASK		GENMASK(2, 0)
+#define CS530X_ASP_TDM_SLOT_MASK	GENMASK(5, 3)
+#define CS530X_ASP_TDM_SLOT_SHIFT	3
+#define CS530X_ASP_CH_REVERSE		BIT(9)
+#define CS530X_TDM_EN_MASK		BIT(2)
+#define CS530X_ASP_FMT_I2S		0
+#define CS530X_ASP_FMT_LJ		1
+#define CS530X_ASP_FMT_DSP_A		0x6
+
+/* TDM Slots */
+#define CS530X_0_1_TDM_SLOT_MASK	GENMASK(1, 0)
+#define CS530X_0_3_TDM_SLOT_MASK	GENMASK(3, 0)
+#define CS530X_0_7_TDM_SLOT_MASK	GENMASK(7, 0)
+#define CS530X_0_7_TDM_SLOT_VAL		0
+
+#define CS530X_2_3_TDM_SLOT_MASK	GENMASK(3, 2)
+#define CS530X_2_3_TDM_SLOT_VAL		1
+
+#define CS530X_4_5_TDM_SLOT_MASK	GENMASK(5, 4)
+#define CS530X_4_7_TDM_SLOT_MASK	GENMASK(7, 4)
+#define CS530X_4_7_TDM_SLOT_VAL		2
+
+#define CS530X_6_7_TDM_SLOT_MASK	GENMASK(7, 6)
+#define CS530X_6_7_TDM_SLOT_VAL		3
+
+#define CS530X_8_9_TDM_SLOT_MASK	GENMASK(9, 8)
+#define CS530X_8_11_TDM_SLOT_MASK	GENMASK(11, 8)
+#define CS530X_8_15_TDM_SLOT_MASK	GENMASK(15, 8)
+#define CS530X_8_15_TDM_SLOT_VAL	4
+
+#define CS530X_10_11_TDM_SLOT_MASK	GENMASK(11, 10)
+#define CS530X_10_11_TDM_SLOT_VAL	5
+
+#define CS530X_12_13_TDM_SLOT_MASK	GENMASK(13, 12)
+#define CS530X_12_15_TDM_SLOT_MASK	GENMASK(15, 12)
+#define CS530X_12_15_TDM_SLOT_VAL	6
+
+#define CS530X_14_15_TDM_SLOT_MASK	GENMASK(15, 14)
+#define CS530X_14_15_TDM_SLOT_VAL	7
+
+/* IN_RAMP_SUM */
+#define CS530X_RAMP_RATE_INC_SHIFT	0
+#define CS530X_RAMP_RATE_DEC_SHIFT	4
+#define CS530X_IN_SUM_MODE_SHIFT	13
+
+/* IN_FILTER */
+#define CS530X_IN_FILTER_SHIFT		8
+#define CS530X_IN_HPF_EN_SHIFT		12
+
+/* IN_HIZ */
+#define CS530X_IN12_HIZ			BIT(0)
+#define CS530X_IN34_HIZ			BIT(1)
+#define CS530X_IN56_HIZ			BIT(2)
+#define CS530X_IN78_HIZ			BIT(3)
+
+/* IN_INV */
+#define CS530X_IN1_INV_SHIFT		0
+#define CS530X_IN2_INV_SHIFT		1
+#define CS530X_IN3_INV_SHIFT		2
+#define CS530X_IN4_INV_SHIFT		3
+#define CS530X_IN5_INV_SHIFT		4
+#define CS530X_IN6_INV_SHIFT		5
+#define CS530X_IN7_INV_SHIFT		6
+#define CS530X_IN8_INV_SHIFT		7
+
+/* IN_VOL_CTLy_z */
+#define CS530X_IN_MUTE			BIT(15)
+
+/* IN_VOL_CTL5 */
+#define CS530X_IN_VU			BIT(0)
+
+/* PAD_FN */
+#define CS530X_DOUT2_FN			BIT(0)
+#define CS530X_DOUT3_FN			BIT(1)
+#define CS530X_DOUT4_FN			BIT(2)
+#define CS530X_SPI_CS_FN		BIT(3)
+#define CS530X_CONFIG2_FN		BIT(6)
+#define CS530X_CONFIG3_FN		BIT(7)
+#define CS530X_CONFIG4_FN		BIT(8)
+#define CS530X_CONFIG5_FN		BIT(9)
+
+/* PAD_LVL */
+#define CS530X_CONFIG2_LVL		BIT(6)
+#define CS530X_CONFIG3_LVL		BIT(7)
+#define CS530X_CONFIG4_LVL		BIT(8)
+#define CS530X_CONFIG5_LVL		BIT(9)
+
+/* System Clock Source */
+#define CS530X_SYSCLK_SRC_MCLK		0
+#define CS530X_SYSCLK_SRC_PLL		1
+
+/* PLL Reference Clock Source */
+#define CS530X_PLL_SRC_BCLK		0
+#define CS530X_PLL_SRC_MCLK		1
+
+#define CS530X_NUM_SUPPLIES		2
+
+enum cs530x_type {
+	CS5302,
+	CS5304,
+	CS5308,
+};
+
+/* codec private data */
+struct cs530x_priv {
+	struct regmap *regmap;
+	struct device *dev;
+	struct snd_soc_dai_driver *dev_dai;
+
+	enum cs530x_type devtype;
+	int num_adcs;
+	int num_dacs;
+
+	struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES];
+
+	unsigned int mclk_rate;
+
+	int tdm_width;
+	int tdm_slots;
+	int fs;
+	int adc_pairs_count;
+
+	struct gpio_desc *reset_gpio;
+};
+
+extern const struct regmap_config cs530x_regmap;
+int cs530x_probe(struct cs530x_priv *cs530x);
+
+#endif
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index c0893146423b2a4e44f0b5efeeb7a8620367abf3..bcbaf28a0b2d98d1d3156e238ef74082a0296eb0 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <sound/pcm_params.h>
@@ -901,7 +900,7 @@ static const struct snd_soc_component_driver cs53l30_driver = {
 	.endianness		= 1,
 };
 
-static struct regmap_config cs53l30_regmap = {
+static const struct regmap_config cs53l30_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index e8e22b1a1963b2f9e22130f4d5a5918e74f4ce36..8cfec8dcf83966d1ad18aef3f6ebdb7ecc699b7e 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -63,11 +63,6 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7400, 100, 0);
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -7400, 100, 0);
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 1200, 0);
 
-struct cx2072x_eq_ctrl {
-	u8 ch;
-	u8 band;
-};
-
 static const DECLARE_TLV_DB_RANGE(hpf_tlv,
 	0, 0, TLV_DB_SCALE_ITEM(120, 0, 0),
 	1, 63, TLV_DB_SCALE_ITEM(30, 30, 0)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index a2b328f3b39fa2a4e510930a7f488bd386dbb835..f3ef6fb5530471f3ade1e2f8b6e56ea99413504a 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1720,7 +1720,7 @@ static int da7213_set_component_pll(struct snd_soc_component *component,
  *	SND_SOC_DAIFMT_CBC_CFC
  *	SND_SOC_DAIFMT_CBP_CFP
  */
-static u64 da7213_dai_formats =
+static const u64 da7213_dai_formats =
 	SND_SOC_POSSIBLE_DAIFMT_I2S	|
 	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
 	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c
new file mode 100644
index 0000000000000000000000000000000000000000..f557e33c26ad9ea42a731d1bae777fbe910e94f8
--- /dev/null
+++ b/sound/soc/codecs/es8311.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * es8311.c -- es8311 ALSA SoC audio driver
+ *
+ * Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
+ *
+ * Author: Matteo Martelli <matteomartelli3@gmail.com>
+ */
+
+#include "linux/array_size.h"
+#include "sound/pcm.h"
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "es8311.h"
+
+#define ES8311_NUM_RATES 10
+#define ES8311_RATES (SNDRV_PCM_RATE_8000_96000)
+#define ES8311_FORMATS                                         \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |  \
+	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct es8311_priv {
+	struct regmap *regmap;
+	struct clk *mclk;
+	unsigned long mclk_freq;
+	bool provider;
+	unsigned int rates[ES8311_NUM_RATES];
+	struct snd_pcm_hw_constraint_list constraints;
+};
+
+static const DECLARE_TLV_DB_SCALE(es8311_adc_vol_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(es8311_pga_gain_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(es8311_adc_scale_tlv, 0, 600, 0);
+
+#define ES8311_DB_LRCK_STEPS \
+	"0.25db/4LRCK", \
+	"0.25db/8LRCK", \
+	"0.25db/16LRCK", \
+	"0.25db/32LRCK", \
+	"0.25db/64LRCK", \
+	"0.25db/128LRCK", \
+	"0.25db/256LRCK", \
+	"0.25db/512LRCK", \
+	"0.25db/1024LRCK", \
+	"0.25db/2048LRCK", \
+	"0.25db/4096LRCK", \
+	"0.25db/8192LRCK", \
+	"0.25db/16384LRCK", \
+	"0.25db/32768LRCK", \
+	"0.25db/65536LRCK",
+
+static const char *const es8311_level_winsize_txt[] = {
+	"0.25db/2LRCK",
+	ES8311_DB_LRCK_STEPS
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	es8311_alc_winsize, ES8311_ADC4,
+	ES8311_ADC4_ALC_WINSIZE_SHIFT, es8311_level_winsize_txt);
+static const DECLARE_TLV_DB_RANGE(es8311_level_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-3010, 600, 0),
+	2, 3, TLV_DB_SCALE_ITEM(-2060, 250, 0),
+	4, 5, TLV_DB_SCALE_ITEM(-1610, 160, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-1320, 120, 0),
+	8, 9, TLV_DB_SCALE_ITEM(-1100, 90, 0),
+	10, 11, TLV_DB_SCALE_ITEM(-930, 80, 0),
+	12, 15, TLV_DB_SCALE_ITEM(-780, 60, 0),
+);
+
+static const char *const es8311_ramprate_txt[] = {
+	"Disabled",
+	ES8311_DB_LRCK_STEPS
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_adc_ramprate, ES8311_ADC1,
+	ES8311_ADC1_RAMPRATE_SHIFT, es8311_ramprate_txt);
+
+static const char *const es8311_automute_winsize_txt[] = {
+	"2048 samples",
+	"4096 samples",
+	"6144 samples",
+	"8192 samples",
+	"10240 samples",
+	"12288 samples",
+	"14336 samples",
+	"16384 samples",
+	"18432 samples",
+	"20480 samples",
+	"22528 samples",
+	"24576 samples",
+	"26624 samples",
+	"28672 samples",
+	"30720 samples",
+	"32768 samples",
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_automute_winsize, ES8311_ADC6,
+	ES8311_ADC6_AUTOMUTE_WS_SHIFT, es8311_automute_winsize_txt);
+static const DECLARE_TLV_DB_RANGE(es8311_automute_ng_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-9600, 600, 0),
+	8, 15, TLV_DB_SCALE_ITEM(-5100, 300, 0),
+);
+static const DECLARE_TLV_DB_SCALE(es8311_automute_vol_tlv, -2800, 400, 0);
+
+static const DECLARE_TLV_DB_SCALE(es8311_dac_vol_tlv, -9550, 50, 0);
+static SOC_ENUM_SINGLE_DECL(
+	es8311_drc_winsize, ES8311_DAC4,
+	ES8311_DAC4_DRC_WINSIZE_SHIFT, es8311_level_winsize_txt);
+static SOC_ENUM_SINGLE_DECL(
+	es8311_dac_ramprate, ES8311_DAC6,
+	ES8311_DAC6_RAMPRATE_SHIFT, es8311_ramprate_txt);
+
+static const char *const es8311_out_mode_txt[] = {
+	"Lineout",
+	"Headphones"
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_out_mode, ES8311_SYS9,
+	ES8311_SYS9_HPSW_SHIFT, es8311_out_mode_txt);
+
+static const struct snd_kcontrol_new es8311_snd_controls[] = {
+	/* Capture path */
+	SOC_SINGLE_TLV("PGA Capture Volume", ES8311_SYS10,
+		       ES8311_SYS10_PGAGAIN_SHIFT, ES8311_SYS10_PGAGAIN_MAX, 0,
+		       es8311_pga_gain_tlv),
+	SOC_SINGLE("ADC Polarity Invert Capture Switch", ES8311_ADC2,
+		   ES8311_ADC2_INV_SHIFT, 1, 0),
+	SOC_SINGLE_TLV("ADC Scale Capture Volume", ES8311_ADC2,
+		       ES8311_ADC2_SCALE_SHIFT, ES8311_ADC2_SCALE_MAX, 0,
+		       es8311_adc_scale_tlv),
+	SOC_SINGLE_TLV("ADC Capture Volume", ES8311_ADC3,
+		       ES8311_ADC3_VOLUME_SHIFT, ES8311_ADC3_VOLUME_MAX, 0,
+		       es8311_adc_vol_tlv),
+	SOC_ENUM("ADC Capture Ramp Rate", es8311_adc_ramprate),
+	SOC_SINGLE("ADC Automute Capture Switch", ES8311_ADC4,
+		   ES8311_ADC4_AUTOMUTE_EN_SHIFT, 1, 0),
+	SOC_ENUM("ADC Automute Capture Winsize", es8311_automute_winsize),
+	SOC_SINGLE_TLV("ADC Automute Noise Gate Capture Volume", ES8311_ADC6,
+		       ES8311_ADC6_AUTOMUTE_NG_SHIFT,
+		       ES8311_ADC6_AUTOMUTE_NG_MAX, 0, es8311_automute_ng_tlv),
+	SOC_SINGLE_TLV("ADC Automute Capture Volume", ES8311_ADC7,
+		       ES8311_ADC7_AUTOMUTE_VOL_SHIFT,
+		       ES8311_ADC7_AUTOMUTE_VOL_MAX, 0,
+		       es8311_automute_vol_tlv),
+	SOC_SINGLE("ADC HPF Capture Switch", ES8311_ADC8, ES8311_ADC8_HPF_SHIFT,
+		   1, 0),
+	SOC_SINGLE("ADC EQ Capture Switch", ES8311_ADC8,
+		   ES8311_ADC8_EQBYPASS_SHIFT, 1, 1),
+	SOC_SINGLE("ALC Capture Switch", ES8311_ADC4, ES8311_ADC4_ALC_EN_SHIFT,
+		   1, 0),
+	SOC_SINGLE_TLV("ALC Capture Max Volume", ES8311_ADC5,
+		       ES8311_ADC5_ALC_MAXLEVEL_SHIFT,
+		       ES8311_ADC5_ALC_MAXLEVEL_MAX, 0, es8311_level_tlv),
+	SOC_SINGLE_TLV("ALC Capture Min Volume", ES8311_ADC5,
+		       ES8311_ADC5_ALC_MINLEVEL_SHIFT,
+		       ES8311_ADC5_ALC_MINLEVEL_MAX, 0, es8311_level_tlv),
+	SOC_ENUM("ALC Capture Winsize", es8311_alc_winsize),
+
+	/* Playback path */
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8311_DAC2, 0,
+		       ES8311_DAC2_VOLUME_MAX, 0, es8311_dac_vol_tlv),
+	SOC_SINGLE("DRC Playback Switch", ES8311_DAC4, ES8311_DAC4_DRC_EN_SHIFT,
+		   1, 0),
+	SOC_SINGLE_TLV("DRC Playback Max Volume", ES8311_DAC5,
+		       ES8311_DAC5_DRC_MAXLEVEL_SHIFT,
+		       ES8311_DAC5_DRC_MAXLEVEL_MAX, 0, es8311_level_tlv),
+	SOC_SINGLE_TLV("DRC Playback Min Volume", ES8311_DAC5,
+		       ES8311_DAC5_DRC_MINLEVEL_SHIFT,
+		       ES8311_DAC5_DRC_MINLEVEL_MAX, 0, es8311_level_tlv),
+	SOC_ENUM("DRC Playback Winsize", es8311_drc_winsize),
+	SOC_ENUM("DAC Playback Ramp Rate", es8311_dac_ramprate),
+	SOC_SINGLE("DAC EQ Playback Switch", ES8311_DAC6,
+		   ES8311_DAC6_EQBYPASS_SHIFT, 1, 1),
+
+	SOC_ENUM("Output Mode", es8311_out_mode),
+};
+
+static const char *const es8311_diff_src_txt[] = {
+	"Disabled",
+	"MIC1P-MIC1N",
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_diff_src_enum, ES8311_SYS10,
+	ES8311_SYS10_LINESEL_SHIFT, es8311_diff_src_txt);
+static const struct snd_kcontrol_new es8311_diff_src_mux =
+	SOC_DAPM_ENUM("Differential Source", es8311_diff_src_enum);
+
+static const char *const es8311_dmic_src_txt[] = {
+	"Disabled",
+	"DMIC from MIC1P",
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_dmic_src_enum, ES8311_SYS10,
+	ES8311_SYS10_DMIC_ON_SHIFT, es8311_dmic_src_txt);
+static const struct snd_kcontrol_new es8311_dmic_src_mux =
+	SOC_DAPM_ENUM("Digital Mic Source", es8311_dmic_src_enum);
+
+static const char * const es8311_aif1tx_src_txt[] = {
+	"ADC + ADC",
+	"ADC + 0",
+	"0 + ADC",
+	"0 + 0",
+	"DACL + ADC",
+	"ADC + DACR",
+	"DACL + DACR",
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_aif1tx_src_enum, ES8311_GPIO,
+	ES8311_GPIO_ADCDAT_SEL_SHIFT, es8311_aif1tx_src_txt);
+static const struct snd_kcontrol_new es8311_aif1tx_src_mux =
+	SOC_DAPM_ENUM("AIF1TX Source", es8311_aif1tx_src_enum);
+
+static const char * const es8311_dac_src_txt[] = {
+	"Left",
+	"Right"
+};
+static SOC_ENUM_SINGLE_DECL(
+	es8311_dac_src_enum, ES8311_SDP_IN,
+	ES8311_SDP_IN_SEL_SHIFT, es8311_dac_src_txt);
+static const struct snd_kcontrol_new es8311_dac_src_mux =
+	SOC_DAPM_ENUM("Mono DAC Source", es8311_dac_src_enum);
+
+static const struct snd_soc_dapm_widget es8311_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Bias", ES8311_SYS3, ES8311_SYS3_PDN_IBIASGEN_SHIFT,
+			    1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Analog power", ES8311_SYS3,
+			    ES8311_SYS3_PDN_ANA_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref", ES8311_SYS3, ES8311_SYS3_PDN_VREF_SHIFT, 1,
+			    NULL, 0),
+
+	/* Capture path */
+	SND_SOC_DAPM_INPUT("DMIC"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+			 &es8311_diff_src_mux),
+	SND_SOC_DAPM_SUPPLY("ADC Bias Gen", ES8311_SYS3,
+			    ES8311_SYS3_PDN_ADCBIASGEN_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Vref Gen", ES8311_SYS3,
+			    ES8311_SYS3_PDN_ADCVREFGEN_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Clock", ES8311_CLKMGR1,
+			    ES8311_CLKMGR1_CLKADC_ON_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Analog Clock", ES8311_CLKMGR1,
+			    ES8311_CLKMGR1_ANACLKADC_ON_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA", ES8311_SYS4, ES8311_SYS4_PDN_PGA_SHIFT, 1, NULL,
+			 0),
+	SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8311_SYS4,
+			 ES8311_SYS4_PDN_MOD_SHIFT, 1),
+	SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
+			 &es8311_dmic_src_mux),
+	SND_SOC_DAPM_MUX("AIF1TX Source Mux", SND_SOC_NOPM, 0, 0,
+			 &es8311_aif1tx_src_mux),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, ES8311_SDP_OUT,
+			     ES8311_SDP_MUTE_SHIFT, 1),
+
+	/* Playback path */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, ES8311_SDP_IN,
+			    ES8311_SDP_MUTE_SHIFT, 1),
+	SND_SOC_DAPM_MUX("Mono DAC Source Mux", SND_SOC_NOPM, 0, 0,
+			 &es8311_dac_src_mux),
+	SND_SOC_DAPM_DAC("Mono DAC", NULL, ES8311_SYS8,
+			 ES8311_SYS8_PDN_DAC_SHIFT, 1),
+	SND_SOC_DAPM_SUPPLY("DAC Clock", ES8311_CLKMGR1,
+			    ES8311_CLKMGR1_CLKDAC_ON_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Analog Clock", ES8311_CLKMGR1,
+			    ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref Gen", ES8311_SYS3,
+			    ES8311_SYS3_PDN_DACVREFGEN_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route es8311_dapm_routes[] = {
+	/* Capture Path */
+	{ "MIC1", NULL, "Bias" },
+	{ "MIC1", NULL, "Analog power" },
+	{ "MIC1", NULL, "Vref" },
+	{ "Differential Mux", "MIC1P-MIC1N", "MIC1" },
+	{ "PGA", NULL, "Differential Mux" },
+	{ "Mono ADC", NULL, "PGA" },
+	{ "Mono ADC", NULL, "ADC Bias Gen" },
+	{ "Mono ADC", NULL, "ADC Vref Gen" },
+	{ "Mono ADC", NULL, "ADC Clock" },
+	{ "Mono ADC", NULL, "ADC Analog Clock" },
+	{ "Digital Mic Mux", "Disabled", "Mono ADC" },
+	{ "Digital Mic Mux", "DMIC from MIC1P", "DMIC" },
+
+	{ "AIF1TX Source Mux", "ADC + ADC", "Digital Mic Mux" },
+	{ "AIF1TX Source Mux", "ADC + 0", "Digital Mic Mux" },
+	{ "AIF1TX Source Mux", "0 + ADC", "Digital Mic Mux" },
+	{ "AIF1TX Source Mux", "DACL + ADC", "Digital Mic Mux" },
+	{ "AIF1TX Source Mux", "ADC + DACR", "Digital Mic Mux" },
+
+	{ "AIF1TX", NULL, "AIF1TX Source Mux" },
+
+	/* Playback Path */
+	{ "Mono DAC Source Mux", "Left", "AIF1RX" },
+	{ "Mono DAC Source Mux", "Right", "AIF1RX" },
+	{ "Mono DAC", NULL, "Mono DAC Source Mux" },
+	{ "Mono DAC", NULL, "DAC Clock" },
+	{ "Mono DAC", NULL, "DAC Analog Clock" },
+	{ "OUT", NULL, "Mono DAC" },
+	{ "OUT", NULL, "Bias" },
+	{ "OUT", NULL, "Analog power" },
+	{ "OUT", NULL, "Vref" },
+	{ "OUT", NULL, "DAC Vref Gen" },
+};
+
+/* Bit clock divider values:
+ * from 1 to 20: the register takes the div value - 1
+ * above 20: the register takes the corresponding idx of the div value
+ *           in the following table + 20
+ */
+#define ES8311_BCLK_DIV_IDX_OFFSET 20
+static const unsigned int es8311_bclk_divs[] = {
+	22, 24, 25, 30, 32, 33, 34, 36, 44, 48, 66, 72
+};
+
+struct es8311_mclk_coeff {
+	unsigned int rate;
+	unsigned int mclk;
+	unsigned int div;
+	unsigned int mult;
+	unsigned int div_adc_dac;
+};
+
+#define ES8311_MCLK_MAX_FREQ 49200000
+
+/* Coefficients for common master clock frequencies based on clock table from
+ * documentation. Limited to have a ratio of adc (or dac) clock to lrclk equal
+ * to 256. This to keep the default adc and dac oversampling and adc scale
+ * settings. Internal mclk dividers and multipliers are dynamically adjusted to
+ * support, respectively, multiples (up to x8) and factors (/2,4,8) of listed
+ * mclks frequencies (see es8311_cmp_adj_mclk_coeff).
+ * All rates are supported when mclk/rate ratio is 32, 64, 128, 256, 384 or 512
+ * (upper limit due to max mclk freq of 49.2MHz).
+ */
+static const struct es8311_mclk_coeff es8311_mclk_coeffs[] = {
+	{ 8000, 2048000, 1, 1, 1 },
+	{ 8000, 6144000, 3, 1, 1 },
+	{ 8000, 18432000, 3, 1, 3 },
+	{ 11025, 2822400, 1, 1, 1 },
+	{ 11025, 8467200, 3, 1, 1 },
+	{ 16000, 4096000, 1, 1, 1 },
+	{ 16000, 12288000, 3, 1, 1 },
+	{ 16000, 18432000, 3, 2, 3 },
+	{ 22050, 5644800, 1, 1, 1 },
+	{ 22050, 16934400, 3, 1, 1 },
+	{ 32000, 8192000, 1, 1, 1 },
+	{ 32000, 12288000, 3, 2, 1 },
+	{ 32000, 18432000, 3, 4, 3 },
+	{ 44100, 11289600, 1, 1, 1 },
+	{ 44100, 33868800, 3, 1, 1 },
+	{ 48000, 12288000, 1, 1, 1 },
+	{ 48000, 18432000, 3, 2, 1 },
+	{ 64000, 8192000, 1, 2, 1 },
+	{ 64000, 12288000, 3, 4, 1 },
+	{ 88200, 11289600, 1, 2, 1 },
+	{ 88200, 33868800, 3, 2, 1 },
+	{ 96000, 12288000, 1, 2, 1 },
+	{ 96000, 18432000, 3, 4, 1 },
+};
+
+/* Compare coeff with provided mclk_freq and adjust it if needed.
+ * If frequencies match, return 0 and the unaltered coeff copy into out_coeff.
+ * If mclk_freq is a valid multiple or factor of coeff mclk freq, return 0 and
+ * the adjusted coeff copy into out_coeff.
+ * Return -EINVAL otherwise.
+ */
+static int es8311_cmp_adj_mclk_coeff(unsigned int mclk_freq,
+				     const struct es8311_mclk_coeff *coeff,
+				     struct es8311_mclk_coeff *out_coeff)
+{
+	if (WARN_ON_ONCE(!coeff))
+		return -EINVAL;
+
+	unsigned int div = coeff->div;
+	unsigned int mult = coeff->mult;
+	bool match = false;
+
+	if (coeff->mclk == mclk_freq) {
+		match = true;
+	} else if (mclk_freq % coeff->mclk == 0) {
+		div = mclk_freq / coeff->mclk;
+		div *= coeff->div;
+		if (div <= 8)
+			match = true;
+	} else if (coeff->mclk % mclk_freq == 0) {
+		mult = coeff->mclk / mclk_freq;
+		if (mult == 2 || mult == 4 || mult == 8) {
+			mult *= coeff->mult;
+			if (mult <= 8)
+				match = true;
+		}
+	}
+	if (!match)
+		return -EINVAL;
+	if (out_coeff) {
+		*out_coeff = *coeff;
+		out_coeff->div = div;
+		out_coeff->mult = mult;
+	}
+	return 0;
+}
+
+static int es8311_get_mclk_coeff(unsigned int mclk_freq, unsigned int rate,
+				 struct es8311_mclk_coeff *out_coeff)
+{
+	for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs); i++) {
+		const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i];
+
+		if (coeff->rate != rate)
+			continue;
+
+		int ret =
+			es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, out_coeff);
+		if (ret == 0)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static void es8311_set_sysclk_constraints(unsigned int mclk_freq,
+					  struct es8311_priv *es8311)
+{
+	unsigned int count = 0;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs) &&
+	     count < ARRAY_SIZE(es8311->rates); i++) {
+		const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i];
+
+		if (count > 0 && coeff->rate == es8311->rates[count - 1])
+			continue;
+
+		int ret = es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, NULL);
+		if (ret == 0)
+			es8311->rates[count++] = coeff->rate;
+	}
+	if (count) {
+		es8311->constraints.list = es8311->rates;
+		es8311->constraints.count = count;
+	}
+}
+
+static int es8311_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int mask = ES8311_DAC1_DAC_DSMMUTE |
+				    ES8311_DAC1_DAC_DEMMUTE;
+		unsigned int val = mute ? mask : 0;
+
+		regmap_update_bits(es8311->regmap, ES8311_DAC1, mask, val);
+	}
+
+	return 0;
+}
+
+static int es8311_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+	if (es8311->constraints.list) {
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_RATE,
+					   &es8311->constraints);
+	}
+
+	return 0;
+}
+
+static int es8311_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 es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+	unsigned int wl;
+	int par_width = params_width(params);
+
+	switch (par_width) {
+	case 16:
+		wl = ES8311_SDP_WL_16;
+		break;
+	case 18:
+		wl = ES8311_SDP_WL_18;
+		break;
+	case 20:
+		wl = ES8311_SDP_WL_20;
+		break;
+	case 24:
+		wl = ES8311_SDP_WL_24;
+		break;
+	case 32:
+		wl = ES8311_SDP_WL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	unsigned int width = (unsigned int)par_width;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		snd_soc_component_update_bits(component, ES8311_SDP_IN,
+					      ES8311_SDP_WL_MASK,
+					      wl << ES8311_SDP_WL_SHIFT);
+	} else {
+		snd_soc_component_update_bits(component, ES8311_SDP_OUT,
+					      ES8311_SDP_WL_MASK,
+					      wl << ES8311_SDP_WL_SHIFT);
+	}
+
+	if (es8311->mclk_freq > ES8311_MCLK_MAX_FREQ) {
+		dev_err(component->dev, "mclk frequency %lu too high\n",
+			es8311->mclk_freq);
+		return -EINVAL;
+	}
+
+	unsigned int mclk_freq = es8311->mclk_freq;
+	unsigned int rate = params_rate(params);
+	unsigned int clkmgr = ES8311_CLKMGR1_MCLK_ON;
+
+	if (!mclk_freq) {
+		if (es8311->provider) {
+			dev_err(component->dev,
+				"mclk not configured, cannot run as master\n");
+			return -EINVAL;
+		}
+		dev_dbg(component->dev,
+			"mclk not configured, use bclk as internal mclk\n");
+
+		clkmgr = ES8311_CLKMGR1_MCLK_SEL;
+
+		mclk_freq = rate * width * 2;
+	}
+
+	struct es8311_mclk_coeff coeff;
+	int ret = es8311_get_mclk_coeff(mclk_freq, rate, &coeff);
+	if (ret) {
+		dev_err(component->dev, "unable to find mclk coefficient\n");
+		return ret;
+	}
+
+	unsigned int mask = ES8311_CLKMGR1_MCLK_SEL | ES8311_CLKMGR1_MCLK_ON |
+			    ES8311_CLKMGR1_BCLK_ON;
+
+	clkmgr |= ES8311_CLKMGR1_BCLK_ON;
+	snd_soc_component_update_bits(component, ES8311_CLKMGR1, mask, clkmgr);
+
+	if (WARN_ON_ONCE(coeff.div == 0 || coeff.div > 8 ||
+			 coeff.div_adc_dac == 0 || coeff.div_adc_dac > 8))
+		return -EINVAL;
+
+	unsigned int mult;
+
+	switch (coeff.mult) {
+	case 1:
+		mult = 0;
+		break;
+	case 2:
+		mult = 1;
+		break;
+	case 4:
+		mult = 2;
+		break;
+	case 8:
+		mult = 3;
+		break;
+	default:
+		WARN_ON_ONCE(true);
+		return -EINVAL;
+	}
+
+	mask = ES8311_CLKMGR2_DIV_PRE_MASK | ES8311_CLKMGR2_MULT_PRE_MASK;
+	clkmgr = (coeff.div - 1) << ES8311_CLKMGR2_DIV_PRE_SHIFT |
+		 mult << ES8311_CLKMGR2_MULT_PRE_SHIFT;
+	snd_soc_component_update_bits(component, ES8311_CLKMGR2, mask, clkmgr);
+
+	mask = ES8311_CLKMGR5_ADC_DIV_MASK | ES8311_CLKMGR5_DAC_DIV_MASK;
+	clkmgr = (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_ADC_DIV_SHIFT |
+		 (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_DAC_DIV_SHIFT;
+	snd_soc_component_update_bits(component, ES8311_CLKMGR5, mask, clkmgr);
+
+	if (es8311->provider) {
+		unsigned int div_lrclk = mclk_freq / rate;
+
+		if (WARN_ON_ONCE(div_lrclk == 0 ||
+				 div_lrclk > ES8311_CLKMGR_LRCLK_DIV_MAX + 1))
+			return -EINVAL;
+
+		mask = ES8311_CLKMGR7_LRCLK_DIV_H_MASK;
+		clkmgr = (div_lrclk - 1) >> 8;
+		snd_soc_component_update_bits(component, ES8311_CLKMGR7, mask,
+					      clkmgr);
+		clkmgr = (div_lrclk - 1) & 0xFF;
+		snd_soc_component_write(component, ES8311_CLKMGR8, clkmgr);
+
+		if (div_lrclk % (2 * width) != 0) {
+			dev_err(component->dev,
+				"unable to divide mclk %u to generate bclk\n",
+				mclk_freq);
+			return -EINVAL;
+		}
+
+		unsigned int div_bclk = div_lrclk / (2 * width);
+
+		mask = ES8311_CLKMGR6_DIV_BCLK_MASK;
+		if (div_bclk <= ES8311_BCLK_DIV_IDX_OFFSET) {
+			clkmgr = div_bclk - 1;
+		} else {
+			unsigned int i;
+
+			for (i = 0; i < ARRAY_SIZE(es8311_bclk_divs); i++) {
+				if (es8311_bclk_divs[i] == div_bclk)
+					break;
+			}
+			if (i == ARRAY_SIZE(es8311_bclk_divs)) {
+				dev_err(component->dev,
+					"bclk divider %u not supported\n",
+					div_bclk);
+				return -EINVAL;
+			}
+
+			clkmgr = i + ES8311_BCLK_DIV_IDX_OFFSET;
+		}
+		snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask,
+					      clkmgr);
+	}
+
+	return 0;
+}
+
+static int es8311_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+			     unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+	if (freq > ES8311_MCLK_MAX_FREQ) {
+		dev_err(component->dev, "invalid frequency %u: too high\n",
+			freq);
+		return -EINVAL;
+	}
+
+	if (es8311->mclk_freq == freq)
+		return 0;
+
+	es8311->mclk_freq = freq;
+	es8311->constraints.list = NULL;
+	es8311->constraints.count = 0;
+
+	if (freq == 0)
+		return 0;
+
+	int ret = clk_set_rate(es8311->mclk, freq);
+	if (ret) {
+		dev_err(component->dev, "unable to set mclk rate\n");
+		return ret;
+	}
+
+	es8311_set_sysclk_constraints(freq, es8311);
+
+	return ret;
+}
+
+static int es8311_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_CBP_CFP:
+		/* Master mode */
+		es8311->provider = true;
+
+		snd_soc_component_update_bits(component, ES8311_RESET,
+					      ES8311_RESET_MSC,
+					      ES8311_RESET_MSC);
+		break;
+	case SND_SOC_DAIFMT_CBC_CFC:
+		/* Slave mode */
+		es8311->provider = false;
+		snd_soc_component_update_bits(component, ES8311_RESET,
+					      ES8311_RESET_MSC, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	unsigned int sdp = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		sdp |= ES8311_SDP_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		sdp |= ES8311_SDP_FMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dev_err(component->dev, "right justified mode not supported\n");
+		return -EINVAL;
+	case SND_SOC_DAIFMT_DSP_B:
+		sdp |= ES8311_SDP_LRP;
+		fallthrough;
+	case SND_SOC_DAIFMT_DSP_A:
+		sdp |= ES8311_SDP_FMT_DSP;
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		default:
+			dev_err(component->dev,
+				"inverted fsync not supported in dsp mode\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	unsigned int clkmgr = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		sdp |= ES8311_SDP_LRP;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		clkmgr |= ES8311_CLKMGR6_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		clkmgr |= ES8311_CLKMGR6_BCLK_INV;
+		sdp |= ES8311_SDP_LRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	unsigned int mask = ES8311_CLKMGR6_BCLK_INV;
+
+	snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask, clkmgr);
+
+	mask = ES8311_SDP_FMT_MASK | ES8311_SDP_LRP;
+	snd_soc_component_update_bits(component, ES8311_SDP_IN, mask, sdp);
+	snd_soc_component_update_bits(component, ES8311_SDP_OUT, mask, sdp);
+
+	return 0;
+}
+
+static int es8311_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct es8311_priv *es8311 = 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:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			int ret = clk_prepare_enable(es8311->mclk);
+			if (ret) {
+				dev_err(component->dev,
+					"unable to prepare mclk\n");
+				return ret;
+			}
+
+			snd_soc_component_update_bits(
+				component, ES8311_SYS3,
+				ES8311_SYS3_PDN_VMIDSEL_MASK,
+				ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
+		}
+
+		break;
+	case SND_SOC_BIAS_OFF:
+		clk_disable_unprepare(es8311->mclk);
+		snd_soc_component_update_bits(
+			component, ES8311_SYS3, ES8311_SYS3_PDN_VMIDSEL_MASK,
+			ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops es8311_dai_ops = {
+	.startup = es8311_startup,
+	.hw_params = es8311_hw_params,
+	.mute_stream = es8311_mute,
+	.set_sysclk = es8311_set_sysclk,
+	.set_fmt = es8311_set_dai_fmt,
+	.no_capture_mute = 1,
+};
+
+static struct snd_soc_dai_driver es8311_dai = {
+	.name = "es8311",
+	.playback = {
+		.stream_name = "AIF1 Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ES8311_RATES,
+		.formats = ES8311_FORMATS,
+	},
+	.capture = {
+		.stream_name = "AIF1 Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ES8311_RATES,
+		.formats = ES8311_FORMATS,
+	},
+	.ops = &es8311_dai_ops,
+	.symmetric_rate = 1,
+};
+
+static void es8311_reset(struct snd_soc_component *component, bool reset)
+{
+	/* Reset procedure:
+	 * (1) power down state machine and reset codec blocks then,
+	 * (2) after a short delay, power up state machine and leave reset mode.
+	 * Specific delay is not documented, using the same as es8316.
+	 */
+	unsigned int mask = ES8311_RESET_CSM_ON | ES8311_RESET_RST_MASK;
+
+	if (reset) {
+		/* Enter reset mode */
+		snd_soc_component_update_bits(component, ES8311_RESET, mask,
+					      ES8311_RESET_RST_MASK);
+	} else {
+		/* Leave reset mode */
+		usleep_range(5000, 5500);
+		snd_soc_component_update_bits(component, ES8311_RESET, mask,
+					      ES8311_RESET_CSM_ON);
+	}
+}
+
+static int es8311_suspend(struct snd_soc_component *component)
+{
+	struct es8311_priv *es8311;
+
+	es8311 = snd_soc_component_get_drvdata(component);
+
+	es8311_reset(component, true);
+
+	regcache_cache_only(es8311->regmap, true);
+	regcache_mark_dirty(es8311->regmap);
+
+	return 0;
+}
+
+static int es8311_resume(struct snd_soc_component *component)
+{
+	struct es8311_priv *es8311;
+
+	es8311 = snd_soc_component_get_drvdata(component);
+
+	es8311_reset(component, false);
+
+	regcache_cache_only(es8311->regmap, false);
+	regcache_sync(es8311->regmap);
+
+	return 0;
+}
+
+static int es8311_component_probe(struct snd_soc_component *component)
+{
+	struct es8311_priv *es8311;
+
+	es8311 = snd_soc_component_get_drvdata(component);
+
+	es8311->mclk = devm_clk_get_optional(component->dev, "mclk");
+	if (IS_ERR(es8311->mclk)) {
+		dev_err(component->dev, "invalid mclk\n");
+		return PTR_ERR(es8311->mclk);
+	}
+
+	es8311->mclk_freq = clk_get_rate(es8311->mclk);
+	if (es8311->mclk_freq > 0 && es8311->mclk_freq < ES8311_MCLK_MAX_FREQ)
+		es8311_set_sysclk_constraints(es8311->mclk_freq, es8311);
+
+	es8311_reset(component, true);
+	es8311_reset(component, false);
+
+	/* Set minimal power up time */
+	snd_soc_component_write(component, ES8311_SYS1, 0);
+	snd_soc_component_write(component, ES8311_SYS2, 0);
+
+	return 0;
+}
+
+static const struct regmap_config es8311_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = ES8311_REG_MAX,
+	.cache_type = REGCACHE_MAPLE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+static const struct snd_soc_component_driver es8311_component_driver = {
+	.probe = es8311_component_probe,
+	.suspend = es8311_suspend,
+	.resume = es8311_resume,
+	.set_bias_level = es8311_set_bias_level,
+	.controls = es8311_snd_controls,
+	.num_controls = ARRAY_SIZE(es8311_snd_controls),
+	.dapm_widgets = es8311_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8311_dapm_widgets),
+	.dapm_routes = es8311_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es8311_dapm_routes),
+	.use_pmdown_time = 1,
+	.endianness = 1,
+};
+
+static int es8311_i2c_probe(struct i2c_client *i2c_client)
+{
+	struct es8311_priv *es8311;
+
+	struct device *dev = &i2c_client->dev;
+
+	es8311 = devm_kzalloc(dev, sizeof(*es8311), GFP_KERNEL);
+	if (es8311 == NULL)
+		return -ENOMEM;
+
+	es8311->regmap =
+		devm_regmap_init_i2c(i2c_client, &es8311_regmap_config);
+	if (IS_ERR(es8311->regmap))
+		return PTR_ERR(es8311->regmap);
+
+	i2c_set_clientdata(i2c_client, es8311);
+
+	return devm_snd_soc_register_component(dev, &es8311_component_driver,
+					       &es8311_dai, 1);
+}
+
+static const struct i2c_device_id es8311_id[] = {
+	{ "es8311" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es8311_id);
+
+static const struct of_device_id es8311_of_match[] = {
+	{
+		.compatible = "everest,es8311",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, es8311_of_match);
+
+static struct i2c_driver es8311_i2c_driver = {
+	.driver = {
+		.name		= "es8311",
+		.of_match_table = es8311_of_match,
+	},
+	.probe = es8311_i2c_probe,
+	.id_table = es8311_id,
+};
+
+module_i2c_driver(es8311_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8311 driver");
+MODULE_AUTHOR("Matteo Martelli <matteomartelli3@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8311.h b/sound/soc/codecs/es8311.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a3105bb84438ed1dce83b94619afed01fff4b18
--- /dev/null
+++ b/sound/soc/codecs/es8311.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8311.c -- es8311 ALSA SoC audio driver
+ *
+ * Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
+ *
+ * Author: Matteo Martelli <matteomartelli3@gmail.com>
+ */
+
+#ifndef _ES8311_H
+#define _ES8311_H
+
+#include <linux/bitops.h>
+
+#define ES8311_RESET 0x00
+#define ES8311_RESET_CSM_ON BIT(7)
+#define ES8311_RESET_MSC BIT(6)
+#define ES8311_RESET_RST_MASK GENMASK(4, 0)
+
+/* Clock Manager Registers */
+#define ES8311_CLKMGR1 0x01
+#define ES8311_CLKMGR1_MCLK_SEL BIT(7)
+#define ES8311_CLKMGR1_MCLK_ON BIT(5)
+#define ES8311_CLKMGR1_BCLK_ON BIT(4)
+#define ES8311_CLKMGR1_CLKADC_ON_SHIFT 3
+#define ES8311_CLKMGR1_CLKDAC_ON_SHIFT 2
+#define ES8311_CLKMGR1_ANACLKADC_ON_SHIFT 1
+#define ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT 0
+#define ES8311_CLKMGR2 0x02
+#define ES8311_CLKMGR2_DIV_PRE_MASK GENMASK(7, 5)
+#define ES8311_CLKMGR2_DIV_PRE_SHIFT 5
+#define ES8311_CLKMGR2_DIV_PRE_MAX 0x07
+#define ES8311_CLKMGR2_MULT_PRE_MASK GENMASK(4, 3)
+#define ES8311_CLKMGR2_MULT_PRE_SHIFT 3
+#define ES8311_CLKMGR3 0x03
+#define ES8311_CLKMGR4 0x04
+#define ES8311_CLKMGR5 0x05
+#define ES8311_CLKMGR5_ADC_DIV_MASK GENMASK(7, 4)
+#define ES8311_CLKMGR5_ADC_DIV_SHIFT 4
+#define ES8311_CLKMGR5_DAC_DIV_MASK GENMASK(3, 0)
+#define ES8311_CLKMGR5_DAC_DIV_SHIFT 0
+#define ES8311_CLKMGR6 0x06
+#define ES8311_CLKMGR6_BCLK_INV BIT(5)
+#define ES8311_CLKMGR6_DIV_BCLK_MASK GENMASK(4, 0)
+#define ES8311_CLKMGR7 0x07
+#define ES8311_CLKMGR7_LRCLK_DIV_H_MASK GENMASK(3, 0)
+#define ES8311_CLKMGR8 0x08
+#define ES8311_CLKMGR_LRCLK_DIV_MAX 0x0FFF
+
+/* SDP Mode Registers */
+#define ES8311_SDP_IN 0x09
+#define ES8311_SDP_IN_SEL_SHIFT 7
+#define ES8311_SDP_OUT 0x0A
+/* Following values are the same for both SPD_IN and SDP_OUT */
+#define ES8311_SDP_MUTE_SHIFT 6
+#define ES8311_SDP_LRP BIT(5)
+#define ES8311_SDP_WL_MASK GENMASK(4, 2)
+#define ES8311_SDP_WL_SHIFT 2
+#define ES8311_SDP_WL_24 0x00
+#define ES8311_SDP_WL_20 0x01
+#define ES8311_SDP_WL_18 0x02
+#define ES8311_SDP_WL_16 0x03
+#define ES8311_SDP_WL_32 0x04
+#define ES8311_SDP_FMT_MASK GENMASK(1, 0)
+#define ES8311_SDP_FMT_I2S 0x00
+#define ES8311_SDP_FMT_LEFT_J 0x01
+#define ES8311_SDP_FMT_DSP 0x03
+
+/* System registers */
+#define ES8311_SYS1 0x0B
+#define ES8311_SYS2 0x0C
+#define ES8311_SYS3 0x0D
+#define ES8311_SYS3_PDN_ANA_SHIFT 7
+#define ES8311_SYS3_PDN_IBIASGEN_SHIFT 6
+#define ES8311_SYS3_PDN_ADCBIASGEN_SHIFT 5
+#define ES8311_SYS3_PDN_ADCVREFGEN_SHIFT 4
+#define ES8311_SYS3_PDN_DACVREFGEN_SHIFT 3
+#define ES8311_SYS3_PDN_VREF_SHIFT 2
+#define ES8311_SYS3_PDN_VMIDSEL_MASK GENMASK(1, 0)
+#define ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN 0
+#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED 1
+#define ES8311_SYS3_PDN_VMIDSEL_NORMAL_OPERATION 2
+#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_FAST_SPEED 3
+#define ES8311_SYS4 0x0E
+#define ES8311_SYS4_PDN_PGA_SHIFT 6
+#define ES8311_SYS4_PDN_MOD_SHIFT 5
+#define ES8311_SYS5 0x0F
+#define ES8311_SYS6 0x10
+#define ES8311_SYS7 0x11
+#define ES8311_SYS8 0x12
+#define ES8311_SYS8_PDN_DAC_SHIFT 1
+#define ES8311_SYS9 0x13
+#define ES8311_SYS9_HPSW_SHIFT 4
+#define ES8311_SYS10 0x14
+#define ES8311_SYS10_DMIC_ON_SHIFT 6
+#define ES8311_SYS10_LINESEL_SHIFT 4
+#define ES8311_SYS10_PGAGAIN_SHIFT 0
+#define ES8311_SYS10_PGAGAIN_MAX 0x0A
+
+/* ADC Registers*/
+#define ES8311_ADC1 0x15
+#define ES8311_ADC1_RAMPRATE_SHIFT 4
+#define ES8311_ADC2 0x16
+#define ES8311_ADC2_INV_SHIFT 4
+#define ES8311_ADC2_SCALE_SHIFT 0
+#define ES8311_ADC2_SCALE_MAX 0x07
+#define ES8311_ADC3 0x17
+#define ES8311_ADC3_VOLUME_SHIFT 0
+#define ES8311_ADC3_VOLUME_MAX 0xFF
+#define ES8311_ADC4 0x18
+#define ES8311_ADC4_ALC_EN_SHIFT 7
+#define ES8311_ADC4_AUTOMUTE_EN_SHIFT 6
+#define ES8311_ADC4_ALC_WINSIZE_SHIFT 0
+#define ES8311_ADC5 0x19
+#define ES8311_ADC5_ALC_MAXLEVEL_SHIFT 4
+#define ES8311_ADC5_ALC_MAXLEVEL_MAX 0x0F
+#define ES8311_ADC5_ALC_MINLEVEL_SHIFT 0
+#define ES8311_ADC5_ALC_MINLEVEL_MAX 0x0F
+#define ES8311_ADC6 0x1A
+#define ES8311_ADC6_AUTOMUTE_WS_SHIFT 4
+#define ES8311_ADC6_AUTOMUTE_NG_SHIFT 0
+#define ES8311_ADC6_AUTOMUTE_NG_MAX 0x0F
+
+#define ES8311_ADC7 0x1B
+#define ES8311_ADC7_AUTOMUTE_VOL_SHIFT 5
+#define ES8311_ADC7_AUTOMUTE_VOL_MAX 0x07
+#define ES8311_ADC8 0x1C
+#define ES8311_ADC8_EQBYPASS_SHIFT 6
+#define ES8311_ADC8_HPF_SHIFT 5
+
+/* DAC Registers */
+#define ES8311_DAC1 0x31
+#define ES8311_DAC1_DAC_DSMMUTE BIT(6)
+#define ES8311_DAC1_DAC_DEMMUTE BIT(5)
+#define ES8311_DAC2 0x32
+#define ES8311_DAC2_VOLUME_MAX 0xFF
+#define ES8311_DAC3 0x33
+#define ES8311_DAC4 0x34
+#define ES8311_DAC4_DRC_EN_SHIFT 7
+#define ES8311_DAC4_DRC_WINSIZE_SHIFT 0
+#define ES8311_DAC5 0x35
+#define ES8311_DAC5_DRC_MAXLEVEL_SHIFT 4
+#define ES8311_DAC5_DRC_MAXLEVEL_MAX 0x0F
+#define ES8311_DAC5_DRC_MINLEVEL_SHIFT 0
+#define ES8311_DAC5_DRC_MINLEVEL_MAX 0x0F
+#define ES8311_DAC6 0x37
+#define ES8311_DAC6_RAMPRATE_SHIFT 4
+#define ES8311_DAC6_EQBYPASS_SHIFT 3
+
+/* GPIO Registers */
+#define ES8311_GPIO 0x44
+#define ES8311_GPIO_ADC2DAC_SEL_SHIFT 7
+#define ES8311_GPIO_ADCDAT_SEL_SHIFT 4
+
+/* Chip Info Registers */
+#define ES8311_CHIPID1 0xFD /* 0x83 */
+#define ES8311_CHIPID2 0xFE /* 0x11 */
+#define ES8311_CHIPVER 0xFF
+
+#define ES8311_REG_MAX 0xFF
+
+#endif
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index 6a4e42e5e35b9947f7670aa1a51d6ad7d1693763..b246694ebb4faa4d7aab7de3c9145eeed9e124b9 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -329,11 +329,29 @@ static bool es8326_volatile_register(struct device *dev, unsigned int reg)
 	}
 }
 
+static bool es8326_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ES8326_BIAS_SW1:
+	case ES8326_BIAS_SW2:
+	case ES8326_BIAS_SW3:
+	case ES8326_BIAS_SW4:
+	case ES8326_ADC_HPFS1:
+	case ES8326_ADC_HPFS2:
+		return false;
+	default:
+		return true;
+	}
+}
+
 static const struct regmap_config es8326_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 	.max_register = 0xff,
+	.use_single_read = true,
+	.use_single_write = true,
 	.volatile_reg = es8326_volatile_register,
+	.writeable_reg = es8326_writeable_register,
 	.cache_type = REGCACHE_RBTREE,
 };
 
@@ -877,6 +895,8 @@ static void es8326_jack_detect_handler(struct work_struct *work)
 		if (es8326->jack->status & SND_JACK_HEADSET) {
 			/* detect button */
 			dev_dbg(comp->dev, "button pressed\n");
+			regmap_write(es8326->regmap, ES8326_INT_SOURCE,
+					(ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
 			queue_delayed_work(system_wq, &es8326->button_press_work, 10);
 			goto exit;
 		}
@@ -972,14 +992,10 @@ static int es8326_calibrate(struct snd_soc_component *component)
 	return 0;
 }
 
-static int es8326_resume(struct snd_soc_component *component)
+static void es8326_init(struct snd_soc_component *component)
 {
 	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
 
-	regcache_cache_only(es8326->regmap, false);
-	regcache_sync(es8326->regmap);
-
-	/* reset internal clock state */
 	regmap_write(es8326->regmap, ES8326_RESET, 0x1f);
 	regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
 	regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
@@ -1035,7 +1051,6 @@ static int es8326_resume(struct snd_soc_component *component)
 	es8326_enable_micbias(es8326->component);
 	usleep_range(50000, 70000);
 	regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
-	regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
 	regmap_write(es8326->regmap, ES8326_INTOUT_IO,
 		     es8326->interrupt_clk);
 	regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
@@ -1051,11 +1066,28 @@ static int es8326_resume(struct snd_soc_component *component)
 			   ES8326_MUTE);
 
 	regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_LRCK, 0xff);
 
-	es8326->jack_remove_retry = 0;
-	es8326->hp = 0;
-	es8326->hpl_vol = 0x03;
-	es8326->hpr_vol = 0x03;
+	msleep(200);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+
+	regcache_cache_only(es8326->regmap, false);
+	regcache_cache_bypass(es8326->regmap, true);
+	regmap_read(es8326->regmap, ES8326_CLK_RESAMPLE, &reg);
+	regcache_cache_bypass(es8326->regmap, false);
+	/* reset internal clock state */
+	if (reg == 0x05)
+		regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
+	else
+		es8326_init(component);
+
+	regcache_sync(es8326->regmap);
 
 	es8326_irq(es8326->irq, es8326);
 	return 0;
@@ -1115,7 +1147,7 @@ static int es8326_probe(struct snd_soc_component *component)
 	}
 	dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
 
-	es8326_resume(component);
+	es8326_init(component);
 	return 0;
 }
 
@@ -1211,6 +1243,10 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
 	}
 
 	es8326->irq = i2c->irq;
+	es8326->jack_remove_retry = 0;
+	es8326->hp = 0;
+	es8326->hpl_vol = 0x03;
+	es8326->hpr_vol = 0x03;
 	INIT_DELAYED_WORK(&es8326->jack_detect_work,
 			  es8326_jack_detect_handler);
 	INIT_DELAYED_WORK(&es8326->button_press_work,
diff --git a/sound/soc/codecs/framer-codec.c b/sound/soc/codecs/framer-codec.c
index e5fcde9ee30804fc52c8c501ecdd49014ca236a4..6f57a3aeecc89240beff3bdea22936a2bb9b05d7 100644
--- a/sound/soc/codecs/framer-codec.c
+++ b/sound/soc/codecs/framer-codec.c
@@ -238,7 +238,7 @@ static int framer_dai_startup(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static u64 framer_dai_formats[] = {
+static const u64 framer_dai_formats[] = {
 	SND_SOC_POSSIBLE_DAIFMT_DSP_B,
 };
 
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index d3abb7ce215330aac5241cd3056ba7b3537996c4..74caae52e1273fda45ab8dd079ae800827f0231f 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -715,7 +715,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction)
  * For example,
  *	${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
  */
-static u64 hdmi_codec_formats =
+static const u64 hdmi_codec_formats =
 	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
 	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
 	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c
index 2cc7b9166e695fe8bc02c6fc95f488ed571d4037..cb7a68c799f8fc336c450e2211901005cf56e6a9 100644
--- a/sound/soc/codecs/idt821034.c
+++ b/sound/soc/codecs/idt821034.c
@@ -860,7 +860,7 @@ static int idt821034_dai_startup(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static u64 idt821034_dai_formats[] = {
+static const u64 idt821034_dai_formats[] = {
 	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
 	SND_SOC_POSSIBLE_DAIFMT_DSP_B,
 };
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
index 9df58e23d3601b6163116f83627908b223995daa..6217e611259fe15f111a193ae9b6c6fbacf0651f 100644
--- a/sound/soc/codecs/jz4760.c
+++ b/sound/soc/codecs/jz4760.c
@@ -821,7 +821,7 @@ static const u8 jz4760_codec_reg_defaults[] = {
 	0x1F, 0x00, 0x00, 0x00
 };
 
-static struct regmap_config jz4760_codec_regmap_config = {
+static const struct regmap_config jz4760_codec_regmap_config = {
 	.reg_bits = 7,
 	.val_bits = 8,
 
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index 1d0c467ab57b449eaf751bca4d4cfc1f7fd7e9c5..acb9eaa7ea1c50e2178d402deed9862a9527d6b1 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -872,7 +872,7 @@ static const u8 jz4770_codec_reg_defaults[] = {
 	0x07, 0x44, 0x1F, 0x00
 };
 
-static struct regmap_config jz4770_codec_regmap_config = {
+static const struct regmap_config jz4770_codec_regmap_config = {
 	.reg_bits = 7,
 	.val_bits = 8,
 
diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c
index da1b422250b8fc86a7f9e0b5ca199f7d1eb33697..6e3b8d0897dd62ba2b6bd5f5c62a5d46e02744ab 100644
--- a/sound/soc/codecs/lpass-macro-common.c
+++ b/sound/soc/codecs/lpass-macro-common.c
@@ -11,6 +11,9 @@
 
 #include "lpass-macro-common.h"
 
+static DEFINE_MUTEX(lpass_codec_mutex);
+static enum lpass_codec_version lpass_codec_version;
+
 struct lpass_macro *lpass_macro_pds_init(struct device *dev)
 {
 	struct lpass_macro *l_pds;
@@ -66,5 +69,25 @@ void lpass_macro_pds_exit(struct lpass_macro *pds)
 }
 EXPORT_SYMBOL_GPL(lpass_macro_pds_exit);
 
+void lpass_macro_set_codec_version(enum lpass_codec_version version)
+{
+	mutex_lock(&lpass_codec_mutex);
+	lpass_codec_version = version;
+	mutex_unlock(&lpass_codec_mutex);
+}
+EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version);
+
+enum lpass_codec_version lpass_macro_get_codec_version(void)
+{
+	enum lpass_codec_version ver;
+
+	mutex_lock(&lpass_codec_mutex);
+	ver = lpass_codec_version;
+	mutex_unlock(&lpass_codec_mutex);
+
+	return ver;
+}
+EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version);
+
 MODULE_DESCRIPTION("Common macro driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h
index d98718b3dc4b07e14f0494dabb5ecae7ffde090e..21cb30ab706d8ac02ec7ec0376db631f8251f3f5 100644
--- a/sound/soc/codecs/lpass-macro-common.h
+++ b/sound/soc/codecs/lpass-macro-common.h
@@ -18,6 +18,19 @@ enum lpass_version {
 	LPASS_VER_11_0_0,
 };
 
+enum lpass_codec_version {
+	LPASS_CODEC_VERSION_UNKNOWN,
+	LPASS_CODEC_VERSION_1_0,
+	LPASS_CODEC_VERSION_1_1,
+	LPASS_CODEC_VERSION_1_2,
+	LPASS_CODEC_VERSION_2_0,
+	LPASS_CODEC_VERSION_2_1,
+	LPASS_CODEC_VERSION_2_5,
+	LPASS_CODEC_VERSION_2_6,
+	LPASS_CODEC_VERSION_2_7,
+	LPASS_CODEC_VERSION_2_8,
+};
+
 struct lpass_macro {
 	struct device *macro_pd;
 	struct device *dcodec_pd;
@@ -25,5 +38,33 @@ struct lpass_macro {
 
 struct lpass_macro *lpass_macro_pds_init(struct device *dev);
 void lpass_macro_pds_exit(struct lpass_macro *pds);
+void lpass_macro_set_codec_version(enum lpass_codec_version version);
+enum lpass_codec_version lpass_macro_get_codec_version(void);
+
+static inline void lpass_macro_pds_exit_action(void *pds)
+{
+	lpass_macro_pds_exit(pds);
+}
+
+static inline const char *lpass_macro_get_codec_version_string(int version)
+{
+	switch (version) {
+	case LPASS_CODEC_VERSION_2_0:
+		return "v2.0";
+	case LPASS_CODEC_VERSION_2_1:
+		return "v2.1";
+	case LPASS_CODEC_VERSION_2_5:
+		return "v2.5";
+	case LPASS_CODEC_VERSION_2_6:
+		return "v2.6";
+	case LPASS_CODEC_VERSION_2_7:
+		return "v2.7";
+	case LPASS_CODEC_VERSION_2_8:
+		return "v2.8";
+	default:
+		break;
+	}
+	return "NA";
+}
 
 #endif /* __LPASS_MACRO_COMMON_H__ */
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index f35187d69cac1af38018ec6f7b39e6e6e7b7ad24..ce42749660c87e4949fdc833445d2a7be521bbc3 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 
+#include <linux/cleanup.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -158,7 +159,7 @@
 #define CDC_RX_INTR_CTRL_LEVEL0		(0x03C0)
 #define CDC_RX_INTR_CTRL_BYPASS0	(0x03C8)
 #define CDC_RX_INTR_CTRL_SET0		(0x03D0)
-#define CDC_RX_RXn_RX_PATH_CTL(n)	(0x0400 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CTL(rx, n)	(0x0400  + rx->rxn_reg_stride * n)
 #define CDC_RX_RX0_RX_PATH_CTL		(0x0400)
 #define CDC_RX_PATH_RESET_EN_MASK	BIT(6)
 #define CDC_RX_PATH_CLK_EN_MASK		BIT(5)
@@ -166,45 +167,47 @@
 #define CDC_RX_PATH_PGA_MUTE_MASK	BIT(4)
 #define CDC_RX_PATH_PGA_MUTE_ENABLE	BIT(4)
 #define CDC_RX_PATH_PCM_RATE_MASK	GENMASK(3, 0)
-#define CDC_RX_RXn_RX_PATH_CFG0(n)	(0x0404 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG0(rx, n)	(0x0404  + rx->rxn_reg_stride * n)
 #define CDC_RX_RXn_COMP_EN_MASK		BIT(1)
 #define CDC_RX_RX0_RX_PATH_CFG0		(0x0404)
 #define CDC_RX_RXn_CLSH_EN_MASK		BIT(6)
 #define CDC_RX_DLY_ZN_EN_MASK		BIT(3)
 #define CDC_RX_DLY_ZN_ENABLE		BIT(3)
 #define CDC_RX_RXn_HD2_EN_MASK		BIT(2)
-#define CDC_RX_RXn_RX_PATH_CFG1(n)	(0x0408 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG1(rx, n)	(0x0408  + rx->rxn_reg_stride * n)
 #define CDC_RX_RXn_SIDETONE_EN_MASK	BIT(4)
 #define CDC_RX_RX0_RX_PATH_CFG1		(0x0408)
 #define CDC_RX_RX0_HPH_L_EAR_SEL_MASK	BIT(1)
-#define CDC_RX_RXn_RX_PATH_CFG2(n)	(0x040C + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG2(rx, n)	(0x040C  + rx->rxn_reg_stride * n)
 #define CDC_RX_RXn_HPF_CUT_FREQ_MASK	GENMASK(1, 0)
 #define CDC_RX_RX0_RX_PATH_CFG2		(0x040C)
-#define CDC_RX_RXn_RX_PATH_CFG3(n)	(0x0410 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG3(rx, n)	(0x0410  + rx->rxn_reg_stride * n)
 #define CDC_RX_RX0_RX_PATH_CFG3		(0x0410)
 #define CDC_RX_DC_COEFF_SEL_MASK	GENMASK(1, 0)
 #define CDC_RX_DC_COEFF_SEL_TWO		0x2
-#define CDC_RX_RXn_RX_VOL_CTL(n)	(0x0414 + 0x80 * n)
+#define CDC_RX_RXn_RX_VOL_CTL(rx, n)	(0x0414  + rx->rxn_reg_stride * n)
 #define CDC_RX_RX0_RX_VOL_CTL		(0x0414)
-#define CDC_RX_RXn_RX_PATH_MIX_CTL(n)	(0x0418 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_MIX_CTL(rx, n)	(0x0418  + rx->rxn_reg_stride * n)
 #define CDC_RX_RXn_MIX_PCM_RATE_MASK	GENMASK(3, 0)
 #define CDC_RX_RXn_MIX_RESET_MASK	BIT(6)
 #define CDC_RX_RXn_MIX_RESET		BIT(6)
 #define CDC_RX_RXn_MIX_CLK_EN_MASK	BIT(5)
 #define CDC_RX_RX0_RX_PATH_MIX_CTL	(0x0418)
 #define CDC_RX_RX0_RX_PATH_MIX_CFG	(0x041C)
-#define CDC_RX_RXn_RX_VOL_MIX_CTL(n)	(0x0420 + 0x80 * n)
+#define CDC_RX_RXn_RX_VOL_MIX_CTL(rx, n)	(0x0420  + rx->rxn_reg_stride * n)
 #define CDC_RX_RX0_RX_VOL_MIX_CTL	(0x0420)
 #define CDC_RX_RX0_RX_PATH_SEC1		(0x0424)
 #define CDC_RX_RX0_RX_PATH_SEC2		(0x0428)
 #define CDC_RX_RX0_RX_PATH_SEC3		(0x042C)
+#define CDC_RX_RXn_RX_PATH_SEC3(rx, n)	(0x042c  + rx->rxn_reg_stride * n)
 #define CDC_RX_RX0_RX_PATH_SEC4		(0x0430)
 #define CDC_RX_RX0_RX_PATH_SEC7		(0x0434)
+#define CDC_RX_RXn_RX_PATH_SEC7(rx, n)	(0x0434  + rx->rxn_reg_stride * n)
 #define CDC_RX_DSM_OUT_DELAY_SEL_MASK	GENMASK(2, 0)
 #define CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE	0x2
 #define CDC_RX_RX0_RX_PATH_MIX_SEC0	(0x0438)
 #define CDC_RX_RX0_RX_PATH_MIX_SEC1	(0x043C)
-#define CDC_RX_RXn_RX_PATH_DSM_CTL(n)	(0x0440 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_DSM_CTL(rx, n)	(0x0440  + rx->rxn_reg_stride * n)
 #define CDC_RX_RXn_DSM_CLK_EN_MASK	BIT(0)
 #define CDC_RX_RX0_RX_PATH_DSM_CTL	(0x0440)
 #define CDC_RX_RX0_RX_PATH_DSM_DATA1	(0x0444)
@@ -213,6 +216,7 @@
 #define CDC_RX_RX0_RX_PATH_DSM_DATA4	(0x0450)
 #define CDC_RX_RX0_RX_PATH_DSM_DATA5	(0x0454)
 #define CDC_RX_RX0_RX_PATH_DSM_DATA6	(0x0458)
+/* RX offsets prior to 2.5 codec version */
 #define CDC_RX_RX1_RX_PATH_CTL		(0x0480)
 #define CDC_RX_RX1_RX_PATH_CFG0		(0x0484)
 #define CDC_RX_RX1_RX_PATH_CFG1		(0x0488)
@@ -259,6 +263,53 @@
 #define CDC_RX_RX2_RX_PATH_MIX_SEC0	(0x0544)
 #define CDC_RX_RX2_RX_PATH_MIX_SEC1	(0x0548)
 #define CDC_RX_RX2_RX_PATH_DSM_CTL	(0x054C)
+
+/* LPASS CODEC version 2.5 rx reg offsets */
+#define CDC_2_5_RX_RX1_RX_PATH_CTL		(0x04c0)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG0		(0x04c4)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG1		(0x04c8)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG2		(0x04cC)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG3		(0x04d0)
+#define CDC_2_5_RX_RX1_RX_VOL_CTL		(0x04d4)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_CTL		(0x04d8)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_CFG		(0x04dC)
+#define CDC_2_5_RX_RX1_RX_VOL_MIX_CTL		(0x04e0)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC1		(0x04e4)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC2		(0x04e8)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC3		(0x04eC)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC4		(0x04f0)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC7		(0x04f4)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0		(0x04f8)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1		(0x04fC)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_CTL		(0x0500)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1	(0x0504)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2	(0x0508)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3	(0x050C)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4	(0x0510)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5	(0x0514)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6	(0x0518)
+
+#define CDC_2_5_RX_RX2_RX_PATH_CTL		(0x0580)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG0		(0x0584)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG1		(0x0588)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG2		(0x058C)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG3		(0x0590)
+#define CDC_2_5_RX_RX2_RX_VOL_CTL		(0x0594)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_CTL		(0x0598)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_CFG		(0x059C)
+#define CDC_2_5_RX_RX2_RX_VOL_MIX_CTL		(0x05a0)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC0		(0x05a4)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC1		(0x05a8)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC2		(0x05aC)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC3		(0x05b0)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC4		(0x05b4)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC5		(0x05b8)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC6		(0x05bC)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC7		(0x05c0)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0		(0x05c4)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1		(0x05c8)
+#define CDC_2_5_RX_RX2_RX_PATH_DSM_CTL		(0x05cC)
+
 #define CDC_RX_IDLE_DETECT_PATH_CTL	(0x0780)
 #define CDC_RX_IDLE_DETECT_CFG0		(0x0784)
 #define CDC_RX_IDLE_DETECT_CFG1		(0x0788)
@@ -463,12 +514,6 @@ static const struct comp_coeff_val comp_coeff_table[HPH_MODE_MAX][COMP_MAX_COEFF
 	},
 };
 
-struct rx_macro_reg_mask_val {
-	u16 reg;
-	u8 mask;
-	u8 val;
-};
-
 enum {
 	INTERP_HPHL,
 	INTERP_HPHR,
@@ -598,6 +643,8 @@ struct rx_macro {
 	int rx_mclk_users;
 	int clsh_users;
 	int rx_mclk_cnt;
+	enum lpass_codec_version codec_version;
+	int rxn_reg_stride;
 	bool is_ear_mode_on;
 	bool hph_pwr_mode;
 	bool hph_hd2_mode;
@@ -759,6 +806,8 @@ static SOC_ENUM_SINGLE_DECL(rx_int0_dem_inp_enum, CDC_RX_RX0_RX_PATH_CFG1, 0,
 			    rx_int_dem_inp_mux_text);
 static SOC_ENUM_SINGLE_DECL(rx_int1_dem_inp_enum, CDC_RX_RX1_RX_PATH_CFG1, 0,
 			    rx_int_dem_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_2_5_int1_dem_inp_enum, CDC_2_5_RX_RX1_RX_PATH_CFG1, 0,
+			    rx_int_dem_inp_mux_text);
 
 static SOC_ENUM_SINGLE_DECL(rx_macro_rx0_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
 static SOC_ENUM_SINGLE_DECL(rx_macro_rx1_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
@@ -976,49 +1025,6 @@ static const struct reg_default rx_defaults[] = {
 	{ CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55 },
 	{ CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55 },
 	{ CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55 },
-	{ CDC_RX_RX1_RX_PATH_CTL, 0x04 },
-	{ CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
-	{ CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
-	{ CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
-	{ CDC_RX_RX1_RX_VOL_CTL, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
-	{ CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
-	{ CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
-	{ CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
-	{ CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
-	{ CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
-	{ CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
-	{ CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
-	{ CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
-	{ CDC_RX_RX2_RX_PATH_CTL, 0x04 },
-	{ CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
-	{ CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
-	{ CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
-	{ CDC_RX_RX2_RX_VOL_CTL, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
-	{ CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
-	{ CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
-	{ CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
-	{ CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
-	{ CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
-	{ CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
 	{ CDC_RX_IDLE_DETECT_PATH_CTL, 0x00 },
 	{ CDC_RX_IDLE_DETECT_CFG0, 0x07 },
 	{ CDC_RX_IDLE_DETECT_CFG1, 0x3C },
@@ -1121,6 +1127,99 @@ static const struct reg_default rx_defaults[] = {
 	{ CDC_RX_DSD1_CFG2, 0x96 },
 };
 
+static const struct reg_default rx_2_5_defaults[] = {
+	{ CDC_2_5_RX_RX1_RX_PATH_CTL, 0x04 },
+	{ CDC_2_5_RX_RX1_RX_PATH_CFG0, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_CFG1, 0x64 },
+	{ CDC_2_5_RX_RX1_RX_PATH_CFG2, 0x8F },
+	{ CDC_2_5_RX_RX1_RX_PATH_CFG3, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_VOL_CTL, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+	{ CDC_2_5_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+	{ CDC_2_5_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_SEC1, 0x08 },
+	{ CDC_2_5_RX_RX1_RX_PATH_SEC2, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_SEC3, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_SEC4, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_SEC7, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+	{ CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+	{ CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+	{ CDC_2_5_RX_RX2_RX_PATH_CTL, 0x04 },
+	{ CDC_2_5_RX_RX2_RX_PATH_CFG0, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_CFG1, 0x64 },
+	{ CDC_2_5_RX_RX2_RX_PATH_CFG2, 0x8F },
+	{ CDC_2_5_RX_RX2_RX_PATH_CFG3, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_VOL_CTL, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+	{ CDC_2_5_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+	{ CDC_2_5_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC0, 0x04 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC1, 0x08 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC2, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC3, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC4, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC5, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC6, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_SEC7, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+	{ CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+	{ CDC_2_5_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+};
+
+static const struct reg_default rx_pre_2_5_defaults[] = {
+	{ CDC_RX_RX1_RX_PATH_CTL, 0x04 },
+	{ CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
+	{ CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
+	{ CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
+	{ CDC_RX_RX1_RX_VOL_CTL, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+	{ CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+	{ CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
+	{ CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+	{ CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+	{ CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+	{ CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+	{ CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+	{ CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+	{ CDC_RX_RX2_RX_PATH_CTL, 0x04 },
+	{ CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
+	{ CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
+	{ CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
+	{ CDC_RX_RX2_RX_VOL_CTL, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+	{ CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+	{ CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
+	{ CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
+	{ CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+	{ CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+	{ CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+
+};
+
 static bool rx_is_wronly_register(struct device *dev,
 					unsigned int reg)
 {
@@ -1175,8 +1274,114 @@ static bool rx_is_volatile_register(struct device *dev, unsigned int reg)
 	return false;
 }
 
+static bool rx_pre_2_5_is_rw_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_RX_RX1_RX_PATH_CTL:
+	case CDC_RX_RX1_RX_PATH_CFG0:
+	case CDC_RX_RX1_RX_PATH_CFG1:
+	case CDC_RX_RX1_RX_PATH_CFG2:
+	case CDC_RX_RX1_RX_PATH_CFG3:
+	case CDC_RX_RX1_RX_VOL_CTL:
+	case CDC_RX_RX1_RX_PATH_MIX_CTL:
+	case CDC_RX_RX1_RX_PATH_MIX_CFG:
+	case CDC_RX_RX1_RX_VOL_MIX_CTL:
+	case CDC_RX_RX1_RX_PATH_SEC1:
+	case CDC_RX_RX1_RX_PATH_SEC2:
+	case CDC_RX_RX1_RX_PATH_SEC3:
+	case CDC_RX_RX1_RX_PATH_SEC4:
+	case CDC_RX_RX1_RX_PATH_SEC7:
+	case CDC_RX_RX1_RX_PATH_MIX_SEC0:
+	case CDC_RX_RX1_RX_PATH_MIX_SEC1:
+	case CDC_RX_RX1_RX_PATH_DSM_CTL:
+	case CDC_RX_RX1_RX_PATH_DSM_DATA1:
+	case CDC_RX_RX1_RX_PATH_DSM_DATA2:
+	case CDC_RX_RX1_RX_PATH_DSM_DATA3:
+	case CDC_RX_RX1_RX_PATH_DSM_DATA4:
+	case CDC_RX_RX1_RX_PATH_DSM_DATA5:
+	case CDC_RX_RX1_RX_PATH_DSM_DATA6:
+	case CDC_RX_RX2_RX_PATH_CTL:
+	case CDC_RX_RX2_RX_PATH_CFG0:
+	case CDC_RX_RX2_RX_PATH_CFG1:
+	case CDC_RX_RX2_RX_PATH_CFG2:
+	case CDC_RX_RX2_RX_PATH_CFG3:
+	case CDC_RX_RX2_RX_VOL_CTL:
+	case CDC_RX_RX2_RX_PATH_MIX_CTL:
+	case CDC_RX_RX2_RX_PATH_MIX_CFG:
+	case CDC_RX_RX2_RX_VOL_MIX_CTL:
+	case CDC_RX_RX2_RX_PATH_SEC0:
+	case CDC_RX_RX2_RX_PATH_SEC1:
+	case CDC_RX_RX2_RX_PATH_SEC2:
+	case CDC_RX_RX2_RX_PATH_SEC3:
+	case CDC_RX_RX2_RX_PATH_SEC4:
+	case CDC_RX_RX2_RX_PATH_SEC5:
+	case CDC_RX_RX2_RX_PATH_SEC6:
+	case CDC_RX_RX2_RX_PATH_SEC7:
+	case CDC_RX_RX2_RX_PATH_MIX_SEC0:
+	case CDC_RX_RX2_RX_PATH_MIX_SEC1:
+	case CDC_RX_RX2_RX_PATH_DSM_CTL:
+		return true;
+	}
+
+	return false;
+}
+
+static bool rx_2_5_is_rw_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_2_5_RX_RX1_RX_PATH_CTL:
+	case CDC_2_5_RX_RX1_RX_PATH_CFG0:
+	case CDC_2_5_RX_RX1_RX_PATH_CFG1:
+	case CDC_2_5_RX_RX1_RX_PATH_CFG2:
+	case CDC_2_5_RX_RX1_RX_PATH_CFG3:
+	case CDC_2_5_RX_RX1_RX_VOL_CTL:
+	case CDC_2_5_RX_RX1_RX_PATH_MIX_CTL:
+	case CDC_2_5_RX_RX1_RX_PATH_MIX_CFG:
+	case CDC_2_5_RX_RX1_RX_VOL_MIX_CTL:
+	case CDC_2_5_RX_RX1_RX_PATH_SEC1:
+	case CDC_2_5_RX_RX1_RX_PATH_SEC2:
+	case CDC_2_5_RX_RX1_RX_PATH_SEC3:
+	case CDC_2_5_RX_RX1_RX_PATH_SEC4:
+	case CDC_2_5_RX_RX1_RX_PATH_SEC7:
+	case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0:
+	case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_CTL:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5:
+	case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6:
+	case CDC_2_5_RX_RX2_RX_PATH_CTL:
+	case CDC_2_5_RX_RX2_RX_PATH_CFG0:
+	case CDC_2_5_RX_RX2_RX_PATH_CFG1:
+	case CDC_2_5_RX_RX2_RX_PATH_CFG2:
+	case CDC_2_5_RX_RX2_RX_PATH_CFG3:
+	case CDC_2_5_RX_RX2_RX_VOL_CTL:
+	case CDC_2_5_RX_RX2_RX_PATH_MIX_CTL:
+	case CDC_2_5_RX_RX2_RX_PATH_MIX_CFG:
+	case CDC_2_5_RX_RX2_RX_VOL_MIX_CTL:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC0:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC1:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC2:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC3:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC4:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC5:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC6:
+	case CDC_2_5_RX_RX2_RX_PATH_SEC7:
+	case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0:
+	case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1:
+	case CDC_2_5_RX_RX2_RX_PATH_DSM_CTL:
+		return true;
+	}
+
+	return false;
+}
+
 static bool rx_is_rw_register(struct device *dev, unsigned int reg)
 {
+	struct rx_macro *rx = dev_get_drvdata(dev);
+
 	switch (reg) {
 	case CDC_RX_TOP_TOP_CFG0:
 	case CDC_RX_TOP_SWR_CTRL:
@@ -1306,49 +1511,6 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
 	case CDC_RX_RX0_RX_PATH_DSM_DATA4:
 	case CDC_RX_RX0_RX_PATH_DSM_DATA5:
 	case CDC_RX_RX0_RX_PATH_DSM_DATA6:
-	case CDC_RX_RX1_RX_PATH_CTL:
-	case CDC_RX_RX1_RX_PATH_CFG0:
-	case CDC_RX_RX1_RX_PATH_CFG1:
-	case CDC_RX_RX1_RX_PATH_CFG2:
-	case CDC_RX_RX1_RX_PATH_CFG3:
-	case CDC_RX_RX1_RX_VOL_CTL:
-	case CDC_RX_RX1_RX_PATH_MIX_CTL:
-	case CDC_RX_RX1_RX_PATH_MIX_CFG:
-	case CDC_RX_RX1_RX_VOL_MIX_CTL:
-	case CDC_RX_RX1_RX_PATH_SEC1:
-	case CDC_RX_RX1_RX_PATH_SEC2:
-	case CDC_RX_RX1_RX_PATH_SEC3:
-	case CDC_RX_RX1_RX_PATH_SEC4:
-	case CDC_RX_RX1_RX_PATH_SEC7:
-	case CDC_RX_RX1_RX_PATH_MIX_SEC0:
-	case CDC_RX_RX1_RX_PATH_MIX_SEC1:
-	case CDC_RX_RX1_RX_PATH_DSM_CTL:
-	case CDC_RX_RX1_RX_PATH_DSM_DATA1:
-	case CDC_RX_RX1_RX_PATH_DSM_DATA2:
-	case CDC_RX_RX1_RX_PATH_DSM_DATA3:
-	case CDC_RX_RX1_RX_PATH_DSM_DATA4:
-	case CDC_RX_RX1_RX_PATH_DSM_DATA5:
-	case CDC_RX_RX1_RX_PATH_DSM_DATA6:
-	case CDC_RX_RX2_RX_PATH_CTL:
-	case CDC_RX_RX2_RX_PATH_CFG0:
-	case CDC_RX_RX2_RX_PATH_CFG1:
-	case CDC_RX_RX2_RX_PATH_CFG2:
-	case CDC_RX_RX2_RX_PATH_CFG3:
-	case CDC_RX_RX2_RX_VOL_CTL:
-	case CDC_RX_RX2_RX_PATH_MIX_CTL:
-	case CDC_RX_RX2_RX_PATH_MIX_CFG:
-	case CDC_RX_RX2_RX_VOL_MIX_CTL:
-	case CDC_RX_RX2_RX_PATH_SEC0:
-	case CDC_RX_RX2_RX_PATH_SEC1:
-	case CDC_RX_RX2_RX_PATH_SEC2:
-	case CDC_RX_RX2_RX_PATH_SEC3:
-	case CDC_RX_RX2_RX_PATH_SEC4:
-	case CDC_RX_RX2_RX_PATH_SEC5:
-	case CDC_RX_RX2_RX_PATH_SEC6:
-	case CDC_RX_RX2_RX_PATH_SEC7:
-	case CDC_RX_RX2_RX_PATH_MIX_SEC0:
-	case CDC_RX_RX2_RX_PATH_MIX_SEC1:
-	case CDC_RX_RX2_RX_PATH_DSM_CTL:
 	case CDC_RX_IDLE_DETECT_PATH_CTL:
 	case CDC_RX_IDLE_DETECT_CFG0:
 	case CDC_RX_IDLE_DETECT_CFG1:
@@ -1435,6 +1597,22 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
 		return true;
 	}
 
+	switch (rx->codec_version) {
+	case LPASS_CODEC_VERSION_1_0:
+	case LPASS_CODEC_VERSION_1_1:
+	case LPASS_CODEC_VERSION_1_2:
+	case LPASS_CODEC_VERSION_2_0:
+	case LPASS_CODEC_VERSION_2_1:
+		return rx_pre_2_5_is_rw_register(dev, reg);
+	case LPASS_CODEC_VERSION_2_5:
+	case LPASS_CODEC_VERSION_2_6:
+	case LPASS_CODEC_VERSION_2_7:
+	case LPASS_CODEC_VERSION_2_8:
+		return rx_2_5_is_rw_register(dev, reg);
+	default:
+		break;
+	}
+
 	return false;
 }
 
@@ -1491,8 +1669,6 @@ static const struct regmap_config rx_regmap_config = {
 	.val_bits = 32, /* 8 but with 32 bit read/write */
 	.reg_stride = 4,
 	.cache_type = REGCACHE_FLAT,
-	.reg_defaults = rx_defaults,
-	.num_reg_defaults = ARRAY_SIZE(rx_defaults),
 	.max_register = RX_MAX_OFFSET,
 	.writeable_reg = rx_is_writeable_register,
 	.volatile_reg = rx_is_volatile_register,
@@ -1504,16 +1680,17 @@ static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
 {
 	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 rx_macro *rx = snd_soc_component_get_drvdata(component);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned short look_ahead_dly_reg;
 	unsigned int val;
 
 	val = ucontrol->value.enumerated.item[0];
 
-	if (e->reg == CDC_RX_RX0_RX_PATH_CFG1)
-		look_ahead_dly_reg = CDC_RX_RX0_RX_PATH_CFG0;
-	else if (e->reg == CDC_RX_RX1_RX_PATH_CFG1)
-		look_ahead_dly_reg = CDC_RX_RX1_RX_PATH_CFG0;
+	if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 0))
+		look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0);
+	else if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 1))
+		look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1);
 
 	/* Set Look Ahead Delay */
 	if (val)
@@ -1534,6 +1711,10 @@ static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
 		SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_int1_dem_inp_enum,
 		  snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
 
+static const struct snd_kcontrol_new rx_2_5_int1_dem_inp_mux =
+		SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_2_5_int1_dem_inp_enum,
+		  snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+
 static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
 					       int rate_reg_val, u32 sample_rate)
 {
@@ -1567,7 +1748,7 @@ static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
 			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_RX_RXn_RX_PATH_CTL(j);
+				int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(rx, j);
 				/* sample_rate is in Hz */
 				snd_soc_component_update_bits(component, int_fs_reg,
 							      CDC_RX_PATH_PCM_RATE_MASK,
@@ -1600,7 +1781,7 @@ static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
 									CDC_RX_INTX_2_SEL_MASK);
 
 			if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
-				int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
+				int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j);
 				snd_soc_component_update_bits(component, int_fs_reg,
 							      CDC_RX_RXn_MIX_PCM_RATE_MASK,
 							      rate_reg_val);
@@ -1654,7 +1835,7 @@ static int rx_macro_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
+static int rx_macro_get_channel_map(const struct snd_soc_dai *dai,
 				    unsigned int *tx_num, unsigned int *tx_slot,
 				    unsigned int *rx_num, unsigned int *rx_slot)
 {
@@ -1719,6 +1900,7 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
 static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
 {
 	struct snd_soc_component *component = dai->component;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
 	uint16_t j, reg, mix_reg, dsm_reg;
 	u16 int_mux_cfg0, int_mux_cfg1;
 	u8 int_mux_cfg0_val, int_mux_cfg1_val;
@@ -1729,9 +1911,9 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
 	case RX_MACRO_AIF3_PB:
 	case RX_MACRO_AIF4_PB:
 		for (j = 0; j < INTERP_MAX; j++) {
-			reg = CDC_RX_RXn_RX_PATH_CTL(j);
-			mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
-			dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j);
+			reg = CDC_RX_RXn_RX_PATH_CTL(rx, j);
+			mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j);
+			dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, j);
 
 			if (mute) {
 				snd_soc_component_update_bits(component, reg,
@@ -1748,7 +1930,7 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
 			}
 
 			if (j == INTERP_AUX)
-				dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+				dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2);
 
 			int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
 			int_mux_cfg1 = int_mux_cfg0 + 4;
@@ -1956,10 +2138,11 @@ static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w,
 					int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
 	u16 gain_reg, reg;
 
-	reg = CDC_RX_RXn_RX_PATH_CTL(w->shift);
-	gain_reg = CDC_RX_RXn_RX_VOL_CTL(w->shift);
+	reg = CDC_RX_RXn_RX_PATH_CTL(rx, w->shift);
+	gain_reg = CDC_RX_RXn_RX_VOL_CTL(rx, w->shift);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1991,7 +2174,7 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 	if (comp == INTERP_AUX)
 		return 0;
 
-	pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(comp)) & 0x0F;
+	pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(rx, comp)) & 0x0F;
 	if (pcm_rate < 0x06)
 		val = 0x03;
 	else if (pcm_rate < 0x08)
@@ -2002,11 +2185,11 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 		val = 0x00;
 
 	if (SND_SOC_DAPM_EVENT_ON(event))
-		snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+		snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp),
 					      CDC_RX_DC_COEFF_SEL_MASK, val);
 
 	if (SND_SOC_DAPM_EVENT_OFF(event))
-		snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+		snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp),
 					      CDC_RX_DC_COEFF_SEL_MASK, 0x3);
 	if (!rx->comp_enabled[comp])
 		return 0;
@@ -2019,14 +2202,14 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 					      CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x1);
 		snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
 					      CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x0);
-		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp),
 					      CDC_RX_RXn_COMP_EN_MASK, 0x1);
 	}
 
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
 					      CDC_RX_COMPANDERn_HALT_MASK, 0x1);
-		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp),
 					      CDC_RX_RXn_COMP_EN_MASK, 0x0);
 		snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
 					      CDC_RX_COMPANDERn_CLK_EN_MASK, 0x0);
@@ -2125,13 +2308,13 @@ static int rx_macro_config_aux_hpf(struct snd_soc_component *component,
 		/* Update Aux HPF control */
 		if (!rx->is_aux_hpf_on)
 			snd_soc_component_update_bits(component,
-				CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00);
+				CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x00);
 	}
 
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		/* Reset to default (HPF=ON) */
 		snd_soc_component_update_bits(component,
-			CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04);
+			CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x04);
 	}
 
 	return 0;
@@ -2183,7 +2366,7 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
 				CDC_RX_CLSH_DECAY_CTRL,
 				CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
 		snd_soc_component_write_field(component,
-				CDC_RX_RX0_RX_PATH_CFG0,
+				CDC_RX_RXn_RX_PATH_CFG0(rx, 0),
 				CDC_RX_RXn_CLSH_EN_MASK, 0x1);
 		break;
 	case INTERP_HPHR:
@@ -2199,15 +2382,15 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
 				CDC_RX_CLSH_DECAY_CTRL,
 				CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
 		snd_soc_component_write_field(component,
-				CDC_RX_RX1_RX_PATH_CFG0,
+				CDC_RX_RXn_RX_PATH_CFG0(rx, 1),
 				CDC_RX_RXn_CLSH_EN_MASK, 0x1);
 		break;
 	case INTERP_AUX:
 		snd_soc_component_update_bits(component,
-				CDC_RX_RX2_RX_PATH_CFG0,
+				CDC_RX_RXn_RX_PATH_CFG0(rx, 2),
 				CDC_RX_RX2_DLY_Z_EN_MASK, 1);
 		snd_soc_component_write_field(component,
-				CDC_RX_RX2_RX_PATH_CFG0,
+				CDC_RX_RXn_RX_PATH_CFG0(rx, 2),
 				CDC_RX_RX2_CLSH_EN_MASK, 1);
 		break;
 	}
@@ -2218,16 +2401,17 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
 static void rx_macro_hd2_control(struct snd_soc_component *component,
 				 u16 interp_idx, int event)
 {
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
 	u16 hd2_scale_reg, hd2_enable_reg;
 
 	switch (interp_idx) {
 	case INTERP_HPHL:
-		hd2_scale_reg = CDC_RX_RX0_RX_PATH_SEC3;
-		hd2_enable_reg = CDC_RX_RX0_RX_PATH_CFG0;
+		hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 0);
+		hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0);
 		break;
 	case INTERP_HPHR:
-		hd2_scale_reg = CDC_RX_RX1_RX_PATH_SEC3;
-		hd2_enable_reg = CDC_RX_RX1_RX_PATH_CFG0;
+		hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 1);
+		hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1);
 		break;
 	}
 
@@ -2482,7 +2666,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
 		if (interp_idx == INTERP_HPHL) {
 			if (rx->is_ear_mode_on)
 				snd_soc_component_write_field(component,
-					CDC_RX_RX0_RX_PATH_CFG1,
+					CDC_RX_RXn_RX_PATH_CFG1(rx, 0),
 					CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x1);
 			else
 				snd_soc_component_write_field(component,
@@ -2499,7 +2683,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
 
 	if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
 		snd_soc_component_write_field(component,
-					CDC_RX_RX0_RX_PATH_CFG1,
+					CDC_RX_RXn_RX_PATH_CFG1(rx, 0),
 					CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x0);
 		snd_soc_component_update_bits(component, hph_lut_bypass_reg,
 					CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 0);
@@ -2516,11 +2700,12 @@ static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
 	u16 main_reg, dsm_reg, rx_cfg2_reg;
 	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
 
-	main_reg = CDC_RX_RXn_RX_PATH_CTL(interp_idx);
-	dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(interp_idx);
+	main_reg = CDC_RX_RXn_RX_PATH_CTL(rx, interp_idx);
+	dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, interp_idx);
 	if (interp_idx == INTERP_AUX)
-		dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
-	rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(interp_idx);
+		dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2);
+
+	rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(rx, interp_idx);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		if (rx->main_clk_users[interp_idx] == 0) {
@@ -2587,10 +2772,11 @@ static int rx_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);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
 	u16 gain_reg, mix_reg;
 
-	gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(w->shift);
-	mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(w->shift);
+	gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(rx, w->shift);
+	mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, w->shift);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -2621,17 +2807,18 @@ static int rx_macro_enable_rx_path_clk(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 rx_macro *rx = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		rx_macro_enable_interp_clk(component, event, w->shift);
-		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift),
 					      CDC_RX_RXn_SIDETONE_EN_MASK, 1);
-		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(w->shift),
+		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(rx, w->shift),
 					      CDC_RX_PATH_CLK_EN_MASK, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift),
 					      CDC_RX_RXn_SIDETONE_EN_MASK, 0);
 		rx_macro_enable_interp_clk(component, event, w->shift);
 		break;
@@ -2801,20 +2988,34 @@ static int rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
-	SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
-			  -84, 40, digital_gain),
+static const struct snd_kcontrol_new rx_macro_def_snd_controls[] = {
 	SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_RX_RX1_RX_VOL_CTL,
 			  -84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_RX_RX2_RX_VOL_CTL,
 			  -84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
-			  -84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_RX_RX1_RX_VOL_MIX_CTL,
 			  -84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_RX_RX2_RX_VOL_MIX_CTL,
 			  -84, 40, digital_gain),
+};
+
+static const struct snd_kcontrol_new rx_macro_2_5_snd_controls[] = {
+
+	SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_2_5_RX_RX1_RX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_2_5_RX_RX2_RX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_2_5_RX_RX1_RX_VOL_MIX_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_2_5_RX_RX2_RX_VOL_MIX_CTL,
+			  -84, 40, digital_gain),
+};
 
+static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
+	SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
+			  -84, 40, digital_gain),
 	SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0,
 		rx_macro_get_compander, rx_macro_set_compander),
 	SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0,
@@ -2932,6 +3133,16 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
+static const struct snd_soc_dapm_widget rx_macro_2_5_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+			 &rx_2_5_int1_dem_inp_mux),
+};
+
+static const struct snd_soc_dapm_widget rx_macro_def_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+			 &rx_int1_dem_inp_mux),
+};
+
 static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0,
 		SND_SOC_NOPM, 0, 0),
@@ -3003,8 +3214,6 @@ static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
 
 	SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
 			 &rx_int0_dem_inp_mux),
-	SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
-			 &rx_int1_dem_inp_mux),
 
 	SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0,
 		&rx_int0_2_mux, rx_macro_enable_mix_path,
@@ -3399,32 +3608,65 @@ static const struct snd_soc_dapm_route rx_audio_map[] = {
 
 static int rx_macro_component_probe(struct snd_soc_component *component)
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+	const struct snd_soc_dapm_widget *widgets;
+	const struct snd_kcontrol_new *controls;
+	unsigned int num_controls, num_widgets;
+	int ret;
 
 	snd_soc_component_init_regmap(component, rx->regmap);
 
-	snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_SEC7,
+	snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 0),
 				      CDC_RX_DSM_OUT_DELAY_SEL_MASK,
 				      CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
-	snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_SEC7,
+	snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 1),
 				      CDC_RX_DSM_OUT_DELAY_SEL_MASK,
 				      CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
-	snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_SEC7,
+	snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 2),
 				      CDC_RX_DSM_OUT_DELAY_SEL_MASK,
 				      CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
-	snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_CFG3,
+	snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 0),
 				      CDC_RX_DC_COEFF_SEL_MASK,
 				      CDC_RX_DC_COEFF_SEL_TWO);
-	snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_CFG3,
+	snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 1),
 				      CDC_RX_DC_COEFF_SEL_MASK,
 				      CDC_RX_DC_COEFF_SEL_TWO);
-	snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_CFG3,
+	snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 2),
 				      CDC_RX_DC_COEFF_SEL_MASK,
 				      CDC_RX_DC_COEFF_SEL_TWO);
 
+	switch (rx->codec_version) {
+	case LPASS_CODEC_VERSION_1_0:
+	case LPASS_CODEC_VERSION_1_1:
+	case LPASS_CODEC_VERSION_1_2:
+	case LPASS_CODEC_VERSION_2_0:
+	case LPASS_CODEC_VERSION_2_1:
+		controls = rx_macro_def_snd_controls;
+		num_controls = ARRAY_SIZE(rx_macro_def_snd_controls);
+		widgets = rx_macro_def_dapm_widgets;
+		num_widgets = ARRAY_SIZE(rx_macro_def_dapm_widgets);
+		break;
+	case LPASS_CODEC_VERSION_2_5:
+	case LPASS_CODEC_VERSION_2_6:
+	case LPASS_CODEC_VERSION_2_7:
+	case LPASS_CODEC_VERSION_2_8:
+		controls = rx_macro_2_5_snd_controls;
+		num_controls = ARRAY_SIZE(rx_macro_2_5_snd_controls);
+		widgets = rx_macro_2_5_dapm_widgets;
+		num_widgets = ARRAY_SIZE(rx_macro_2_5_dapm_widgets);
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	rx->component = component;
 
-	return 0;
+	ret = snd_soc_add_component_controls(component, controls, num_controls);
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
 }
 
 static int swclk_gate_enable(struct clk_hw *hw)
@@ -3527,7 +3769,7 @@ static int rx_macro_probe(struct platform_device *pdev)
 	kernel_ulong_t flags;
 	struct rx_macro *rx;
 	void __iomem *base;
-	int ret;
+	int ret, def_count;
 
 	flags = (kernel_ulong_t)device_get_match_data(dev);
 
@@ -3561,17 +3803,62 @@ static int rx_macro_probe(struct platform_device *pdev)
 	if (IS_ERR(rx->pds))
 		return PTR_ERR(rx->pds);
 
+	ret = devm_add_action_or_reset(dev, lpass_macro_pds_exit_action, rx->pds);
+	if (ret)
+		return ret;
+
 	base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(base)) {
-		ret = PTR_ERR(base);
-		goto err;
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	rx->codec_version = lpass_macro_get_codec_version();
+	struct reg_default *reg_defaults __free(kfree) = NULL;
+
+	switch (rx->codec_version) {
+	case LPASS_CODEC_VERSION_1_0:
+	case LPASS_CODEC_VERSION_1_1:
+	case LPASS_CODEC_VERSION_1_2:
+	case LPASS_CODEC_VERSION_2_0:
+	case LPASS_CODEC_VERSION_2_1:
+		rx->rxn_reg_stride = 0x80;
+		def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults);
+		reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
+		if (!reg_defaults)
+			return -ENOMEM;
+		memcpy(&reg_defaults[0], rx_defaults, sizeof(rx_defaults));
+		memcpy(&reg_defaults[ARRAY_SIZE(rx_defaults)],
+				rx_pre_2_5_defaults, sizeof(rx_pre_2_5_defaults));
+		break;
+	case LPASS_CODEC_VERSION_2_5:
+	case LPASS_CODEC_VERSION_2_6:
+	case LPASS_CODEC_VERSION_2_7:
+	case LPASS_CODEC_VERSION_2_8:
+		rx->rxn_reg_stride = 0xc0;
+		def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults);
+		reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
+		if (!reg_defaults)
+			return -ENOMEM;
+		memcpy(&reg_defaults[0], rx_defaults, sizeof(rx_defaults));
+		memcpy(&reg_defaults[ARRAY_SIZE(rx_defaults)],
+				rx_2_5_defaults, sizeof(rx_2_5_defaults));
+		break;
+	default:
+		dev_err(dev, "Unsupported Codec version (%d)\n", rx->codec_version);
+		return -EINVAL;
 	}
 
-	rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config);
-	if (IS_ERR(rx->regmap)) {
-		ret = PTR_ERR(rx->regmap);
-		goto err;
-	}
+	struct regmap_config *reg_config __free(kfree) = kmemdup(&rx_regmap_config,
+								 sizeof(*reg_config),
+								 GFP_KERNEL);
+	if (!reg_config)
+		return -ENOMEM;
+
+	reg_config->reg_defaults = reg_defaults;
+	reg_config->num_reg_defaults = def_count;
+
+	rx->regmap = devm_regmap_init_mmio(dev, base, reg_config);
+	if (IS_ERR(rx->regmap))
+		return PTR_ERR(rx->regmap);
 
 	dev_set_drvdata(dev, rx);
 
@@ -3583,7 +3870,7 @@ static int rx_macro_probe(struct platform_device *pdev)
 
 	ret = clk_prepare_enable(rx->macro);
 	if (ret)
-		goto err;
+		return ret;
 
 	ret = clk_prepare_enable(rx->dcodec);
 	if (ret)
@@ -3641,8 +3928,6 @@ static int rx_macro_probe(struct platform_device *pdev)
 	clk_disable_unprepare(rx->dcodec);
 err_dcodec:
 	clk_disable_unprepare(rx->macro);
-err:
-	lpass_macro_pds_exit(rx->pds);
 
 	return ret;
 }
@@ -3656,8 +3941,6 @@ static void rx_macro_remove(struct platform_device *pdev)
 	clk_disable_unprepare(rx->fsgen);
 	clk_disable_unprepare(rx->macro);
 	clk_disable_unprepare(rx->dcodec);
-
-	lpass_macro_pds_exit(rx->pds);
 }
 
 static const struct of_device_id rx_macro_dt_match[] = {
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index c98b0b747a92513636a93dc09db6b079b6ccb74c..209c12ec16ddf1fca0aa59fc413e4ab00e200bfe 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -1167,7 +1167,7 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int tx_macro_get_channel_map(struct snd_soc_dai *dai,
+static int tx_macro_get_channel_map(const struct snd_soc_dai *dai,
 				    unsigned int *tx_num, unsigned int *tx_slot,
 				    unsigned int *rx_num, unsigned int *rx_slot)
 {
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 6eceeff10bf6dca64fa39960499ca402e62402bd..b852cc7ffad9d9417897acbf79fa64e6a9b58dbe 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -892,7 +892,7 @@ static int va_macro_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int va_macro_get_channel_map(struct snd_soc_dai *dai,
+static int va_macro_get_channel_map(const struct snd_soc_dai *dai,
 				    unsigned int *tx_num, unsigned int *tx_slot,
 				    unsigned int *rx_num, unsigned int *rx_slot)
 {
@@ -1461,6 +1461,33 @@ static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
 	return dmic_sample_rate;
 }
 
+static void va_macro_set_lpass_codec_version(struct va_macro *va)
+{
+	int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0;
+	int version = LPASS_CODEC_VERSION_UNKNOWN;
+
+	regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &core_id_0);
+	regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &core_id_1);
+	regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_2, &core_id_2);
+
+	if ((core_id_0 == 0x01) && (core_id_1 == 0x0F))
+		version = LPASS_CODEC_VERSION_2_0;
+	if ((core_id_0 == 0x02) && (core_id_1 == 0x0E))
+		version = LPASS_CODEC_VERSION_2_1;
+	if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x50 || core_id_2 == 0x51))
+		version = LPASS_CODEC_VERSION_2_5;
+	if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x60 || core_id_2 == 0x61))
+		version = LPASS_CODEC_VERSION_2_6;
+	if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x70 || core_id_2 == 0x71))
+		version = LPASS_CODEC_VERSION_2_7;
+	if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x80 || core_id_2 == 0x81))
+		version = LPASS_CODEC_VERSION_2_8;
+
+	lpass_macro_set_codec_version(version);
+
+	dev_dbg(va->dev, "LPASS Codec Version %s\n", lpass_macro_get_codec_version_string(version));
+}
+
 static int va_macro_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1554,6 +1581,8 @@ static int va_macro_probe(struct platform_device *pdev)
 			goto err_npl;
 	}
 
+	va_macro_set_lpass_codec_version(va);
+
 	if (va->has_swr_master) {
 		/* Set default CLK div to 1 */
 		regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0,
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 6ce309980cd10e200dc62a1941b07f6f7728d3cd..73a5882894080019b2a6330c5e7258dd1de3b28a 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 
+#include <linux/cleanup.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -44,11 +45,7 @@
 #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_INP0_SEL_MASK	GENMASK(2, 0)
-#define CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK	GENMASK(5, 3)
 #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1		(0x0104)
-#define CDC_WSA_RX_INTX_2_SEL_MASK		GENMASK(2, 0)
-#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK	GENMASK(5, 3)
 #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)
@@ -173,22 +170,7 @@
 #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)
+/* CDC_WSA_COMPANDER1_CTLx and CDC_WSA_SOFTCLIPx differ per LPASS codec versions */
 #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)
@@ -217,6 +199,65 @@
 #define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO	(0x0760)
 #define WSA_MAX_OFFSET				(0x0760)
 
+/* LPASS codec version <=2.4 register offsets */
+#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)
+
+/* LPASS codec version >=2.5 register offsets */
+#define CDC_WSA_TOP_FS_UNGATE			(0x00AC)
+#define CDC_WSA_TOP_GRP_SEL			(0x00B0)
+#define CDC_WSA_TOP_FS_UNGATE2			(0x00DC)
+#define CDC_2_5_WSA_COMPANDER0_CTL8		(0x05A0)
+#define CDC_2_5_WSA_COMPANDER0_CTL9		(0x05A4)
+#define CDC_2_5_WSA_COMPANDER0_CTL10		(0x05A8)
+#define CDC_2_5_WSA_COMPANDER0_CTL11		(0x05AC)
+#define CDC_2_5_WSA_COMPANDER0_CTL12		(0x05B0)
+#define CDC_2_5_WSA_COMPANDER0_CTL13		(0x05B4)
+#define CDC_2_5_WSA_COMPANDER0_CTL14		(0x05B8)
+#define CDC_2_5_WSA_COMPANDER0_CTL15		(0x05BC)
+#define CDC_2_5_WSA_COMPANDER0_CTL16		(0x05C0)
+#define CDC_2_5_WSA_COMPANDER0_CTL17		(0x05C4)
+#define CDC_2_5_WSA_COMPANDER0_CTL18		(0x05C8)
+#define CDC_2_5_WSA_COMPANDER0_CTL19		(0x05CC)
+#define CDC_2_5_WSA_COMPANDER1_CTL0		(0x05E0)
+#define CDC_2_5_WSA_COMPANDER1_CTL1		(0x05E4)
+#define CDC_2_5_WSA_COMPANDER1_CTL2		(0x05E8)
+#define CDC_2_5_WSA_COMPANDER1_CTL3		(0x05EC)
+#define CDC_2_5_WSA_COMPANDER1_CTL4		(0x05F0)
+#define CDC_2_5_WSA_COMPANDER1_CTL5		(0x05F4)
+#define CDC_2_5_WSA_COMPANDER1_CTL6		(0x05F8)
+#define CDC_2_5_WSA_COMPANDER1_CTL7		(0x05FC)
+#define CDC_2_5_WSA_COMPANDER1_CTL8		(0x0600)
+#define CDC_2_5_WSA_COMPANDER1_CTL9		(0x0604)
+#define CDC_2_5_WSA_COMPANDER1_CTL10		(0x0608)
+#define CDC_2_5_WSA_COMPANDER1_CTL11		(0x060C)
+#define CDC_2_5_WSA_COMPANDER1_CTL12		(0x0610)
+#define CDC_2_5_WSA_COMPANDER1_CTL13		(0x0614)
+#define CDC_2_5_WSA_COMPANDER1_CTL14		(0x0618)
+#define CDC_2_5_WSA_COMPANDER1_CTL15		(0x061C)
+#define CDC_2_5_WSA_COMPANDER1_CTL16		(0x0620)
+#define CDC_2_5_WSA_COMPANDER1_CTL17		(0x0624)
+#define CDC_2_5_WSA_COMPANDER1_CTL18		(0x0628)
+#define CDC_2_5_WSA_COMPANDER1_CTL19		(0x062C)
+#define CDC_2_5_WSA_SOFTCLIP0_CRC		(0x0640)
+#define CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL	(0x0644)
+#define CDC_2_5_WSA_SOFTCLIP1_CRC		(0x0660)
+#define CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL	(0x0664)
+
 #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)
@@ -235,11 +276,8 @@
 #define NUM_INTERPOLATORS 2
 #define WSA_NUM_CLKS_MAX	5
 #define WSA_MACRO_MCLK_FREQ 19200000
-#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
@@ -335,12 +373,34 @@ enum {
 	WSA_MACRO_MAX_DAIS,
 };
 
+/**
+ * struct wsa_reg_layout - Register layout differences
+ * @rx_intx_1_mix_inp0_sel_mask: register mask for RX_INTX_1_MIX_INP0_SEL_MASK
+ * @rx_intx_1_mix_inp1_sel_mask: register mask for RX_INTX_1_MIX_INP1_SEL_MASK
+ * @rx_intx_1_mix_inp2_sel_mask: register mask for RX_INTX_1_MIX_INP2_SEL_MASK
+ * @rx_intx_2_sel_mask: register mask for RX_INTX_2_SEL_MASK
+ * @compander1_reg_offset: offset between compander registers (compander1 - compander0)
+ * @softclip0_reg_base: base address of softclip0 register
+ * @softclip1_reg_offset: offset between compander registers (softclip1 - softclip0)
+ */
+struct wsa_reg_layout {
+	unsigned int rx_intx_1_mix_inp0_sel_mask;
+	unsigned int rx_intx_1_mix_inp1_sel_mask;
+	unsigned int rx_intx_1_mix_inp2_sel_mask;
+	unsigned int rx_intx_2_sel_mask;
+	unsigned int compander1_reg_offset;
+	unsigned int softclip0_reg_base;
+	unsigned int softclip1_reg_offset;
+};
+
 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;
+	enum lpass_codec_version codec_version;
+	const struct wsa_reg_layout *reg_layout;
 	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];
@@ -359,16 +419,44 @@ struct wsa_macro {
 };
 #define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw)
 
+static const struct wsa_reg_layout wsa_codec_v2_1 = {
+	.rx_intx_1_mix_inp0_sel_mask		= GENMASK(2, 0),
+	.rx_intx_1_mix_inp1_sel_mask		= GENMASK(5, 3),
+	.rx_intx_1_mix_inp2_sel_mask		= GENMASK(5, 3),
+	.rx_intx_2_sel_mask			= GENMASK(2, 0),
+	.compander1_reg_offset			= 0x40,
+	.softclip0_reg_base			= 0x600,
+	.softclip1_reg_offset			= 0x40,
+};
+
+static const struct wsa_reg_layout wsa_codec_v2_5 = {
+	.rx_intx_1_mix_inp0_sel_mask		= GENMASK(3, 0),
+	.rx_intx_1_mix_inp1_sel_mask		= GENMASK(7, 4),
+	.rx_intx_1_mix_inp2_sel_mask		= GENMASK(7, 4),
+	.rx_intx_2_sel_mask			= GENMASK(3, 0),
+	.compander1_reg_offset			= 0x60,
+	.softclip0_reg_base			= 0x640,
+	.softclip1_reg_offset			= 0x20,
+};
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
 
-static const char *const rx_text[] = {
+static const char *const rx_text_v2_1[] = {
 	"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1"
 };
 
-static const char *const rx_mix_text[] = {
+static const char *const rx_text_v2_5[] = {
+	"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1"
+};
+
+static const char *const rx_mix_text_v2_1[] = {
 	"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1"
 };
 
+static const char *const rx_mix_text_v2_5[] = {
+	"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8"
+};
+
 static const char *const rx_mix_ec_text[] = {
 	"ZERO", "RX_MIX_TX0", "RX_MIX_TX1"
 };
@@ -390,68 +478,124 @@ 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 =
+static const struct soc_enum rx0_prim_inp0_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
-		0, 7, rx_text);
+		0, 7, rx_text_v2_1);
 
-static const struct soc_enum rx0_prim_inp1_chain_enum =
+static const struct soc_enum rx0_prim_inp1_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
-		3, 7, rx_text);
+		3, 7, rx_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp2_chain_enum_v2_1 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+		3, 7, rx_text_v2_1);
 
-static const struct soc_enum rx0_prim_inp2_chain_enum =
+static const struct soc_enum rx0_mix_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
-		3, 7, rx_text);
+		0, 5, rx_mix_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp0_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+		0, 12, rx_text_v2_5);
+
+static const struct soc_enum rx0_prim_inp1_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+		4, 12, rx_text_v2_5);
 
-static const struct soc_enum rx0_mix_chain_enum =
+static const struct soc_enum rx0_prim_inp2_chain_enum_v2_5 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
-		0, 5, rx_mix_text);
+		4, 12, rx_text_v2_5);
+
+static const struct soc_enum rx0_mix_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+		0, 10, rx_mix_text_v2_5);
 
 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_inp0_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_mix_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_1);
 
-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_inp0_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_5);
 
-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_prim_inp1_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_5);
 
-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_prim_inp2_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx0_mix_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_5);
 
 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 =
+static const struct soc_enum rx1_prim_inp0_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
-		0, 7, rx_text);
+		0, 7, rx_text_v2_1);
 
-static const struct soc_enum rx1_prim_inp1_chain_enum =
+static const struct soc_enum rx1_prim_inp1_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
-		3, 7, rx_text);
+		3, 7, rx_text_v2_1);
 
-static const struct soc_enum rx1_prim_inp2_chain_enum =
+static const struct soc_enum rx1_prim_inp2_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
-		3, 7, rx_text);
+		3, 7, rx_text_v2_1);
 
-static const struct soc_enum rx1_mix_chain_enum =
+static const struct soc_enum rx1_mix_chain_enum_v2_1 =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
-		0, 5, rx_mix_text);
+		0, 5, rx_mix_text_v2_1);
 
-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 soc_enum rx1_prim_inp0_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+		0, 12, rx_text_v2_5);
 
-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 soc_enum rx1_prim_inp1_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+		4, 12, rx_text_v2_5);
 
-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 soc_enum rx1_prim_inp2_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+		4, 12, rx_text_v2_5);
+
+static const struct soc_enum rx1_mix_chain_enum_v2_5 =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+		0, 10, rx_mix_text_v2_5);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_mix_mux_v2_1 =
+	SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_5);
 
-static const struct snd_kcontrol_new rx1_mix_mux =
-	SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum);
+static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx1_mix_mux_v2_5 =
+	SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_5);
 
 static const struct soc_enum rx_mix_ec0_enum =
 	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
@@ -490,14 +634,6 @@ static const struct reg_default wsa_defaults[] = {
 	{ 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},
@@ -562,18 +698,6 @@ static const struct reg_default wsa_defaults[] = {
 	{ 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},
@@ -598,6 +722,79 @@ static const struct reg_default wsa_defaults[] = {
 	{ CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00},
 };
 
+static const struct reg_default wsa_defaults_v2_1[] = {
+	{ 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_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},
+};
+
+static const struct reg_default wsa_defaults_v2_5[] = {
+	{ CDC_WSA_TOP_FS_UNGATE, 0xFF},
+	{ CDC_WSA_TOP_GRP_SEL, 0x08},
+	{ CDC_WSA_TOP_FS_UNGATE2, 0x1F},
+	{ CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x04},
+	{ CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x02},
+	{ CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x04},
+	{ CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x02},
+	{ CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x04},
+	{ CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x02},
+	{ CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x04},
+	{ CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x02},
+	{ CDC_2_5_WSA_COMPANDER0_CTL8, 0x00},
+	{ CDC_2_5_WSA_COMPANDER0_CTL9, 0x00},
+	{ CDC_2_5_WSA_COMPANDER0_CTL10, 0x06},
+	{ CDC_2_5_WSA_COMPANDER0_CTL11, 0x12},
+	{ CDC_2_5_WSA_COMPANDER0_CTL12, 0x1E},
+	{ CDC_2_5_WSA_COMPANDER0_CTL13, 0x24},
+	{ CDC_2_5_WSA_COMPANDER0_CTL14, 0x24},
+	{ CDC_2_5_WSA_COMPANDER0_CTL15, 0x24},
+	{ CDC_2_5_WSA_COMPANDER0_CTL16, 0x00},
+	{ CDC_2_5_WSA_COMPANDER0_CTL17, 0x24},
+	{ CDC_2_5_WSA_COMPANDER0_CTL18, 0x2A},
+	{ CDC_2_5_WSA_COMPANDER0_CTL19, 0x16},
+	{ CDC_2_5_WSA_COMPANDER1_CTL0, 0x60},
+	{ CDC_2_5_WSA_COMPANDER1_CTL1, 0xDB},
+	{ CDC_2_5_WSA_COMPANDER1_CTL2, 0xFF},
+	{ CDC_2_5_WSA_COMPANDER1_CTL3, 0x35},
+	{ CDC_2_5_WSA_COMPANDER1_CTL4, 0xFF},
+	{ CDC_2_5_WSA_COMPANDER1_CTL5, 0x00},
+	{ CDC_2_5_WSA_COMPANDER1_CTL6, 0x01},
+	{ CDC_2_5_WSA_COMPANDER1_CTL7, 0x28},
+	{ CDC_2_5_WSA_COMPANDER1_CTL8, 0x00},
+	{ CDC_2_5_WSA_COMPANDER1_CTL9, 0x00},
+	{ CDC_2_5_WSA_COMPANDER1_CTL10, 0x06},
+	{ CDC_2_5_WSA_COMPANDER1_CTL11, 0x12},
+	{ CDC_2_5_WSA_COMPANDER1_CTL12, 0x1E},
+	{ CDC_2_5_WSA_COMPANDER1_CTL13, 0x24},
+	{ CDC_2_5_WSA_COMPANDER1_CTL14, 0x24},
+	{ CDC_2_5_WSA_COMPANDER1_CTL15, 0x24},
+	{ CDC_2_5_WSA_COMPANDER1_CTL16, 0x00},
+	{ CDC_2_5_WSA_COMPANDER1_CTL17, 0x24},
+	{ CDC_2_5_WSA_COMPANDER1_CTL18, 0x2A},
+	{ CDC_2_5_WSA_COMPANDER1_CTL19, 0x16},
+	{ CDC_2_5_WSA_SOFTCLIP0_CRC, 0x00},
+	{ CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+	{ CDC_2_5_WSA_SOFTCLIP1_CRC, 0x00},
+	{ CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+};
+
 static bool wsa_is_wronly_register(struct device *dev,
 					unsigned int reg)
 {
@@ -611,8 +808,77 @@ static bool wsa_is_wronly_register(struct device *dev,
 	return false;
 }
 
+static bool wsa_is_rw_register_v2_1(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	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:
+		return true;
+	}
+
+	return false;
+}
+
+static bool wsa_is_rw_register_v2_5(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_WSA_TOP_FS_UNGATE:
+	case CDC_WSA_TOP_GRP_SEL:
+	case CDC_WSA_TOP_FS_UNGATE2:
+	case CDC_2_5_WSA_COMPANDER0_CTL8:
+	case CDC_2_5_WSA_COMPANDER0_CTL9:
+	case CDC_2_5_WSA_COMPANDER0_CTL10:
+	case CDC_2_5_WSA_COMPANDER0_CTL11:
+	case CDC_2_5_WSA_COMPANDER0_CTL12:
+	case CDC_2_5_WSA_COMPANDER0_CTL13:
+	case CDC_2_5_WSA_COMPANDER0_CTL14:
+	case CDC_2_5_WSA_COMPANDER0_CTL15:
+	case CDC_2_5_WSA_COMPANDER0_CTL16:
+	case CDC_2_5_WSA_COMPANDER0_CTL17:
+	case CDC_2_5_WSA_COMPANDER0_CTL18:
+	case CDC_2_5_WSA_COMPANDER0_CTL19:
+	case CDC_2_5_WSA_COMPANDER1_CTL0:
+	case CDC_2_5_WSA_COMPANDER1_CTL1:
+	case CDC_2_5_WSA_COMPANDER1_CTL2:
+	case CDC_2_5_WSA_COMPANDER1_CTL3:
+	case CDC_2_5_WSA_COMPANDER1_CTL4:
+	case CDC_2_5_WSA_COMPANDER1_CTL5:
+	case CDC_2_5_WSA_COMPANDER1_CTL7:
+	case CDC_2_5_WSA_COMPANDER1_CTL8:
+	case CDC_2_5_WSA_COMPANDER1_CTL9:
+	case CDC_2_5_WSA_COMPANDER1_CTL10:
+	case CDC_2_5_WSA_COMPANDER1_CTL11:
+	case CDC_2_5_WSA_COMPANDER1_CTL12:
+	case CDC_2_5_WSA_COMPANDER1_CTL13:
+	case CDC_2_5_WSA_COMPANDER1_CTL14:
+	case CDC_2_5_WSA_COMPANDER1_CTL15:
+	case CDC_2_5_WSA_COMPANDER1_CTL16:
+	case CDC_2_5_WSA_COMPANDER1_CTL17:
+	case CDC_2_5_WSA_COMPANDER1_CTL18:
+	case CDC_2_5_WSA_COMPANDER1_CTL19:
+	case CDC_2_5_WSA_SOFTCLIP0_CRC:
+	case CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+	case CDC_2_5_WSA_SOFTCLIP1_CRC:
+	case CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+		return true;
+	}
+
+	return false;
+}
+
 static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
 {
+	struct wsa_macro *wsa = dev_get_drvdata(dev);
+
 	switch (reg) {
 	case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL:
 	case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL:
@@ -702,17 +968,6 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
 	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:
@@ -728,7 +983,10 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
 		return true;
 	}
 
-	return false;
+	if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+		return wsa_is_rw_register_v2_5(dev, reg);
+
+	return wsa_is_rw_register_v2_1(dev, reg);
 }
 
 static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
@@ -742,8 +1000,30 @@ static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
 	return ret;
 }
 
+static bool wsa_is_readable_register_v2_1(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_WSA_COMPANDER1_CTL6:
+		return true;
+	}
+
+	return wsa_is_rw_register(dev, reg);
+}
+
+static bool wsa_is_readable_register_v2_5(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_2_5_WSA_COMPANDER1_CTL6:
+		return true;
+	}
+
+	return wsa_is_rw_register(dev, reg);
+}
+
 static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
 {
+	struct wsa_macro *wsa = dev_get_drvdata(dev);
+
 	switch (reg) {
 	case CDC_WSA_INTR_CTRL_CLR_COMMIT:
 	case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
@@ -751,7 +1031,6 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int 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:
@@ -765,17 +1044,41 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
 		return true;
 	}
 
-	return wsa_is_rw_register(dev, reg);
+	if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+		return wsa_is_readable_register_v2_5(dev, reg);
+
+	return wsa_is_readable_register_v2_1(dev, reg);
+}
+
+static bool wsa_is_volatile_register_v2_1(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_WSA_COMPANDER1_CTL6:
+		return true;
+	}
+
+	return false;
+}
+
+static bool wsa_is_volatile_register_v2_5(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_2_5_WSA_COMPANDER1_CTL6:
+		return true;
+	}
+
+	return false;
 }
 
 static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
 {
+	struct wsa_macro *wsa = dev_get_drvdata(dev);
+
 	/* 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:
@@ -788,7 +1091,11 @@ static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
 	case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
 		return true;
 	}
-	return false;
+
+	if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+		return wsa_is_volatile_register_v2_5(dev, reg);
+
+	return wsa_is_volatile_register_v2_1(dev, reg);
 }
 
 static const struct regmap_config wsa_regmap_config = {
@@ -797,8 +1104,7 @@ static const struct regmap_config wsa_regmap_config = {
 	.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),
+	/* .reg_defaults and .num_reg_defaults set in probe() */
 	.max_register = WSA_MAX_OFFSET,
 	.writeable_reg = wsa_is_writeable_register,
 	.volatile_reg = wsa_is_volatile_register,
@@ -872,11 +1178,11 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
 		for (j = 0; j < NUM_INTERPOLATORS; j++) {
 			int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
 			inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0, 
-								CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
-			inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0, 
-								CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
+								wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask);
+			inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+								wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask);
 			inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
-								CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
+								wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask);
 
 			if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
 			    (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
@@ -917,7 +1223,7 @@ static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
 		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_field(component, int_mux_cfg1,
-									CDC_WSA_RX_INTX_2_SEL_MASK);
+									wsa->reg_layout->rx_intx_2_sel_mask);
 
 			if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
 				int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL +
@@ -992,7 +1298,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+static int wsa_macro_get_channel_map(const struct snd_soc_dai *dai,
 				     unsigned int *tx_num, unsigned int *tx_slot,
 				     unsigned int *rx_num, unsigned int *rx_slot)
 {
@@ -1300,7 +1606,7 @@ static int wsa_macro_config_compander(struct snd_soc_component *component,
 		return 0;
 
 	comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 +
-					(comp * WSA_MACRO_RX_COMP_OFFSET);
+					(comp * wsa->reg_layout->compander1_reg_offset);
 	rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 +
 					(comp * WSA_MACRO_RX_PATH_OFFSET);
 
@@ -1346,8 +1652,8 @@ static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component,
 					 int path,
 					 bool enable)
 {
-	u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC +
-			(path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+	u16 softclip_clk_reg = wsa->reg_layout->softclip0_reg_base +
+			(path * wsa->reg_layout->softclip1_reg_offset);
 	u8 softclip_mux_mask = (1 << path);
 	u8 softclip_mux_value = (1 << path);
 
@@ -1392,7 +1698,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component,
 		return 0;
 
 	softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL +
-				(softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+				(softclip_path * wsa->reg_layout->softclip1_reg_offset);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		/* Enable Softclip clock and mux */
@@ -1417,6 +1723,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component,
 static bool wsa_macro_adie_lb(struct snd_soc_component *component,
 			      int interp_idx)
 {
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
 	u16 int_mux_cfg0,  int_mux_cfg1;
 	u8 int_n_inp0, int_n_inp1, int_n_inp2;
 
@@ -1424,19 +1731,19 @@ static bool wsa_macro_adie_lb(struct snd_soc_component *component,
 	int_mux_cfg1 = int_mux_cfg0 + 4;
 
 	int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
-						  CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
+						  wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask);
 	if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
 		int_n_inp0 == INTn_1_INP_SEL_DEC1)
 		return true;
 
 	int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
-						  CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
+						  wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask);
 	if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
 		int_n_inp1 == INTn_1_INP_SEL_DEC1)
 		return true;
 
 	int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
-						  CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
+						  wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask);
 	if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
 		int_n_inp2 == INTn_1_INP_SEL_DEC1)
 		return true;
@@ -2074,19 +2381,6 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
 	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", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
-			   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", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
-			   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,
@@ -2137,6 +2431,36 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_1[] = {
+	SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_1),
+	SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_1),
+	SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_1),
+	SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
+			   0, &rx0_mix_mux_v2_1, 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_v2_1),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_1),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_1),
+	SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
+			   0, &rx1_mix_mux_v2_1, wsa_macro_enable_mix_path,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_5[] = {
+	SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_5),
+	SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_5),
+	SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_5),
+	SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
+			   0, &rx0_mix_mux_v2_5, 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_v2_5),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_5),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_5),
+	SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
+			   0, &rx1_mix_mux_v2_5, wsa_macro_enable_mix_path,
+			   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"},
@@ -2282,7 +2606,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
 
 static int wsa_macro_component_probe(struct snd_soc_component *comp)
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(comp);
 	struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp);
+	const struct snd_soc_dapm_widget *widgets;
+	unsigned int num_widgets;
 
 	snd_soc_component_init_regmap(comp, wsa->regmap);
 
@@ -2299,7 +2626,27 @@ static int wsa_macro_component_probe(struct snd_soc_component *comp)
 
 	wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1);
 
-	return 0;
+	switch (wsa->codec_version) {
+	case LPASS_CODEC_VERSION_1_0:
+	case LPASS_CODEC_VERSION_1_1:
+	case LPASS_CODEC_VERSION_1_2:
+	case LPASS_CODEC_VERSION_2_0:
+	case LPASS_CODEC_VERSION_2_1:
+		widgets = wsa_macro_dapm_widgets_v2_1;
+		num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_1);
+		break;
+	case LPASS_CODEC_VERSION_2_5:
+	case LPASS_CODEC_VERSION_2_6:
+	case LPASS_CODEC_VERSION_2_7:
+	case LPASS_CODEC_VERSION_2_8:
+		widgets = wsa_macro_dapm_widgets_v2_5;
+		num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_5);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
 }
 
 static int swclk_gate_enable(struct clk_hw *hw)
@@ -2382,7 +2729,7 @@ static int wsa_macro_probe(struct platform_device *pdev)
 	struct wsa_macro *wsa;
 	kernel_ulong_t flags;
 	void __iomem *base;
-	int ret;
+	int ret, def_count;
 
 	flags = (kernel_ulong_t)device_get_match_data(dev);
 
@@ -2416,7 +2763,56 @@ static int wsa_macro_probe(struct platform_device *pdev)
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config);
+	wsa->codec_version = lpass_macro_get_codec_version();
+	struct reg_default *reg_defaults __free(kfree) = NULL;
+
+	switch (wsa->codec_version) {
+	case LPASS_CODEC_VERSION_1_0:
+	case LPASS_CODEC_VERSION_1_1:
+	case LPASS_CODEC_VERSION_1_2:
+	case LPASS_CODEC_VERSION_2_0:
+	case LPASS_CODEC_VERSION_2_1:
+		wsa->reg_layout = &wsa_codec_v2_1;
+		def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_1);
+		reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults),
+					     GFP_KERNEL);
+		if (!reg_defaults)
+			return -ENOMEM;
+		memcpy(&reg_defaults[0], wsa_defaults, sizeof(wsa_defaults));
+		memcpy(&reg_defaults[ARRAY_SIZE(wsa_defaults)],
+		       wsa_defaults_v2_1, sizeof(wsa_defaults_v2_1));
+		break;
+
+	case LPASS_CODEC_VERSION_2_5:
+	case LPASS_CODEC_VERSION_2_6:
+	case LPASS_CODEC_VERSION_2_7:
+	case LPASS_CODEC_VERSION_2_8:
+		wsa->reg_layout = &wsa_codec_v2_5;
+		def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_5);
+		reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults),
+					     GFP_KERNEL);
+		if (!reg_defaults)
+			return -ENOMEM;
+		memcpy(&reg_defaults[0], wsa_defaults, sizeof(wsa_defaults));
+		memcpy(&reg_defaults[ARRAY_SIZE(wsa_defaults)],
+		       wsa_defaults_v2_5, sizeof(wsa_defaults_v2_5));
+		break;
+
+	default:
+		dev_err(dev, "Unsupported Codec version (%d)\n", wsa->codec_version);
+		return -EINVAL;
+	}
+
+	struct regmap_config *reg_config __free(kfree) = kmemdup(&wsa_regmap_config,
+								 sizeof(*reg_config),
+								 GFP_KERNEL);
+	if (!reg_config)
+		return -ENOMEM;
+
+	reg_config->reg_defaults = reg_defaults;
+	reg_config->num_reg_defaults = def_count;
+
+	wsa->regmap = devm_regmap_init_mmio(dev, base, reg_config);
 	if (IS_ERR(wsa->regmap))
 		return PTR_ERR(wsa->regmap);
 
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 8b56ee550c09e2c784385ac10dd4c38d442a4434..8b0645c63462070d6d584c7d43d96d21f3dd6cfb 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1318,6 +1318,7 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
                                   enum snd_soc_bias_level level)
 {
 	struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -1333,10 +1334,13 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
 		 */
 		if (!IS_ERR(max98088->mclk)) {
 			if (snd_soc_component_get_bias_level(component) ==
-			    SND_SOC_BIAS_ON)
+			    SND_SOC_BIAS_ON) {
 				clk_disable_unprepare(max98088->mclk);
-			else
-				clk_prepare_enable(max98088->mclk);
+			} else {
+				ret = clk_prepare_enable(max98088->mclk);
+				if (ret)
+					return ret;
+			}
 		}
 		break;
 
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 57fa2db1e14899806c4572aefe4cdd5248863e66..1bae253618fd07d2d796a47267829d42a3d14fe3 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -13,7 +13,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/time.h>
diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c
index 93412b966b33672a87d053200c3778d2519fadea..6b6a7ece4cecc3d114da276faf859c8176955300 100644
--- a/sound/soc/codecs/max98504.c
+++ b/sound/soc/codecs/max98504.c
@@ -220,8 +220,10 @@ static int max98504_set_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 static int max98504_set_channel_map(struct snd_soc_dai *dai,
-		unsigned int tx_num, unsigned int *tx_slot,
-		unsigned int rx_num, unsigned int *rx_slot)
+				    unsigned int tx_num,
+				    const unsigned int *tx_slot,
+				    unsigned int rx_num,
+				    const unsigned int *rx_slot)
 {
 	struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
 	struct regmap *map = max98504->regmap;
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index 0284e29c11d3c8bca15bbe109c38b8dd08b51b4e..9247b90d1b99e2e3a85d4abc54f2dbf55dac6516 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -96,7 +96,7 @@ struct mt6358_priv {
 
 	int wov_enabled;
 
-	unsigned int dmic_one_wire_mode;
+	int dmic_one_wire_mode;
 };
 
 int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
@@ -577,6 +577,39 @@ static int mt6358_put_wov(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int mt6358_dmic_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
+
+	ucontrol->value.integer.value[0] = priv->dmic_one_wire_mode;
+	dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+	return 0;
+}
+
+static int mt6358_dmic_mode_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
+	int enabled = ucontrol->value.integer.value[0];
+
+	if (enabled < 0 || enabled > 1)
+		return -EINVAL;
+
+	if (priv->dmic_one_wire_mode != enabled) {
+		priv->dmic_one_wire_mode = enabled;
+		dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+		return 1;
+	}
+	dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+	return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
 static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
 
@@ -599,6 +632,9 @@ static const struct snd_kcontrol_new mt6358_snd_controls[] = {
 
 	SOC_SINGLE_BOOL_EXT("Wake-on-Voice Phase2 Switch", 0,
 			    mt6358_get_wov, mt6358_put_wov),
+
+	SOC_SINGLE_BOOL_EXT("Dmic Mode Switch", 0,
+			    mt6358_dmic_mode_get, mt6358_dmic_mode_set),
 };
 
 /* MUX */
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index e6909e64dfa39d6d5e44e44e909c122c4b148d7a..e1cbaf8a944d8cf94992fbe249743a9c2d3d6259 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -14,6 +14,7 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
@@ -612,20 +613,6 @@ static const struct snd_soc_dapm_route nau8822_dapm_routes[] = {
 	{"Right DAC", NULL, "Digital Loopback"},
 };
 
-static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
-				 unsigned int freq, int dir)
-{
-	struct snd_soc_component *component = dai->component;
-	struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
-
-	nau8822->div_id = clk_id;
-	nau8822->sysclk = freq;
-	dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq,
-		clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK");
-
-	return 0;
-}
-
 static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs,
 				struct nau8822_pll *pll_param)
 {
@@ -782,6 +769,35 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	return 0;
 }
 
+static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+	unsigned long mclk_freq;
+
+	nau8822->div_id = clk_id;
+	nau8822->sysclk = freq;
+
+	if (nau8822->mclk) {
+		mclk_freq = clk_get_rate(nau8822->mclk);
+		if (mclk_freq != freq) {
+			int ret = nau8822_set_pll(dai, NAU8822_CLK_MCLK,
+				NAU8822_CLK_MCLK, mclk_freq, freq);
+			if (ret) {
+				dev_err(component->dev, "Failed to set PLL\n");
+				return ret;
+			}
+			nau8822->div_id = NAU8822_CLK_PLL;
+		}
+	}
+
+	dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq,
+		nau8822->div_id == NAU8822_CLK_PLL ? "PLL" : "MCLK");
+
+	return 0;
+}
+
 static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_component *component = dai->component;
@@ -848,7 +864,7 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_component *component = dai->component;
 	struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
-	int val_len = 0, val_rate = 0;
+	int div = 0, val_len = 0, val_rate = 0;
 	unsigned int ctrl_val, bclk_fs, bclk_div;
 
 	/* make BCLK and LRC divide configuration if the codec as master. */
@@ -915,8 +931,10 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream,
 	/* If the master clock is from MCLK, provide the runtime FS for driver
 	 * to get the master clock prescaler configuration.
 	 */
-	if (nau8822->div_id == NAU8822_CLK_MCLK)
-		nau8822_config_clkdiv(dai, 0, params_rate(params));
+	if (nau8822->div_id != NAU8822_CLK_MCLK)
+		div = nau8822->pll.mclk_scaler;
+
+	nau8822_config_clkdiv(dai, div, params_rate(params));
 
 	return 0;
 }
@@ -940,15 +958,34 @@ static int nau8822_mute(struct snd_soc_dai *dai, int mute, int direction)
 static int nau8822_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
+	struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
+		break;
+
 	case SND_SOC_BIAS_PREPARE:
+		if (nau8822->mclk &&
+			snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON) {
+			int ret = clk_prepare_enable(nau8822->mclk);
+
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to enable MCLK: %d\n", ret);
+				return ret;
+			}
+		}
+
 		snd_soc_component_update_bits(component,
 			NAU8822_REG_POWER_MANAGEMENT_1,
 			NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
+		if (nau8822->mclk &&
+			snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_OFF)
+			clk_disable_unprepare(nau8822->mclk);
+
 		snd_soc_component_update_bits(component,
 			NAU8822_REG_POWER_MANAGEMENT_1,
 			NAU8822_IOBUF_EN | NAU8822_ABIAS_EN,
@@ -1125,6 +1162,11 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
 	}
 	i2c_set_clientdata(i2c, nau8822);
 
+	nau8822->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+	if (IS_ERR(nau8822->mclk))
+		return dev_err_probe(&i2c->dev, PTR_ERR(nau8822->mclk),
+			"Error getting mclk\n");
+
 	nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config);
 	if (IS_ERR(nau8822->regmap)) {
 		ret = PTR_ERR(nau8822->regmap);
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index 6ecd46e459230dc80b24e75f5cd4a325684e7846..13fe0a091e9ed4f2f95c4b8ae8a3e26b423b9310 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -215,6 +215,7 @@ struct nau8822_pll {
 struct nau8822 {
 	struct device *dev;
 	struct regmap *regmap;
+	struct clk *mclk;
 	struct nau8822_pll pll;
 	int sysclk;
 	int div_id;
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index f92b95b21cae4b44aa1d1602b5a3bf9cd38aa131..12540397fd4d544eb6dee34a7badbb2d917785ea 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -506,6 +506,7 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
 	struct regmap *regmap = nau8824->regmap;
 	unsigned int value;
 	bool clk_fll, error;
+	int ret;
 
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		dev_dbg(nau8824->dev, "system clock control : POWER OFF\n");
@@ -520,8 +521,15 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
 		} else {
 			nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
 		}
+
+		clk_disable_unprepare(nau8824->mclk);
 	} else {
 		dev_dbg(nau8824->dev, "system clock control : POWER ON\n");
+
+		ret = clk_prepare_enable(nau8824->mclk);
+		if (ret)
+			return ret;
+
 		/* Check the clock source setting is proper or not
 		 * no matter the source is from FLL or MCLK.
 		 */
@@ -563,16 +571,21 @@ static int dmic_clock_control(struct snd_soc_dapm_widget *w,
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	int src;
+	unsigned int freq;
+
+	freq = clk_get_rate(nau8824->mclk);
+	if (!freq)
+		freq = nau8824->fs * 256;
 
 	/* The DMIC clock is gotten from system clock (256fs) divided by
 	 * DMIC_SRC (1, 2, 4, 8, 16, 32). The clock has to be equal or
 	 * less than 3.072 MHz.
 	 */
 	for (src = 0; src < 5; src++) {
-		if ((0x1 << (8 - src)) * nau8824->fs <= DMIC_CLK)
+		if (freq / (0x1 << src) <= DMIC_CLK)
 			break;
 	}
-	dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, nau8824->fs * 256);
+	dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, freq);
 	regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
 		NAU8824_CLK_DMIC_SRC_MASK, (src << NAU8824_CLK_DMIC_SRC_SFT));
 
@@ -1871,6 +1884,10 @@ static int nau8824_read_device_properties(struct device *dev,
 	if (ret)
 		nau8824->jack_eject_debounce = 1;
 
+	nau8824->mclk = devm_clk_get_optional(dev, "mclk");
+	if (IS_ERR(nau8824->mclk))
+		return PTR_ERR(nau8824->mclk);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
index 5fcfc43dfc85587c3353b566a7f8beb12838d693..d8e19515133c803c20dfcb167f073515daa6f39a 100644
--- a/sound/soc/codecs/nau8824.h
+++ b/sound/soc/codecs/nau8824.h
@@ -434,6 +434,7 @@ struct nau8824 {
 	struct snd_soc_jack *jack;
 	struct work_struct jdet_work;
 	struct semaphore jd_sem;
+	struct clk *mclk;
 	int fs;
 	int irq;
 	int resume_lock;
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 9d6431338fb7153cbe47b994a79220dfa5a5561a..fac0617ab95b65ca07c689d072c039bac9b8a9de 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -11,7 +11,6 @@
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 
@@ -563,7 +562,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static u64 pcm3168a_dai_formats[] = {
+static const u64 pcm3168a_dai_formats[] = {
 	/*
 	 * Select below from Sound Card, not here
 	 *	SND_SOC_DAIFMT_CBC_CFC
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 4be476a280e10ba30c5d764383d4b4646ff857b3..92bcf5179779ff4ef702ac75e7b15fb72e4ff11c 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -39,6 +39,7 @@ static const struct i2c_device_id pcm512x_i2c_id[] = {
 	{ "pcm5122", },
 	{ "pcm5141", },
 	{ "pcm5142", },
+	{ "pcm5242", },
 	{ "tas5754", },
 	{ "tas5756", },
 	{ }
@@ -51,6 +52,7 @@ static const struct of_device_id pcm512x_of_match[] = {
 	{ .compatible = "ti,pcm5122", },
 	{ .compatible = "ti,pcm5141", },
 	{ .compatible = "ti,pcm5142", },
+	{ .compatible = "ti,pcm5242", },
 	{ .compatible = "ti,tas5754", },
 	{ .compatible = "ti,tas5756", },
 	{ }
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 4d29e71963800b1dd80aca3af4785b5f4a9ef3a0..6629b862f47d055699be59143fe5e9dcaff61af8 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -36,6 +36,7 @@ static const struct spi_device_id pcm512x_spi_id[] = {
 	{ "pcm5122", },
 	{ "pcm5141", },
 	{ "pcm5142", },
+	{ "pcm5242", },
 	{ },
 };
 MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
@@ -45,6 +46,7 @@ static const struct of_device_id pcm512x_of_match[] = {
 	{ .compatible = "ti,pcm5122", },
 	{ .compatible = "ti,pcm5141", },
 	{ .compatible = "ti,pcm5142", },
+	{ .compatible = "ti,pcm5242", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index 86e126783a1df13c3f8dea7ffc08e7ee5cc67218..6641e7c1ddf444a84d2d590c59b82d975f2752d4 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -18,6 +18,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of_irq.h>
+#include <linux/of_address.h>
 #include <linux/regmap.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -57,12 +58,6 @@ static const char *const pcmdev_ctrl_name[] = {
 	"%s i2c%d Dev%d Ch%d Fine Volume",
 };
 
-static const char *const pcmdev_ctrl_name_with_prefix[] = {
-	"%s Dev%d Ch%d Ana Volume",
-	"%s Dev%d Ch%d Digi Volume",
-	"%s Dev%d Ch%d Fine Volume",
-};
-
 static const struct pcmdevice_mixer_control adc5120_analog_gain_ctl[] = {
 	{
 		.shift = 1,
@@ -1365,10 +1360,7 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev,
 
 	name_id = pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl_name_id;
 
-	if (comp->name_prefix)
-		ctrl_name = pcmdev_ctrl_name_with_prefix[name_id];
-	else
-		ctrl_name = pcmdev_ctrl_name[name_id];
+	ctrl_name = pcmdev_ctrl_name[name_id];
 
 	for (chn = 1; chn <= nr_chn; chn++) {
 		name = devm_kzalloc(pcm_dev->dev,
@@ -1377,13 +1369,9 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev,
 			ret = -ENOMEM;
 			goto out;
 		}
-		if (comp->name_prefix)
-			scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
-				ctrl_name, comp->name_prefix, dev_no, chn);
-		else
-			scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
-				ctrl_name, pcm_dev->upper_dev_name, adap->nr,
-				dev_no, chn);
+		scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+			ctrl_name, pcm_dev->upper_dev_name, adap->nr,
+			dev_no, chn);
 		pcmdev_controls[mix_index].tlv.p =
 			pcmdev_gain_ctl_info[id][ctl_id].gain;
 		pcmdev_ctrl = devm_kmemdup(pcm_dev->dev,
@@ -1437,13 +1425,8 @@ static int pcmdev_profile_ctrl_add(struct pcmdevice_priv *pcm_dev)
 	if (!name)
 		return -ENOMEM;
 
-	if (comp->name_prefix)
-		scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
-			"%s Profile id", comp->name_prefix);
-	else
-		scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
-			"%s i2c%d Profile id", pcm_dev->upper_dev_name,
-			adap->nr);
+	scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+		"%s i2c%d Profile id", pcm_dev->upper_dev_name, adap->nr);
 	pcmdev_ctrl->name = name;
 	pcmdev_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	pcmdev_ctrl->info = pcmdevice_info_profile;
@@ -2081,16 +2064,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
 	struct device_node *np;
 	unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES];
 	int ret = 0, i = 0, ndev = 0;
-#ifdef CONFIG_OF
-	const __be32 *reg, *reg_end;
-	int len, sw, aw;
-#endif
 
 	pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL);
-	if (!pcm_dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!pcm_dev)
+		return -ENOMEM;
 
 	pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0;
 
@@ -2120,27 +2097,19 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
 	i2c_set_clientdata(i2c, pcm_dev);
 	mutex_init(&pcm_dev->codec_lock);
 	np = pcm_dev->dev->of_node;
-#ifdef CONFIG_OF
-	aw = of_n_addr_cells(np);
-	sw = of_n_size_cells(np);
-	if (sw == 0) {
-		reg = (const __be32 *)of_get_property(np,
-			"reg", &len);
-		reg_end = reg + len/sizeof(*reg);
-		ndev = 0;
-		do {
-			dev_addrs[ndev] = of_read_number(reg, aw);
-			reg += aw;
-			ndev++;
-		} while (reg < reg_end);
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		u64 addr;
+
+		for (i = 0; i < PCMDEVICE_MAX_I2C_DEVICES; i++) {
+			if (of_property_read_reg(np, i, &addr, NULL))
+				break;
+			dev_addrs[ndev++] = addr;
+		}
 	} else {
 		ndev = 1;
 		dev_addrs[0] = i2c->addr;
 	}
-#else
-	ndev = 1;
-	dev_addrs[0] = i2c->addr;
-#endif
 	pcm_dev->irq_info.gpio = of_irq_get(np, 0);
 
 	for (i = 0; i < ndev; i++)
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index 5dec69be0acb2eece6fbc030f02a2640ef8d910e..76ee7e3f4d9b9b8ac8a59cebe946b90c81c37755 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -814,7 +814,7 @@ static int peb2466_dai_startup(struct snd_pcm_substream *substream,
 					  &peb2466_sample_bits_constr);
 }
 
-static u64 peb2466_dai_formats[] = {
+static const u64 peb2466_dai_formats[] = {
 	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
 	SND_SOC_POSSIBLE_DAIFMT_DSP_B,
 };
diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c
index d4da98469f8b898dab6585cf0321091857e0a908..5fea600bc3a429cae639450bf9df539cd0542a81 100644
--- a/sound/soc/codecs/rk817_codec.c
+++ b/sound/soc/codecs/rk817_codec.c
@@ -10,7 +10,6 @@
 #include <linux/mfd/rk808.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <sound/core.h>
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
new file mode 100644
index 0000000000000000000000000000000000000000..83b29b441be980cf5f7a21b03417764419a89673
--- /dev/null
+++ b/sound/soc/codecs/rt1318.c
@@ -0,0 +1,1354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1318.c  --  RT1318 ALSA SoC audio amplifier driver
+// Author: Jack Yu <jack.yu@realtek.com>
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/acpi.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.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 <sound/rt1318.h>
+
+#include "rt1318.h"
+
+static struct reg_sequence init_list[] = {
+	{ 0x0000C000, 0x01},
+	{ 0x0000F20D, 0x00},
+	{ 0x0000F212, 0x3E},
+	{ 0x0000C001, 0x02},
+	{ 0x0000C003, 0x22},
+	{ 0x0000C004, 0x44},
+	{ 0x0000C005, 0x44},
+	{ 0x0000C007, 0x64},
+	{ 0x0000C00E, 0xE7},
+	{ 0x0000F223, 0x7F},
+	{ 0x0000F224, 0xDB},
+	{ 0x0000F225, 0xEE},
+	{ 0x0000F226, 0x3F},
+	{ 0x0000F227, 0x0F},
+	{ 0x0000F21A, 0x78},
+	{ 0x0000F242, 0x3C},
+	{ 0x0000C120, 0x40},
+	{ 0x0000C125, 0x03},
+	{ 0x0000C321, 0x0A},
+	{ 0x0000C200, 0xD8},
+	{ 0x0000C201, 0x27},
+	{ 0x0000C202, 0x0F},
+	{ 0x0000C400, 0x0E},
+	{ 0x0000C401, 0x43},
+	{ 0x0000C402, 0xE0},
+	{ 0x0000C403, 0x00},
+	{ 0x0000C404, 0x4C},
+	{ 0x0000C406, 0x40},
+	{ 0x0000C407, 0x02},
+	{ 0x0000C408, 0x3F},
+	{ 0x0000C300, 0x01},
+	{ 0x0000C125, 0x03},
+	{ 0x0000DF00, 0x10},
+	{ 0x0000F20B, 0x2A},
+	{ 0x0000DF5F, 0x01},
+	{ 0x0000DF60, 0xA7},
+	{ 0x0000C203, 0x84},
+	{ 0x0000C206, 0x78},
+	{ 0x0000F10A, 0x09},
+	{ 0x0000F10B, 0x4C},
+	{ 0x0000F104, 0xF4},
+	{ 0x0000F105, 0x03},
+	{ 0x0000F109, 0xE0},
+	{ 0x0000F10B, 0x5C},
+	{ 0x0000F104, 0xF4},
+	{ 0x0000F105, 0x04},
+	{ 0x0000F109, 0x65},
+	{ 0x0000F10B, 0x5C},
+	{ 0x0000F104, 0xF4},
+	{ 0x0000F105, 0x02},
+	{ 0x0000F109, 0x30},
+	{ 0x0000F10B, 0x5C},
+	{ 0x0000E706, 0x0F},
+	{ 0x0000E707, 0x30},
+	{ 0x0000E806, 0x0F},
+	{ 0x0000E807, 0x30},
+	{ 0x0000CE04, 0x03},
+	{ 0x0000CE05, 0x5F},
+	{ 0x0000CE06, 0xA2},
+	{ 0x0000CE07, 0x6B},
+	{ 0x0000CF04, 0x03},
+	{ 0x0000CF05, 0x5F},
+	{ 0x0000CF06, 0xA2},
+	{ 0x0000CF07, 0x6B},
+	{ 0x0000CE60, 0xE3},
+	{ 0x0000C130, 0x51},
+	{ 0x0000E000, 0xA8},
+	{ 0x0000F102, 0x00},
+	{ 0x0000F103, 0x00},
+	{ 0x0000F104, 0xF5},
+	{ 0x0000F105, 0x23},
+	{ 0x0000F109, 0x04},
+	{ 0x0000F10A, 0x0B},
+	{ 0x0000F10B, 0x4C},
+	{ 0x0000F10B, 0x5C},
+	{ 0x41001888, 0x00},
+	{ 0x0000C121, 0x0B},
+	{ 0x0000F102, 0x00},
+	{ 0x0000F103, 0x00},
+	{ 0x0000F104, 0xF5},
+	{ 0x0000F105, 0x23},
+	{ 0x0000F109, 0x00},
+	{ 0x0000F10A, 0x0B},
+	{ 0x0000F10B, 0x4C},
+	{ 0x0000F10B, 0x5C},
+	{ 0x0000F800, 0x20},
+	{ 0x0000CA00, 0x80},
+	{ 0x0000CA10, 0x00},
+	{ 0x0000CA02, 0x78},
+	{ 0x0000CA12, 0x78},
+	{ 0x0000ED00, 0x90},
+	{ 0x0000E604, 0x00},
+	{ 0x0000DB00, 0x0C},
+	{ 0x0000DD00, 0x0C},
+	{ 0x0000DC19, 0x00},
+	{ 0x0000DC1A, 0x6A},
+	{ 0x0000DC1B, 0xAA},
+	{ 0x0000DC1C, 0xAB},
+	{ 0x0000DC1D, 0x00},
+	{ 0x0000DC1E, 0x16},
+	{ 0x0000DC1F, 0xDB},
+	{ 0x0000DC20, 0x6D},
+	{ 0x0000DE19, 0x00},
+	{ 0x0000DE1A, 0x6A},
+	{ 0x0000DE1B, 0xAA},
+	{ 0x0000DE1C, 0xAB},
+	{ 0x0000DE1D, 0x00},
+	{ 0x0000DE1E, 0x16},
+	{ 0x0000DE1F, 0xDB},
+	{ 0x0000DE20, 0x6D},
+	{ 0x0000DB32, 0x00},
+	{ 0x0000DD32, 0x00},
+	{ 0x0000DB33, 0x0A},
+	{ 0x0000DD33, 0x0A},
+	{ 0x0000DB34, 0x1A},
+	{ 0x0000DD34, 0x1A},
+	{ 0x0000DB15, 0xEF},
+	{ 0x0000DD15, 0xEF},
+	{ 0x0000DB17, 0xEF},
+	{ 0x0000DD17, 0xEF},
+	{ 0x0000DB94, 0x70},
+	{ 0x0000DD94, 0x70},
+	{ 0x0000DB19, 0x40},
+	{ 0x0000DD19, 0x40},
+	{ 0x0000DB12, 0xC0},
+	{ 0x0000DD12, 0xC0},
+	{ 0x0000DB00, 0x4C},
+	{ 0x0000DB04, 0x05},
+	{ 0x0000DB05, 0x03},
+	{ 0x0000DD04, 0x05},
+	{ 0x0000DD05, 0x03},
+	{ 0x0000DBBB, 0x09},
+	{ 0x0000DBBC, 0x30},
+	{ 0x0000DBBD, 0xF0},
+	{ 0x0000DBBE, 0xF1},
+	{ 0x0000DDBB, 0x09},
+	{ 0x0000DDBC, 0x30},
+	{ 0x0000DDBD, 0xF0},
+	{ 0x0000DDBE, 0xF1},
+	{ 0x0000DB01, 0x79},
+	{ 0x0000DD01, 0x79},
+	{ 0x0000DB08, 0x40},
+	{ 0x0000DD08, 0x40},
+	{ 0x0000DC52, 0xEF},
+	{ 0x0000DE52, 0xEF},
+	{ 0x0000DB00, 0xCC},
+	{ 0x0000CC2C, 0x00},
+	{ 0x0000CC2D, 0x2A},
+	{ 0x0000CC2E, 0x83},
+	{ 0x0000CC2F, 0xA8},
+	{ 0x0000CD2C, 0x00},
+	{ 0x0000CD2D, 0x2A},
+	{ 0x0000CD2E, 0x83},
+	{ 0x0000CD2F, 0xA8},
+	{ 0x0000CC24, 0x00},
+	{ 0x0000CC25, 0x51},
+	{ 0x0000CC26, 0xEB},
+	{ 0x0000CC27, 0x85},
+	{ 0x0000CD24, 0x00},
+	{ 0x0000CD25, 0x51},
+	{ 0x0000CD26, 0xEB},
+	{ 0x0000CD27, 0x85},
+	{ 0x0000CC20, 0x00},
+	{ 0x0000CC21, 0x00},
+	{ 0x0000CC22, 0x43},
+	{ 0x0000CD20, 0x00},
+	{ 0x0000CD21, 0x00},
+	{ 0x0000CD22, 0x43},
+	{ 0x0000CC16, 0x0F},
+	{ 0x0000CC17, 0x00},
+	{ 0x0000CD16, 0x0F},
+	{ 0x0000CD17, 0x00},
+	{ 0x0000CC29, 0x5D},
+	{ 0x0000CC2A, 0xC0},
+	{ 0x0000CD29, 0x5D},
+	{ 0x0000CD2A, 0xC0},
+	{ 0x0000CC31, 0x20},
+	{ 0x0000CC32, 0x00},
+	{ 0x0000CC33, 0x00},
+	{ 0x0000CC34, 0x00},
+	{ 0x0000CD31, 0x20},
+	{ 0x0000CD32, 0x00},
+	{ 0x0000CD33, 0x00},
+	{ 0x0000CD34, 0x00},
+	{ 0x0000CC36, 0x79},
+	{ 0x0000CC37, 0x99},
+	{ 0x0000CC38, 0x99},
+	{ 0x0000CC39, 0x99},
+	{ 0x0000CD36, 0x79},
+	{ 0x0000CD37, 0x99},
+	{ 0x0000CD38, 0x99},
+	{ 0x0000CD39, 0x99},
+	{ 0x0000CC09, 0x00},
+	{ 0x0000CC0A, 0x07},
+	{ 0x0000CC0B, 0x5F},
+	{ 0x0000CC0C, 0x6F},
+	{ 0x0000CD09, 0x00},
+	{ 0x0000CD0A, 0x07},
+	{ 0x0000CD0B, 0x5F},
+	{ 0x0000CD0C, 0x6F},
+	{ 0x0000CC0E, 0x00},
+	{ 0x0000CC0F, 0x03},
+	{ 0x0000CC10, 0xAF},
+	{ 0x0000CC11, 0xB7},
+	{ 0x0000CD0E, 0x00},
+	{ 0x0000CD0F, 0x03},
+	{ 0x0000CD10, 0xAF},
+	{ 0x0000CD11, 0xB7},
+	{ 0x0000CCD6, 0x00},
+	{ 0x0000CCD7, 0x03},
+	{ 0x0000CDD6, 0x00},
+	{ 0x0000CDD7, 0x03},
+	{ 0x0000CCD8, 0x00},
+	{ 0x0000CCD9, 0x03},
+	{ 0x0000CDD8, 0x00},
+	{ 0x0000CDD9, 0x03},
+	{ 0x0000CCDA, 0x00},
+	{ 0x0000CCDB, 0x03},
+	{ 0x0000CDDA, 0x00},
+	{ 0x0000CDDB, 0x03},
+	{ 0x0000C320, 0x20},
+	{ 0x0000C203, 0x9C},
+};
+#define rt1318_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt1318_reg[] = {
+	{ 0xc000, 0x00 },
+	{ 0xc001, 0x43 },
+	{ 0xc003, 0x22 },
+	{ 0xc004, 0x44 },
+	{ 0xc005, 0x44 },
+	{ 0xc006, 0x33 },
+	{ 0xc007, 0x64 },
+	{ 0xc008, 0x05 },
+	{ 0xc00a, 0xfc },
+	{ 0xc00b, 0x0f },
+	{ 0xc00c, 0x0e },
+	{ 0xc00d, 0xef },
+	{ 0xc00e, 0xe5 },
+	{ 0xc00f, 0xff },
+	{ 0xc120, 0xc0 },
+	{ 0xc121, 0x00 },
+	{ 0xc122, 0x00 },
+	{ 0xc123, 0x14 },
+	{ 0xc125, 0x00 },
+	{ 0xc130, 0x59 },
+	{ 0xc200, 0x00 },
+	{ 0xc201, 0x00 },
+	{ 0xc202, 0x00 },
+	{ 0xc203, 0x04 },
+	{ 0xc204, 0x00 },
+	{ 0xc205, 0x00 },
+	{ 0xc206, 0x68 },
+	{ 0xc207, 0x70 },
+	{ 0xc208, 0x00 },
+	{ 0xc20a, 0x00 },
+	{ 0xc20b, 0x01 },
+	{ 0xc20c, 0x7f },
+	{ 0xc20d, 0x01 },
+	{ 0xc20e, 0x7f },
+	{ 0xc300, 0x00 },
+	{ 0xc301, 0x00 },
+	{ 0xc303, 0x80 },
+	{ 0xc320, 0x00 },
+	{ 0xc321, 0x09 },
+	{ 0xc322, 0x02 },
+	{ 0xc400, 0x00 },
+	{ 0xc401, 0x00 },
+	{ 0xc402, 0x00 },
+	{ 0xc403, 0x00 },
+	{ 0xc404, 0x00 },
+	{ 0xc405, 0x00 },
+	{ 0xc406, 0x00 },
+	{ 0xc407, 0x00 },
+	{ 0xc408, 0x00 },
+	{ 0xc410, 0x04 },
+	{ 0xc430, 0x00 },
+	{ 0xc431, 0x00 },
+	{ 0xca00, 0x10 },
+	{ 0xca01, 0x00 },
+	{ 0xca02, 0x0b },
+	{ 0xca10, 0x10 },
+	{ 0xca11, 0x00 },
+	{ 0xca12, 0x0b },
+	{ 0xce04, 0x08 },
+	{ 0xce05, 0x00 },
+	{ 0xce06, 0x00 },
+	{ 0xce07, 0x00 },
+	{ 0xce60, 0x63 },
+	{ 0xcf04, 0x08 },
+	{ 0xcf05, 0x00 },
+	{ 0xcf06, 0x00 },
+	{ 0xcf07, 0x00 },
+	{ 0xdb00, 0x00 },
+	{ 0xdb08, 0x40 },
+	{ 0xdb12, 0x00 },
+	{ 0xdb35, 0x00 },
+	{ 0xdbb5, 0x00 },
+	{ 0xdbb6, 0x40 },
+	{ 0xdbb7, 0x00 },
+	{ 0xdbb8, 0x00 },
+	{ 0xdbc5, 0x00 },
+	{ 0xdbc6, 0x00 },
+	{ 0xdbc7, 0x00 },
+	{ 0xdbc8, 0x00 },
+	{ 0xdd08, 0x40 },
+	{ 0xdd12, 0x00 },
+	{ 0xdd35, 0x00 },
+	{ 0xddb5, 0x00 },
+	{ 0xddb6, 0x40 },
+	{ 0xddb7, 0x00 },
+	{ 0xddb8, 0x00 },
+	{ 0xddc5, 0x00 },
+	{ 0xddc6, 0x00 },
+	{ 0xddc7, 0x00 },
+	{ 0xddc8, 0x00 },
+	{ 0xdd93, 0x00 },
+	{ 0xdd94, 0x64 },
+	{ 0xdf00, 0x00 },
+	{ 0xdf5f, 0x00 },
+	{ 0xdf60, 0x00 },
+	{ 0xe000, 0x08 },
+	{ 0xe300, 0xa0 },
+	{ 0xe400, 0x22 },
+	{ 0xe706, 0x2f },
+	{ 0xe707, 0x2f },
+	{ 0xe806, 0x2f },
+	{ 0xe807, 0x2f },
+	{ 0xea00, 0x43 },
+	{ 0xed00, 0x80 },
+	{ 0xed01, 0x0f },
+	{ 0xed02, 0xff },
+	{ 0xed03, 0x00 },
+	{ 0xed04, 0x00 },
+	{ 0xed05, 0x0f },
+	{ 0xed06, 0xff },
+	{ 0xf010, 0x10 },
+	{ 0xf011, 0xec },
+	{ 0xf012, 0x68 },
+	{ 0xf013, 0x21 },
+	{ 0xf102, 0x00 },
+	{ 0xf103, 0x00 },
+	{ 0xf104, 0x00 },
+	{ 0xf105, 0x00 },
+	{ 0xf106, 0x00 },
+	{ 0xf107, 0x00 },
+	{ 0xf108, 0x00 },
+	{ 0xf109, 0x00 },
+	{ 0xf10a, 0x03 },
+	{ 0xf10b, 0x40 },
+	{ 0xf20b, 0x28 },
+	{ 0xf20d, 0x00 },
+	{ 0xf212, 0x00 },
+	{ 0xf21a, 0x00 },
+	{ 0xf223, 0x40 },
+	{ 0xf224, 0x00 },
+	{ 0xf225, 0x00 },
+	{ 0xf226, 0x00 },
+	{ 0xf227, 0x00 },
+	{ 0xf242, 0x0c },
+	{ 0xf800, 0x00 },
+	{ 0xf801, 0x12 },
+	{ 0xf802, 0xe0 },
+	{ 0xf803, 0x2f },
+	{ 0xf804, 0x00 },
+	{ 0xf805, 0x00 },
+	{ 0xf806, 0x07 },
+	{ 0xf807, 0xff },
+};
+
+static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0xc000:
+	case 0xc301:
+	case 0xc410:
+	case 0xc430 ... 0xc431:
+	case 0xdb06:
+	case 0xdb12:
+	case 0xdb1d ... 0xdb1f:
+	case 0xdb35:
+	case 0xdb37:
+	case 0xdb8a ... 0xdb92:
+	case 0xdbc5 ... 0xdbc8:
+	case 0xdc2b ... 0xdc49:
+	case 0xdd0b:
+	case 0xdd12:
+	case 0xdd1d ... 0xdd1f:
+	case 0xdd35:
+	case 0xdd8a ... 0xdd92:
+	case 0xddc5 ... 0xddc8:
+	case 0xde2b ... 0xde44:
+	case 0xdf4a ... 0xdf55:
+	case 0xe224 ... 0xe23b:
+	case 0xea01:
+	case 0xebc5:
+	case 0xebc8:
+	case 0xebcb ... 0xebcc:
+	case 0xed03 ... 0xed06:
+	case 0xf010 ... 0xf014:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool rt1318_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0xc000 ... 0xc00f:
+	case 0xc120 ... 0xc130:
+	case 0xc200 ... 0xc20e:
+	case 0xc300 ... 0xc303:
+	case 0xc320 ... 0xc322:
+	case 0xc400 ... 0xc408:
+	case 0xc430 ... 0xc431:
+	case 0xca00 ... 0xca02:
+	case 0xca10 ... 0xca12:
+	case 0xcb00 ... 0xcb0b:
+	case 0xcc00 ... 0xcce5:
+	case 0xcd00 ... 0xcde5:
+	case 0xce00 ... 0xce6a:
+	case 0xcf00 ... 0xcf53:
+	case 0xd000 ... 0xd0cc:
+	case 0xd100 ... 0xd1b9:
+	case 0xdb00 ... 0xdc53:
+	case 0xdd00 ... 0xde53:
+	case 0xdf00 ... 0xdf6b:
+	case 0xe000:
+	case 0xe300:
+	case 0xe400:
+	case 0xe706 ... 0xe707:
+	case 0xe806 ... 0xe807:
+	case 0xea00:
+	case 0xeb00 ... 0xebcc:
+	case 0xec00 ... 0xecb9:
+	case 0xed00 ... 0xed06:
+	case 0xf010 ... 0xf014:
+	case 0xf102 ... 0xf10b:
+	case 0xf20b:
+	case 0xf20d ... 0xf242:
+	case 0xf800 ... 0xf807:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int rt1318_dac_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1,
+				RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_HIGH);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1,
+				RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_LOW);
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int rt1318_dvol_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	rt1318->rt1318_dvol = ucontrol->value.integer.value[0];
+
+	if (rt1318->rt1318_dvol <= RT1318_DVOL_STEP && rt1318->rt1318_dvol >= 0) {
+		regmap_write(rt1318->regmap, RT1318_DA_VOL_L_8,
+			rt1318->rt1318_dvol >> 8);
+		regmap_write(rt1318->regmap, RT1318_DA_VOL_L_1_7,
+			rt1318->rt1318_dvol & 0xff);
+		regmap_write(rt1318->regmap, RT1318_DA_VOL_R_8,
+			rt1318->rt1318_dvol >> 8);
+		regmap_write(rt1318->regmap, RT1318_DA_VOL_R_1_7,
+			rt1318->rt1318_dvol & 0xff);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int rt1318_dvol_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rt1318->rt1318_dvol;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new rt1318_snd_controls[] = {
+	SOC_SINGLE_EXT("Amp Playback Volume", SND_SOC_NOPM, 0, 383, 0,
+		rt1318_dvol_get, rt1318_dvol_put),
+};
+
+static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	/* DACs */
+	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
+		rt1318_dac_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("Amp"),
+};
+
+static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
+	{"DAC", NULL, "AIF1RX"},
+	{"Amp", NULL, "DAC"},
+};
+
+static int rt1318_get_clk_info(int sclk, int rate)
+{
+	int i, pd[] = {1, 2, 4, 8, 16, 24};
+
+	if (sclk <= 0 || rate <= 0)
+		return -EINVAL;
+
+	rate = rate << 8;
+	for (i = 0; i < ARRAY_SIZE(pd); i++)
+		if (sclk == rate * pd[i])
+			return i;
+
+	return -EINVAL;
+}
+
+static int rt1318_clk_ip_info(struct snd_soc_component *component, int lrclk)
+{
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	switch (lrclk) {
+	case RT1318_LRCLK_48000:
+	case RT1318_LRCLK_44100:
+	case RT1318_LRCLK_16000:
+		regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+				RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+				RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON4);
+		break;
+	case RT1318_LRCLK_96000:
+		regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+				RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+				RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON2);
+		break;
+	case RT1318_LRCLK_192000:
+		regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+				RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+				RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON1);
+		break;
+	default:
+		dev_err(component->dev, "Unsupported clock rate.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt1318_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+	int data_len = 0, ch_len = 0;
+	int pre_div, ret;
+
+	rt1318->lrck = params_rate(params);
+	pre_div = rt1318_get_clk_info(rt1318->sysclk, rt1318->lrck);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting\n");
+		return -EINVAL;
+	}
+	ret = rt1318_clk_ip_info(component, rt1318->lrck);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupported clock setting\n");
+		return -EINVAL;
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		data_len = RT1318_I2S_DL_20;
+		ch_len = RT1318_I2S_DL_20;
+		break;
+	case 24:
+		data_len = RT1318_I2S_DL_24;
+		ch_len = RT1318_I2S_DL_24;
+		break;
+	case 32:
+		data_len = RT1318_I2S_DL_32;
+		ch_len = RT1318_I2S_DL_32;
+		break;
+	case 8:
+		data_len = RT1318_I2S_DL_8;
+		ch_len = RT1318_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(rt1318->regmap, RT1318_CLK2,
+				RT1318_DIV_AP_MASK | RT1318_DIV_DAMOD_MASK,
+				pre_div << RT1318_DIV_AP_SFT |
+				pre_div << RT1318_DIV_DAMOD_SFT);
+	regmap_update_bits(rt1318->regmap, RT1318_CLK3,
+				RT1318_AD_STO1_MASK | RT1318_AD_STO2_MASK,
+				pre_div << RT1318_AD_STO1_SFT |
+				pre_div << RT1318_AD_STO2_SFT);
+	regmap_update_bits(rt1318->regmap, RT1318_CLK4,
+				RT1318_AD_ANA_STO1_MASK | RT1318_AD_ANA_STO2_MASK,
+				pre_div << RT1318_AD_ANA_STO1_SFT |
+				pre_div << RT1318_AD_ANA_STO2_SFT);
+	regmap_update_bits(rt1318->regmap, RT1318_CLK5,
+				RT1318_DIV_FIFO_IN_MASK | RT1318_DIV_FIFO_OUT_MASK,
+				pre_div << RT1318_DIV_FIFO_IN_SFT |
+				pre_div << RT1318_DIV_FIFO_OUT_SFT);
+	regmap_update_bits(rt1318->regmap, RT1318_CLK6,
+				RT1318_DIV_NLMS_MASK | RT1318_DIV_AD_MONO_MASK |
+				RT1318_DIV_POST_G_MASK,  pre_div << RT1318_DIV_NLMS_SFT |
+				pre_div << RT1318_DIV_AD_MONO_SFT |
+				pre_div << RT1318_DIV_POST_G_SFT);
+
+	regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2,
+				RT1318_I2S_DL_MASK, data_len << RT1318_I2S_DL_SFT);
+	regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3,
+				RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK,
+				ch_len << RT1318_I2S_TX_CHL_SFT |
+				ch_len << RT1318_I2S_RX_CHL_SFT);
+
+	return 0;
+}
+
+static int rt1318_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, reg_val2 = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val2 |= RT1318_TDM_BCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT1318_FMT_LEFT_J;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT1318_FMT_PCM_A_R;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT1318_FMT_PCM_B_R;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1,
+			RT1318_I2S_FMT_MASK, reg_val);
+	regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1,
+			RT1318_TDM_BCLK_MASK, reg_val2);
+
+	return 0;
+}
+
+static int rt1318_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+	int reg_val = 0;
+
+	if (freq == rt1318->sysclk && clk_id == rt1318->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT1318_SCLK_S_BCLK:
+		reg_val |= RT1318_SYSCLK_BCLK;
+		break;
+	case RT1318_SCLK_S_SDW:
+		reg_val |= RT1318_SYSCLK_SDW;
+		break;
+	case RT1318_SCLK_S_PLL2F:
+		reg_val |= RT1318_SYSCLK_PLL2F;
+		break;
+	case RT1318_SCLK_S_PLL2B:
+		reg_val |= RT1318_SYSCLK_PLL2B;
+		break;
+	case RT1318_SCLK_S_MCLK:
+		reg_val |= RT1318_SYSCLK_MCLK;
+		break;
+	case RT1318_SCLK_S_RC0:
+		reg_val |= RT1318_SYSCLK_RC1;
+		break;
+	case RT1318_SCLK_S_RC1:
+		reg_val |= RT1318_SYSCLK_RC2;
+		break;
+	case RT1318_SCLK_S_RC2:
+		reg_val |= RT1318_SYSCLK_RC3;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	rt1318->sysclk = freq;
+	rt1318->sysclk_src = clk_id;
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+	regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_SYSCLK_SEL_MASK, reg_val);
+
+	return 0;
+}
+
+static const struct pll_calc_map pll_preset_table[] = {
+	{512000, 4096000, 22, 190, 0, true, false},
+	{1024000, 4096000, 22, 94, 0, true, false},
+	{1024000, 16384000, 4, 190, 0, true, false},
+	{1411200, 11289600, 6, 62, 0, true, false},
+	{1536000, 12288000, 6, 62, 0, true, false},
+	{2822400, 11289600, 6, 62, 0, true, false},
+	{2822400, 45158400, 0, 62, 0, true, false},
+	{2822400, 49152000, 0, 62, 0, true, false},
+	{3072000, 12288000, 6, 62, 0, true, false},
+	{3072000, 24576000, 2, 62, 0, true, false},
+	{3072000, 49152000, 0, 62, 0, true, false},
+	{6144000, 24576000, 2, 94, 4, false, false},
+	{6144000, 49152000, 0, 30, 0, true, false},
+	{6144000, 98304000, 0, 94, 4, false, true},
+	{12288000, 49152000, 0, 62, 6, false, false},
+};
+
+static int rt1318_pll_calc(const unsigned int freq_in,
+	const unsigned int freq_out, struct rt1318_pll_code *pll_code)
+{
+	int max_n = RT1318_PLL_N_MAX, max_m = RT1318_PLL_M_MAX;
+	int i, k, red, n_t, pll_out, in_t, out_t;
+	int n = 0, m = 0, m_t = 0;
+	int red_t = abs(freq_out - freq_in);
+	bool m_bypass = false, k_bypass = false;
+
+	if (RT1318_PLL_INP_MAX < freq_in || RT1318_PLL_INP_MIN > freq_in)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+		if (freq_in == pll_preset_table[i].pll_in &&
+			freq_out == pll_preset_table[i].pll_out) {
+			k = pll_preset_table[i].k;
+			m = pll_preset_table[i].m;
+			n = pll_preset_table[i].n;
+			m_bypass = pll_preset_table[i].m_bp;
+			k_bypass = pll_preset_table[i].k_bp;
+			goto code_find;
+		}
+	}
+
+	k = 100000000 / freq_out - 2;
+	if (k > RT1318_PLL_K_MAX)
+		k = RT1318_PLL_K_MAX;
+	if (k < 0) {
+		k = 0;
+		k_bypass = true;
+	}
+	for (n_t = 0; n_t <= max_n; n_t++) {
+		in_t = freq_in / (k_bypass ? 1 : (k + 2));
+		pll_out = freq_out / (n_t + 2);
+		if (in_t < 0)
+			continue;
+		if (in_t == pll_out) {
+			m_bypass = true;
+			n = n_t;
+			goto code_find;
+		}
+		red = abs(in_t - pll_out);
+		if (red < red_t) {
+			m_bypass = true;
+			n = n_t;
+			m = m_t;
+			if (red == 0)
+				goto code_find;
+			red_t = red;
+		}
+		for (m_t = 0; m_t <= max_m; m_t++) {
+			out_t = in_t / (m_t + 2);
+			red = abs(out_t - pll_out);
+			if (red < red_t) {
+				m_bypass = false;
+				n = n_t;
+				m = m_t;
+				if (red == 0)
+					goto code_find;
+				red_t = red;
+			}
+		}
+	}
+	pr_debug("Only get approximation about PLL\n");
+
+code_find:
+
+	pll_code->m_bp = m_bypass;
+	pll_code->k_bp = k_bypass;
+	pll_code->m_code = m;
+	pll_code->n_code = n;
+	pll_code->k_code = k;
+	return 0;
+}
+
+static int rt1318_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+	struct rt1318_pll_code pll_code;
+	int ret;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+		rt1318->pll_in = 0;
+		rt1318->pll_out = 0;
+		return 0;
+	}
+
+	if (source == rt1318->pll_src && freq_in == rt1318->pll_in &&
+		freq_out == rt1318->pll_out)
+		return 0;
+
+	switch (source) {
+	case RT1318_PLL_S_BCLK0:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK0);
+		break;
+	case RT1318_PLL_S_BCLK1:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK1);
+		break;
+	case RT1318_PLL_S_RC:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_RC);
+		break;
+	case RT1318_PLL_S_MCLK:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_MCLK);
+		break;
+	case RT1318_PLL_S_SDW_IN_PLL:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_SDW1);
+		break;
+	case RT1318_PLL_S_SDW_0:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_SDW2);
+		break;
+	case RT1318_PLL_S_SDW_1:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_SDW3);
+		break;
+	case RT1318_PLL_S_SDW_2:
+		regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+			RT1318_PLLIN_MASK, RT1318_PLLIN_SDW4);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rt1318_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	regmap_update_bits(rt1318->regmap, RT1318_PLL1_K,
+			RT1318_K_PLL1_MASK, pll_code.k_code);
+	regmap_update_bits(rt1318->regmap, RT1318_PLL1_M,
+			RT1318_M_PLL1_MASK, (pll_code.m_bp ? 0 : pll_code.m_code));
+	regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_8,
+			RT1318_N_8_PLL1_MASK, pll_code.n_code >> 8);
+	regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_7_0,
+			RT1318_N_7_0_PLL1_MASK, pll_code.n_code);
+
+	rt1318->pll_in = freq_in;
+	rt1318->pll_out = freq_out;
+	rt1318->pll_src = source;
+
+	return 0;
+}
+
+static int rt1318_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;
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+	unsigned int cn = 0, cl = 0, rx_slotnum;
+	int ret = 0, first_bit;
+
+	switch (slots) {
+	case 4:
+		cn |= RT1318_I2S_CH_TX_4CH;
+		cn |= RT1318_I2S_CH_RX_4CH;
+		break;
+	case 6:
+		cn |= RT1318_I2S_CH_TX_6CH;
+		cn |= RT1318_I2S_CH_RX_6CH;
+		break;
+	case 8:
+		cn |= RT1318_I2S_CH_TX_8CH;
+		cn |= RT1318_I2S_CH_RX_8CH;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		cl |= RT1318_I2S_TX_CHL_20;
+		cl |= RT1318_I2S_RX_CHL_20;
+		break;
+	case 24:
+		cl |= RT1318_I2S_TX_CHL_24;
+		cl |= RT1318_I2S_RX_CHL_24;
+		break;
+	case 32:
+		cl |= RT1318_I2S_TX_CHL_32;
+		cl |= RT1318_I2S_RX_CHL_32;
+		break;
+	case 8:
+		cl |= RT1318_I2S_TX_CHL_8;
+		cl |= RT1318_I2S_RX_CHL_8;
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* 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_;
+	}
+
+	first_bit = __ffs(rx_mask);
+	switch (first_bit) {
+	case 0:
+	case 2:
+	case 4:
+	case 6:
+		regmap_update_bits(rt1318->regmap,
+			RT1318_TDM_CTRL9,
+			RT1318_TDM_I2S_TX_L_DAC1_1_MASK |
+			RT1318_TDM_I2S_TX_R_DAC1_1_MASK,
+			(first_bit << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) |
+			((first_bit + 1) << RT1318_TDM_I2S_TX_R_DAC1_1_SFT));
+		break;
+	case 1:
+	case 3:
+	case 5:
+	case 7:
+		regmap_update_bits(rt1318->regmap,
+			RT1318_TDM_CTRL9,
+			RT1318_TDM_I2S_TX_L_DAC1_1_MASK |
+			RT1318_TDM_I2S_TX_R_DAC1_1_MASK,
+			((first_bit - 1) << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) |
+			(first_bit << RT1318_TDM_I2S_TX_R_DAC1_1_SFT));
+		break;
+	default:
+		ret = -EINVAL;
+		goto _set_tdm_err_;
+	}
+
+	regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2,
+			RT1318_I2S_CH_TX_MASK | RT1318_I2S_CH_RX_MASK, cn);
+	regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3,
+			RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, cl);
+
+_set_tdm_err_:
+	return ret;
+}
+
+static int rt1318_probe(struct snd_soc_component *component)
+{
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	rt1318->component = component;
+
+	schedule_work(&rt1318->cali_work);
+	rt1318->rt1318_dvol = RT1318_DVOL_STEP;
+
+	return 0;
+}
+
+static void rt1318_remove(struct snd_soc_component *component)
+{
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	cancel_work_sync(&rt1318->cali_work);
+}
+
+#ifdef CONFIG_PM
+static int rt1318_suspend(struct snd_soc_component *component)
+{
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt1318->regmap, true);
+	regcache_mark_dirty(rt1318->regmap);
+	return 0;
+}
+
+static int rt1318_resume(struct snd_soc_component *component)
+{
+	struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt1318->regmap, false);
+	regcache_sync(rt1318->regmap);
+	return 0;
+}
+#else
+#define rt1318_suspend NULL
+#define rt1318_resume NULL
+#endif
+
+#define RT1318_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
+	.hw_params = rt1318_hw_params,
+	.set_fmt = rt1318_set_dai_fmt,
+	.set_sysclk = rt1318_set_dai_sysclk,
+	.set_pll = rt1318_set_dai_pll,
+	.set_tdm_slot = rt1318_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt1318_dai[] = {
+	{
+		.name = "rt1318-aif",
+		.id = 0,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT1318_STEREO_RATES,
+			.formats = RT1318_FORMATS,
+		},
+		.ops = &rt1318_aif_dai_ops,
+	}
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt1318 = {
+	.probe = rt1318_probe,
+	.remove = rt1318_remove,
+	.suspend = rt1318_suspend,
+	.resume = rt1318_resume,
+	.controls = rt1318_snd_controls,
+	.num_controls = ARRAY_SIZE(rt1318_snd_controls),
+	.dapm_widgets = rt1318_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
+	.dapm_routes = rt1318_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
+	.use_pmdown_time = 1,
+	.endianness = 1,
+};
+
+static const struct regmap_config rt1318_regmap = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.readable_reg = rt1318_readable_register,
+	.volatile_reg = rt1318_volatile_register,
+	.max_register = 0x41001888,
+	.reg_defaults = rt1318_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt1318_reg),
+	.cache_type = REGCACHE_RBTREE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+static const struct i2c_device_id rt1318_i2c_id[] = {
+	{ "rt1318" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id);
+
+static const struct of_device_id rt1318_of_match[] = {
+	{ .compatible = "realtek,rt1318", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt1318_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt1318_acpi_match[] = {
+	{ "10EC1318", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match);
+#endif
+
+static int rt1318_parse_dt(struct rt1318_priv *rt1318, struct device *dev)
+{
+	device_property_read_u32(dev, "realtek,r0_l",
+		&rt1318->pdata.init_r0_l);
+	device_property_read_u32(dev, "realtek,r0_r",
+		&rt1318->pdata.init_r0_r);
+
+	return 0;
+}
+
+static void rt1318_calibration_sequence(struct rt1318_priv *rt1318)
+{
+	regmap_write(rt1318->regmap, RT1318_CLK1, 0x22);
+	regmap_write(rt1318->regmap, RT1318_PLL1_N_7_0, 0x06);
+	regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xCC);
+	regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x40);
+	regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x40);
+	regmap_write(rt1318->regmap, RT1318_SINE_GEN0, 0x20);
+	regmap_write(rt1318->regmap, RT1318_SPK_VOL_TH, 0x00);
+	regmap_write(rt1318->regmap, RT1318_FEEDBACK_PATH, 0x0B);
+	regmap_write(rt1318->regmap, RT1318_TCON, 0x1C);
+	regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x58);
+	regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x78);
+	regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xC2);
+}
+
+static void rt1318_r0_calculate(struct rt1318_priv *rt1318)
+{
+	unsigned int r0_l, r0_l_byte0, r0_l_byte1, r0_l_byte2, r0_l_byte3;
+	unsigned int r0_r, r0_r_byte0, r0_r_byte1, r0_r_byte2, r0_r_byte3;
+	unsigned int r0_l_integer, r0_l_factor, r0_r_integer, r0_r_factor;
+	unsigned int format = 16777216; /* 2^24 */
+
+	regmap_read(rt1318->regmap, RT1318_R0_L_24, &r0_l_byte0);
+	regmap_read(rt1318->regmap, RT1318_R0_L_23_16, &r0_l_byte1);
+	regmap_read(rt1318->regmap, RT1318_R0_L_15_8, &r0_l_byte2);
+	regmap_read(rt1318->regmap, RT1318_R0_L_7_0, &r0_l_byte3);
+	r0_l = r0_l_byte0 << 24 | r0_l_byte1 << 16 | r0_l_byte2 << 8 | r0_l_byte3;
+	r0_l_integer = format / r0_l;
+	r0_l_factor = (format * 10) / r0_l - r0_l_integer * 10;
+
+	regmap_read(rt1318->regmap, RT1318_R0_R_24, &r0_r_byte0);
+	regmap_read(rt1318->regmap, RT1318_R0_R_23_16, &r0_r_byte1);
+	regmap_read(rt1318->regmap, RT1318_R0_R_15_8, &r0_r_byte2);
+	regmap_read(rt1318->regmap, RT1318_R0_R_7_0, &r0_r_byte3);
+	r0_r = r0_r_byte0 << 24 | r0_r_byte1 << 16 | r0_r_byte2 << 8 | r0_r_byte3;
+	r0_r_integer = format / r0_r;
+	r0_r_factor = (format * 10) / r0_r - r0_r_integer * 10;
+
+	dev_dbg(rt1318->component->dev, "r0_l_ch:%d.%d ohm\n", r0_l_integer, r0_l_factor);
+	dev_dbg(rt1318->component->dev, "r0_r_ch:%d.%d ohm\n", r0_r_integer, r0_r_factor);
+}
+
+static void rt1318_r0_restore(struct rt1318_priv *rt1318)
+{
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_L_24,
+		(rt1318->pdata.init_r0_l >> 24) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_L_23_16,
+		(rt1318->pdata.init_r0_l >> 16) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_L_15_8,
+		(rt1318->pdata.init_r0_l >> 8) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_L_7_0,
+		(rt1318->pdata.init_r0_l >> 0) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_R_24,
+		(rt1318->pdata.init_r0_r >> 24) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_R_23_16,
+		(rt1318->pdata.init_r0_r >> 16) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_R_15_8,
+		(rt1318->pdata.init_r0_r >> 8) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_PRE_R0_R_7_0,
+		(rt1318->pdata.init_r0_r >> 0) & 0xff);
+	regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x80);
+	regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x80);
+	regmap_write(rt1318->regmap, RT1318_R0_CMP_L_FLAG, 0xc0);
+	regmap_write(rt1318->regmap, RT1318_R0_CMP_R_FLAG, 0xc0);
+	regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xc0);
+	regmap_write(rt1318->regmap, RT1318_STP_R0_EN_R, 0xc0);
+	regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xcc);
+	regmap_write(rt1318->regmap, RT1318_TCON, 0x9c);
+}
+
+static int rt1318_calibrate(struct rt1318_priv *rt1318)
+{
+	int chk_cnt = 30, count = 0;
+	int val, val2;
+
+	regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x1);
+	usleep_range(0, 10000);
+	rt1318_calibration_sequence(rt1318);
+
+	while (count < chk_cnt) {
+		msleep(100);
+		regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val);
+		regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2);
+		val = (val >> 1) & 0x1;
+		val2 = (val2 >> 1) & 0x1;
+		if (val & val2) {
+			dev_dbg(rt1318->component->dev, "Calibration done.\n");
+			break;
+		}
+		count++;
+		if (count == chk_cnt) {
+			regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0);
+			return RT1318_R0_CALIB_NOT_DONE;
+		}
+	}
+	regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0);
+	regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val);
+	regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2);
+	if ((val & 0x1) & (val2 & 0x1))
+		return RT1318_R0_IN_RANGE;
+	else
+		return RT1318_R0_OUT_OF_RANGE;
+}
+
+static void rt1318_calibration_work(struct work_struct *work)
+{
+	struct rt1318_priv *rt1318 =
+		container_of(work, struct rt1318_priv, cali_work);
+	int ret;
+
+	if (rt1318->pdata.init_r0_l && rt1318->pdata.init_r0_r)
+		rt1318_r0_restore(rt1318);
+	else {
+		ret = rt1318_calibrate(rt1318);
+		if (ret == RT1318_R0_IN_RANGE)
+			rt1318_r0_calculate(rt1318);
+		dev_dbg(rt1318->component->dev, "Calibrate R0 result:%d\n", ret);
+	}
+}
+
+static int rt1318_i2c_probe(struct i2c_client *i2c)
+{
+	struct rt1318_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt1318_priv *rt1318;
+	int ret, val, val2, dev_id;
+
+	rt1318 = devm_kzalloc(&i2c->dev, sizeof(struct rt1318_priv),
+				GFP_KERNEL);
+	if (!rt1318)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt1318);
+
+	if (pdata)
+		rt1318->pdata = *pdata;
+	else
+		rt1318_parse_dt(rt1318, &i2c->dev);
+
+	rt1318->regmap = devm_regmap_init_i2c(i2c, &rt1318_regmap);
+	if (IS_ERR(rt1318->regmap)) {
+		ret = PTR_ERR(rt1318->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt1318->regmap, RT1318_DEV_ID1, &val);
+	regmap_read(rt1318->regmap, RT1318_DEV_ID2, &val2);
+	dev_id = (val << 8) | val2;
+	if (dev_id != 0x6821) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt1318\n",
+			dev_id);
+		return -ENODEV;
+	}
+
+	ret = regmap_register_patch(rt1318->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	INIT_WORK(&rt1318->cali_work, rt1318_calibration_work);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+		&soc_component_dev_rt1318, rt1318_dai, ARRAY_SIZE(rt1318_dai));
+}
+
+static struct i2c_driver rt1318_i2c_driver = {
+	.driver = {
+		.name = "rt1318",
+		.of_match_table = of_match_ptr(rt1318_of_match),
+		.acpi_match_table = ACPI_PTR(rt1318_acpi_match),
+	},
+	.probe = rt1318_i2c_probe,
+	.id_table = rt1318_i2c_id,
+};
+module_i2c_driver(rt1318_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1318 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1318.h b/sound/soc/codecs/rt1318.h
new file mode 100644
index 0000000000000000000000000000000000000000..cec40b484216d484d9875b36a032d49679b61dc5
--- /dev/null
+++ b/sound/soc/codecs/rt1318.h
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1318.h -- Platform data for RT1318
+ *
+ * Copyright 2024 Realtek Semiconductor Corp.
+ */
+#include <sound/rt1318.h>
+
+#ifndef __RT1318_H__
+#define __RT1318_H__
+
+struct rt1318_priv {
+	struct snd_soc_component *component;
+	struct rt1318_platform_data pdata;
+	struct work_struct cali_work;
+	struct regmap *regmap;
+
+	unsigned int r0_l_integer;
+	unsigned int r0_l_factor;
+	unsigned int r0_r_integer;
+	unsigned int r0_r_factor;
+	int rt1318_init;
+	int rt1318_dvol;
+	int sysclk_src;
+	int sysclk;
+	int lrck;
+	int bclk;
+	int master;
+	int pll_src;
+	int pll_in;
+	int pll_out;
+};
+
+#define RT1318_PLL_INP_MAX	40000000
+#define RT1318_PLL_INP_MIN	256000
+#define RT1318_PLL_N_MAX	0x1ff
+#define RT1318_PLL_K_MAX	0x1f
+#define RT1318_PLL_M_MAX	0x1f
+
+#define RT1318_LRCLK_192000 192000
+#define RT1318_LRCLK_96000 96000
+#define RT1318_LRCLK_48000 48000
+#define RT1318_LRCLK_44100 44100
+#define RT1318_LRCLK_16000 16000
+#define RT1318_DVOL_STEP 383
+
+#define RT1318_CLK1				0xc001
+#define RT1318_CLK2				0xc003
+#define RT1318_CLK3				0xc004
+#define RT1318_CLK4				0xc005
+#define RT1318_CLK5				0xc006
+#define RT1318_CLK6				0xc007
+#define RT1318_CLK7				0xc008
+#define RT1318_PWR_STA1				0xc121
+#define RT1318_SPK_VOL_TH			0xc130
+#define RT1318_TCON				0xc203
+#define RT1318_SRC_TCON				0xc204
+#define RT1318_TCON_RELATE			0xc206
+#define RT1318_DA_VOL_L_8			0xc20b
+#define RT1318_DA_VOL_L_1_7			0xc20c
+#define RT1318_DA_VOL_R_8			0xc20d
+#define RT1318_DA_VOL_R_1_7			0xc20e
+#define RT1318_FEEDBACK_PATH			0xc321
+#define RT1318_STP_TEMP_L			0xdb00
+#define RT1318_STP_SEL_L			0xdb08
+#define RT1318_STP_R0_EN_L			0xdb12
+#define RT1318_R0_CMP_L_FLAG			0xdb35
+#define RT1318_PRE_R0_L_24			0xdbb5
+#define RT1318_PRE_R0_L_23_16			0xdbb6
+#define RT1318_PRE_R0_L_15_8			0xdbb7
+#define RT1318_PRE_R0_L_7_0			0xdbb8
+#define RT1318_R0_L_24				0xdbc5
+#define RT1318_R0_L_23_16			0xdbc6
+#define RT1318_R0_L_15_8			0xdbc7
+#define RT1318_R0_L_7_0				0xdbc8
+#define RT1318_STP_SEL_R			0xdd08
+#define RT1318_STP_R0_EN_R			0xdd12
+#define RT1318_R0_CMP_R_FLAG			0xdd35
+#define RT1318_PRE_R0_R_24			0xddb5
+#define RT1318_PRE_R0_R_23_16			0xddb6
+#define RT1318_PRE_R0_R_15_8			0xddb7
+#define RT1318_PRE_R0_R_7_0			0xddb8
+#define RT1318_R0_R_24				0xddc5
+#define RT1318_R0_R_23_16			0xddc6
+#define RT1318_R0_R_15_8			0xddc7
+#define RT1318_R0_R_7_0				0xddc8
+#define RT1318_DEV_ID1				0xf012
+#define RT1318_DEV_ID2				0xf013
+#define RT1318_PLL1_K				0xf20d
+#define RT1318_PLL1_M				0xf20f
+#define RT1318_PLL1_N_8				0xf211
+#define RT1318_PLL1_N_7_0			0xf212
+#define RT1318_SINE_GEN0			0xf800
+#define RT1318_TDM_CTRL1			0xf900
+#define RT1318_TDM_CTRL2			0xf901
+#define RT1318_TDM_CTRL3			0xf902
+#define RT1318_TDM_CTRL9			0xf908
+
+
+/* Clock-1  (0xC001) */
+#define RT1318_PLLIN_MASK			(0x7 << 4)
+#define RT1318_PLLIN_BCLK0			(0x0 << 4)
+#define RT1318_PLLIN_BCLK1			(0x1 << 4)
+#define RT1318_PLLIN_RC				(0x2 << 4)
+#define RT1318_PLLIN_MCLK			(0x3 << 4)
+#define RT1318_PLLIN_SDW1			(0x4 << 4)
+#define RT1318_PLLIN_SDW2			(0x5 << 4)
+#define RT1318_PLLIN_SDW3			(0x6 << 4)
+#define RT1318_PLLIN_SDW4			(0x7 << 4)
+#define RT1318_SYSCLK_SEL_MASK			(0x7 << 0)
+#define RT1318_SYSCLK_BCLK			(0x0 << 0)
+#define RT1318_SYSCLK_SDW			(0x1 << 0)
+#define RT1318_SYSCLK_PLL2F			(0x2 << 0)
+#define RT1318_SYSCLK_PLL2B			(0x3 << 0)
+#define RT1318_SYSCLK_MCLK			(0x4 << 0)
+#define RT1318_SYSCLK_RC1			(0x5 << 0)
+#define RT1318_SYSCLK_RC2			(0x6 << 0)
+#define RT1318_SYSCLK_RC3			(0x7 << 0)
+/* Clock-2  (0xC003) */
+#define RT1318_DIV_AP_MASK			(0x3 << 4)
+#define RT1318_DIV_AP_SFT			4
+#define RT1318_DIV_AP_DIV1			(0x0 << 4)
+#define RT1318_DIV_AP_DIV2			(0x1 << 4)
+#define RT1318_DIV_AP_DIV4			(0x2 << 4)
+#define RT1318_DIV_AP_DIV8			(0x3 << 4)
+#define RT1318_DIV_DAMOD_MASK			(0x3 << 0)
+#define RT1318_DIV_DAMOD_SFT			0
+#define RT1318_DIV_DAMOD_DIV1			(0x0 << 0)
+#define RT1318_DIV_DAMOD_DIV2			(0x1 << 0)
+#define RT1318_DIV_DAMOD_DIV4			(0x2 << 0)
+#define RT1318_DIV_DAMOD_DIV8			(0x3 << 0)
+/* Clock-3  (0xC004) */
+#define RT1318_AD_STO1_MASK			(0x7 << 4)
+#define RT1318_AD_STO1_SFT			4
+#define RT1318_AD_STO1_DIV1			(0x0 << 4)
+#define RT1318_AD_STO1_DIV2			(0x1 << 4)
+#define RT1318_AD_STO1_DIV4			(0x2 << 4)
+#define RT1318_AD_STO1_DIV8			(0x3 << 4)
+#define RT1318_AD_STO1_DIV16			(0x4 << 4)
+#define RT1318_AD_STO2_MASK			(0x7 << 0)
+#define RT1318_AD_STO2_SFT			0
+#define RT1318_AD_STO2_DIV1			(0x0 << 0)
+#define RT1318_AD_STO2_DIV2			(0x1 << 0)
+#define RT1318_AD_STO2_DIV4			(0x2 << 0)
+#define RT1318_AD_STO2_DIV8			(0x3 << 0)
+#define RT1318_AD_STO2_DIV16			(0x4 << 0)
+#define RT1318_AD_STO2_SFT			0
+/* Clock-4  (0xC005) */
+#define RT1318_AD_ANA_STO1_MASK			(0x7 << 4)
+#define RT1318_AD_ANA_STO1_SFT			4
+#define RT1318_AD_ANA_STO1_DIV1			(0x0 << 4)
+#define RT1318_AD_ANA_STO1_DIV2			(0x1 << 4)
+#define RT1318_AD_ANA_STO1_DIV4			(0x2 << 4)
+#define RT1318_AD_ANA_STO1_DIV8			(0x3 << 4)
+#define RT1318_AD_ANA_STO1_DIV16		(0x4 << 4)
+#define RT1318_AD_ANA_STO2_MASK			(0x7 << 0)
+#define RT1318_AD_ANA_STO2_DIV1			(0x0 << 0)
+#define RT1318_AD_ANA_STO2_DIV2			(0x1 << 0)
+#define RT1318_AD_ANA_STO2_DIV4			(0x2 << 0)
+#define RT1318_AD_ANA_STO2_DIV8			(0x3 << 0)
+#define RT1318_AD_ANA_STO2_DIV16		(0x4 << 0)
+#define RT1318_AD_ANA_STO2_SFT			0
+/* Clock-5  (0xC006) */
+#define RT1318_DIV_FIFO_IN_MASK			(0x3 << 4)
+#define RT1318_DIV_FIFO_IN_SFT			4
+#define RT1318_DIV_FIFO_IN_DIV1			(0x0 << 4)
+#define RT1318_DIV_FIFO_IN_DIV2			(0x1 << 4)
+#define RT1318_DIV_FIFO_IN_DIV4			(0x2 << 4)
+#define RT1318_DIV_FIFO_IN_DIV8			(0x3 << 4)
+#define RT1318_DIV_FIFO_OUT_MASK		(0x3 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV1		(0x0 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV2		(0x1 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV4		(0x2 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV8		(0x3 << 0)
+#define RT1318_DIV_FIFO_OUT_SFT			0
+/* Clock-6  (0xC007) */
+#define RT1318_DIV_NLMS_MASK			(0x3 << 6)
+#define RT1318_DIV_NLMS_SFT				6
+#define RT1318_DIV_NLMS_DIV1			(0x0 << 6)
+#define RT1318_DIV_NLMS_DIV2			(0x1 << 6)
+#define RT1318_DIV_NLMS_DIV4			(0x2 << 6)
+#define RT1318_DIV_NLMS_DIV8			(0x3 << 6)
+#define RT1318_DIV_AD_MONO_MASK			(0x7 << 3)
+#define RT1318_DIV_AD_MONO_SFT			3
+#define RT1318_DIV_AD_MONO_DIV1			(0x0 << 3)
+#define RT1318_DIV_AD_MONO_DIV2			(0x1 << 3)
+#define RT1318_DIV_AD_MONO_DIV4			(0x2 << 3)
+#define RT1318_DIV_AD_MONO_DIV8			(0x3 << 3)
+#define RT1318_DIV_AD_MONO_DIV16		(0x4 << 3)
+#define RT1318_DIV_POST_G_MASK			(0x7 << 0)
+#define RT1318_DIV_POST_G_SFT			0
+#define RT1318_DIV_POST_G_DIV1			(0x0 << 0)
+#define RT1318_DIV_POST_G_DIV2			(0x1 << 0)
+#define RT1318_DIV_POST_G_DIV4			(0x2 << 0)
+#define RT1318_DIV_POST_G_DIV8			(0x3 << 0)
+#define RT1318_DIV_POST_G_DIV16			(0x4 << 0)
+/* Power Status 1  (0xC121) */
+#define RT1318_PDB_CTRL_MASK			(0x1)
+#define RT1318_PDB_CTRL_LOW			(0x0)
+#define RT1318_PDB_CTRL_HIGH			(0x1)
+#define RT1318_PDB_CTRL_SFT			0
+/* SRC Tcon(0xc204) */
+#define RT1318_SRCIN_IN_SEL_MASK		(0x3 << 6)
+#define RT1318_SRCIN_IN_48K			(0x0 << 6)
+#define RT1318_SRCIN_IN_44P1			(0x1 << 6)
+#define RT1318_SRCIN_IN_32K			(0x2 << 6)
+#define RT1318_SRCIN_IN_16K			(0x3 << 6)
+#define RT1318_SRCIN_F12288_MASK		(0x3 << 4)
+#define RT1318_SRCIN_TCON1			(0x0 << 4)
+#define RT1318_SRCIN_TCON2			(0x1 << 4)
+#define RT1318_SRCIN_TCON4			(0x2 << 4)
+#define RT1318_SRCIN_TCON8			(0x3 << 4)
+#define RT1318_SRCIN_DACLK_MASK			(0x3 << 2)
+#define RT1318_DACLK_TCON1			(0x0 << 2)
+#define RT1318_DACLK_TCON2			(0x1 << 2)
+#define RT1318_DACLK_TCON4			(0x2 << 2)
+#define RT1318_DACLK_TCON8			(0x3 << 2)
+/* R0 Compare Flag  (0xDB35) */
+#define RT1318_R0_RANGE_MASK			(0x1)
+#define RT1318_R0_OUTOFRANGE			(0x0)
+#define RT1318_R0_INRANGE			(0x1)
+/* PLL internal setting (0xF20D), K value */
+#define RT1318_K_PLL1_MASK			(0x1f << 0)
+/* PLL internal setting (0xF20F), M value */
+#define RT1318_M_PLL1_MASK			(0x1f << 0)
+/* PLL internal setting (0xF211), N_8 value */
+#define RT1318_N_8_PLL1_MASK			(0x1 << 0)
+/* PLL internal setting (0xF212), N_7_0 value */
+#define RT1318_N_7_0_PLL1_MASK			(0xff << 0)
+/* TDM CTRL 1  (0xf900) */
+#define RT1318_TDM_BCLK_MASK			(0x1 << 7)
+#define RT1318_TDM_BCLK_NORM			(0x0 << 7)
+#define RT1318_TDM_BCLK_INV			(0x1 << 7)
+#define RT1318_I2S_FMT_MASK			(0x7 << 0)
+#define RT1318_FMT_I2S				(0x0 << 0)
+#define RT1318_FMT_LEFT_J			(0x1 << 0)
+#define RT1318_FMT_PCM_A_R			(0x2 << 0)
+#define RT1318_FMT_PCM_B_R			(0x3 << 0)
+#define RT1318_FMT_PCM_A_F			(0x6 << 0)
+#define RT1318_FMT_PCM_B_F			(0x7 << 0)
+#define RT1318_I2S_FMT_SFT			0
+/* TDM CTRL 2  (0xf901) */
+#define RT1318_I2S_CH_TX_MASK			(0x3 << 6)
+#define RT1318_I2S_CH_TX_2CH			(0x0 << 6)
+#define RT1318_I2S_CH_TX_4CH			(0x1 << 6)
+#define RT1318_I2S_CH_TX_6CH			(0x2 << 6)
+#define RT1318_I2S_CH_TX_8CH			(0x3 << 6)
+#define RT1318_I2S_CH_RX_MASK			(0x3 << 4)
+#define RT1318_I2S_CH_RX_2CH			(0x0 << 4)
+#define RT1318_I2S_CH_RX_4CH			(0x1 << 4)
+#define RT1318_I2S_CH_RX_6CH			(0x2 << 4)
+#define RT1318_I2S_CH_RX_8CH			(0x3 << 4)
+#define RT1318_I2S_DL_MASK			0x7
+#define RT1318_I2S_DL_SFT			0
+#define RT1318_I2S_DL_16			0x0
+#define RT1318_I2S_DL_20			0x1
+#define RT1318_I2S_DL_24			0x2
+#define RT1318_I2S_DL_32			0x3
+#define RT1318_I2S_DL_8				0x4
+/* TDM CTRL 3  (0xf902) */
+#define RT1318_I2S_TX_CHL_MASK			(0x7 << 4)
+#define RT1318_I2S_TX_CHL_SFT			4
+#define RT1318_I2S_TX_CHL_16			(0x0 << 4)
+#define RT1318_I2S_TX_CHL_20			(0x1 << 4)
+#define RT1318_I2S_TX_CHL_24			(0x2 << 4)
+#define RT1318_I2S_TX_CHL_32			(0x3 << 4)
+#define RT1318_I2S_TX_CHL_8			(0x4 << 4)
+#define RT1318_I2S_RX_CHL_MASK			(0x7 << 0)
+#define RT1318_I2S_RX_CHL_SFT			0
+#define RT1318_I2S_RX_CHL_16			(0x0 << 0)
+#define RT1318_I2S_RX_CHL_20			(0x1 << 0)
+#define RT1318_I2S_RX_CHL_24			(0x2 << 0)
+#define RT1318_I2S_RX_CHL_32			(0x3 << 0)
+#define RT1318_I2S_RX_CHL_8			(0x4 << 0)
+/* TDM CTRL 9  (0xf908) */
+#define RT1318_TDM_I2S_TX_L_DAC1_1_MASK		(0x7 << 4)
+#define RT1318_TDM_I2S_TX_R_DAC1_1_MASK		0x7
+#define RT1318_TDM_I2S_TX_L_DAC1_1_SFT		4
+#define RT1318_TDM_I2S_TX_R_DAC1_1_SFT		0
+
+#define RT1318_REG_DISP_LEN 23
+
+/* System Clock Source */
+enum {
+	RT1318_SCLK_S_BCLK,
+	RT1318_SCLK_S_SDW,
+	RT1318_SCLK_S_PLL2F,
+	RT1318_SCLK_S_PLL2B,
+	RT1318_SCLK_S_MCLK,
+	RT1318_SCLK_S_RC0,
+	RT1318_SCLK_S_RC1,
+	RT1318_SCLK_S_RC2,
+};
+
+/* PLL Source */
+enum {
+	RT1318_PLL_S_BCLK0,
+	RT1318_PLL_S_BCLK1,
+	RT1318_PLL_S_RC,
+	RT1318_PLL_S_MCLK,
+	RT1318_PLL_S_SDW_IN_PLL,
+	RT1318_PLL_S_SDW_0,
+	RT1318_PLL_S_SDW_1,
+	RT1318_PLL_S_SDW_2,
+};
+
+/* TDM channel */
+enum {
+	RT1318_2CH,
+	RT1318_4CH,
+	RT1318_6CH,
+	RT1318_8CH,
+};
+
+/* R0 calibration result */
+enum {
+	RT1318_R0_OUT_OF_RANGE,
+	RT1318_R0_IN_RANGE,
+	RT1318_R0_CALIB_NOT_DONE,
+};
+
+/* PLL pre-defined M/N/K */
+
+struct pll_calc_map {
+	unsigned int pll_in;
+	unsigned int pll_out;
+	int k;
+	int n;
+	int m;
+	bool m_bp;
+	bool k_bp;
+};
+
+struct rt1318_pll_code {
+	bool m_bp; /* Indicates bypass m code or not. */
+	bool k_bp; /* Indicates bypass k code or not. */
+	int m_code;
+	int n_code;
+	int k_code;
+};
+
+#endif /* __RT1318_H__ */
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
new file mode 100644
index 0000000000000000000000000000000000000000..2916fa77b791533a8d5775a1b92e0201c79fac0f
--- /dev/null
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -0,0 +1,2260 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1320-sdw.c -- rt1320 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/sdw.h>
+#include "rt1320-sdw.h"
+
+/*
+ * The 'blind writes' is an SDCA term to deal with platform-specific initialization.
+ * It might include vendor-specific or SDCA control registers.
+ */
+static const struct reg_sequence rt1320_blind_write[] = {
+	{ 0xc003, 0xe0 },
+	{ 0xc01b, 0xfc },
+	{ 0xc5c3, 0xf2 },
+	{ 0xc5c2, 0x00 },
+	{ 0xc5c6, 0x10 },
+	{ 0xc5c4, 0x12 },
+	{ 0xc5c8, 0x03 },
+	{ 0xc5d8, 0x0a },
+	{ 0xc5f7, 0x22 },
+	{ 0xc5f6, 0x22 },
+	{ 0xc5d0, 0x0f },
+	{ 0xc5d1, 0x89 },
+	{ 0xc057, 0x51 },
+	{ 0xc054, 0x35 },
+	{ 0xc053, 0x55 },
+	{ 0xc052, 0x55 },
+	{ 0xc051, 0x13 },
+	{ 0xc050, 0x15 },
+	{ 0xc060, 0x77 },
+	{ 0xc061, 0x55 },
+	{ 0xc063, 0x55 },
+	{ 0xc065, 0xa5 },
+	{ 0xc06b, 0x0a },
+	{ 0xca05, 0xd6 },
+	{ 0xca25, 0xd6 },
+	{ 0xcd00, 0x05 },
+	{ 0xc604, 0x40 },
+	{ 0xc609, 0x40 },
+	{ 0xc046, 0xff },
+	{ 0xc045, 0xff },
+	{ 0xc044, 0xff },
+	{ 0xc043, 0xff },
+	{ 0xc042, 0xff },
+	{ 0xc041, 0xff },
+	{ 0xc040, 0xff },
+	{ 0xcc10, 0x01 },
+	{ 0xc700, 0xf0 },
+	{ 0xc701, 0x13 },
+	{ 0xc901, 0x04 },
+	{ 0xc900, 0x73 },
+	{ 0xde03, 0x05 },
+	{ 0xdd0b, 0x0d },
+	{ 0xdd0a, 0xff },
+	{ 0xdd09, 0x0d },
+	{ 0xdd08, 0xff },
+	{ 0xc570, 0x08 },
+	{ 0xe803, 0xbe },
+	{ 0xc003, 0xc0 },
+	{ 0xc081, 0xfe },
+	{ 0xce31, 0x0d },
+	{ 0xce30, 0xae },
+	{ 0xce37, 0x0b },
+	{ 0xce36, 0xd2 },
+	{ 0xce39, 0x04 },
+	{ 0xce38, 0x80 },
+	{ 0xce3f, 0x00 },
+	{ 0xce3e, 0x00 },
+	{ 0xd470, 0x8b },
+	{ 0xd471, 0x18 },
+	{ 0xc019, 0x10 },
+	{ 0xd487, 0x3f },
+	{ 0xd486, 0xc3 },
+};
+
+/*
+ * The 'patch code' is written to the patch code area.
+ * The patch code area is used for SDCA register expansion flexibility.
+ */
+static const struct reg_sequence rt1320_patch_code_write[] = {
+	{ 0x10007000, 0x37 },
+	{ 0x10007001, 0x77 },
+	{ 0x10007002, 0x00 },
+	{ 0x10007003, 0x10 },
+	{ 0x10007004, 0xb7 },
+	{ 0x10007005, 0xe7 },
+	{ 0x10007006, 0x00 },
+	{ 0x10007007, 0x10 },
+	{ 0x10007008, 0x13 },
+	{ 0x10007009, 0x07 },
+	{ 0x1000700a, 0x07 },
+	{ 0x1000700b, 0x40 },
+	{ 0x1000700c, 0x23 },
+	{ 0x1000700d, 0xae },
+	{ 0x1000700e, 0xe7 },
+	{ 0x1000700f, 0xda },
+	{ 0x10007010, 0x37 },
+	{ 0x10007011, 0x77 },
+	{ 0x10007012, 0x00 },
+	{ 0x10007013, 0x10 },
+	{ 0x10007014, 0x13 },
+	{ 0x10007015, 0x07 },
+	{ 0x10007016, 0x47 },
+	{ 0x10007017, 0x61 },
+	{ 0x10007018, 0x23 },
+	{ 0x10007019, 0xa4 },
+	{ 0x1000701a, 0xe7 },
+	{ 0x1000701b, 0xde },
+	{ 0x1000701c, 0x37 },
+	{ 0x1000701d, 0x77 },
+	{ 0x1000701e, 0x00 },
+	{ 0x1000701f, 0x10 },
+	{ 0x10007020, 0x13 },
+	{ 0x10007021, 0x07 },
+	{ 0x10007022, 0x07 },
+	{ 0x10007023, 0x52 },
+	{ 0x10007024, 0x23 },
+	{ 0x10007025, 0xae },
+	{ 0x10007026, 0xe7 },
+	{ 0x10007027, 0xde },
+	{ 0x10007028, 0x37 },
+	{ 0x10007029, 0x77 },
+	{ 0x1000702a, 0x00 },
+	{ 0x1000702b, 0x10 },
+	{ 0x1000702c, 0x13 },
+	{ 0x1000702d, 0x07 },
+	{ 0x1000702e, 0x47 },
+	{ 0x1000702f, 0x54 },
+	{ 0x10007030, 0x23 },
+	{ 0x10007031, 0xaa },
+	{ 0x10007032, 0xe7 },
+	{ 0x10007033, 0xe4 },
+	{ 0x10007034, 0x37 },
+	{ 0x10007035, 0x87 },
+	{ 0x10007036, 0x00 },
+	{ 0x10007037, 0x10 },
+	{ 0x10007038, 0x13 },
+	{ 0x10007039, 0x07 },
+	{ 0x1000703a, 0x47 },
+	{ 0x1000703b, 0x81 },
+	{ 0x1000703c, 0x23 },
+	{ 0x1000703d, 0xa2 },
+	{ 0x1000703e, 0xe7 },
+	{ 0x1000703f, 0xe8 },
+	{ 0x10007040, 0x23 },
+	{ 0x10007041, 0xa4 },
+	{ 0x10007042, 0xe7 },
+	{ 0x10007043, 0xe8 },
+	{ 0x10007044, 0x37 },
+	{ 0x10007045, 0x77 },
+	{ 0x10007046, 0x00 },
+	{ 0x10007047, 0x10 },
+	{ 0x10007048, 0x13 },
+	{ 0x10007049, 0x07 },
+	{ 0x1000704a, 0x07 },
+	{ 0x1000704b, 0x59 },
+	{ 0x1000704c, 0x23 },
+	{ 0x1000704d, 0xa8 },
+	{ 0x1000704e, 0xe7 },
+	{ 0x1000704f, 0xea },
+	{ 0x10007050, 0x37 },
+	{ 0x10007051, 0x77 },
+	{ 0x10007052, 0x00 },
+	{ 0x10007053, 0x10 },
+	{ 0x10007054, 0x13 },
+	{ 0x10007055, 0x07 },
+	{ 0x10007056, 0x07 },
+	{ 0x10007057, 0x78 },
+	{ 0x10007058, 0x23 },
+	{ 0x10007059, 0xa6 },
+	{ 0x1000705a, 0xe7 },
+	{ 0x1000705b, 0xec },
+	{ 0x1000705c, 0x67 },
+	{ 0x1000705d, 0x80 },
+	{ 0x1000705e, 0x00 },
+	{ 0x1000705f, 0x00 },
+	{ 0x10007400, 0x37 },
+	{ 0x10007401, 0xd7 },
+	{ 0x10007402, 0x00 },
+	{ 0x10007403, 0x00 },
+	{ 0x10007404, 0x83 },
+	{ 0x10007405, 0x27 },
+	{ 0x10007406, 0x47 },
+	{ 0x10007407, 0x56 },
+	{ 0x10007408, 0xb7 },
+	{ 0x10007409, 0x06 },
+	{ 0x1000740a, 0x00 },
+	{ 0x1000740b, 0x02 },
+	{ 0x1000740c, 0xb3 },
+	{ 0x1000740d, 0xf7 },
+	{ 0x1000740e, 0xd7 },
+	{ 0x1000740f, 0x00 },
+	{ 0x10007410, 0x63 },
+	{ 0x10007411, 0x8a },
+	{ 0x10007412, 0x07 },
+	{ 0x10007413, 0x00 },
+	{ 0x10007414, 0x93 },
+	{ 0x10007415, 0x06 },
+	{ 0x10007416, 0x10 },
+	{ 0x10007417, 0x00 },
+	{ 0x10007418, 0x23 },
+	{ 0x10007419, 0x83 },
+	{ 0x1000741a, 0xd1 },
+	{ 0x1000741b, 0x44 },
+	{ 0x1000741c, 0x93 },
+	{ 0x1000741d, 0x07 },
+	{ 0x1000741e, 0xf0 },
+	{ 0x1000741f, 0xff },
+	{ 0x10007420, 0x23 },
+	{ 0x10007421, 0x22 },
+	{ 0x10007422, 0xf7 },
+	{ 0x10007423, 0x56 },
+	{ 0x10007424, 0x37 },
+	{ 0x10007425, 0xd7 },
+	{ 0x10007426, 0x00 },
+	{ 0x10007427, 0x00 },
+	{ 0x10007428, 0x83 },
+	{ 0x10007429, 0x27 },
+	{ 0x1000742a, 0x47 },
+	{ 0x1000742b, 0x58 },
+	{ 0x1000742c, 0x93 },
+	{ 0x1000742d, 0xf7 },
+	{ 0x1000742e, 0x17 },
+	{ 0x1000742f, 0x00 },
+	{ 0x10007430, 0x63 },
+	{ 0x10007431, 0x86 },
+	{ 0x10007432, 0x07 },
+	{ 0x10007433, 0x00 },
+	{ 0x10007434, 0x93 },
+	{ 0x10007435, 0x07 },
+	{ 0x10007436, 0x10 },
+	{ 0x10007437, 0x00 },
+	{ 0x10007438, 0x23 },
+	{ 0x10007439, 0x22 },
+	{ 0x1000743a, 0xf7 },
+	{ 0x1000743b, 0x58 },
+	{ 0x1000743c, 0xb7 },
+	{ 0x1000743d, 0xd7 },
+	{ 0x1000743e, 0x00 },
+	{ 0x1000743f, 0x00 },
+	{ 0x10007440, 0x03 },
+	{ 0x10007441, 0xa7 },
+	{ 0x10007442, 0x47 },
+	{ 0x10007443, 0x58 },
+	{ 0x10007444, 0xb7 },
+	{ 0x10007445, 0x07 },
+	{ 0x10007446, 0x00 },
+	{ 0x10007447, 0x04 },
+	{ 0x10007448, 0x33 },
+	{ 0x10007449, 0x77 },
+	{ 0x1000744a, 0xf7 },
+	{ 0x1000744b, 0x00 },
+	{ 0x1000744c, 0x93 },
+	{ 0x1000744d, 0x07 },
+	{ 0x1000744e, 0x00 },
+	{ 0x1000744f, 0x00 },
+	{ 0x10007450, 0x63 },
+	{ 0x10007451, 0x0e },
+	{ 0x10007452, 0x07 },
+	{ 0x10007453, 0x04 },
+	{ 0x10007454, 0x37 },
+	{ 0x10007455, 0x07 },
+	{ 0x10007456, 0x00 },
+	{ 0x10007457, 0x11 },
+	{ 0x10007458, 0x03 },
+	{ 0x10007459, 0x47 },
+	{ 0x1000745a, 0x87 },
+	{ 0x1000745b, 0x0e },
+	{ 0x1000745c, 0x93 },
+	{ 0x1000745d, 0x06 },
+	{ 0x1000745e, 0x40 },
+	{ 0x1000745f, 0x00 },
+	{ 0x10007460, 0x13 },
+	{ 0x10007461, 0x77 },
+	{ 0x10007462, 0xf7 },
+	{ 0x10007463, 0x0f },
+	{ 0x10007464, 0x63 },
+	{ 0x10007465, 0x02 },
+	{ 0x10007466, 0xd7 },
+	{ 0x10007467, 0x0a },
+	{ 0x10007468, 0x93 },
+	{ 0x10007469, 0x06 },
+	{ 0x1000746a, 0x70 },
+	{ 0x1000746b, 0x00 },
+	{ 0x1000746c, 0x63 },
+	{ 0x1000746d, 0x10 },
+	{ 0x1000746e, 0xd7 },
+	{ 0x1000746f, 0x04 },
+	{ 0x10007470, 0x93 },
+	{ 0x10007471, 0x07 },
+	{ 0x10007472, 0x60 },
+	{ 0x10007473, 0x06 },
+	{ 0x10007474, 0x37 },
+	{ 0x10007475, 0xd7 },
+	{ 0x10007476, 0x00 },
+	{ 0x10007477, 0x00 },
+	{ 0x10007478, 0x83 },
+	{ 0x10007479, 0x46 },
+	{ 0x1000747a, 0x77 },
+	{ 0x1000747b, 0xa6 },
+	{ 0x1000747c, 0x93 },
+	{ 0x1000747d, 0xe6 },
+	{ 0x1000747e, 0x06 },
+	{ 0x1000747f, 0xf8 },
+	{ 0x10007480, 0x93 },
+	{ 0x10007481, 0xf6 },
+	{ 0x10007482, 0xf6 },
+	{ 0x10007483, 0x0f },
+	{ 0x10007484, 0xa3 },
+	{ 0x10007485, 0x03 },
+	{ 0x10007486, 0xd7 },
+	{ 0x10007487, 0xa6 },
+	{ 0x10007488, 0x83 },
+	{ 0x10007489, 0x46 },
+	{ 0x1000748a, 0x77 },
+	{ 0x1000748b, 0xa8 },
+	{ 0x1000748c, 0x93 },
+	{ 0x1000748d, 0xe6 },
+	{ 0x1000748e, 0x06 },
+	{ 0x1000748f, 0xf8 },
+	{ 0x10007490, 0x93 },
+	{ 0x10007491, 0xf6 },
+	{ 0x10007492, 0xf6 },
+	{ 0x10007493, 0x0f },
+	{ 0x10007494, 0xa3 },
+	{ 0x10007495, 0x03 },
+	{ 0x10007496, 0xd7 },
+	{ 0x10007497, 0xa8 },
+	{ 0x10007498, 0xb7 },
+	{ 0x10007499, 0xc6 },
+	{ 0x1000749a, 0x00 },
+	{ 0x1000749b, 0x00 },
+	{ 0x1000749c, 0x23 },
+	{ 0x1000749d, 0x84 },
+	{ 0x1000749e, 0xf6 },
+	{ 0x1000749f, 0x06 },
+	{ 0x100074a0, 0xa3 },
+	{ 0x100074a1, 0x84 },
+	{ 0x100074a2, 0xf6 },
+	{ 0x100074a3, 0x06 },
+	{ 0x100074a4, 0xb7 },
+	{ 0x100074a5, 0x06 },
+	{ 0x100074a6, 0x00 },
+	{ 0x100074a7, 0x04 },
+	{ 0x100074a8, 0x23 },
+	{ 0x100074a9, 0x22 },
+	{ 0x100074aa, 0xd7 },
+	{ 0x100074ab, 0x58 },
+	{ 0x100074ac, 0x37 },
+	{ 0x100074ad, 0xd7 },
+	{ 0x100074ae, 0x00 },
+	{ 0x100074af, 0x00 },
+	{ 0x100074b0, 0x03 },
+	{ 0x100074b1, 0x27 },
+	{ 0x100074b2, 0x47 },
+	{ 0x100074b3, 0x58 },
+	{ 0x100074b4, 0xb7 },
+	{ 0x100074b5, 0x06 },
+	{ 0x100074b6, 0x00 },
+	{ 0x100074b7, 0x08 },
+	{ 0x100074b8, 0x33 },
+	{ 0x100074b9, 0x77 },
+	{ 0x100074ba, 0xd7 },
+	{ 0x100074bb, 0x00 },
+	{ 0x100074bc, 0x63 },
+	{ 0x100074bd, 0x04 },
+	{ 0x100074be, 0x07 },
+	{ 0x100074bf, 0x04 },
+	{ 0x100074c0, 0x37 },
+	{ 0x100074c1, 0x07 },
+	{ 0x100074c2, 0x00 },
+	{ 0x100074c3, 0x11 },
+	{ 0x100074c4, 0x03 },
+	{ 0x100074c5, 0x47 },
+	{ 0x100074c6, 0xc7 },
+	{ 0x100074c7, 0x0e },
+	{ 0x100074c8, 0x93 },
+	{ 0x100074c9, 0x06 },
+	{ 0x100074ca, 0x40 },
+	{ 0x100074cb, 0x00 },
+	{ 0x100074cc, 0x13 },
+	{ 0x100074cd, 0x77 },
+	{ 0x100074ce, 0xf7 },
+	{ 0x100074cf, 0x0f },
+	{ 0x100074d0, 0x63 },
+	{ 0x100074d1, 0x00 },
+	{ 0x100074d2, 0xd7 },
+	{ 0x100074d3, 0x04 },
+	{ 0x100074d4, 0x93 },
+	{ 0x100074d5, 0x06 },
+	{ 0x100074d6, 0x70 },
+	{ 0x100074d7, 0x00 },
+	{ 0x100074d8, 0x63 },
+	{ 0x100074d9, 0x00 },
+	{ 0x100074da, 0xd7 },
+	{ 0x100074db, 0x04 },
+	{ 0x100074dc, 0x63 },
+	{ 0x100074dd, 0x84 },
+	{ 0x100074de, 0x07 },
+	{ 0x100074df, 0x02 },
+	{ 0x100074e0, 0xb7 },
+	{ 0x100074e1, 0xd6 },
+	{ 0x100074e2, 0x00 },
+	{ 0x100074e3, 0x00 },
+	{ 0x100074e4, 0x03 },
+	{ 0x100074e5, 0xc7 },
+	{ 0x100074e6, 0x56 },
+	{ 0x100074e7, 0xa4 },
+	{ 0x100074e8, 0x13 },
+	{ 0x100074e9, 0x67 },
+	{ 0x100074ea, 0x07 },
+	{ 0x100074eb, 0xf8 },
+	{ 0x100074ec, 0x13 },
+	{ 0x100074ed, 0x77 },
+	{ 0x100074ee, 0xf7 },
+	{ 0x100074ef, 0x0f },
+	{ 0x100074f0, 0xa3 },
+	{ 0x100074f1, 0x82 },
+	{ 0x100074f2, 0xe6 },
+	{ 0x100074f3, 0xa4 },
+	{ 0x100074f4, 0x37 },
+	{ 0x100074f5, 0xc7 },
+	{ 0x100074f6, 0x00 },
+	{ 0x100074f7, 0x00 },
+	{ 0x100074f8, 0x23 },
+	{ 0x100074f9, 0x02 },
+	{ 0x100074fa, 0xf7 },
+	{ 0x100074fb, 0x06 },
+	{ 0x100074fc, 0xb7 },
+	{ 0x100074fd, 0x07 },
+	{ 0x100074fe, 0x00 },
+	{ 0x100074ff, 0x08 },
+	{ 0x10007500, 0x23 },
+	{ 0x10007501, 0xa2 },
+	{ 0x10007502, 0xf6 },
+	{ 0x10007503, 0x58 },
+	{ 0x10007504, 0x67 },
+	{ 0x10007505, 0x80 },
+	{ 0x10007506, 0x00 },
+	{ 0x10007507, 0x00 },
+	{ 0x10007508, 0x93 },
+	{ 0x10007509, 0x07 },
+	{ 0x1000750a, 0x80 },
+	{ 0x1000750b, 0x08 },
+	{ 0x1000750c, 0x6f },
+	{ 0x1000750d, 0xf0 },
+	{ 0x1000750e, 0x9f },
+	{ 0x1000750f, 0xf6 },
+	{ 0x10007510, 0x93 },
+	{ 0x10007511, 0x07 },
+	{ 0x10007512, 0x80 },
+	{ 0x10007513, 0x08 },
+	{ 0x10007514, 0x6f },
+	{ 0x10007515, 0xf0 },
+	{ 0x10007516, 0xdf },
+	{ 0x10007517, 0xfc },
+	{ 0x10007518, 0x93 },
+	{ 0x10007519, 0x07 },
+	{ 0x1000751a, 0x60 },
+	{ 0x1000751b, 0x06 },
+	{ 0x1000751c, 0x6f },
+	{ 0x1000751d, 0xf0 },
+	{ 0x1000751e, 0x5f },
+	{ 0x1000751f, 0xfc },
+	{ 0x10007520, 0x37 },
+	{ 0x10007521, 0xd7 },
+	{ 0x10007522, 0x00 },
+	{ 0x10007523, 0x00 },
+	{ 0x10007524, 0x83 },
+	{ 0x10007525, 0x27 },
+	{ 0x10007526, 0x07 },
+	{ 0x10007527, 0x53 },
+	{ 0x10007528, 0xb7 },
+	{ 0x10007529, 0x06 },
+	{ 0x1000752a, 0x02 },
+	{ 0x1000752b, 0x00 },
+	{ 0x1000752c, 0xb3 },
+	{ 0x1000752d, 0xf7 },
+	{ 0x1000752e, 0xd7 },
+	{ 0x1000752f, 0x00 },
+	{ 0x10007530, 0x63 },
+	{ 0x10007531, 0x88 },
+	{ 0x10007532, 0x07 },
+	{ 0x10007533, 0x00 },
+	{ 0x10007534, 0x13 },
+	{ 0x10007535, 0x06 },
+	{ 0x10007536, 0xa0 },
+	{ 0x10007537, 0x05 },
+	{ 0x10007538, 0x23 },
+	{ 0x10007539, 0xa8 },
+	{ 0x1000753a, 0xc1 },
+	{ 0x1000753b, 0x56 },
+	{ 0x1000753c, 0x23 },
+	{ 0x1000753d, 0x28 },
+	{ 0x1000753e, 0xd7 },
+	{ 0x1000753f, 0x52 },
+	{ 0x10007540, 0x67 },
+	{ 0x10007541, 0x80 },
+	{ 0x10007542, 0x00 },
+	{ 0x10007543, 0x00 },
+	{ 0x10007544, 0x37 },
+	{ 0x10007545, 0xd7 },
+	{ 0x10007546, 0x00 },
+	{ 0x10007547, 0x10 },
+	{ 0x10007548, 0x83 },
+	{ 0x10007549, 0x47 },
+	{ 0x1000754a, 0x07 },
+	{ 0x1000754b, 0xd9 },
+	{ 0x1000754c, 0x93 },
+	{ 0x1000754d, 0x06 },
+	{ 0x1000754e, 0x20 },
+	{ 0x1000754f, 0x00 },
+	{ 0x10007550, 0x93 },
+	{ 0x10007551, 0xf7 },
+	{ 0x10007552, 0xf7 },
+	{ 0x10007553, 0x0f },
+	{ 0x10007554, 0x63 },
+	{ 0x10007555, 0x9c },
+	{ 0x10007556, 0xd7 },
+	{ 0x10007557, 0x02 },
+	{ 0x10007558, 0xb7 },
+	{ 0x10007559, 0xc6 },
+	{ 0x1000755a, 0x00 },
+	{ 0x1000755b, 0x00 },
+	{ 0x1000755c, 0x83 },
+	{ 0x1000755d, 0xc7 },
+	{ 0x1000755e, 0x26 },
+	{ 0x1000755f, 0x04 },
+	{ 0x10007560, 0x93 },
+	{ 0x10007561, 0xf7 },
+	{ 0x10007562, 0xf7 },
+	{ 0x10007563, 0x07 },
+	{ 0x10007564, 0x23 },
+	{ 0x10007565, 0x81 },
+	{ 0x10007566, 0xf6 },
+	{ 0x10007567, 0x04 },
+	{ 0x10007568, 0xb7 },
+	{ 0x10007569, 0xd6 },
+	{ 0x1000756a, 0x00 },
+	{ 0x1000756b, 0x00 },
+	{ 0x1000756c, 0x83 },
+	{ 0x1000756d, 0xc7 },
+	{ 0x1000756e, 0xa6 },
+	{ 0x1000756f, 0xe1 },
+	{ 0x10007570, 0x93 },
+	{ 0x10007571, 0xf7 },
+	{ 0x10007572, 0xf7 },
+	{ 0x10007573, 0x07 },
+	{ 0x10007574, 0x23 },
+	{ 0x10007575, 0x8d },
+	{ 0x10007576, 0xf6 },
+	{ 0x10007577, 0xe0 },
+	{ 0x10007578, 0x23 },
+	{ 0x10007579, 0x08 },
+	{ 0x1000757a, 0x07 },
+	{ 0x1000757b, 0xd8 },
+	{ 0x1000757c, 0x83 },
+	{ 0x1000757d, 0x47 },
+	{ 0x1000757e, 0x47 },
+	{ 0x1000757f, 0xd9 },
+	{ 0x10007580, 0x93 },
+	{ 0x10007581, 0x87 },
+	{ 0x10007582, 0x17 },
+	{ 0x10007583, 0x00 },
+	{ 0x10007584, 0x93 },
+	{ 0x10007585, 0xf7 },
+	{ 0x10007586, 0xf7 },
+	{ 0x10007587, 0x0f },
+	{ 0x10007588, 0x23 },
+	{ 0x10007589, 0x0a },
+	{ 0x1000758a, 0xf7 },
+	{ 0x1000758b, 0xd8 },
+	{ 0x1000758c, 0x67 },
+	{ 0x1000758d, 0x80 },
+	{ 0x1000758e, 0x00 },
+	{ 0x1000758f, 0x00 },
+	{ 0x10007590, 0xb7 },
+	{ 0x10007591, 0xd7 },
+	{ 0x10007592, 0x00 },
+	{ 0x10007593, 0x00 },
+	{ 0x10007594, 0x83 },
+	{ 0x10007595, 0xc7 },
+	{ 0x10007596, 0x07 },
+	{ 0x10007597, 0x47 },
+	{ 0x10007598, 0x93 },
+	{ 0x10007599, 0xf7 },
+	{ 0x1000759a, 0x07 },
+	{ 0x1000759b, 0x01 },
+	{ 0x1000759c, 0x63 },
+	{ 0x1000759d, 0x8a },
+	{ 0x1000759e, 0x07 },
+	{ 0x1000759f, 0x06 },
+	{ 0x100075a0, 0x63 },
+	{ 0x100075a1, 0x02 },
+	{ 0x100075a2, 0x05 },
+	{ 0x100075a3, 0x06 },
+	{ 0x100075a4, 0x37 },
+	{ 0x100075a5, 0xc7 },
+	{ 0x100075a6, 0x00 },
+	{ 0x100075a7, 0x00 },
+	{ 0x100075a8, 0x83 },
+	{ 0x100075a9, 0x27 },
+	{ 0x100075aa, 0xc7 },
+	{ 0x100075ab, 0x5f },
+	{ 0x100075ac, 0x23 },
+	{ 0x100075ad, 0xae },
+	{ 0x100075ae, 0xf1 },
+	{ 0x100075af, 0x40 },
+	{ 0x100075b0, 0xb7 },
+	{ 0x100075b1, 0x06 },
+	{ 0x100075b2, 0x00 },
+	{ 0x100075b3, 0x10 },
+	{ 0x100075b4, 0xb3 },
+	{ 0x100075b5, 0xf7 },
+	{ 0x100075b6, 0xd7 },
+	{ 0x100075b7, 0x00 },
+	{ 0x100075b8, 0x63 },
+	{ 0x100075b9, 0x8c },
+	{ 0x100075ba, 0x07 },
+	{ 0x100075bb, 0x04 },
+	{ 0x100075bc, 0x83 },
+	{ 0x100075bd, 0x47 },
+	{ 0x100075be, 0x07 },
+	{ 0x100075bf, 0x56 },
+	{ 0x100075c0, 0x93 },
+	{ 0x100075c1, 0xf7 },
+	{ 0x100075c2, 0x87 },
+	{ 0x100075c3, 0x01 },
+	{ 0x100075c4, 0x63 },
+	{ 0x100075c5, 0x86 },
+	{ 0x100075c6, 0x07 },
+	{ 0x100075c7, 0x04 },
+	{ 0x100075c8, 0x83 },
+	{ 0x100075c9, 0x47 },
+	{ 0x100075ca, 0x17 },
+	{ 0x100075cb, 0x08 },
+	{ 0x100075cc, 0x93 },
+	{ 0x100075cd, 0xf7 },
+	{ 0x100075ce, 0x47 },
+	{ 0x100075cf, 0x00 },
+	{ 0x100075d0, 0x63 },
+	{ 0x100075d1, 0x80 },
+	{ 0x100075d2, 0x07 },
+	{ 0x100075d3, 0x04 },
+	{ 0x100075d4, 0xb7 },
+	{ 0x100075d5, 0xc7 },
+	{ 0x100075d6, 0xc2 },
+	{ 0x100075d7, 0x3f },
+	{ 0x100075d8, 0x93 },
+	{ 0x100075d9, 0x87 },
+	{ 0x100075da, 0x07 },
+	{ 0x100075db, 0xfc },
+	{ 0x100075dc, 0x83 },
+	{ 0x100075dd, 0xa7 },
+	{ 0x100075de, 0x47 },
+	{ 0x100075df, 0x00 },
+	{ 0x100075e0, 0x93 },
+	{ 0x100075e1, 0xd7 },
+	{ 0x100075e2, 0x17 },
+	{ 0x100075e3, 0x00 },
+	{ 0x100075e4, 0x93 },
+	{ 0x100075e5, 0xf7 },
+	{ 0x100075e6, 0x17 },
+	{ 0x100075e7, 0x00 },
+	{ 0x100075e8, 0x63 },
+	{ 0x100075e9, 0x84 },
+	{ 0x100075ea, 0x07 },
+	{ 0x100075eb, 0x02 },
+	{ 0x100075ec, 0x23 },
+	{ 0x100075ed, 0x8a },
+	{ 0x100075ee, 0xf1 },
+	{ 0x100075ef, 0x40 },
+	{ 0x100075f0, 0xb7 },
+	{ 0x100075f1, 0x07 },
+	{ 0x100075f2, 0x00 },
+	{ 0x100075f3, 0xc0 },
+	{ 0x100075f4, 0x37 },
+	{ 0x100075f5, 0xf7 },
+	{ 0x100075f6, 0x00 },
+	{ 0x100075f7, 0x00 },
+	{ 0x100075f8, 0x93 },
+	{ 0x100075f9, 0x87 },
+	{ 0x100075fa, 0xf7 },
+	{ 0x100075fb, 0xff },
+	{ 0x100075fc, 0x23 },
+	{ 0x100075fd, 0x2c },
+	{ 0x100075fe, 0xf7 },
+	{ 0x100075ff, 0x06 },
+	{ 0x10007600, 0x67 },
+	{ 0x10007601, 0x80 },
+	{ 0x10007602, 0x00 },
+	{ 0x10007603, 0x00 },
+	{ 0x10007604, 0x23 },
+	{ 0x10007605, 0x8a },
+	{ 0x10007606, 0x01 },
+	{ 0x10007607, 0x40 },
+	{ 0x10007608, 0xb7 },
+	{ 0x10007609, 0xf7 },
+	{ 0x1000760a, 0x00 },
+	{ 0x1000760b, 0x00 },
+	{ 0x1000760c, 0x23 },
+	{ 0x1000760d, 0xac },
+	{ 0x1000760e, 0x07 },
+	{ 0x1000760f, 0x06 },
+	{ 0x10007610, 0x67 },
+	{ 0x10007611, 0x80 },
+	{ 0x10007612, 0x00 },
+	{ 0x10007613, 0x00 },
+	{ 0x10007614, 0x13 },
+	{ 0x10007615, 0x01 },
+	{ 0x10007616, 0x01 },
+	{ 0x10007617, 0xff },
+	{ 0x10007618, 0x23 },
+	{ 0x10007619, 0x26 },
+	{ 0x1000761a, 0x11 },
+	{ 0x1000761b, 0x00 },
+	{ 0x1000761c, 0x23 },
+	{ 0x1000761d, 0x24 },
+	{ 0x1000761e, 0x81 },
+	{ 0x1000761f, 0x00 },
+	{ 0x10007620, 0x37 },
+	{ 0x10007621, 0xc7 },
+	{ 0x10007622, 0x00 },
+	{ 0x10007623, 0x00 },
+	{ 0x10007624, 0x83 },
+	{ 0x10007625, 0x47 },
+	{ 0x10007626, 0x07 },
+	{ 0x10007627, 0x56 },
+	{ 0x10007628, 0x93 },
+	{ 0x10007629, 0xf7 },
+	{ 0x1000762a, 0x17 },
+	{ 0x1000762b, 0x00 },
+	{ 0x1000762c, 0x63 },
+	{ 0x1000762d, 0x98 },
+	{ 0x1000762e, 0x07 },
+	{ 0x1000762f, 0x00 },
+	{ 0x10007630, 0x83 },
+	{ 0x10007631, 0x47 },
+	{ 0x10007632, 0x07 },
+	{ 0x10007633, 0x56 },
+	{ 0x10007634, 0x93 },
+	{ 0x10007635, 0xf7 },
+	{ 0x10007636, 0x27 },
+	{ 0x10007637, 0x00 },
+	{ 0x10007638, 0x63 },
+	{ 0x10007639, 0x82 },
+	{ 0x1000763a, 0x07 },
+	{ 0x1000763b, 0x08 },
+	{ 0x1000763c, 0x37 },
+	{ 0x1000763d, 0xd4 },
+	{ 0x1000763e, 0x00 },
+	{ 0x1000763f, 0x00 },
+	{ 0x10007640, 0x83 },
+	{ 0x10007641, 0x47 },
+	{ 0x10007642, 0x14 },
+	{ 0x10007643, 0x47 },
+	{ 0x10007644, 0x93 },
+	{ 0x10007645, 0xf7 },
+	{ 0x10007646, 0x27 },
+	{ 0x10007647, 0x00 },
+	{ 0x10007648, 0x63 },
+	{ 0x10007649, 0x8a },
+	{ 0x1000764a, 0x07 },
+	{ 0x1000764b, 0x06 },
+	{ 0x1000764c, 0x93 },
+	{ 0x1000764d, 0x05 },
+	{ 0x1000764e, 0x10 },
+	{ 0x1000764f, 0x00 },
+	{ 0x10007650, 0x13 },
+	{ 0x10007651, 0x05 },
+	{ 0x10007652, 0x20 },
+	{ 0x10007653, 0x10 },
+	{ 0x10007654, 0xef },
+	{ 0x10007655, 0xa0 },
+	{ 0x10007656, 0x8f },
+	{ 0x10007657, 0x9a },
+	{ 0x10007658, 0x37 },
+	{ 0x10007659, 0x05 },
+	{ 0x1000765a, 0x01 },
+	{ 0x1000765b, 0x00 },
+	{ 0x1000765c, 0x93 },
+	{ 0x1000765d, 0x05 },
+	{ 0x1000765e, 0x00 },
+	{ 0x1000765f, 0x01 },
+	{ 0x10007660, 0x13 },
+	{ 0x10007661, 0x05 },
+	{ 0x10007662, 0xb5 },
+	{ 0x10007663, 0xa0 },
+	{ 0x10007664, 0xef },
+	{ 0x10007665, 0xa0 },
+	{ 0x10007666, 0x8f },
+	{ 0x10007667, 0x99 },
+	{ 0x10007668, 0x83 },
+	{ 0x10007669, 0x47 },
+	{ 0x1000766a, 0x24 },
+	{ 0x1000766b, 0xe0 },
+	{ 0x1000766c, 0x13 },
+	{ 0x1000766d, 0x05 },
+	{ 0x1000766e, 0x80 },
+	{ 0x1000766f, 0x3e },
+	{ 0x10007670, 0x93 },
+	{ 0x10007671, 0x05 },
+	{ 0x10007672, 0x00 },
+	{ 0x10007673, 0x00 },
+	{ 0x10007674, 0x93 },
+	{ 0x10007675, 0xe7 },
+	{ 0x10007676, 0x07 },
+	{ 0x10007677, 0xf8 },
+	{ 0x10007678, 0x93 },
+	{ 0x10007679, 0xf7 },
+	{ 0x1000767a, 0xf7 },
+	{ 0x1000767b, 0x0f },
+	{ 0x1000767c, 0x23 },
+	{ 0x1000767d, 0x01 },
+	{ 0x1000767e, 0xf4 },
+	{ 0x1000767f, 0xe0 },
+	{ 0x10007680, 0x83 },
+	{ 0x10007681, 0x47 },
+	{ 0x10007682, 0x24 },
+	{ 0x10007683, 0xe0 },
+	{ 0x10007684, 0x93 },
+	{ 0x10007685, 0xf7 },
+	{ 0x10007686, 0xf7 },
+	{ 0x10007687, 0x0f },
+	{ 0x10007688, 0x93 },
+	{ 0x10007689, 0xe7 },
+	{ 0x1000768a, 0x07 },
+	{ 0x1000768b, 0x04 },
+	{ 0x1000768c, 0x23 },
+	{ 0x1000768d, 0x01 },
+	{ 0x1000768e, 0xf4 },
+	{ 0x1000768f, 0xe0 },
+	{ 0x10007690, 0xef },
+	{ 0x10007691, 0xe0 },
+	{ 0x10007692, 0x8f },
+	{ 0x10007693, 0xb9 },
+	{ 0x10007694, 0x83 },
+	{ 0x10007695, 0x47 },
+	{ 0x10007696, 0x34 },
+	{ 0x10007697, 0xe0 },
+	{ 0x10007698, 0x93 },
+	{ 0x10007699, 0xf7 },
+	{ 0x1000769a, 0x07 },
+	{ 0x1000769b, 0x02 },
+	{ 0x1000769c, 0xe3 },
+	{ 0x1000769d, 0x9c },
+	{ 0x1000769e, 0x07 },
+	{ 0x1000769f, 0xfe },
+	{ 0x100076a0, 0x37 },
+	{ 0x100076a1, 0x05 },
+	{ 0x100076a2, 0x01 },
+	{ 0x100076a3, 0x00 },
+	{ 0x100076a4, 0x93 },
+	{ 0x100076a5, 0x05 },
+	{ 0x100076a6, 0x00 },
+	{ 0x100076a7, 0x00 },
+	{ 0x100076a8, 0x13 },
+	{ 0x100076a9, 0x05 },
+	{ 0x100076aa, 0xb5 },
+	{ 0x100076ab, 0xa0 },
+	{ 0x100076ac, 0xef },
+	{ 0x100076ad, 0xa0 },
+	{ 0x100076ae, 0x0f },
+	{ 0x100076af, 0x95 },
+	{ 0x100076b0, 0x83 },
+	{ 0x100076b1, 0x47 },
+	{ 0x100076b2, 0x14 },
+	{ 0x100076b3, 0x47 },
+	{ 0x100076b4, 0x93 },
+	{ 0x100076b5, 0xf7 },
+	{ 0x100076b6, 0xd7 },
+	{ 0x100076b7, 0x0f },
+	{ 0x100076b8, 0xa3 },
+	{ 0x100076b9, 0x08 },
+	{ 0x100076ba, 0xf4 },
+	{ 0x100076bb, 0x46 },
+	{ 0x100076bc, 0x03 },
+	{ 0x100076bd, 0xa7 },
+	{ 0x100076be, 0x01 },
+	{ 0x100076bf, 0x57 },
+	{ 0x100076c0, 0x93 },
+	{ 0x100076c1, 0x07 },
+	{ 0x100076c2, 0xa0 },
+	{ 0x100076c3, 0x05 },
+	{ 0x100076c4, 0x63 },
+	{ 0x100076c5, 0x14 },
+	{ 0x100076c6, 0xf7 },
+	{ 0x100076c7, 0x04 },
+	{ 0x100076c8, 0x37 },
+	{ 0x100076c9, 0x07 },
+	{ 0x100076ca, 0x00 },
+	{ 0x100076cb, 0x11 },
+	{ 0x100076cc, 0x83 },
+	{ 0x100076cd, 0x47 },
+	{ 0x100076ce, 0x07 },
+	{ 0x100076cf, 0x01 },
+	{ 0x100076d0, 0x13 },
+	{ 0x100076d1, 0x06 },
+	{ 0x100076d2, 0x30 },
+	{ 0x100076d3, 0x00 },
+	{ 0x100076d4, 0x93 },
+	{ 0x100076d5, 0xf7 },
+	{ 0x100076d6, 0xf7 },
+	{ 0x100076d7, 0x0f },
+	{ 0x100076d8, 0x63 },
+	{ 0x100076d9, 0x9a },
+	{ 0x100076da, 0xc7 },
+	{ 0x100076db, 0x02 },
+	{ 0x100076dc, 0x03 },
+	{ 0x100076dd, 0x47 },
+	{ 0x100076de, 0x87 },
+	{ 0x100076df, 0x01 },
+	{ 0x100076e0, 0x13 },
+	{ 0x100076e1, 0x77 },
+	{ 0x100076e2, 0xf7 },
+	{ 0x100076e3, 0x0f },
+	{ 0x100076e4, 0x63 },
+	{ 0x100076e5, 0x14 },
+	{ 0x100076e6, 0xf7 },
+	{ 0x100076e7, 0x02 },
+	{ 0x100076e8, 0x37 },
+	{ 0x100076e9, 0xd7 },
+	{ 0x100076ea, 0x00 },
+	{ 0x100076eb, 0x00 },
+	{ 0x100076ec, 0x83 },
+	{ 0x100076ed, 0x47 },
+	{ 0x100076ee, 0x37 },
+	{ 0x100076ef, 0x54 },
+	{ 0x100076f0, 0x93 },
+	{ 0x100076f1, 0xf7 },
+	{ 0x100076f2, 0xf7 },
+	{ 0x100076f3, 0x0f },
+	{ 0x100076f4, 0x93 },
+	{ 0x100076f5, 0xe7 },
+	{ 0x100076f6, 0x07 },
+	{ 0x100076f7, 0x02 },
+	{ 0x100076f8, 0xa3 },
+	{ 0x100076f9, 0x01 },
+	{ 0x100076fa, 0xf7 },
+	{ 0x100076fb, 0x54 },
+	{ 0x100076fc, 0x83 },
+	{ 0x100076fd, 0x47 },
+	{ 0x100076fe, 0x37 },
+	{ 0x100076ff, 0x54 },
+	{ 0x10007700, 0x93 },
+	{ 0x10007701, 0xf7 },
+	{ 0x10007702, 0xf7 },
+	{ 0x10007703, 0x0d },
+	{ 0x10007704, 0xa3 },
+	{ 0x10007705, 0x01 },
+	{ 0x10007706, 0xf7 },
+	{ 0x10007707, 0x54 },
+	{ 0x10007708, 0x23 },
+	{ 0x10007709, 0xa8 },
+	{ 0x1000770a, 0x01 },
+	{ 0x1000770b, 0x56 },
+	{ 0x1000770c, 0xb7 },
+	{ 0x1000770d, 0xd7 },
+	{ 0x1000770e, 0x00 },
+	{ 0x1000770f, 0x10 },
+	{ 0x10007710, 0x03 },
+	{ 0x10007711, 0xc7 },
+	{ 0x10007712, 0x07 },
+	{ 0x10007713, 0xd9 },
+	{ 0x10007714, 0x93 },
+	{ 0x10007715, 0x06 },
+	{ 0x10007716, 0x10 },
+	{ 0x10007717, 0x00 },
+	{ 0x10007718, 0x13 },
+	{ 0x10007719, 0x77 },
+	{ 0x1000771a, 0xf7 },
+	{ 0x1000771b, 0x0f },
+	{ 0x1000771c, 0x63 },
+	{ 0x1000771d, 0x1a },
+	{ 0x1000771e, 0xd7 },
+	{ 0x1000771f, 0x04 },
+	{ 0x10007720, 0x03 },
+	{ 0x10007721, 0xc7 },
+	{ 0x10007722, 0x27 },
+	{ 0x10007723, 0xd9 },
+	{ 0x10007724, 0x13 },
+	{ 0x10007725, 0x07 },
+	{ 0x10007726, 0x17 },
+	{ 0x10007727, 0x00 },
+	{ 0x10007728, 0x13 },
+	{ 0x10007729, 0x77 },
+	{ 0x1000772a, 0xf7 },
+	{ 0x1000772b, 0x0f },
+	{ 0x1000772c, 0x23 },
+	{ 0x1000772d, 0x89 },
+	{ 0x1000772e, 0xe7 },
+	{ 0x1000772f, 0xd8 },
+	{ 0x10007730, 0x83 },
+	{ 0x10007731, 0xc6 },
+	{ 0x10007732, 0x27 },
+	{ 0x10007733, 0xd9 },
+	{ 0x10007734, 0x03 },
+	{ 0x10007735, 0xc7 },
+	{ 0x10007736, 0x17 },
+	{ 0x10007737, 0xd9 },
+	{ 0x10007738, 0x93 },
+	{ 0x10007739, 0xf6 },
+	{ 0x1000773a, 0xf6 },
+	{ 0x1000773b, 0x0f },
+	{ 0x1000773c, 0x13 },
+	{ 0x1000773d, 0x77 },
+	{ 0x1000773e, 0xf7 },
+	{ 0x1000773f, 0x0f },
+	{ 0x10007740, 0x63 },
+	{ 0x10007741, 0xe8 },
+	{ 0x10007742, 0xe6 },
+	{ 0x10007743, 0x02 },
+	{ 0x10007744, 0xb7 },
+	{ 0x10007745, 0xd6 },
+	{ 0x10007746, 0x00 },
+	{ 0x10007747, 0x00 },
+	{ 0x10007748, 0x03 },
+	{ 0x10007749, 0xc7 },
+	{ 0x1000774a, 0xa6 },
+	{ 0x1000774b, 0xe1 },
+	{ 0x1000774c, 0x13 },
+	{ 0x1000774d, 0x67 },
+	{ 0x1000774e, 0x07 },
+	{ 0x1000774f, 0xf8 },
+	{ 0x10007750, 0x13 },
+	{ 0x10007751, 0x77 },
+	{ 0x10007752, 0xf7 },
+	{ 0x10007753, 0x0f },
+	{ 0x10007754, 0x23 },
+	{ 0x10007755, 0x8d },
+	{ 0x10007756, 0xe6 },
+	{ 0x10007757, 0xe0 },
+	{ 0x10007758, 0x03 },
+	{ 0x10007759, 0xc7 },
+	{ 0x1000775a, 0x37 },
+	{ 0x1000775b, 0xd9 },
+	{ 0x1000775c, 0x13 },
+	{ 0x1000775d, 0x07 },
+	{ 0x1000775e, 0x17 },
+	{ 0x1000775f, 0x00 },
+	{ 0x10007760, 0x13 },
+	{ 0x10007761, 0x77 },
+	{ 0x10007762, 0xf7 },
+	{ 0x10007763, 0x0f },
+	{ 0x10007764, 0xa3 },
+	{ 0x10007765, 0x89 },
+	{ 0x10007766, 0xe7 },
+	{ 0x10007767, 0xd8 },
+	{ 0x10007768, 0x13 },
+	{ 0x10007769, 0x07 },
+	{ 0x1000776a, 0x20 },
+	{ 0x1000776b, 0x00 },
+	{ 0x1000776c, 0x23 },
+	{ 0x1000776d, 0x88 },
+	{ 0x1000776e, 0xe7 },
+	{ 0x1000776f, 0xd8 },
+	{ 0x10007770, 0x83 },
+	{ 0x10007771, 0x20 },
+	{ 0x10007772, 0xc1 },
+	{ 0x10007773, 0x00 },
+	{ 0x10007774, 0x03 },
+	{ 0x10007775, 0x24 },
+	{ 0x10007776, 0x81 },
+	{ 0x10007777, 0x00 },
+	{ 0x10007778, 0x13 },
+	{ 0x10007779, 0x01 },
+	{ 0x1000777a, 0x01 },
+	{ 0x1000777b, 0x01 },
+	{ 0x1000777c, 0x67 },
+	{ 0x1000777d, 0x80 },
+	{ 0x1000777e, 0x00 },
+	{ 0x1000777f, 0x00 },
+	{ 0x10007780, 0x03 },
+	{ 0x10007781, 0xc7 },
+	{ 0x10007782, 0xa1 },
+	{ 0x10007783, 0x40 },
+	{ 0x10007784, 0x93 },
+	{ 0x10007785, 0x06 },
+	{ 0x10007786, 0x10 },
+	{ 0x10007787, 0x00 },
+	{ 0x10007788, 0x63 },
+	{ 0x10007789, 0x16 },
+	{ 0x1000778a, 0xd7 },
+	{ 0x1000778b, 0x00 },
+	{ 0x1000778c, 0xb7 },
+	{ 0x1000778d, 0xd6 },
+	{ 0x1000778e, 0x00 },
+	{ 0x1000778f, 0x10 },
+	{ 0x10007790, 0xa3 },
+	{ 0x10007791, 0x8a },
+	{ 0x10007792, 0xe6 },
+	{ 0x10007793, 0xd8 },
+	{ 0x10007794, 0x83 },
+	{ 0x10007795, 0xc7 },
+	{ 0x10007796, 0xa1 },
+	{ 0x10007797, 0x40 },
+	{ 0x10007798, 0x63 },
+	{ 0x10007799, 0x9c },
+	{ 0x1000779a, 0x07 },
+	{ 0x1000779b, 0x06 },
+	{ 0x1000779c, 0x13 },
+	{ 0x1000779d, 0x01 },
+	{ 0x1000779e, 0x01 },
+	{ 0x1000779f, 0xff },
+	{ 0x100077a0, 0x23 },
+	{ 0x100077a1, 0x22 },
+	{ 0x100077a2, 0x91 },
+	{ 0x100077a3, 0x00 },
+	{ 0x100077a4, 0x23 },
+	{ 0x100077a5, 0x26 },
+	{ 0x100077a6, 0x11 },
+	{ 0x100077a7, 0x00 },
+	{ 0x100077a8, 0x23 },
+	{ 0x100077a9, 0x24 },
+	{ 0x100077aa, 0x81 },
+	{ 0x100077ab, 0x00 },
+	{ 0x100077ac, 0xb7 },
+	{ 0x100077ad, 0xc4 },
+	{ 0x100077ae, 0x00 },
+	{ 0x100077af, 0x00 },
+	{ 0x100077b0, 0x83 },
+	{ 0x100077b1, 0xc7 },
+	{ 0x100077b2, 0x04 },
+	{ 0x100077b3, 0x56 },
+	{ 0x100077b4, 0x13 },
+	{ 0x100077b5, 0x07 },
+	{ 0x100077b6, 0x80 },
+	{ 0x100077b7, 0x01 },
+	{ 0x100077b8, 0x93 },
+	{ 0x100077b9, 0xf7 },
+	{ 0x100077ba, 0xf7 },
+	{ 0x100077bb, 0x0f },
+	{ 0x100077bc, 0x63 },
+	{ 0x100077bd, 0x70 },
+	{ 0x100077be, 0xf7 },
+	{ 0x100077bf, 0x04 },
+	{ 0x100077c0, 0x37 },
+	{ 0x100077c1, 0xd4 },
+	{ 0x100077c2, 0x00 },
+	{ 0x100077c3, 0x10 },
+	{ 0x100077c4, 0x83 },
+	{ 0x100077c5, 0x47 },
+	{ 0x100077c6, 0x54 },
+	{ 0x100077c7, 0xd9 },
+	{ 0x100077c8, 0x93 },
+	{ 0x100077c9, 0xf7 },
+	{ 0x100077ca, 0xf7 },
+	{ 0x100077cb, 0x0f },
+	{ 0x100077cc, 0x63 },
+	{ 0x100077cd, 0x88 },
+	{ 0x100077ce, 0x07 },
+	{ 0x100077cf, 0x02 },
+	{ 0x100077d0, 0x93 },
+	{ 0x100077d1, 0x07 },
+	{ 0x100077d2, 0x10 },
+	{ 0x100077d3, 0x00 },
+	{ 0x100077d4, 0x23 },
+	{ 0x100077d5, 0x82 },
+	{ 0x100077d6, 0xf4 },
+	{ 0x100077d7, 0x58 },
+	{ 0x100077d8, 0x03 },
+	{ 0x100077d9, 0x45 },
+	{ 0x100077da, 0x64 },
+	{ 0x100077db, 0xd9 },
+	{ 0x100077dc, 0xb7 },
+	{ 0x100077dd, 0x15 },
+	{ 0x100077de, 0x00 },
+	{ 0x100077df, 0x00 },
+	{ 0x100077e0, 0x93 },
+	{ 0x100077e1, 0x85 },
+	{ 0x100077e2, 0x85 },
+	{ 0x100077e3, 0x38 },
+	{ 0x100077e4, 0x13 },
+	{ 0x100077e5, 0x75 },
+	{ 0x100077e6, 0xf5 },
+	{ 0x100077e7, 0x0f },
+	{ 0x100077e8, 0xef },
+	{ 0x100077e9, 0xe0 },
+	{ 0x100077ea, 0x9f },
+	{ 0x100077eb, 0xd0 },
+	{ 0x100077ec, 0x93 },
+	{ 0x100077ed, 0x55 },
+	{ 0x100077ee, 0xf5 },
+	{ 0x100077ef, 0x41 },
+	{ 0x100077f0, 0xef },
+	{ 0x100077f1, 0xe0 },
+	{ 0x100077f2, 0x8f },
+	{ 0x100077f3, 0xa3 },
+	{ 0x100077f4, 0x23 },
+	{ 0x100077f5, 0x82 },
+	{ 0x100077f6, 0x04 },
+	{ 0x100077f7, 0x58 },
+	{ 0x100077f8, 0xa3 },
+	{ 0x100077f9, 0x0a },
+	{ 0x100077fa, 0x04 },
+	{ 0x100077fb, 0xd8 },
+	{ 0x100077fc, 0x83 },
+	{ 0x100077fd, 0x20 },
+	{ 0x100077fe, 0xc1 },
+	{ 0x100077ff, 0x00 },
+	{ 0x10007800, 0x03 },
+	{ 0x10007801, 0x24 },
+	{ 0x10007802, 0x81 },
+	{ 0x10007803, 0x00 },
+	{ 0x10007804, 0x83 },
+	{ 0x10007805, 0x24 },
+	{ 0x10007806, 0x41 },
+	{ 0x10007807, 0x00 },
+	{ 0x10007808, 0x13 },
+	{ 0x10007809, 0x01 },
+	{ 0x1000780a, 0x01 },
+	{ 0x1000780b, 0x01 },
+	{ 0x1000780c, 0x67 },
+	{ 0x1000780d, 0x80 },
+	{ 0x1000780e, 0x00 },
+	{ 0x1000780f, 0x00 },
+	{ 0x10007810, 0x67 },
+	{ 0x10007811, 0x80 },
+	{ 0x10007812, 0x00 },
+	{ 0x10007813, 0x00 },
+	{ 0x10007814, 0x13 },
+	{ 0x10007815, 0x01 },
+	{ 0x10007816, 0x01 },
+	{ 0x10007817, 0xff },
+	{ 0x10007818, 0x23 },
+	{ 0x10007819, 0x26 },
+	{ 0x1000781a, 0x11 },
+	{ 0x1000781b, 0x00 },
+	{ 0x1000781c, 0xef },
+	{ 0x1000781d, 0xd0 },
+	{ 0x1000781e, 0x8f },
+	{ 0x1000781f, 0x86 },
+	{ 0x10007820, 0x83 },
+	{ 0x10007821, 0xc7 },
+	{ 0x10007822, 0x11 },
+	{ 0x10007823, 0x42 },
+	{ 0x10007824, 0x63 },
+	{ 0x10007825, 0x86 },
+	{ 0x10007826, 0x07 },
+	{ 0x10007827, 0x00 },
+	{ 0x10007828, 0x03 },
+	{ 0x10007829, 0xc7 },
+	{ 0x1000782a, 0x01 },
+	{ 0x1000782b, 0x42 },
+	{ 0x1000782c, 0x63 },
+	{ 0x1000782d, 0x10 },
+	{ 0x1000782e, 0x07 },
+	{ 0x1000782f, 0x02 },
+	{ 0x10007830, 0x83 },
+	{ 0x10007831, 0xc6 },
+	{ 0x10007832, 0x21 },
+	{ 0x10007833, 0x41 },
+	{ 0x10007834, 0x13 },
+	{ 0x10007835, 0x07 },
+	{ 0x10007836, 0xf0 },
+	{ 0x10007837, 0x01 },
+	{ 0x10007838, 0x13 },
+	{ 0x10007839, 0x05 },
+	{ 0x1000783a, 0xf0 },
+	{ 0x1000783b, 0x01 },
+	{ 0x1000783c, 0x63 },
+	{ 0x1000783d, 0x98 },
+	{ 0x1000783e, 0xe6 },
+	{ 0x1000783f, 0x02 },
+	{ 0x10007840, 0x63 },
+	{ 0x10007841, 0x8a },
+	{ 0x10007842, 0x07 },
+	{ 0x10007843, 0x02 },
+	{ 0x10007844, 0x83 },
+	{ 0x10007845, 0xc7 },
+	{ 0x10007846, 0x01 },
+	{ 0x10007847, 0x42 },
+	{ 0x10007848, 0x63 },
+	{ 0x10007849, 0x86 },
+	{ 0x1000784a, 0x07 },
+	{ 0x1000784b, 0x02 },
+	{ 0x1000784c, 0x83 },
+	{ 0x1000784d, 0xc7 },
+	{ 0x1000784e, 0x31 },
+	{ 0x1000784f, 0x42 },
+	{ 0x10007850, 0x63 },
+	{ 0x10007851, 0x86 },
+	{ 0x10007852, 0x07 },
+	{ 0x10007853, 0x00 },
+	{ 0x10007854, 0x83 },
+	{ 0x10007855, 0xc7 },
+	{ 0x10007856, 0x21 },
+	{ 0x10007857, 0x42 },
+	{ 0x10007858, 0x63 },
+	{ 0x10007859, 0x9e },
+	{ 0x1000785a, 0x07 },
+	{ 0x1000785b, 0x00 },
+	{ 0x1000785c, 0x03 },
+	{ 0x1000785d, 0xc7 },
+	{ 0x1000785e, 0x21 },
+	{ 0x1000785f, 0x41 },
+	{ 0x10007860, 0x93 },
+	{ 0x10007861, 0x07 },
+	{ 0x10007862, 0xb0 },
+	{ 0x10007863, 0x01 },
+	{ 0x10007864, 0x63 },
+	{ 0x10007865, 0x08 },
+	{ 0x10007866, 0xf7 },
+	{ 0x10007867, 0x00 },
+	{ 0x10007868, 0x13 },
+	{ 0x10007869, 0x05 },
+	{ 0x1000786a, 0xb0 },
+	{ 0x1000786b, 0x01 },
+	{ 0x1000786c, 0xef },
+	{ 0x1000786d, 0xd0 },
+	{ 0x1000786e, 0x0f },
+	{ 0x1000786f, 0xcf },
+	{ 0x10007870, 0xef },
+	{ 0x10007871, 0xd0 },
+	{ 0x10007872, 0x8f },
+	{ 0x10007873, 0xa4 },
+	{ 0x10007874, 0x93 },
+	{ 0x10007875, 0x06 },
+	{ 0x10007876, 0x10 },
+	{ 0x10007877, 0x00 },
+	{ 0x10007878, 0xa3 },
+	{ 0x10007879, 0x89 },
+	{ 0x1000787a, 0xd1 },
+	{ 0x1000787b, 0x40 },
+	{ 0x1000787c, 0x37 },
+	{ 0x1000787d, 0xd7 },
+	{ 0x1000787e, 0x00 },
+	{ 0x1000787f, 0x10 },
+	{ 0x10007880, 0x83 },
+	{ 0x10007881, 0x47 },
+	{ 0x10007882, 0x07 },
+	{ 0x10007883, 0xd9 },
+	{ 0x10007884, 0x93 },
+	{ 0x10007885, 0xf7 },
+	{ 0x10007886, 0xf7 },
+	{ 0x10007887, 0x0f },
+	{ 0x10007888, 0x63 },
+	{ 0x10007889, 0x90 },
+	{ 0x1000788a, 0x07 },
+	{ 0x1000788b, 0x02 },
+	{ 0x1000788c, 0x37 },
+	{ 0x1000788d, 0xc6 },
+	{ 0x1000788e, 0x00 },
+	{ 0x1000788f, 0x00 },
+	{ 0x10007890, 0x83 },
+	{ 0x10007891, 0x47 },
+	{ 0x10007892, 0x26 },
+	{ 0x10007893, 0x04 },
+	{ 0x10007894, 0x93 },
+	{ 0x10007895, 0xe7 },
+	{ 0x10007896, 0x07 },
+	{ 0x10007897, 0xf8 },
+	{ 0x10007898, 0x93 },
+	{ 0x10007899, 0xf7 },
+	{ 0x1000789a, 0xf7 },
+	{ 0x1000789b, 0x0f },
+	{ 0x1000789c, 0x23 },
+	{ 0x1000789d, 0x01 },
+	{ 0x1000789e, 0xf6 },
+	{ 0x1000789f, 0x04 },
+	{ 0x100078a0, 0x23 },
+	{ 0x100078a1, 0x08 },
+	{ 0x100078a2, 0xd7 },
+	{ 0x100078a3, 0xd8 },
+	{ 0x100078a4, 0x23 },
+	{ 0x100078a5, 0x09 },
+	{ 0x100078a6, 0x07 },
+	{ 0x100078a7, 0xd8 },
+	{ 0x100078a8, 0x83 },
+	{ 0x100078a9, 0x20 },
+	{ 0x100078aa, 0xc1 },
+	{ 0x100078ab, 0x00 },
+	{ 0x100078ac, 0x13 },
+	{ 0x100078ad, 0x01 },
+	{ 0x100078ae, 0x01 },
+	{ 0x100078af, 0x01 },
+	{ 0x100078b0, 0x67 },
+	{ 0x100078b1, 0x80 },
+	{ 0x100078b2, 0x00 },
+	{ 0x100078b3, 0x00 },
+	{ 0x3fc2bfc7, 0x00 },
+	{ 0x3fc2bfc6, 0x00 },
+	{ 0x3fc2bfc5, 0x00 },
+	{ 0x3fc2bfc4, 0x01 },
+	{ 0x0000d486, 0x43 },
+	{ 0x1000db00, 0x02 },
+	{ 0x1000db01, 0x00 },
+	{ 0x1000db02, 0x11 },
+	{ 0x1000db03, 0x00 },
+	{ 0x1000db04, 0x00 },
+	{ 0x1000db05, 0x82 },
+	{ 0x1000db06, 0x04 },
+	{ 0x1000db07, 0xf1 },
+	{ 0x1000db08, 0x00 },
+	{ 0x1000db09, 0x00 },
+	{ 0x1000db0a, 0x40 },
+	{ 0x0000d540, 0x01 },
+};
+
+static const struct reg_default rt1320_reg_defaults[] = {
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+static const struct reg_default rt1320_mbq_defaults[] = {
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+};
+
+static bool rt1320_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0xc000 ... 0xc086:
+	case 0xc400 ... 0xc409:
+	case 0xc480 ... 0xc48f:
+	case 0xc4c0 ... 0xc4c4:
+	case 0xc4e0 ... 0xc4e7:
+	case 0xc500:
+	case 0xc560 ... 0xc56b:
+	case 0xc570:
+	case 0xc580 ... 0xc59a:
+	case 0xc5b0 ... 0xc60f:
+	case 0xc640 ... 0xc64f:
+	case 0xc670:
+	case 0xc680 ... 0xc683:
+	case 0xc700 ... 0xc76f:
+	case 0xc800 ... 0xc801:
+	case 0xc820:
+	case 0xc900 ... 0xc901:
+	case 0xc920 ... 0xc921:
+	case 0xca00 ... 0xca07:
+	case 0xca20 ... 0xca27:
+	case 0xca40 ... 0xca4b:
+	case 0xca60 ... 0xca68:
+	case 0xca80 ... 0xca88:
+	case 0xcb00 ... 0xcb0c:
+	case 0xcc00 ... 0xcc12:
+	case 0xcc80 ... 0xcc81:
+	case 0xcd00:
+	case 0xcd80 ... 0xcd82:
+	case 0xce00 ... 0xce4d:
+	case 0xcf00 ... 0xcf25:
+	case 0xd000 ... 0xd0ff:
+	case 0xd100 ... 0xd1ff:
+	case 0xd200 ... 0xd2ff:
+	case 0xd300 ... 0xd3ff:
+	case 0xd400 ... 0xd403:
+	case 0xd410 ... 0xd417:
+	case 0xd470 ... 0xd497:
+	case 0xd4dc ... 0xd50f:
+	case 0xd520 ... 0xd543:
+	case 0xd560 ... 0xd5ef:
+	case 0xd600 ... 0xd663:
+	case 0xda00 ... 0xda6e:
+	case 0xda80 ... 0xda9e:
+	case 0xdb00 ... 0xdb7f:
+	case 0xdc00:
+	case 0xdc20 ... 0xdc21:
+	case 0xdd00 ... 0xdd17:
+	case 0xde00 ... 0xde09:
+	case 0xdf00 ... 0xdf1b:
+	case 0xe000 ... 0xe847:
+	case 0xf717 ... 0xf719:
+	case 0xf720 ... 0xf723:
+	case 0x1000f008:
+	case 0x3fe2e000 ... 0x3fe2e003:
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0xc402 ... 0xc406:
+	case 0xc48c ... 0xc48f:
+	case 0xc560:
+	case 0xc5b5 ... 0xc5b7:
+	case 0xc5fc ... 0xc5ff:
+	case 0xc820:
+	case 0xc900:
+	case 0xc920:
+	case 0xca42:
+	case 0xca62:
+	case 0xca82:
+	case 0xcd00:
+	case 0xce03:
+	case 0xce10:
+	case 0xce14 ... 0xce17:
+	case 0xce44 ... 0xce49:
+	case 0xce4c ... 0xce4d:
+	case 0xcf0c:
+	case 0xcf10 ... 0xcf25:
+	case 0xd486 ... 0xd487:
+	case 0xd4e5 ... 0xd4e6:
+	case 0xd4e8 ... 0xd4ff:
+	case 0xd530:
+	case 0xd540:
+	case 0xd543:
+	case 0xdb58 ... 0xdb5f:
+	case 0xdb60 ... 0xdb63:
+	case 0xdb68 ... 0xdb69:
+	case 0xdb6d:
+	case 0xdb70 ... 0xdb71:
+	case 0xdb76:
+	case 0xdb7a:
+	case 0xdb7c ... 0xdb7f:
+	case 0xdd0c ... 0xdd13:
+	case 0xde02:
+	case 0xdf14 ... 0xdf1b:
+	case 0xe83c ... 0xe847:
+	case 0xf717 ... 0xf719:
+	case 0xf720 ... 0xf723:
+	case 0x10000000 ... 0x10007fff:
+	case 0x1000c000 ... 0x1000dfff:
+	case 0x1000f008:
+	case 0x3fc2bfc4 ... 0x3fc2bfc7:
+	case 0x3fe2e000 ... 0x3fe2e003:
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config rt1320_sdw_regmap = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.readable_reg = rt1320_readable_register,
+	.volatile_reg = rt1320_volatile_register,
+	.max_register = 0x41081488,
+	.reg_defaults = rt1320_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(rt1320_reg_defaults),
+	.cache_type = REGCACHE_MAPLE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+static const struct regmap_config rt1320_mbq_regmap = {
+	.name = "sdw-mbq",
+	.reg_bits = 32,
+	.val_bits = 16,
+	.readable_reg = rt1320_mbq_readable_register,
+	.max_register = 0x41000192,
+	.reg_defaults = rt1320_mbq_defaults,
+	.num_reg_defaults = ARRAY_SIZE(rt1320_mbq_defaults),
+	.cache_type = REGCACHE_MAPLE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+static int rt1320_read_prop(struct sdw_slave *slave)
+{
+	struct sdw_slave_prop *prop = &slave->prop;
+	int nval;
+	int i, j;
+	u32 bit;
+	unsigned long addr;
+	struct sdw_dpn_prop *dpn;
+
+	/*
+	 * Due to support the multi-lane, we call 'sdw_slave_read_prop' to get the lane mapping
+	 */
+	sdw_slave_read_prop(slave);
+
+	prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+	prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+	prop->paging_support = true;
+	prop->lane_control_support = true;
+
+	/* first we need to allocate memory for set bits in port lists */
+	prop->source_ports = BIT(4);
+	prop->sink_ports = BIT(1);
+
+	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;
+
+	i = 0;
+	dpn = prop->src_dpn_prop;
+	addr = prop->source_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++;
+	}
+
+	/* do this again for sink now */
+	nval = hweight32(prop->sink_ports);
+	prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+		sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+	if (!prop->sink_dpn_prop)
+		return -ENOMEM;
+
+	j = 0;
+	dpn = prop->sink_dpn_prop;
+	addr = prop->sink_ports;
+	for_each_set_bit(bit, &addr, 32) {
+		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 */
+	prop->clk_stop_timeout = 64;
+
+	return 0;
+}
+
+static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
+{
+	struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+	unsigned int amp_func_status, val, tmp;
+
+	if (rt1320->hw_init)
+		return 0;
+
+	regcache_cache_only(rt1320->regmap, false);
+	regcache_cache_only(rt1320->mbq_regmap, false);
+	if (rt1320->first_hw_init) {
+		regcache_cache_bypass(rt1320->regmap, true);
+		regcache_cache_bypass(rt1320->mbq_regmap, true);
+	} else {
+		/*
+		 * PM runtime status is marked as 'active' only when a Slave reports as Attached
+		 */
+		/* update count of parent 'active' children */
+		pm_runtime_set_active(&slave->dev);
+	}
+
+	pm_runtime_get_noresume(&slave->dev);
+
+	if (rt1320->version_id < 0) {
+		regmap_read(rt1320->regmap, RT1320_DEV_VERSION_ID_1, &val);
+		rt1320->version_id = val;
+	}
+
+	regmap_read(rt1320->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+	dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
+
+	/* initialization write */
+	if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt1320->first_hw_init)) {
+		regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write));
+		regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write,
+			ARRAY_SIZE(rt1320_patch_code_write));
+
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0),
+			FUNCTION_NEEDS_INITIALIZATION);
+	}
+	if (!rt1320->first_hw_init) {
+		regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+			RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0);
+		regmap_read(rt1320->regmap, RT1320_HIFI_VER_0, &val);
+		regmap_read(rt1320->regmap, RT1320_HIFI_VER_1, &tmp);
+		val = (tmp << 8) | val;
+		regmap_read(rt1320->regmap, RT1320_HIFI_VER_2, &tmp);
+		val = (tmp << 16) | val;
+		regmap_read(rt1320->regmap, RT1320_HIFI_VER_3, &tmp);
+		val = (tmp << 24) | val;
+		dev_dbg(dev, "%s ROM version=0x%x\n", __func__, val);
+		/*
+		 * We call the version b which has the new DSP ROM code against version a.
+		 * Therefore, we read the DSP address to check the ID.
+		 */
+		if (val == RT1320_VER_B_ID)
+			rt1320->version_id = RT1320_VB;
+		regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+			RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 3);
+	}
+	dev_dbg(dev, "%s version_id=%d\n", __func__, rt1320->version_id);
+
+	if (rt1320->first_hw_init) {
+		regcache_cache_bypass(rt1320->regmap, false);
+		regcache_cache_bypass(rt1320->mbq_regmap, false);
+		regcache_mark_dirty(rt1320->regmap);
+		regcache_mark_dirty(rt1320->mbq_regmap);
+	}
+
+	/* Mark Slave initialization complete */
+	rt1320->first_hw_init = true;
+	rt1320->hw_init = true;
+
+	pm_runtime_mark_last_busy(&slave->dev);
+	pm_runtime_put_autosuspend(&slave->dev);
+
+	dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+	return 0;
+}
+
+static int rt1320_update_status(struct sdw_slave *slave,
+					enum sdw_slave_status status)
+{
+	struct  rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev);
+
+	if (status == SDW_SLAVE_UNATTACHED)
+		rt1320->hw_init = false;
+
+	/*
+	 * Perform initialization only if slave status is present and
+	 * hw_init flag is false
+	 */
+	if (rt1320->hw_init || status != SDW_SLAVE_ATTACHED)
+		return 0;
+
+	/* perform I/O transfers required for Slave initialization */
+	return rt1320_io_init(&slave->dev, slave);
+}
+
+static int rt1320_pde23_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+	unsigned char ps0 = 0x0, ps3 = 0x3;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+				RT1320_SDCA_CTL_REQ_POWER_STATE, 0),
+				ps0);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+				RT1320_SDCA_CTL_REQ_POWER_STATE, 0),
+				ps3);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt1320_set_gain_put(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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+	unsigned int read_l, read_r, gain_l_val, gain_r_val;
+	unsigned int lvalue, rvalue;
+	const unsigned int interval_offset = 0xc0;
+
+	regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue);
+	regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue);
+
+	/* L Channel */
+	gain_l_val = ucontrol->value.integer.value[0];
+	if (gain_l_val > mc->max)
+		gain_l_val = mc->max;
+	gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset);
+	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;
+	gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset);
+	gain_r_val &= 0xffff;
+
+	if (lvalue == gain_l_val && rvalue == gain_r_val)
+		return 0;
+
+	/* Lch*/
+	regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val);
+	/* Rch */
+	regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val);
+
+	regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
+	regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
+	if (read_r == gain_r_val && read_l == gain_l_val)
+		return 1;
+
+	return -EIO;
+}
+
+static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
+	const unsigned int interval_offset = 0xc0;
+
+	regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
+	regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
+
+	ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset);
+
+	if (read_l != read_r)
+		ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset);
+	else
+		ctl_r = ctl_l;
+
+	ucontrol->value.integer.value[0] = ctl_l;
+	ucontrol->value.integer.value[1] = ctl_r;
+	return 0;
+}
+
+static const char * const rt1320_rx_data_ch_select[] = {
+	"L,R",
+	"R,L",
+	"L,L",
+	"R,R",
+	"L,L+R",
+	"R,L+R",
+	"L+R,L",
+	"L+R,R",
+	"L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum,
+	SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0,
+	rt1320_rx_data_ch_select);
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+
+static const struct snd_kcontrol_new rt1320_snd_controls[] = {
+	SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume",
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01),
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02),
+		0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv),
+	SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1320_spk_l_dac =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01),
+		0, 1, 1);
+static const struct snd_kcontrol_new rt1320_spk_r_dac =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02),
+		0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+		rt1320_pde23_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Output */
+	SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac),
+	SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt1320_spk_r_dac),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+
+	/* Input */
+	SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SIGGEN("AEC Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
+	{ "FU21", NULL, "DP1RX" },
+	{ "FU21", NULL, "PDE 23" },
+	{ "OT23 L", "Switch", "FU21" },
+	{ "OT23 R", "Switch", "FU21" },
+	{ "SPOL", NULL, "OT23 L" },
+	{ "SPOR", NULL, "OT23 R" },
+
+	{ "AEC Data", NULL, "AEC Gen" },
+	{ "DP4TX", NULL, "AEC Data" },
+};
+
+static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+				int direction)
+{
+	snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+	return 0;
+}
+
+static void rt1320_sdw_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt1320_sdw_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 rt1320_sdw_priv *rt1320 =
+		snd_soc_component_get_drvdata(component);
+	struct sdw_stream_config stream_config;
+	struct sdw_port_config port_config;
+	struct sdw_stream_runtime *sdw_stream;
+	int retval;
+	unsigned int sampling_rate;
+
+	dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+	sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+	if (!sdw_stream)
+		return -EINVAL;
+
+	if (!rt1320->sdw_slave)
+		return -EINVAL;
+
+	/* SoundWire specific configuration */
+	snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (dai->id == RT1320_AIF1)
+			port_config.num = 1;
+		else
+			return -EINVAL;
+	} else {
+		if (dai->id == RT1320_AIF1)
+			port_config.num = 4;
+		else
+			return -EINVAL;
+	}
+
+	retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+				&port_config, 1, sdw_stream);
+	if (retval) {
+		dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
+		return retval;
+	}
+
+	/* sampling rate configuration */
+	switch (params_rate(params)) {
+	case 16000:
+		sampling_rate = RT1320_SDCA_RATE_16000HZ;
+		break;
+	case 32000:
+		sampling_rate = RT1320_SDCA_RATE_32000HZ;
+		break;
+	case 44100:
+		sampling_rate = RT1320_SDCA_RATE_44100HZ;
+		break;
+	case 48000:
+		sampling_rate = RT1320_SDCA_RATE_48000HZ;
+		break;
+	case 96000:
+		sampling_rate = RT1320_SDCA_RATE_96000HZ;
+		break;
+	case 192000:
+		sampling_rate = RT1320_SDCA_RATE_192000HZ;
+		break;
+	default:
+		dev_err(component->dev, "%s: Rate %d is not supported\n",
+			__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	/* set sampling frequency */
+	regmap_write(rt1320->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+		sampling_rate);
+
+	return 0;
+}
+
+static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1320_sdw_priv *rt1320 =
+		snd_soc_component_get_drvdata(component);
+	struct sdw_stream_runtime *sdw_stream =
+		snd_soc_dai_get_dma_data(dai, substream);
+
+	if (!rt1320->sdw_slave)
+		return -EINVAL;
+
+	sdw_stream_remove_slave(rt1320->sdw_slave, sdw_stream);
+	return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static const struct sdw_slave_ops rt1320_slave_ops = {
+	.read_prop = rt1320_read_prop,
+	.update_status = rt1320_update_status,
+};
+
+static int rt1320_sdw_component_probe(struct snd_soc_component *component)
+{
+	int ret;
+	struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+	rt1320->component = component;
+
+	if (!rt1320->first_hw_init)
+		return 0;
+
+	ret = pm_runtime_resume(component->dev);
+	dev_dbg(&rt1320->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
+	if (ret < 0 && ret != -EACCES)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1320 = {
+	.probe = rt1320_sdw_component_probe,
+	.controls = rt1320_snd_controls,
+	.num_controls = ARRAY_SIZE(rt1320_snd_controls),
+	.dapm_widgets = rt1320_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt1320_dapm_widgets),
+	.dapm_routes = rt1320_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt1320_dapm_routes),
+	.endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt1320_aif_dai_ops = {
+	.hw_params = rt1320_sdw_hw_params,
+	.hw_free	= rt1320_sdw_pcm_hw_free,
+	.set_stream	= rt1320_set_sdw_stream,
+	.shutdown	= rt1320_sdw_shutdown,
+};
+
+#define RT1320_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1320_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rt1320_sdw_dai[] = {
+	{
+		.name = "rt1320-aif1",
+		.id = RT1320_AIF1,
+		.playback = {
+			.stream_name = "DP1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT1320_STEREO_RATES,
+			.formats = RT1320_FORMATS,
+		},
+		.capture = {
+			.stream_name = "DP4 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT1320_STEREO_RATES,
+			.formats = RT1320_FORMATS,
+		},
+		.ops = &rt1320_aif_dai_ops,
+	},
+};
+
+static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
+				struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+	struct rt1320_sdw_priv *rt1320;
+	int ret;
+
+	rt1320 = devm_kzalloc(dev, sizeof(*rt1320), GFP_KERNEL);
+	if (!rt1320)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, rt1320);
+	rt1320->sdw_slave = slave;
+	rt1320->mbq_regmap = mbq_regmap;
+	rt1320->regmap = regmap;
+
+	regcache_cache_only(rt1320->regmap, true);
+	regcache_cache_only(rt1320->mbq_regmap, true);
+
+	/*
+	 * Mark hw_init to false
+	 * HW init will be performed when device reports present
+	 */
+	rt1320->hw_init = false;
+	rt1320->first_hw_init = false;
+	rt1320->version_id = -1;
+
+	ret =  devm_snd_soc_register_component(dev,
+				&soc_component_sdw_rt1320,
+				rt1320_sdw_dai,
+				ARRAY_SIZE(rt1320_sdw_dai));
+	if (ret < 0)
+		return ret;
+
+	/* set autosuspend parameters */
+	pm_runtime_set_autosuspend_delay(dev, 3000);
+	pm_runtime_use_autosuspend(dev);
+
+	/* make sure the device does not suspend immediately */
+	pm_runtime_mark_last_busy(dev);
+
+	pm_runtime_enable(dev);
+
+	/* important note: the device is NOT tagged as 'active' and will remain
+	 * 'suspended' until the hardware is enumerated/initialized. This is required
+	 * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+	 * fail with -EACCESS because of race conditions between card creation and enumeration
+	 */
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	return ret;
+}
+
+static int rt1320_sdw_probe(struct sdw_slave *slave,
+				const struct sdw_device_id *id)
+{
+	struct regmap *regmap, *mbq_regmap;
+
+	/* Regmap Initialization */
+	mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt1320_mbq_regmap);
+	if (IS_ERR(mbq_regmap))
+		return PTR_ERR(mbq_regmap);
+
+	regmap = devm_regmap_init_sdw(slave, &rt1320_sdw_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return rt1320_sdw_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt1320_sdw_remove(struct sdw_slave *slave)
+{
+	pm_runtime_disable(&slave->dev);
+
+	return 0;
+}
+
+/*
+ * Version A/B will use the class id 0
+ * The newer version than A/B will use the class id 1, so add it in advance
+ */
+static const struct sdw_device_id rt1320_id[] = {
+	SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x0, 0),
+	SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x1, 0),
+	{},
+};
+MODULE_DEVICE_TABLE(sdw, rt1320_id);
+
+static int __maybe_unused rt1320_dev_suspend(struct device *dev)
+{
+	struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+
+	if (!rt1320->hw_init)
+		return 0;
+
+	regcache_cache_only(rt1320->regmap, true);
+	regcache_cache_only(rt1320->mbq_regmap, true);
+	return 0;
+}
+
+#define RT1320_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1320_dev_resume(struct device *dev)
+{
+	struct sdw_slave *slave = dev_to_sdw_dev(dev);
+	struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+	unsigned long time;
+
+	if (!rt1320->first_hw_init)
+		return 0;
+
+	if (!slave->unattach_request)
+		goto regmap_sync;
+
+	time = wait_for_completion_timeout(&slave->initialization_complete,
+				msecs_to_jiffies(RT1320_PROBE_TIMEOUT));
+	if (!time) {
+		dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+regmap_sync:
+	slave->unattach_request = 0;
+	regcache_cache_only(rt1320->regmap, false);
+	regcache_sync(rt1320->regmap);
+	regcache_cache_only(rt1320->mbq_regmap, false);
+	regcache_sync(rt1320->mbq_regmap);
+	return 0;
+}
+
+static const struct dev_pm_ops rt1320_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume)
+	SET_RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1320_sdw_driver = {
+	.driver = {
+		.name = "rt1320-sdca",
+		.pm = &rt1320_pm,
+	},
+	.probe = rt1320_sdw_probe,
+	.remove = rt1320_sdw_remove,
+	.ops = &rt1320_slave_ops,
+	.id_table = rt1320_id,
+};
+module_sdw_driver(rt1320_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1320 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
new file mode 100644
index 0000000000000000000000000000000000000000..b23228e74568c82af8952856fb7efc7b07371194
--- /dev/null
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1320-sdw.h -- RT1320 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1320_SDW_H__
+#define __RT1320_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* imp-defined registers */
+#define RT1320_DEV_VERSION_ID_1 0xc404
+
+#define RT1320_KR0_STATUS_CNT 0x1000f008
+#define RT1320_HIFI_VER_0 0x3fe2e000
+#define RT1320_HIFI_VER_1 0x3fe2e001
+#define RT1320_HIFI_VER_2 0x3fe2e002
+#define RT1320_HIFI_VER_3 0x3fe2e003
+
+/* RT1320 SDCA Control - function number */
+#define FUNC_NUM_AMP 0x04
+
+/* RT1320 SDCA entity */
+#define RT1320_SDCA_ENT0 0x00
+#define RT1320_SDCA_ENT_PDE11 0x2a
+#define RT1320_SDCA_ENT_PDE23 0x33
+#define RT1320_SDCA_ENT_PDE27 0x27
+#define RT1320_SDCA_ENT_FU14 0x32
+#define RT1320_SDCA_ENT_FU21 0x03
+#define RT1320_SDCA_ENT_FU113 0x30
+#define RT1320_SDCA_ENT_CS14 0x13
+#define RT1320_SDCA_ENT_CS21 0x21
+#define RT1320_SDCA_ENT_CS113 0x12
+#define RT1320_SDCA_ENT_SAPU 0x29
+#define RT1320_SDCA_ENT_PPU21 0x04
+
+/* RT1320 SDCA control */
+#define RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1320_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1320_SDCA_CTL_FU_MUTE 0x01
+#define RT1320_SDCA_CTL_FU_VOLUME 0x02
+#define RT1320_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
+#define RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
+#define RT1320_SDCA_CTL_POSTURE_NUMBER 0x10
+#define RT1320_SDCA_CTL_FUNC_STATUS 0x10
+
+/* RT1320 SDCA channel */
+#define CH_01 0x01
+#define CH_02 0x02
+
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION		BIT(5)
+
+/* Sample Frequency Index */
+#define RT1320_SDCA_RATE_16000HZ		0x04
+#define RT1320_SDCA_RATE_32000HZ		0x07
+#define RT1320_SDCA_RATE_44100HZ		0x08
+#define RT1320_SDCA_RATE_48000HZ		0x09
+#define RT1320_SDCA_RATE_96000HZ		0x0b
+#define RT1320_SDCA_RATE_192000HZ		0x0d
+
+enum {
+	RT1320_AIF1,
+};
+
+/*
+ * The version id will be useful to distinguish the capability between the different IC versions.
+ * Currently, VA and VB have different DSP FW versions.
+ */
+enum rt1320_version_id {
+	RT1320_VA,
+	RT1320_VB,
+};
+
+#define RT1320_VER_B_ID 0x07392238
+
+struct rt1320_sdw_priv {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+	struct regmap *mbq_regmap;
+	struct sdw_slave *sdw_slave;
+	struct sdw_bus_params params;
+	bool hw_init;
+	bool first_hw_init;
+	int version_id;
+};
+
+#endif /* __RT1320_SDW_H__ */
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 1e8dbfc3ecd969be3a87cb5f00aed853a56e2a41..dd6ccf17afd4399f1fe0c505d92517048279d6a7 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -81,6 +81,24 @@ static void rt711_sdca_reset(struct rt711_sdca_priv *rt711)
 		RT711_HDA_LEGACY_RESET_CTL, 0x1, 0x1);
 }
 
+static void rt711_sdca_ge_force_jack_type(struct rt711_sdca_priv *rt711, unsigned int det_mode)
+{
+	switch (det_mode) {
+	case 0x00:
+		rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x0000);
+		rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x10, 0x00);
+		break;
+	case 0x03:
+		rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8000);
+		rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x13);
+		break;
+	case 0x05:
+		rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8400);
+		rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x15);
+		break;
+	}
+}
+
 static int rt711_sdca_calibration(struct rt711_sdca_priv *rt711)
 {
 	unsigned int val, loop_rc = 0, loop_dc = 0;
@@ -248,6 +266,8 @@ static int rt711_sdca_headset_detect(struct rt711_sdca_priv *rt711)
 	unsigned int det_mode;
 	int ret;
 
+	rt711_sdca_ge_force_jack_type(rt711, rt711->ge_mode_override);
+
 	/* get detected_mode */
 	ret = regmap_read(rt711->regmap,
 		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0),
@@ -790,6 +810,56 @@ static int rt711_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
 	return changed;
 }
 
+static int rt711_sdca_ge_select_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+	unsigned int val, item;
+
+	val = (rt711->ge_mode_override >> e->shift_l) & e->mask;
+	item = snd_soc_enum_val_to_item(e, val);
+	ucontrol->value.enumerated.item[0] = item;
+	return 0;
+}
+
+static int rt711_sdca_ge_select_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+	unsigned int val, change = 0;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+	if (rt711->ge_mode_override != val) {
+		rt711->ge_mode_override = val;
+		change = 1;
+	}
+
+	return change;
+}
+
+static const char * const rt711_sdca_ge_select[] = {
+	"Auto",
+	"Headphone",
+	"Headset",
+};
+
+static int rt711_sdca_ge_select_values[] = {
+	0,
+	3,
+	5,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt711_sdca_ge_mode_enum, SND_SOC_NOPM,
+	0, 0x7, rt711_sdca_ge_select, rt711_sdca_ge_select_values);
+
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
 static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
@@ -824,6 +894,8 @@ static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = {
 		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R),
 		8, 3, 0,
 		rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, mic_vol_tlv),
+	SOC_ENUM_EXT("GE49 Selected Mode", rt711_sdca_ge_mode_enum,
+		rt711_sdca_ge_select_get, rt711_sdca_ge_select_put),
 };
 
 static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h
index 11d421e8ab2b6ecbea4ffe4c4280eab1ef4195e7..15263dcb0314ac7b3aa70e92821cdb75a7cdfc23 100644
--- a/sound/soc/codecs/rt711-sdca.h
+++ b/sound/soc/codecs/rt711-sdca.h
@@ -33,6 +33,7 @@ struct  rt711_sdca_priv {
 	int hw_ver;
 	bool fu0f_dapm_mute, fu0f_mixer_l_mute, fu0f_mixer_r_mute;
 	bool fu1e_dapm_mute, fu1e_mixer_l_mute, fu1e_mixer_r_mute;
+	unsigned int ge_mode_override;
 };
 
 /* NID */
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index ce337db86d1a1f3bc55de44b2ed98b6cee894bb7..90d5aaddbd5b946788dbc8313ba572ff2111a8e9 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -34,6 +34,10 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg)
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
 		SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
 	case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
 		return true;
 	default:
@@ -56,6 +60,10 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg)
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
 		SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
 	case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
 		return true;
 	default:
@@ -78,13 +86,21 @@ static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re
 	case 0x5c00000 ... 0x5c0009a:
 	case 0x5d00000 ... 0x5d00009:
 	case 0x5f00000 ... 0x5f00030:
-	case 0x6100000 ... 0x6100068:
-	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L):
-	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R):
-	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L):
-	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R):
-	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L):
-	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R):
+	case 0x6100000 ... 0x61000f1:
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04):
 		return true;
 	default:
 		return false;
@@ -96,7 +112,9 @@ static bool rt712_sdca_mbq_volatile_register(struct device *dev, unsigned int re
 	switch (reg) {
 	case 0x2000000:
 	case 0x200001a:
+	case 0x2000020:
 	case 0x2000024:
+	case 0x2000030:
 	case 0x2000046:
 	case 0x200008a:
 	case 0x5800000:
@@ -178,13 +196,15 @@ static int rt712_sdca_read_prop(struct sdw_slave *slave)
 	unsigned long addr;
 	struct sdw_dpn_prop *dpn;
 
+	sdw_slave_read_prop(slave);
+
 	prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
 	prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
 
 	prop->paging_support = true;
 
 	/* first we need to allocate memory for set bits in port lists */
-	prop->source_ports = BIT(4); /* BITMAP: 00010000 */
+	prop->source_ports = BIT(8) | BIT(4); /* BITMAP: 100010000 */
 	prop->sink_ports = BIT(3) | BIT(1); /* BITMAP:  00001010 */
 
 	nval = hweight32(prop->source_ports);
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index 4be22ccd8561868783222ae50cce6313ac18af0e..99fd2d67f04dbc470c48f89990bf767874c76eda 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -12,68 +12,31 @@
 #include <linux/soundwire/sdw_registers.h>
 
 static const struct reg_default rt712_sdca_reg_defaults[] = {
-	{ 0x201a, 0x00 },
-	{ 0x201b, 0x00 },
-	{ 0x201c, 0x00 },
-	{ 0x201d, 0x00 },
-	{ 0x201e, 0x00 },
-	{ 0x201f, 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 },
-	{ 0x2f01, 0x00 },
-	{ 0x2f02, 0x09 },
-	{ 0x2f03, 0x00 },
-	{ 0x2f04, 0x00 },
-	{ 0x2f05, 0x0b },
-	{ 0x2f06, 0x01 },
-	{ 0x2f08, 0x00 },
-	{ 0x2f09, 0x00 },
-	{ 0x2f0a, 0x01 },
-	{ 0x2f35, 0x01 },
-	{ 0x2f36, 0xcf },
-	{ 0x2f50, 0x0f },
-	{ 0x2f54, 0x01 },
-	{ 0x2f58, 0x07 },
-	{ 0x2f59, 0x09 },
-	{ 0x2f5a, 0x01 },
-	{ 0x2f5b, 0x07 },
-	{ 0x2f5c, 0x05 },
-	{ 0x2f5d, 0x05 },
-	{ 0x3201, 0x01 },
-	{ 0x320c, 0x00 },
-	{ 0x3301, 0x01 },
-	{ 0x3302, 0x00 },
-	{ 0x3303, 0x1f },
+
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 };
 
 static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ 0x2000004, 0xaa01 },
 	{ 0x200000e, 0x21e0 },
-	{ 0x2000024, 0x01ba },
 	{ 0x200004a, 0x8830 },
 	{ 0x2000067, 0xf100 },
 	{ 0x5800000, 0x1893 },
@@ -81,12 +44,8 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ 0x5b00005, 0x0000 },
 	{ 0x5b00029, 0x3fff },
 	{ 0x5b0002a, 0xf000 },
-	{ 0x5f00008, 0x7000 },
+	{ 0x6100000, 0x04e4 },
 	{ 0x610000e, 0x0007 },
-	{ 0x6100022, 0x2828 },
-	{ 0x6100023, 0x2929 },
-	{ 0x6100026, 0x2c29 },
-	{ 0x610002c, 0x4150 },
 	{ 0x6100045, 0x0860 },
 	{ 0x6100046, 0x0029 },
 	{ 0x6100053, 0x3fff },
@@ -95,14 +54,22 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ 0x6100064, 0x8000 },
 	{ 0x6100065, 0x0000 },
 	{ 0x6100067, 0xff12 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
 };
 
 #endif /* __RT712_SDW_H__ */
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index b503de9fda80e71cbe78e8916a6a7f41286ac5b2..e210c574bb74a1f0e9d96f93367ff36ba728cfb8 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -82,7 +82,8 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
 	dev = regmap_get_device(regmap);
 
 	/* Set HP-JD source from JD1 */
-	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+	if (rt712->version_id == RT712_VA)
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
 
 	/* FSM switch to calibration manual mode */
 	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100);
@@ -198,11 +199,17 @@ static unsigned int rt712_sdca_button_detect(struct rt712_sdca_priv *rt712)
 
 _end_btn_det_:
 	/* Host is owner, so set back to device */
-	if (owner == 0)
+	if (owner == 0) {
 		/* set owner to device */
-		regmap_write(rt712->regmap,
-			SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
-				RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+		if (rt712->version_id == RT712_VA)
+			regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+					RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+		else
+			regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+					RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+	}
 
 	return btn_type;
 }
@@ -415,8 +422,9 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
 
 		switch (rt712->jd_src) {
 		case RT712_JD1:
-			/* Set HP-JD source from JD1 */
-			rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+			/* Set HP-JD source from JD1, VB uses JD1 in default */
+			if (rt712->version_id == RT712_VA)
+				rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
 			break;
 		default:
 			dev_warn(rt712->component->dev, "Wrong JD source\n");
@@ -592,20 +600,20 @@ static int rt712_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
 static int rt712_sdca_set_fu0f_capture_ctl(struct rt712_sdca_priv *rt712)
 {
 	int err;
-	unsigned int ch_l, ch_r;
+	unsigned int ch_01, ch_02;
 
-	ch_l = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00;
-	ch_r = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+	ch_01 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+	ch_02 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00;
 
 	err = regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F,
-			RT712_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+			RT712_SDCA_CTL_FU_MUTE, CH_01), ch_01);
 	if (err < 0)
 		return err;
 
 	err = regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F,
-			RT712_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+			RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02);
 	if (err < 0)
 		return err;
 
@@ -649,28 +657,28 @@ static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0);
 
 static const struct snd_kcontrol_new rt712_sdca_controls[] = {
 	SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
-		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L),
-		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02),
 		0, 0x57, 0,
 		rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv),
 	SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
 		rt712_sdca_fu0f_capture_get, rt712_sdca_fu0f_capture_put),
 	SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
-		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L),
-		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02),
 		0, 0x3f, 0,
 		rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, mic_vol_tlv),
 	SOC_DOUBLE_R_EXT_TLV("FU44 Boost Volume",
-		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L),
-		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R),
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02),
 		8, 3, 0,
 		rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, boost_vol_tlv),
 };
 
 static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = {
 	SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L),
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02),
 		0, 0x57, 0,
 		rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv),
 };
@@ -763,21 +771,21 @@ static int rt712_sdca_fu05_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMU:
 		regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
-				RT712_SDCA_CTL_FU_MUTE, CH_L),
+				RT712_SDCA_CTL_FU_MUTE, CH_01),
 				unmute);
 		regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
-				RT712_SDCA_CTL_FU_MUTE, CH_R),
+				RT712_SDCA_CTL_FU_MUTE, CH_02),
 				unmute);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
-				RT712_SDCA_CTL_FU_MUTE, CH_L),
+				RT712_SDCA_CTL_FU_MUTE, CH_01),
 				mute);
 		regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
-				RT712_SDCA_CTL_FU_MUTE, CH_R),
+				RT712_SDCA_CTL_FU_MUTE, CH_02),
 				mute);
 		break;
 	}
@@ -854,7 +862,7 @@ static int rt712_sdca_pde12_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
+static int rt712_sdca_pde23_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component =
@@ -883,10 +891,13 @@ static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static const struct snd_kcontrol_new rt712_spk_sto_dac =
-	SOC_DAPM_DOUBLE_R("Switch",
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L),
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R),
+static const struct snd_kcontrol_new rt712_spk_l_dac =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01),
+		0, 1, 1);
+static const struct snd_kcontrol_new rt712_spk_r_dac =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02),
 		0, 1, 1);
 
 static const struct snd_soc_dapm_widget rt712_sdca_dapm_widgets[] = {
@@ -931,20 +942,26 @@ static const struct snd_soc_dapm_widget rt712_sdca_spk_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
 
 	/* Digital Interface */
-	SND_SOC_DAPM_SWITCH("FU06", SND_SOC_NOPM, 0, 0, &rt712_spk_sto_dac),
+	SND_SOC_DAPM_PGA("FU06", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+		rt712_sdca_pde23_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 	/* Output */
-	SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
-		rt712_sdca_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt712_spk_l_dac),
+	SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt712_spk_r_dac),
 	SND_SOC_DAPM_OUTPUT("SPOL"),
 	SND_SOC_DAPM_OUTPUT("SPOR"),
 };
 
 static const struct snd_soc_dapm_route rt712_sdca_spk_dapm_routes[] = {
-	{ "FU06", "Switch", "DP3RX" },
-	{ "CLASS D", NULL, "FU06" },
-	{ "SPOL", NULL, "CLASS D" },
-	{ "SPOR", NULL, "CLASS D" },
+	{ "FU06", NULL, "DP3RX" },
+	{ "FU06", NULL, "PDE 23" },
+	{ "OT23 L", "Switch", "FU06" },
+	{ "OT23 R", "Switch", "FU06" },
+	{ "SPOL", NULL, "OT23 L" },
+	{ "SPOR", NULL, "OT23 R" },
 };
 
 static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev)
@@ -983,6 +1000,376 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
 	return 0;
 }
 
+static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	unsigned int regvalue, ctl, i;
+	unsigned int adc_vol_flag = 0;
+	const unsigned int interval_offset = 0xc0;
+
+	if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+		adc_vol_flag = 1;
+
+	/* check all channels */
+	for (i = 0; i < p->count; i++) {
+		regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue);
+
+		if (!adc_vol_flag) /* boost gain */
+			ctl = regvalue / 0x0a00;
+		else { /* ADC gain */
+			if (adc_vol_flag)
+				ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+			else
+				ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
+		}
+
+		ucontrol->value.integer.value[i] = ctl;
+	}
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	unsigned int gain_val[4];
+	unsigned int i, adc_vol_flag = 0, changed = 0;
+	unsigned int regvalue[4];
+	const unsigned int interval_offset = 0xc0;
+	int err;
+
+	if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+		adc_vol_flag = 1;
+
+	/* check all channels */
+	for (i = 0; i < p->count; i++) {
+		regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue[i]);
+
+		gain_val[i] = ucontrol->value.integer.value[i];
+		if (gain_val[i] > p->max)
+			gain_val[i] = p->max;
+
+		if (!adc_vol_flag) /* boost gain */
+			gain_val[i] = gain_val[i] * 0x0a00;
+		else { /* ADC gain */
+			gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+			gain_val[i] &= 0xffff;
+		}
+
+		if (regvalue[i] != gain_val[i])
+			changed = 1;
+	}
+
+	if (!changed)
+		return 0;
+
+	for (i = 0; i < p->count; i++) {
+		err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]);
+		if (err < 0)
+			dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+	}
+
+	return changed;
+}
+
+static int rt712_sdca_set_fu1e_capture_ctl(struct rt712_sdca_priv *rt712)
+{
+	int err, i;
+	unsigned int ch_mute;
+
+	for (i = 0; i < ARRAY_SIZE(rt712->fu1e_mixer_mute); i++) {
+		ch_mute = (rt712->fu1e_dapm_mute || rt712->fu1e_mixer_mute[i]) ? 0x01 : 0x00;
+		err = regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E,
+				RT712_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	unsigned int i;
+
+	for (i = 0; i < p->count; i++)
+		ucontrol->value.integer.value[i] = !rt712->fu1e_mixer_mute[i];
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	int err, changed = 0, i;
+
+	for (i = 0; i < p->count; i++) {
+		if (rt712->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+			changed = 1;
+		rt712->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+	}
+
+	err = rt712_sdca_set_fu1e_capture_ctl(rt712);
+	if (err < 0)
+		return err;
+
+	return changed;
+}
+
+static int rt712_sdca_fu_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+
+	if (p->max == 1)
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	else
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = p->count;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = p->max;
+	return 0;
+}
+
+#define RT712_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+	((unsigned long)&(struct rt712_dmic_kctrl_priv) \
+		{.reg_base = xreg_base, .count = xcount, .max = xmax, \
+		.invert = xinvert})
+
+#define RT712_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = rt712_sdca_fu_info, \
+	.get = rt712_sdca_dmic_fu1e_capture_get, \
+	.put = rt712_sdca_dmic_fu1e_capture_put, \
+	.private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT712_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+	 xhandler_put, xcount, xmax, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p = (tlv_array), \
+	.info = rt712_sdca_fu_info, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = {
+	RT712_SDCA_FU_CTRL("FU1E Capture Switch",
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01),
+		1, 1, 4),
+	RT712_SDCA_EXT_TLV("FU1E Capture Volume",
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+		rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 0x3f, in_vol_tlv),
+	RT712_SDCA_EXT_TLV("FU15 Boost Volume",
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+		rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 3, dmic_vol_tlv),
+};
+
+static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_kcontrol_component(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0, mask_sft;
+
+	if (strstr(ucontrol->id.name, "ADC 0A Mux"))
+		mask_sft = 0;
+	else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+		mask_sft = 4;
+	else
+		return -EINVAL;
+
+	rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+		RT712_HDA_LEGACY_MUX_CTL0, &val);
+
+	ucontrol->value.enumerated.item[0] = (((val >> mask_sft) & 0xf) == 0x4) ? 0 : 1;
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_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 rt712_sdca_priv *rt712 = 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 0A Mux"))
+		mask_sft = 0;
+	else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+		mask_sft = 4;
+	else
+		return -EINVAL;
+
+	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+	rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+		RT712_HDA_LEGACY_MUX_CTL0, &val2);
+	val2 = ((0xf << mask_sft) & val2) >> mask_sft;
+
+	if (val == 0)
+		val = 0x4;
+	else if (val >= 1)
+		val = 0xe;
+
+	if (val == val2)
+		change = 0;
+	else
+		change = 1;
+
+	if (change)
+		rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+			RT712_HDA_LEGACY_MUX_CTL0, 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_dmic_mux_text[] = {
+	"DMIC1",
+	"DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt712_adc0a_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt712_adc0b_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0a_mux =
+	SOC_DAPM_ENUM_EXT("ADC 0A Mux", rt712_adc0a_enum,
+			rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0b_mux =
+	SOC_DAPM_ENUM_EXT("ADC 0B Mux", rt712_adc0b_enum,
+			rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static int rt712_sdca_dmic_fu1e_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		rt712->fu1e_dapm_mute = false;
+		rt712_sdca_set_fu1e_capture_ctl(rt712);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		rt712->fu1e_dapm_mute = true;
+		rt712_sdca_set_fu1e_capture_ctl(rt712);
+		break;
+	}
+	return 0;
+}
+
+static int rt712_sdca_dmic_pde11_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	unsigned char ps0 = 0x0, ps3 = 0x3;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+				RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+				ps0);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+				RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+				ps3);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt712_sdca_dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("DMIC2"),
+
+	SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+		rt712_sdca_dmic_pde11_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0,
+		rt712_sdca_dmic_fu1e_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX("ADC 0A Mux", SND_SOC_NOPM, 0, 0,
+		&rt712_sdca_dmic_adc0a_mux),
+	SND_SOC_DAPM_MUX("ADC 0B Mux", SND_SOC_NOPM, 0, 0,
+		&rt712_sdca_dmic_adc0b_mux),
+
+	SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt712_sdca_dmic_audio_map[] = {
+	{"DP8TX", NULL, "FU 1E"},
+
+	{"FU 1E", NULL, "PDE 11"},
+	{"FU 1E", NULL, "ADC 0A Mux"},
+	{"FU 1E", NULL, "ADC 0B Mux"},
+	{"ADC 0A Mux", "DMIC1", "DMIC1"},
+	{"ADC 0A Mux", "DMIC2", "DMIC2"},
+	{"ADC 0B Mux", "DMIC1", "DMIC1"},
+	{"ADC 0B Mux", "DMIC2", "DMIC2"},
+};
+
+static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
+{
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	rt712->dmic_component = component;
+
+	if (!rt712->first_hw_init)
+		return 0;
+
+	ret = pm_runtime_resume(component->dev);
+	if (ret < 0 && ret != -EACCES)
+		return ret;
+
+	return 0;
+}
+
 static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
 	.probe = rt712_sdca_probe,
 	.controls = rt712_sdca_controls,
@@ -995,6 +1382,20 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
 	.endianness = 1,
 };
 
+static const struct snd_soc_component_driver soc_sdca_dev_rt712_dmic = {
+	.probe = rt712_sdca_dmic_probe,
+	.controls = rt712_sdca_dmic_snd_controls,
+	.num_controls = ARRAY_SIZE(rt712_sdca_dmic_snd_controls),
+	.dapm_widgets = rt712_sdca_dmic_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt712_sdca_dmic_dapm_widgets),
+	.dapm_routes = rt712_sdca_dmic_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(rt712_sdca_dmic_audio_map),
+	.endianness = 1,
+#ifdef CONFIG_DEBUG_FS
+	.debugfs_prefix = "dmic",
+#endif
+};
+
 static int rt712_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 				int direction)
 {
@@ -1022,7 +1423,7 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 	int retval, port, num_channels;
 	unsigned int sampling_rate;
 
-	dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+	dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
 	sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
 
 	if (!sdw_stream)
@@ -1031,6 +1432,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (!rt712->slave)
 		return -EINVAL;
 
+	/* VA doesn't support AIF3 */
+	if (dai->id == RT712_AIF3 && rt712->version_id == RT712_VA)
+		return -EINVAL;
+
 	/* SoundWire specific configuration */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		direction = SDW_DATA_DIR_RX;
@@ -1044,6 +1449,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 		direction = SDW_DATA_DIR_TX;
 		if (dai->id == RT712_AIF1)
 			port = 4;
+		else if (dai->id == RT712_AIF3)
+			port = 8;
 		else
 			return -EINVAL;
 	}
@@ -1105,6 +1512,14 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
 			sampling_rate);
 		break;
+	case RT712_AIF3:
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+		break;
 	default:
 		dev_err(component->dev, "%s: Wrong DAI id\n", __func__);
 		return -EINVAL;
@@ -1174,6 +1589,21 @@ static struct snd_soc_dai_driver rt712_sdca_dai[] = {
 	}
 };
 
+static struct snd_soc_dai_driver rt712_sdca_dmic_dai[] = {
+	{
+		.name = "rt712-sdca-aif3",
+		.id = RT712_AIF3,
+		.capture = {
+			.stream_name = "DP8 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = RT712_STEREO_RATES,
+			.formats = RT712_FORMATS,
+		},
+		.ops = &rt712_sdca_ops,
+	}
+};
+
 int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 			struct regmap *mbq_regmap, struct sdw_slave *slave)
 {
@@ -1206,6 +1636,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 	rt712->first_hw_init = false;
 	rt712->fu0f_dapm_mute = true;
 	rt712->fu0f_mixer_l_mute = rt712->fu0f_mixer_r_mute = true;
+	rt712->fu1e_dapm_mute = true;
+	rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] =
+		rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true;
 
 	/* JD source uses JD1 in default */
 	rt712->jd_src = RT712_JD1;
@@ -1239,35 +1672,11 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 	return 0;
 }
 
-int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712)
 {
-	struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
 	int ret = 0;
-	unsigned int val, hibernation_flag;
-
-	rt712->disable_irq = false;
-
-	if (rt712->hw_init)
-		return 0;
-
-	regcache_cache_only(rt712->regmap, false);
-	regcache_cache_only(rt712->mbq_regmap, false);
-	if (rt712->first_hw_init) {
-		regcache_cache_bypass(rt712->regmap, true);
-		regcache_cache_bypass(rt712->mbq_regmap, true);
-	} else {
-		/*
-		 *  PM runtime status is marked as 'active' only when a Slave reports as Attached
-		 */
-
-		/* update count of parent 'active' children */
-		pm_runtime_set_active(&slave->dev);
-	}
-
-	pm_runtime_get_noresume(&slave->dev);
-
-	rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
-	rt712->hw_id = (val & 0xf000) >> 12;
+	unsigned int hibernation_flag;
+	struct device *dev = &rt712->slave->dev;
 
 	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
 	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
@@ -1307,6 +1716,131 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
 		regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
 	}
+}
+
+static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
+{
+	int ret = 0;
+	unsigned int jack_func_status, mic_func_status, amp_func_status;
+	struct device *dev = &rt712->slave->dev;
+
+	regmap_read(rt712->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status);
+	regmap_read(rt712->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status);
+	regmap_read(rt712->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+	dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n",
+		__func__, jack_func_status, mic_func_status, amp_func_status);
+
+	/* DMIC */
+	if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_CH12_FLOAT_CTL, 0x0304);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL, 0x1f1e);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0B_FU_CH12_FLOAT_CTL, 0x0304);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_HDA_LEGACY_CONFIG_CTL0, 0x8010);
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT11, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+		rt712_sdca_index_write(rt712, RT712_ULTRA_SOUND_DET, RT712_ULTRA_SOUND_DETECTOR6, 0x3200);
+		regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+
+		/* clear flag */
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+				FUNCTION_NEEDS_INITIALIZATION);
+	}
+
+	/* Jack */
+	if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+		rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_SEL_VEE2_HP_CTL1, 0x042a);
+		rt712_sdca_index_write(rt712, RT712_CHARGE_PUMP, RT712_HP_DET_CTL3, 0x1fff);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec67);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL1, 0x0000);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL2, 0x0000);
+		regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL1, 0x2802);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL6, 0xf215);
+
+		/* calibration */
+		ret = rt712_sdca_calibration(rt712);
+		if (ret < 0)
+			dev_err(dev, "%s, calibration failed!\n", __func__);
+
+		rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, RT712_MIXER_CTL1, 0x3000, 0x0000);
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_IT09, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_MISC_CTL_FOR_UAJ, 0x0003);
+
+		/* clear flag */
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+				FUNCTION_NEEDS_INITIALIZATION);
+	}
+
+	/* SPK */
+	if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+		if (rt712->hw_id != RT712_DEV_ID_713) {
+			rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec63);
+			rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL1, 0xfff5);
+			rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_EAPD_CTL, 0x0002);
+			regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+		}
+		/* clear flag */
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+				FUNCTION_NEEDS_INITIALIZATION);
+	}
+}
+
+int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+	struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
+	int ret = 0;
+	unsigned int val;
+	struct sdw_slave_prop *prop = &slave->prop;
+
+	rt712->disable_irq = false;
+
+	if (rt712->hw_init)
+		return 0;
+
+	regcache_cache_only(rt712->regmap, false);
+	regcache_cache_only(rt712->mbq_regmap, false);
+	if (rt712->first_hw_init) {
+		regcache_cache_bypass(rt712->regmap, true);
+		regcache_cache_bypass(rt712->mbq_regmap, true);
+	} else {
+		/*
+		 *  PM runtime status is marked as 'active' only when a Slave reports as Attached
+		 */
+
+		/* update count of parent 'active' children */
+		pm_runtime_set_active(&slave->dev);
+	}
+
+	pm_runtime_get_noresume(&slave->dev);
+
+	rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
+	rt712->hw_id = (val & 0xf000) >> 12;
+	rt712->version_id = (val & 0x0f00) >> 8;
+	dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
+
+	if (rt712->version_id == RT712_VA)
+		rt712_sdca_va_io_init(rt712);
+	else {
+		/* multilanes and DMIC are supported by rt712vb */
+		ret =  devm_snd_soc_register_component(dev,
+			&soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai));
+		if (ret < 0)
+			return ret;
+
+		prop->lane_control_support = true;
+		rt712_sdca_vb_io_init(rt712);
+	}
 
 	/*
 	 * if set_jack callback occurred early than io_init,
@@ -1315,8 +1849,7 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
 	if (rt712->hs_jack)
 		rt712_sdca_jack_init(rt712);
 
-	if (!hibernation_flag)
-		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
+	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
 
 	if (rt712->first_hw_init) {
 		regcache_cache_bypass(rt712->regmap, false);
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index ff79e03118ce82830b04fc8e857d6935f13731aa..2169f2f726b9fb91bb23b15d59dc72185179eb5a 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -19,6 +19,7 @@ struct  rt712_sdca_priv {
 	struct regmap *regmap;
 	struct regmap *mbq_regmap;
 	struct snd_soc_component *component;
+	struct snd_soc_component *dmic_component;
 	struct sdw_slave *slave;
 	struct sdw_bus_params params;
 	bool hw_init;
@@ -34,13 +35,31 @@ struct  rt712_sdca_priv {
 	unsigned int scp_sdca_stat1;
 	unsigned int scp_sdca_stat2;
 	unsigned int hw_id;
+	unsigned int version_id;
 	bool fu0f_dapm_mute;
 	bool fu0f_mixer_l_mute;
 	bool fu0f_mixer_r_mute;
+	bool fu1e_dapm_mute;
+	bool fu1e_mixer_mute[4];
 };
 
+struct rt712_dmic_kctrl_priv {
+	unsigned int reg_base;
+	unsigned int count;
+	unsigned int max;
+	unsigned int invert;
+};
+
+/* SDCA (Channel) */
+#define CH_01	0x01
+#define CH_02	0x02
+#define CH_03	0x03
+#define CH_04	0x04
+
 /* NID */
 #define RT712_VENDOR_REG			0x20
+#define RT712_EQ_CTRL				0x53
+#define RT712_CHARGE_PUMP			0x57
 #define RT712_VENDOR_CALI			0x58
 #define RT712_ULTRA_SOUND_DET			0x59
 #define RT712_VENDOR_IMS_DRE			0x5b
@@ -50,9 +69,13 @@ struct  rt712_sdca_priv {
 /* Index (NID:20h) */
 #define RT712_JD_PRODUCT_NUM			0x00
 #define RT712_ANALOG_BIAS_CTL3			0x04
+#define RT712_JD_CTL1				0x09
+#define RT712_IO_CTL				0x0c
 #define RT712_LDO2_3_CTL1			0x0e
 #define RT712_PARA_VERB_CTL			0x1a
 #define RT712_CC_DET1				0x24
+#define RT712_CLASSD_AMP_CTL1			0x37
+#define RT712_CLASSD_AMP_CTL6			0x3c
 #define RT712_COMBO_JACK_AUTO_CTL1		0x45
 #define RT712_COMBO_JACK_AUTO_CTL2		0x46
 #define RT712_COMBO_JACK_AUTO_CTL3		0x47
@@ -61,6 +84,9 @@ struct  rt712_sdca_priv {
 #define RT712_SW_CONFIG1			0x8a
 #define RT712_SW_CONFIG2			0x8b
 
+/* Index (NID:57h) */
+#define RT712_HP_DET_CTL3			0x0c
+
 /* Index (NID:58h) */
 #define RT712_DAC_DC_CALI_CTL1			0x00
 #define RT712_DAC_DC_CALI_CTL2			0x01
@@ -71,6 +97,7 @@ struct  rt712_sdca_priv {
 /* Index (NID:5bh) */
 #define RT712_IMS_DIGITAL_CTL1			0x00
 #define RT712_IMS_DIGITAL_CTL5			0x05
+#define RT712_SEL_VEE2_HP_CTL1			0x23
 #define RT712_HP_DETECT_RLDET_CTL1		0x29
 #define RT712_HP_DETECT_RLDET_CTL2		0x2a
 
@@ -109,6 +136,11 @@ struct  rt712_sdca_priv {
 #define RT712_UMP_HID_CTL6				0x66
 #define RT712_UMP_HID_CTL7				0x67
 #define RT712_UMP_HID_CTL8				0x68
+#define RT712_MISC_CTL_FOR_UAJ				0x72
+#define RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL		0xa2
+#define RT712_DMIC2_FU_IT_FLOAT_CTL			0xa6
+#define RT712_ADC0B_FU_CH12_FLOAT_CTL			0xb0
+#define RT712_DMIC2_FU_CH12_FLOAT_CTL			0xb1
 
 /* Parameter & Verb control 01 (0x1a)(NID:20h) */
 #define RT712_HIDDEN_REG_SW_RESET (0x1 << 14)
@@ -139,6 +171,7 @@ struct  rt712_sdca_priv {
 #define FUNC_NUM_AMP 0x04
 
 /* RT712 SDCA entity */
+#define RT712_SDCA_ENT0 0x00
 #define RT712_SDCA_ENT_HID01 0x01
 #define RT712_SDCA_ENT_GE49 0x49
 #define RT712_SDCA_ENT_USER_FU05 0x05
@@ -157,6 +190,7 @@ struct  rt712_sdca_priv {
 #define RT712_SDCA_ENT_CS1C 0x1c
 #define RT712_SDCA_ENT_CS31 0x31
 #define RT712_SDCA_ENT_OT23 0x42
+#define RT712_SDCA_ENT_IT11 0x26
 #define RT712_SDCA_ENT_IT26 0x26
 #define RT712_SDCA_ENT_IT09 0x09
 #define RT712_SDCA_ENT_PLATFORM_FU15 0x15
@@ -175,10 +209,12 @@ struct  rt712_sdca_priv {
 #define RT712_SDCA_CTL_REQ_POWER_STATE 0x01
 #define RT712_SDCA_CTL_VENDOR_DEF 0x30
 #define RT712_SDCA_CTL_FU_CH_GAIN 0x0b
+#define RT712_SDCA_CTL_FUNC_STATUS 0x10
 
-/* RT712 SDCA channel */
-#define CH_L 0x01
-#define CH_R 0x02
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION		BIT(5)
+#define FUNCTION_HAS_BEEN_RESET			BIT(6)
+#define FUNCTION_BUSY				BIT(7)
 
 /* sample frequency index */
 #define RT712_SDCA_RATE_16000HZ		0x04
@@ -191,6 +227,7 @@ struct  rt712_sdca_priv {
 enum {
 	RT712_AIF1,
 	RT712_AIF2,
+	RT712_AIF3,
 };
 
 enum rt712_sdca_jd_src {
@@ -207,6 +244,11 @@ enum rt712_sdca_hw_id {
 
 #define RT712_PART_ID_713 0x713
 
+enum rt712_sdca_version {
+	RT712_VA,
+	RT712_VB,
+};
+
 int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
 int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 			struct regmap *mbq_regmap, struct sdw_slave *slave);
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
index bf67de12d20b7f6de7d75c551664c0bdf67264d6..240af0563283e5a9dd720d51a2cefd22bd241faa 100644
--- a/sound/soc/codecs/simple-mux.c
+++ b/sound/soc/codecs/simple-mux.c
@@ -9,12 +9,21 @@
 #include <linux/regulator/consumer.h>
 #include <sound/soc.h>
 
+#define MUX_TEXT_SIZE	2
+#define MUX_WIDGET_SIZE	4
+#define MUX_ROUTE_SIZE	3
 struct simple_mux {
 	struct gpio_desc *gpiod_mux;
 	unsigned int mux;
+	const char *mux_texts[MUX_TEXT_SIZE];
+	struct soc_enum mux_enum;
+	struct snd_kcontrol_new mux_mux;
+	struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE];
+	struct snd_soc_dapm_route mux_routes[MUX_ROUTE_SIZE];
+	struct snd_soc_component_driver mux_driver;
 };
 
-static const char * const simple_mux_texts[] = {
+static const char * const simple_mux_texts[MUX_TEXT_SIZE] = {
 	"Input 1", "Input 2"
 };
 
@@ -66,30 +75,23 @@ static unsigned int simple_mux_read(struct snd_soc_component *component,
 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[] = {
+static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = {
 	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_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), // see simple_mux_probe()
 	SND_SOC_DAPM_OUTPUT("OUT"),
 };
 
-static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = {
+static const struct snd_soc_dapm_route simple_mux_dapm_routes[MUX_ROUTE_SIZE] = {
 	{ "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),
-	.read			= simple_mux_read,
+	{ "MUX", "Input 1", "IN1" }, // see simple_mux_probe()
+	{ "MUX", "Input 2", "IN2" }, // see simple_mux_probe()
 };
 
 static int simple_mux_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
 	struct simple_mux *priv;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -103,7 +105,30 @@ static int simple_mux_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, PTR_ERR(priv->gpiod_mux),
 				     "Failed to get 'mux' gpio");
 
-	return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0);
+	/* Copy default settings */
+	memcpy(&priv->mux_texts,	&simple_mux_texts,		sizeof(priv->mux_texts));
+	memcpy(&priv->mux_enum,		&simple_mux_enum,		sizeof(priv->mux_enum));
+	memcpy(&priv->mux_mux,		&simple_mux_mux,		sizeof(priv->mux_mux));
+	memcpy(&priv->mux_widgets,	&simple_mux_dapm_widgets,	sizeof(priv->mux_widgets));
+	memcpy(&priv->mux_routes,	&simple_mux_dapm_routes,	sizeof(priv->mux_routes));
+
+	priv->mux_driver.dapm_widgets		= priv->mux_widgets;
+	priv->mux_driver.num_dapm_widgets	= MUX_WIDGET_SIZE;
+	priv->mux_driver.dapm_routes		= priv->mux_routes;
+	priv->mux_driver.num_dapm_routes	= MUX_ROUTE_SIZE;
+	priv->mux_driver.read			= simple_mux_read;
+
+	/* Overwrite text ("Input 1", "Input 2") if property exists */
+	of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE);
+
+	/* switch to use priv data instead of default */
+	priv->mux_enum.texts			= priv->mux_texts;
+	priv->mux_mux.private_value		= (unsigned long)&priv->mux_enum;
+	priv->mux_widgets[2].kcontrol_news	= &priv->mux_mux;
+	priv->mux_routes[1].control		= priv->mux_texts[0]; // "Input 1"
+	priv->mux_routes[2].control		= priv->mux_texts[1]; // "Input 2"
+
+	return devm_snd_soc_register_component(dev, &priv->mux_driver, NULL, 0);
 }
 
 #ifdef CONFIG_OF
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index a7ed59ec49a6f0527d2aec10a4d10d59b0a2d58d..9e68afc0989728cb3f15d5cd6955b5cf6d402809 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -13,7 +13,6 @@
 #include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
-#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 1dc719d726ab5d371767df141414af69a29cf910..5eaddf07aadcc7962cbd16e843784baa155921f4 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -15,7 +15,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 67bc1c8b0131782d855f58474573b32582110b74..5601fba17c9607d09ba2c3116852e287567d82f2 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -20,7 +20,6 @@
 #include <linux/firmware.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index a18ccf5fb7ad2c4e7333f9d21745d89a7e371ac6..6902bfef185b873b607178b8d059aad7932246b9 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -11,7 +11,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c
index 3aa81514dad76f319e3bd0fc86b1709855dde28c..1fbf4560f5cc2639ad89b2b406e349bde9ef2092 100644
--- a/sound/soc/codecs/tas2781-comlib.c
+++ b/sound/soc/codecs/tas2781-comlib.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 //
-// tas2781-lib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers
+// TAS2781 Common functions for HDA and ASoC Audio drivers
 //
-// Copyright 2023 Texas Instruments, Inc.
+// Copyright 2023 - 2024 Texas Instruments, Inc.
 //
 // Author: Shenghao Ding <shenghao-ding@ti.com>
 
@@ -243,7 +243,7 @@ struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c)
 }
 EXPORT_SYMBOL_GPL(tasdevice_kzalloc);
 
-void tas2781_reset(struct tasdevice_priv *tas_dev)
+void tasdevice_reset(struct tasdevice_priv *tas_dev)
 {
 	int ret, i;
 
@@ -254,8 +254,8 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
 	} else {
 		for (i = 0; i < tas_dev->ndev; i++) {
 			ret = tasdevice_dev_write(tas_dev, i,
-				TAS2781_REG_SWRESET,
-				TAS2781_REG_SWRESET_RESET);
+				TASDEVICE_REG_SWRESET,
+				TASDEVICE_REG_SWRESET_RESET);
 			if (ret < 0)
 				dev_err(tas_dev->dev,
 					"dev %d swreset fail, %d\n",
@@ -264,7 +264,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
 	}
 	usleep_range(1000, 1050);
 }
-EXPORT_SYMBOL_GPL(tas2781_reset);
+EXPORT_SYMBOL_GPL(tasdevice_reset);
 
 int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
 	struct module *module,
@@ -277,8 +277,13 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
 	 */
 	mutex_lock(&tas_priv->codec_lock);
 
-	scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
-		tas_priv->dev_name, tas_priv->ndev);
+	if (tas_priv->name_prefix)
+		scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
+			tas_priv->name_prefix, tas_priv->dev_name,
+			tas_priv->ndev);
+	else
+		scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
+			tas_priv->dev_name, tas_priv->ndev);
 	crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
 	tas_priv->codec = codec;
 	ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 265a8ca25cbbe640d6432fe88f5999fc22ac53fb..63626b982d04239216d202978be5467d7b3d0cc7 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -21,7 +21,7 @@
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <sound/tas2781.h>
-
+#include <asm/unaligned.h>
 
 #define ERROR_PRAM_CRCCHK			0x0000000
 #define ERROR_YRAM_CRCCHK			0x0000001
@@ -187,8 +187,7 @@ static struct tasdevice_config_info *tasdevice_add_config(
 	/* convert data[offset], data[offset + 1], data[offset + 2] and
 	 * data[offset + 3] into host
 	 */
-	cfg_info->nblocks =
-		be32_to_cpup((__be32 *)&config_data[config_offset]);
+	cfg_info->nblocks = get_unaligned_be32(&config_data[config_offset]);
 	config_offset += 4;
 
 	/* Several kinds of dsp/algorithm firmwares can run on tas2781,
@@ -232,14 +231,14 @@ static struct tasdevice_config_info *tasdevice_add_config(
 
 		}
 		bk_da[i]->yram_checksum =
-			be16_to_cpup((__be16 *)&config_data[config_offset]);
+			get_unaligned_be16(&config_data[config_offset]);
 		config_offset += 2;
 		bk_da[i]->block_size =
-			be32_to_cpup((__be32 *)&config_data[config_offset]);
+			get_unaligned_be32(&config_data[config_offset]);
 		config_offset += 4;
 
 		bk_da[i]->n_subblks =
-			be32_to_cpup((__be32 *)&config_data[config_offset]);
+			get_unaligned_be32(&config_data[config_offset]);
 
 		config_offset += 4;
 
@@ -289,7 +288,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
 	}
 	buf = (unsigned char *)fmw->data;
 
-	fw_hdr->img_sz = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->img_sz = get_unaligned_be32(&buf[offset]);
 	offset += 4;
 	if (fw_hdr->img_sz != fmw->size) {
 		dev_err(tas_priv->dev,
@@ -300,9 +299,9 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
 		goto out;
 	}
 
-	fw_hdr->checksum = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->checksum = get_unaligned_be32(&buf[offset]);
 	offset += 4;
-	fw_hdr->binary_version_num = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->binary_version_num = get_unaligned_be32(&buf[offset]);
 	if (fw_hdr->binary_version_num < 0x103) {
 		dev_err(tas_priv->dev, "File version 0x%04x is too low",
 			fw_hdr->binary_version_num);
@@ -311,7 +310,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
 		goto out;
 	}
 	offset += 4;
-	fw_hdr->drv_fw_version = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]);
 	offset += 8;
 	fw_hdr->plat_type = buf[offset];
 	offset += 1;
@@ -339,11 +338,11 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
 	for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++)
 		fw_hdr->devs[i] = buf[offset];
 
-	fw_hdr->nconfig = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->nconfig = get_unaligned_be32(&buf[offset]);
 	offset += 4;
 
 	for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) {
-		fw_hdr->config_size[i] = be32_to_cpup((__be32 *)&buf[offset]);
+		fw_hdr->config_size[i] = get_unaligned_be32(&buf[offset]);
 		offset += 4;
 		total_config_sz += fw_hdr->config_size[i];
 	}
@@ -423,7 +422,7 @@ static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw,
 	/* convert data[offset], data[offset + 1], data[offset + 2] and
 	 * data[offset + 3] into host
 	 */
-	block->type = be32_to_cpup((__be32 *)&data[offset]);
+	block->type = get_unaligned_be32(&data[offset]);
 	offset += 4;
 
 	block->is_pchksum_present = data[offset];
@@ -438,10 +437,10 @@ static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw,
 	block->ychksum = data[offset];
 	offset++;
 
-	block->blk_size = be32_to_cpup((__be32 *)&data[offset]);
+	block->blk_size = get_unaligned_be32(&data[offset]);
 	offset += 4;
 
-	block->nr_subblocks = be32_to_cpup((__be32 *)&data[offset]);
+	block->nr_subblocks = get_unaligned_be32(&data[offset]);
 	offset += 4;
 
 	/* fixed m68k compiling issue:
@@ -482,7 +481,7 @@ static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw,
 		offset = -EINVAL;
 		goto out;
 	}
-	img_data->nr_blk = be32_to_cpup((__be32 *)&data[offset]);
+	img_data->nr_blk = get_unaligned_be32(&data[offset]);
 	offset += 4;
 
 	img_data->dev_blks = kcalloc(img_data->nr_blk,
@@ -578,14 +577,14 @@ static int fw_parse_variable_header_kernel(
 		offset = -EINVAL;
 		goto out;
 	}
-	fw_hdr->device_family = be16_to_cpup((__be16 *)&buf[offset]);
+	fw_hdr->device_family = get_unaligned_be16(&buf[offset]);
 	if (fw_hdr->device_family != 0) {
 		dev_err(tas_priv->dev, "%s:not TAS device\n", __func__);
 		offset = -EINVAL;
 		goto out;
 	}
 	offset += 2;
-	fw_hdr->device = be16_to_cpup((__be16 *)&buf[offset]);
+	fw_hdr->device = get_unaligned_be16(&buf[offset]);
 	if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
 		fw_hdr->device == 6) {
 		dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
@@ -603,7 +602,7 @@ static int fw_parse_variable_header_kernel(
 		goto out;
 	}
 
-	tas_fmw->nr_programs = be32_to_cpup((__be32 *)&buf[offset]);
+	tas_fmw->nr_programs = get_unaligned_be32(&buf[offset]);
 	offset += 4;
 
 	if (tas_fmw->nr_programs == 0 || tas_fmw->nr_programs >
@@ -622,14 +621,14 @@ static int fw_parse_variable_header_kernel(
 
 	for (i = 0; i < tas_fmw->nr_programs; i++) {
 		program = &(tas_fmw->programs[i]);
-		program->prog_size = be32_to_cpup((__be32 *)&buf[offset]);
+		program->prog_size = get_unaligned_be32(&buf[offset]);
 		offset += 4;
 	}
 
 	/* Skip the unused prog_size */
 	offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs);
 
-	tas_fmw->nr_configurations = be32_to_cpup((__be32 *)&buf[offset]);
+	tas_fmw->nr_configurations = get_unaligned_be32(&buf[offset]);
 	offset += 4;
 
 	/* The max number of config in firmware greater than 4 pieces of
@@ -661,7 +660,7 @@ static int fw_parse_variable_header_kernel(
 
 	for (i = 0; i < tas_fmw->nr_programs; i++) {
 		config = &(tas_fmw->configs[i]);
-		config->cfg_size = be32_to_cpup((__be32 *)&buf[offset]);
+		config->cfg_size = get_unaligned_be32(&buf[offset]);
 		offset += 4;
 	}
 
@@ -699,7 +698,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
 		switch (subblk_typ) {
 		case TASDEVICE_CMD_SING_W: {
 			int i;
-			unsigned short len = be16_to_cpup((__be16 *)&data[2]);
+			unsigned short len = get_unaligned_be16(&data[2]);
 
 			subblk_offset += 2;
 			if (subblk_offset + 4 * len > sublocksize) {
@@ -725,7 +724,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
 		}
 			break;
 		case TASDEVICE_CMD_BURST: {
-			unsigned short len = be16_to_cpup((__be16 *)&data[2]);
+			unsigned short len = get_unaligned_be16(&data[2]);
 
 			subblk_offset += 2;
 			if (subblk_offset + 4 + len > sublocksize) {
@@ -766,7 +765,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
 				is_err = true;
 				break;
 			}
-			sleep_time = be16_to_cpup((__be16 *)&data[2]) * 1000;
+			sleep_time = get_unaligned_be16(&data[2]) * 1000;
 			usleep_range(sleep_time, sleep_time + 50);
 			subblk_offset += 2;
 		}
@@ -910,7 +909,7 @@ static int fw_parse_variable_hdr(struct tasdevice_priv
 
 	offset += len;
 
-	fw_hdr->device_family = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->device_family = get_unaligned_be32(&buf[offset]);
 	if (fw_hdr->device_family != 0) {
 		dev_err(tas_priv->dev, "%s: not TAS device\n", __func__);
 		offset = -EINVAL;
@@ -918,7 +917,7 @@ static int fw_parse_variable_hdr(struct tasdevice_priv
 	}
 	offset += 4;
 
-	fw_hdr->device = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_hdr->device = get_unaligned_be32(&buf[offset]);
 	if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
 		fw_hdr->device == 6) {
 		dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
@@ -963,7 +962,7 @@ static int fw_parse_block_data(struct tasdevice_fw *tas_fmw,
 		offset = -EINVAL;
 		goto out;
 	}
-	block->type = be32_to_cpup((__be32 *)&data[offset]);
+	block->type = get_unaligned_be32(&data[offset]);
 	offset += 4;
 
 	if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) {
@@ -988,7 +987,7 @@ static int fw_parse_block_data(struct tasdevice_fw *tas_fmw,
 		block->is_ychksum_present = 0;
 	}
 
-	block->nr_cmds = be32_to_cpup((__be32 *)&data[offset]);
+	block->nr_cmds = get_unaligned_be32(&data[offset]);
 	offset += 4;
 
 	n = block->nr_cmds * 4;
@@ -1039,7 +1038,7 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw,
 		goto out;
 	}
 	offset += n;
-	img_data->nr_blk = be16_to_cpup((__be16 *)&data[offset]);
+	img_data->nr_blk = get_unaligned_be16(&data[offset]);
 	offset += 2;
 
 	img_data->dev_blks = kcalloc(img_data->nr_blk,
@@ -1076,7 +1075,7 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
 		offset = -EINVAL;
 		goto out;
 	}
-	tas_fmw->nr_programs = be16_to_cpup((__be16 *)&buf[offset]);
+	tas_fmw->nr_programs = get_unaligned_be16(&buf[offset]);
 	offset += 2;
 
 	if (tas_fmw->nr_programs == 0) {
@@ -1143,7 +1142,7 @@ static int fw_parse_configuration_data(
 		offset = -EINVAL;
 		goto out;
 	}
-	tas_fmw->nr_configurations = be16_to_cpup((__be16 *)&data[offset]);
+	tas_fmw->nr_configurations = get_unaligned_be16(&data[offset]);
 	offset += 2;
 
 	if (tas_fmw->nr_configurations == 0) {
@@ -1775,7 +1774,7 @@ static int fw_parse_header(struct tasdevice_priv *tas_priv,
 	/* Convert data[offset], data[offset + 1], data[offset + 2] and
 	 * data[offset + 3] into host
 	 */
-	fw_fixed_hdr->fwsize = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_fixed_hdr->fwsize = get_unaligned_be32(&buf[offset]);
 	offset += 4;
 	if (fw_fixed_hdr->fwsize != fmw->size) {
 		dev_err(tas_priv->dev, "File size not match, %lu %u",
@@ -1784,9 +1783,9 @@ static int fw_parse_header(struct tasdevice_priv *tas_priv,
 		goto out;
 	}
 	offset += 4;
-	fw_fixed_hdr->ppcver = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_fixed_hdr->ppcver = get_unaligned_be32(&buf[offset]);
 	offset += 8;
-	fw_fixed_hdr->drv_ver = be32_to_cpup((__be32 *)&buf[offset]);
+	fw_fixed_hdr->drv_ver = get_unaligned_be32(&buf[offset]);
 	offset += 72;
 
  out:
@@ -1828,7 +1827,7 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
 		offset = -EINVAL;
 		goto out;
 	}
-	tas_fmw->nr_calibrations = be16_to_cpup((__be16 *)&data[offset]);
+	tas_fmw->nr_calibrations = get_unaligned_be16(&data[offset]);
 	offset += 2;
 
 	if (tas_fmw->nr_calibrations != 1) {
@@ -2324,14 +2323,21 @@ void tasdevice_tuning_switch(void *context, int state)
 	struct tasdevice_fw *tas_fmw = tas_priv->fmw;
 	int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
 
-	if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
-		dev_err(tas_priv->dev, "DSP bin file not loaded\n");
+	/*
+	 * Only RCA-based Playback can still work with no dsp program running
+	 * inside the chip.
+	 */
+	switch (tas_priv->fw_state) {
+	case TASDEVICE_RCA_FW_OK:
+	case TASDEVICE_DSP_FW_ALL_OK:
+		break;
+	default:
 		return;
 	}
 
 	if (state == 0) {
-		if (tas_priv->cur_prog < tas_fmw->nr_programs) {
-			/*dsp mode or tuning mode*/
+		if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) {
+			/* dsp mode or tuning mode */
 			profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
 			tasdevice_select_tuningprm_cfg(tas_priv,
 				tas_priv->cur_prog, tas_priv->cur_conf,
@@ -2340,9 +2346,10 @@ void tasdevice_tuning_switch(void *context, int state)
 
 		tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
 			TASDEVICE_BIN_BLK_PRE_POWER_UP);
-	} else
+	} else {
 		tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
 			TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
+	}
 }
 EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch,
 	SND_SOC_TAS2781_FMWLIB);
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 9350972dfefe7e92df320602cd7f96762a946247..e79d613745b4057f494b11821d5760d9be019568 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/regmap.h>
@@ -30,6 +31,7 @@
 #include <sound/tas2781.h>
 #include <sound/tlv.h>
 #include <sound/tas2781-tlv.h>
+#include <asm/unaligned.h>
 
 static const struct i2c_device_id tasdevice_id[] = {
 	{ "tas2563", TAS2563 },
@@ -103,7 +105,7 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
 	return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
 }
 
-static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component =
@@ -118,7 +120,7 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component =
@@ -139,6 +141,106 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
 	return change;
 }
 
+static int tas2563_digital_gain_get(
+	struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+	unsigned int l = 0, r = mc->max;
+	unsigned int target, ar_mid, mid, ar_l, ar_r;
+	unsigned int reg = mc->reg;
+	unsigned char data[4];
+	int ret;
+
+	mutex_lock(&tas_dev->codec_lock);
+	/* Read the primary device */
+	ret =  tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+	if (ret) {
+		dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+		goto out;
+	}
+
+	target = get_unaligned_be32(&data[0]);
+
+	while (r > 1 + l) {
+		mid = (l + r) / 2;
+		ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]);
+		if (target < ar_mid)
+			r = mid;
+		else
+			l = mid;
+	}
+
+	ar_l = get_unaligned_be32(tas2563_dvc_table[l]);
+	ar_r = get_unaligned_be32(tas2563_dvc_table[r]);
+
+	/* find out the member same as or closer to the current volume */
+	ucontrol->value.integer.value[0] =
+		abs(target - ar_l) <= abs(target - ar_r) ? l : r;
+out:
+	mutex_unlock(&tas_dev->codec_lock);
+	return 0;
+}
+
+static int tas2563_digital_gain_put(
+	struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+	int vol = ucontrol->value.integer.value[0];
+	int status = 0, max = mc->max, rc = 1;
+	int i, ret;
+	unsigned int reg = mc->reg;
+	unsigned int volrd, volwr;
+	unsigned char data[4];
+
+	vol = clamp(vol, 0, max);
+	mutex_lock(&tas_dev->codec_lock);
+	/* Read the primary device */
+	ret =  tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+	if (ret) {
+		dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+		rc = -1;
+		goto out;
+	}
+
+	volrd = get_unaligned_be32(&data[0]);
+	volwr = get_unaligned_be32(tas2563_dvc_table[vol]);
+
+	if (volrd == volwr) {
+		rc = 0;
+		goto out;
+	}
+
+	for (i = 0; i < tas_dev->ndev; i++) {
+		ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
+			(unsigned char *)tas2563_dvc_table[vol], 4);
+		if (ret) {
+			dev_err(tas_dev->dev,
+				"%s, set digital vol error in dev %d\n",
+				__func__, i);
+			status |= BIT(i);
+		}
+	}
+
+	if (status)
+		rc = -1;
+out:
+	mutex_unlock(&tas_dev->codec_lock);
+	return rc;
+}
+
+static const struct snd_kcontrol_new tasdevice_snd_controls[] = {
+	SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+		tasdev_force_fwload_get, tasdev_force_fwload_put),
+};
+
 static const struct snd_kcontrol_new tas2781_snd_controls[] = {
 	SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
 		1, 0, 20, 0, tas2781_amp_getvol,
@@ -146,8 +248,13 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
 	SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
 		0, 0, 200, 1, tas2781_digital_getvol,
 		tas2781_digital_putvol, dvc_tlv),
-	SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
-		tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas2563_snd_controls[] = {
+	SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0,
+		0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
+		tas2563_digital_gain_get, tas2563_digital_gain_put,
+		tas2563_dvc_tlv),
 };
 
 static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
@@ -380,23 +487,41 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
 	mutex_lock(&tas_priv->codec_lock);
 
 	ret = tasdevice_rca_parser(tas_priv, fmw);
-	if (ret)
+	if (ret) {
+		tasdevice_config_info_remove(tas_priv);
 		goto out;
+	}
 	tasdevice_create_control(tas_priv);
 
 	tasdevice_dsp_remove(tas_priv);
 	tasdevice_calbin_remove(tas_priv);
-	tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
-	scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
-		tas_priv->dev_name);
+	/*
+	 * The baseline is the RCA-only case, and then the code attempts to
+	 * load DSP firmware but in case of failures just keep going, i.e.
+	 * failing to load DSP firmware is NOT an error.
+	 */
+	tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
+	if (tas_priv->name_prefix)
+		scnprintf(tas_priv->rca_binaryname, 64, "%s-%s_coef.bin",
+			tas_priv->name_prefix, tas_priv->dev_name);
+	else
+		scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
+			tas_priv->dev_name);
 	ret = tasdevice_dsp_parser(tas_priv);
 	if (ret) {
 		dev_err(tas_priv->dev, "dspfw load %s error\n",
 			tas_priv->coef_binaryname);
-		tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
 		goto out;
 	}
-	tasdevice_dsp_create_ctrls(tas_priv);
+
+	/*
+	 * If no dsp-related kcontrol created, the dsp resource will be freed.
+	 */
+	ret = tasdevice_dsp_create_ctrls(tas_priv);
+	if (ret) {
+		dev_err(tas_priv->dev, "dsp controls error\n");
+		goto out;
+	}
 
 	tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
 
@@ -404,8 +529,15 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
 	 * calibrated data inside algo.
 	 */
 	for (i = 0; i < tas_priv->ndev; i++) {
-		scnprintf(tas_priv->cal_binaryname[i], 64, "%s_cal_0x%02x.bin",
-			tas_priv->dev_name, tas_priv->tasdevice[i].dev_addr);
+		if (tas_priv->name_prefix)
+			scnprintf(tas_priv->cal_binaryname[i], 64,
+				"%s-%s_cal_0x%02x.bin", tas_priv->name_prefix,
+				tas_priv->dev_name,
+				tas_priv->tasdevice[i].dev_addr);
+		else
+			scnprintf(tas_priv->cal_binaryname[i], 64,
+				"%s_cal_0x%02x.bin", tas_priv->dev_name,
+				tas_priv->tasdevice[i].dev_addr);
 		ret = tas2781_load_calibration(tas_priv,
 			tas_priv->cal_binaryname[i], i);
 		if (ret != 0)
@@ -417,9 +549,8 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
 	tasdevice_prmg_load(tas_priv, 0);
 	tas_priv->cur_prog = 0;
 out:
-	if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
-		/*If DSP FW fail, kcontrol won't be created */
-		tasdevice_config_info_remove(tas_priv);
+	if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
+		/* If DSP FW fail, DSP kcontrol won't be created. */
 		tasdevice_dsp_remove(tas_priv);
 	}
 	mutex_unlock(&tas_priv->codec_lock);
@@ -466,14 +597,14 @@ static int tasdevice_startup(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_component *codec = dai->component;
 	struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
-	int ret = 0;
 
-	if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) {
-		dev_err(tas_priv->dev, "DSP bin file not loaded\n");
-		ret = -EINVAL;
+	switch (tas_priv->fw_state) {
+	case TASDEVICE_RCA_FW_OK:
+	case TASDEVICE_DSP_FW_ALL_OK:
+		return 0;
+	default:
+		return -EINVAL;
 	}
-
-	return ret;
 }
 
 static int tasdevice_hw_params(struct snd_pcm_substream *substream,
@@ -565,7 +696,28 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
 static int tasdevice_codec_probe(struct snd_soc_component *codec)
 {
 	struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+	struct snd_kcontrol_new *p;
+	unsigned int size;
+	int rc;
+
+	switch (tas_priv->chip_id) {
+	case TAS2781:
+		p = (struct snd_kcontrol_new *)tas2781_snd_controls;
+		size = ARRAY_SIZE(tas2781_snd_controls);
+		break;
+	default:
+		p = (struct snd_kcontrol_new *)tas2563_snd_controls;
+		size = ARRAY_SIZE(tas2563_snd_controls);
+	}
+
+	rc = snd_soc_add_component_controls(codec, p, size);
+	if (rc < 0) {
+		dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+			__func__, rc);
+		return rc;
+	}
 
+	tas_priv->name_prefix = codec->name_prefix;
 	return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
 }
 
@@ -591,8 +743,8 @@ static const struct snd_soc_component_driver
 	soc_codec_driver_tasdevice = {
 	.probe			= tasdevice_codec_probe,
 	.remove			= tasdevice_codec_remove,
-	.controls		= tas2781_snd_controls,
-	.num_controls		= ARRAY_SIZE(tas2781_snd_controls),
+	.controls		= tasdevice_snd_controls,
+	.num_controls		= ARRAY_SIZE(tasdevice_snd_controls),
 	.dapm_widgets		= tasdevice_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(tasdevice_dapm_widgets),
 	.dapm_routes		= tasdevice_audio_map,
@@ -622,33 +774,20 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
 
 		tas_priv->irq_info.irq_gpio =
 			acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0);
-	} else {
+	} else if (IS_ENABLED(CONFIG_OF)) {
 		struct device_node *np = tas_priv->dev->of_node;
-#ifdef CONFIG_OF
-		const __be32 *reg, *reg_end;
-		int len, sw, aw;
-
-		aw = of_n_addr_cells(np);
-		sw = of_n_size_cells(np);
-		if (sw == 0) {
-			reg = (const __be32 *)of_get_property(np,
-				"reg", &len);
-			reg_end = reg + len/sizeof(*reg);
-			ndev = 0;
-			do {
-				dev_addrs[ndev] = of_read_number(reg, aw);
-				reg += aw;
-				ndev++;
-			} while (reg < reg_end);
-		} else {
-			ndev = 1;
-			dev_addrs[0] = client->addr;
+		u64 addr;
+
+		for (i = 0; i < TASDEVICE_MAX_CHANNELS; i++) {
+			if (of_property_read_reg(np, i, &addr, NULL))
+				break;
+			dev_addrs[ndev++] = addr;
 		}
-#else
+
+		tas_priv->irq_info.irq_gpio = of_irq_get(np, 0);
+	} else {
 		ndev = 1;
 		dev_addrs[0] = client->addr;
-#endif
-		tas_priv->irq_info.irq_gpio = of_irq_get(np, 0);
 	}
 	tas_priv->ndev = ndev;
 	for (i = 0; i < ndev; i++)
@@ -714,6 +853,8 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c)
 	if (ret)
 		goto err;
 
+	tasdevice_reset(tas_priv);
+
 	ret = devm_snd_soc_register_component(tas_priv->dev,
 		&soc_codec_driver_tasdevice,
 		tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver));
@@ -746,7 +887,7 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
 
 static struct i2c_driver tasdevice_i2c_driver = {
 	.driver = {
-		.name = "tas2781-codec",
+		.name = "tasdev-codec",
 		.of_match_table = of_match_ptr(tasdevice_of_match),
 #ifdef CONFIG_ACPI
 		.acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 6d45df3b9ba4922d6575dfa2c111062f85fa7cf6..4bc1fdd232bb78feb476d0c1178805be597def3e 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -24,14 +24,13 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -246,7 +245,7 @@ struct tas5086_private {
 	/* Current sample rate for de-emphasis control */
 	int		rate;
 	/* GPIO driving Reset pin, if any */
-	int		gpio_nreset;
+	struct gpio_desc *reset;
 	struct		regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
@@ -462,11 +461,11 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 
 static void tas5086_reset(struct tas5086_private *priv)
 {
-	if (gpio_is_valid(priv->gpio_nreset)) {
+	if (priv->reset) {
 		/* Reset codec - minimum assertion time is 400ns */
-		gpio_direction_output(priv->gpio_nreset, 0);
+		gpiod_direction_output(priv->reset, 1);
 		udelay(1);
-		gpio_set_value(priv->gpio_nreset, 1);
+		gpiod_set_value(priv->reset, 0);
 
 		/* Codec needs ~15ms to wake up */
 		msleep(15);
@@ -867,9 +866,9 @@ static void tas5086_remove(struct snd_soc_component *component)
 {
 	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
-	if (gpio_is_valid(priv->gpio_nreset))
+	if (priv->reset)
 		/* Set codec to the reset state */
-		gpio_set_value(priv->gpio_nreset, 0);
+		gpiod_set_value(priv->reset, 1);
 
 	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
 };
@@ -914,7 +913,6 @@ static int tas5086_i2c_probe(struct i2c_client *i2c)
 {
 	struct tas5086_private *priv;
 	struct device *dev = &i2c->dev;
-	int gpio_nreset = -EINVAL;
 	int i, ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -940,12 +938,11 @@ static int tas5086_i2c_probe(struct i2c_client *i2c)
 
 	i2c_set_clientdata(i2c, priv);
 
-	gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
-	if (gpio_is_valid(gpio_nreset))
-		if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
-			gpio_nreset = -EINVAL;
-
-	priv->gpio_nreset = gpio_nreset;
+	/* Request line asserted */
+	priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->reset))
+		return PTR_ERR(priv->reset);
+	gpiod_set_consumer_name(priv->reset, "TAS5086 Reset");
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
 	if (ret < 0) {
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index e100cc9f5c1929e3fa3c1111b0757c099873e333..7073b9d1cda845157a01c229c189538c564935f5 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -25,7 +25,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/cdev.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -40,9 +39,10 @@
  */
 
 #define ADC3XXX_MICBIAS_PINS		2
+#define ADC3XXX_GPIO_PINS		2
 
 /* Number of GPIO pins exposed via the gpiolib interface */
-#define ADC3XXX_GPIOS_MAX		2
+#define ADC3XXX_GPIOS_MAX		(ADC3XXX_MICBIAS_PINS + ADC3XXX_GPIO_PINS)
 
 #define ADC3XXX_RATES		SNDRV_PCM_RATE_8000_96000
 #define ADC3XXX_FORMATS		(SNDRV_PCM_FMTBIT_S16_LE | \
@@ -321,7 +321,8 @@ struct adc3xxx {
 	struct gpio_desc *rst_pin;
 	unsigned int pll_mode;
 	unsigned int sysclk;
-	unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set)  */
+	unsigned int gpio_cfg[ADC3XXX_GPIO_PINS]; /* value+1 (0 => not set)  */
+	unsigned int micbias_gpo[ADC3XXX_MICBIAS_PINS]; /* 1 => pin is GPO */
 	unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS];
 	int master;
 	u8 page_no;
@@ -329,7 +330,7 @@ struct adc3xxx {
 	struct gpio_chip gpio_chip;
 };
 
-static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = {
+static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIO_PINS] = {
 	ADC3XXX_GPIO1_CTRL,
 	ADC3XXX_GPIO2_CTRL
 };
@@ -960,14 +961,23 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset)
 	if (offset >= ADC3XXX_GPIOS_MAX)
 		return -EINVAL;
 
-	/* GPIO1 is offset 0, GPIO2 is offset 1 */
-	/* We check here that the GPIO pins are either not configured in the
-	 * DT, or that they purposely are set as outputs.
-	 * (Input mode not yet implemented).
-	 */
-	if (adc3xxx->gpio_cfg[offset] != 0 &&
-	    adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
-		return -EINVAL;
+	if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) {
+		/* GPIO1 is offset 0, GPIO2 is offset 1 */
+		/* We check here that the GPIO pins are either not configured
+		 * in the DT, or that they purposely are set as outputs.
+		 * (Input mode not yet implemented).
+		 */
+		if (adc3xxx->gpio_cfg[offset] != 0 &&
+		    adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
+			return -EINVAL;
+	} else if (offset >= ADC3XXX_GPIO_PINS && offset < ADC3XXX_GPIOS_MAX) {
+		/* MICBIAS1 is offset 2, MICBIAS2 is offset 3 */
+		/* We check here if the MICBIAS pins are in fact configured
+		 * as GPOs.
+		 */
+		if (!adc3xxx->micbias_gpo[offset - ADC3XXX_GPIO_PINS])
+			return -EINVAL;
+	}
 
 	return 0;
 }
@@ -977,6 +987,21 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip,
 {
 	struct adc3xxx *adc3xxx = gpiochip_get_data(chip);
 
+	/* For the MICBIAS pins, they are by definition outputs. */
+	if (offset >= ADC3XXX_GPIO_PINS) {
+		unsigned int vg;
+		unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
+
+		if (value)
+			vg = adc3xxx->micbias_vg[micbias];
+		else
+			vg = ADC3XXX_MICBIAS_OFF;
+		return regmap_update_bits(adc3xxx->regmap,
+					   ADC3XXX_MICBIAS_CTRL,
+					   ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias],
+					   vg << adc3xxx_micbias_shift[micbias]);
+	}
+
 	/* Set GPIO output function. */
 	return regmap_update_bits(adc3xxx->regmap,
 				  adc3xxx_gpio_ctrl_reg[offset],
@@ -1005,9 +1030,17 @@ static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	unsigned int regval;
 	int ret;
 
-	/* We only allow output pins, so just read the value set in the output
-	 * pin register field.
-	 */
+	/* We only allow output pins, so just read the value prevously set. */
+	if (offset >= ADC3XXX_GPIO_PINS) {
+		/* MICBIAS pins */
+		unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
+
+		ret = regmap_read(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, &regval);
+		if (ret)
+			return ret;
+		return ((regval >> adc3xxx_micbias_shift[micbias]) & ADC3XXX_MICBIAS_MASK) !=
+		       ADC3XXX_MICBIAS_OFF;
+	}
 	ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], &regval);
 	if (ret)
 		return ret;
@@ -1049,7 +1082,7 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
 	 * This allows us to set up things which are not software
 	 * controllable GPIOs, such as PDM microphone I/O,
 	 */
-	for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) {
+	for (gpio = 0; gpio < ADC3XXX_GPIO_PINS; gpio++) {
 		unsigned int cfg = adc3xxx->gpio_cfg[gpio];
 
 		if (cfg) {
@@ -1061,9 +1094,15 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
 		}
 	}
 
-	/* Set up micbias voltage */
+	/* Set up micbias voltage. */
+	/* If pin is configured as GPO, set off initially. */
 	for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) {
-		unsigned int vg = adc3xxx->micbias_vg[micbias];
+		unsigned int vg;
+
+		if (adc3xxx->micbias_gpo[micbias])
+			vg = ADC3XXX_MICBIAS_OFF;
+		else
+			vg = adc3xxx->micbias_vg[micbias];
 
 		regmap_update_bits(adc3xxx->regmap,
 				   ADC3XXX_MICBIAS_CTRL,
@@ -1091,8 +1130,19 @@ static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx,
 	return 0;
 }
 
-static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx,
-				    const char *propname, unsigned int *vg)
+static int adc3xxx_parse_dt_micbias_gpo(struct adc3xxx *adc3xxx,
+					const char *propname,
+					unsigned int *cfg)
+{
+	struct device *dev = adc3xxx->dev;
+	struct device_node *np = dev->of_node;
+
+	*cfg = of_property_read_bool(np, propname);
+	return 0;
+}
+
+static int adc3xxx_parse_dt_micbias_vg(struct adc3xxx *adc3xxx,
+				       const char *propname, unsigned int *vg)
 {
 	struct device *dev = adc3xxx->dev;
 	struct device_node *np = dev->of_node;
@@ -1383,16 +1433,28 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c)
 		dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk));
 	}
 
+	/* Configure mode for DMDIN/GPIO1 pin */
 	ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]);
 	if (ret < 0)
 		goto err_unprepare_mclk;
+	/* Configure mode for DMCLK/GPIO2 pin */
 	ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]);
 	if (ret < 0)
 		goto err_unprepare_mclk;
-	ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
+	/* Configure mode for MICBIAS1: as Mic Bias output or GPO */
+	ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias1-gpo", &adc3xxx->micbias_gpo[0]);
+	if (ret < 0)
+		goto err_unprepare_mclk;
+	/* Configure mode for MICBIAS2: as Mic Bias output or GPO */
+	ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias2-gpo", &adc3xxx->micbias_gpo[1]);
+	if (ret < 0)
+		goto err_unprepare_mclk;
+	/* Configure voltage for MICBIAS1 pin (ON voltage when used as GPO) */
+	ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
 	if (ret < 0)
 		goto err_unprepare_mclk;
-	ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
+	/* Configure voltage for MICBIAS2 pin (ON voltage when used as GPO) */
+	ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
 	if (ret < 0)
 		goto err_unprepare_mclk;
 
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 41342b34068032d4e4a7c37c8aba1ac7458f8826..d594bf166c0e79cbe8b6d91c1799702ad9687b25 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -12,7 +12,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/acpi.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 4d7c5a80c6edda86f244e092710170aacb3b34cc..2f94cfda0e3302823cdc8bc89d0f96f68e9995ee 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -23,7 +23,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/acpi.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/jack.h>
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index dbf448dd88649a7b6cd64359df7397fea9f344ad..b9eb59e3bfa0a4f6b1877d4f04704954a1f98351 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -10,7 +10,6 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/acpi.h>
 
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 0e6218ed0e5e013882a3d77b26c8f120ee3bad0f..d589a212b7688d6e75a13f526649d6ed551ca054 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -50,7 +50,7 @@ struct wcd_mbhc {
 	struct wcd_mbhc_config *cfg;
 	const struct wcd_mbhc_cb *mbhc_cb;
 	const struct wcd_mbhc_intr *intr_ids;
-	struct wcd_mbhc_field *fields;
+	const struct wcd_mbhc_field *fields;
 	/* Delayed work to report long button press */
 	struct delayed_work mbhc_btn_dwork;
 	/* Work to handle plug report */
@@ -1505,7 +1505,7 @@ EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
 			       const struct wcd_mbhc_cb *mbhc_cb,
 			       const struct wcd_mbhc_intr *intr_ids,
-			       struct wcd_mbhc_field *fields,
+			       const struct wcd_mbhc_field *fields,
 			       bool impedance_det_en)
 {
 	struct device *dev = component->dev;
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index df68e99c81a33766591ccfda5a31303715db2ab4..b977e8f87d7cb733d23ed0c3301896add30d394b 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -279,7 +279,7 @@ int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc);
 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
 		      const struct wcd_mbhc_cb *mbhc_cb,
 		      const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
-		      struct wcd_mbhc_field *fields,
+		      const struct wcd_mbhc_field *fields,
 		      bool impedance_det_en);
 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
 			   uint32_t *zr);
@@ -300,7 +300,7 @@ static inline void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
 static inline struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
 		      const struct wcd_mbhc_cb *mbhc_cb,
 		      const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
-		      struct wcd_mbhc_field *fields,
+		      const struct wcd_mbhc_field *fields,
 		      bool impedance_det_en)
 {
 	return ERR_PTR(-ENOTSUPP);
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index deb15b95992d5cc494562a91f13adbc348e2dd31..373a31ddccb2d6977c222078851c6e6e2c5bff99 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/cleanup.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
@@ -297,7 +298,6 @@ struct wcd9335_codec {
 	struct clk *mclk;
 	struct clk *native_clk;
 	u32 mclk_rate;
-	u8 version;
 
 	struct slim_device *slim;
 	struct slim_device *slim_ifc_dev;
@@ -345,10 +345,6 @@ struct wcd9335_codec {
 	int dmic_0_1_clk_cnt;
 	int dmic_2_3_clk_cnt;
 	int dmic_4_5_clk_cnt;
-	int dmic_sample_rate;
-	int mad_dmic_sample_rate;
-
-	int native_clk_users;
 };
 
 struct wcd9335_irq {
@@ -397,13 +393,13 @@ struct interp_sample_rate {
 	int rate_val;
 };
 
-static struct interp_sample_rate int_mix_rate_val[] = {
+static const struct interp_sample_rate int_mix_rate_val[] = {
 	{48000, 0x4},	/* 48K */
 	{96000, 0x5},	/* 96K */
 	{192000, 0x6},	/* 192K */
 };
 
-static struct interp_sample_rate int_prim_rate_val[] = {
+static const struct interp_sample_rate int_prim_rate_val[] = {
 	{8000, 0x0},	/* 8K */
 	{16000, 0x1},	/* 16K */
 	{24000, -EINVAL},/* 24K */
@@ -1983,8 +1979,10 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
-				   unsigned int tx_num, unsigned int *tx_slot,
-				   unsigned int rx_num, unsigned int *rx_slot)
+				   unsigned int tx_num,
+				   const unsigned int *tx_slot,
+				   unsigned int rx_num,
+				   const unsigned int *rx_slot)
 {
 	struct wcd9335_codec *wcd;
 	int i;
@@ -2012,7 +2010,7 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
+static int wcd9335_get_channel_map(const struct snd_soc_dai *dai,
 				   unsigned int *tx_num, unsigned int *tx_slot,
 				   unsigned int *rx_num, unsigned int *rx_slot)
 {
@@ -2717,25 +2715,23 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
 	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
 	unsigned int decimator;
 	char *dec_adc_mux_name = NULL;
-	char *widget_name = NULL;
-	char *wname;
+	char *widget_name;
 	int ret = 0, amic_n;
 	u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
 	u16 tx_gain_ctl_reg;
 	char *dec;
 	u8 hpf_coff_freq;
 
-	widget_name = kmemdup_nul(w->name, 15, GFP_KERNEL);
-	if (!widget_name)
+	char *wname __free(kfree) = kmemdup_nul(w->name, 15, GFP_KERNEL);
+	if (!wname)
 		return -ENOMEM;
 
-	wname = widget_name;
+	widget_name = wname;
 	dec_adc_mux_name = strsep(&widget_name, " ");
 	if (!dec_adc_mux_name) {
 		dev_err(comp->dev, "%s: Invalid decimator = %s\n",
 			__func__, w->name);
-		ret =  -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 	dec_adc_mux_name = widget_name;
 
@@ -2743,16 +2739,14 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
 	if (!dec) {
 		dev_err(comp->dev, "%s: decimator index not found\n",
 			__func__);
-		ret =  -EINVAL;
-		goto out;
+		return  -EINVAL;
 	}
 
 	ret = kstrtouint(dec, 10, &decimator);
 	if (ret < 0) {
 		dev_err(comp->dev, "%s: Invalid decimator = %s\n",
 			__func__, wname);
-		ret =  -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator;
@@ -2839,62 +2833,20 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
 		snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00);
 		break;
 	}
-out:
-	kfree(wname);
+
 	return ret;
 }
 
 static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component,
-				 u32 mclk_rate, u32 dmic_clk_rate)
+				 u32 mclk_rate)
 {
-	u32 div_factor;
 	u8 dmic_ctl_val;
 
-	dev_err(component->dev,
-		"%s: mclk_rate = %d, dmic_sample_rate = %d\n",
-		__func__, mclk_rate, dmic_clk_rate);
-
-	/* Default value to return in case of error */
 	if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ)
 		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
 	else
 		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
 
-	if (dmic_clk_rate == 0) {
-		dev_err(component->dev,
-			"%s: dmic_sample_rate cannot be 0\n",
-			__func__);
-		goto done;
-	}
-
-	div_factor = mclk_rate / dmic_clk_rate;
-	switch (div_factor) {
-	case 2:
-		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
-		break;
-	case 3:
-		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
-		break;
-	case 4:
-		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4;
-		break;
-	case 6:
-		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6;
-		break;
-	case 8:
-		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8;
-		break;
-	case 16:
-		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16;
-		break;
-	default:
-		dev_err(component->dev,
-			"%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
-			__func__, div_factor, mclk_rate, dmic_clk_rate);
-		break;
-	}
-
-done:
 	return dmic_ctl_val;
 }
 
@@ -2948,11 +2900,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		dmic_rate_val =
-			wcd9335_get_dmic_clk_val(comp,
-					wcd->mclk_rate,
-					wcd->dmic_sample_rate);
-
+		dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate);
 		(*dmic_clk_cnt)++;
 		if (*dmic_clk_cnt == 1) {
 			snd_soc_component_update_bits(comp, dmic_clk_reg,
@@ -2964,10 +2912,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
 
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		dmic_rate_val =
-			wcd9335_get_dmic_clk_val(comp,
-					wcd->mclk_rate,
-					wcd->mad_dmic_sample_rate);
+		dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate);
 		(*dmic_clk_cnt)--;
 		if (*dmic_clk_cnt  == 0) {
 			snd_soc_component_update_bits(comp, dmic_clk_reg,
@@ -4024,7 +3969,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
 	return ret;
 }
 
-static struct wcd9335_irq wcd9335_irqs[] = {
+static const struct wcd9335_irq wcd9335_irqs[] = {
 	{
 		.irq = WCD9335_IRQ_SLIMBUS,
 		.handler = wcd9335_slimbus_irq,
@@ -4961,7 +4906,7 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
 	}
 }
 
-static struct regmap_config wcd9335_regmap_config = {
+static const struct regmap_config wcd9335_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 8,
 	.cache_type = REGCACHE_MAPLE,
@@ -4985,7 +4930,7 @@ static const struct regmap_range_cfg wcd9335_ifc_ranges[] = {
 	},
 };
 
-static struct regmap_config wcd9335_ifc_regmap_config = {
+static const struct regmap_config wcd9335_ifc_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 8,
 	.can_multi_write = true,
@@ -5032,22 +4977,16 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
 	int ret;
 
 	wcd->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);
-	if (wcd->reset_gpio < 0) {
-		dev_err(dev, "Reset GPIO missing from DT\n");
-		return wcd->reset_gpio;
-	}
+	if (wcd->reset_gpio < 0)
+		return dev_err_probe(dev, wcd->reset_gpio, "Reset GPIO missing from DT\n");
 
 	wcd->mclk = devm_clk_get(dev, "mclk");
-	if (IS_ERR(wcd->mclk)) {
-		dev_err(dev, "mclk not found\n");
-		return PTR_ERR(wcd->mclk);
-	}
+	if (IS_ERR(wcd->mclk))
+		return dev_err_probe(dev, PTR_ERR(wcd->mclk), "mclk not found\n");
 
 	wcd->native_clk = devm_clk_get(dev, "slimbus");
-	if (IS_ERR(wcd->native_clk)) {
-		dev_err(dev, "slimbus clock not found\n");
-		return PTR_ERR(wcd->native_clk);
-	}
+	if (IS_ERR(wcd->native_clk))
+		return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n");
 
 	wcd->supplies[0].supply = "vdd-buck";
 	wcd->supplies[1].supply = "vdd-buck-sido";
@@ -5056,10 +4995,8 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
 	wcd->supplies[4].supply = "vdd-io";
 
 	ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies);
-	if (ret) {
-		dev_err(dev, "Failed to get supplies: err = %d\n", ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get supplies\n");
 
 	return 0;
 }
@@ -5107,7 +5044,6 @@ static int wcd9335_bring_up(struct wcd9335_codec *wcd)
 
 	if (byte0 == 0x1) {
 		dev_info(wcd->dev, "WCD9335 CODEC version is v2.0\n");
-		wcd->version = WCD9335_VERSION_2_0;
 		regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01);
 		regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00);
 		regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
@@ -5159,10 +5095,8 @@ static int wcd9335_slim_probe(struct slim_device *slim)
 
 	wcd->dev = dev;
 	ret = wcd9335_parse_dt(wcd);
-	if (ret) {
-		dev_err(dev, "Error parsing DT: %d\n", ret);
+	if (ret)
 		return ret;
-	}
 
 	ret = wcd9335_power_on_reset(wcd);
 	if (ret)
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index de870c7819caa1a88d488d26aeaa4ae9c3dead26..291d0c80a6fcf1a5d1c0bfb8385d79312be3f9fa 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2019, Linaro Limited
 
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/interrupt.h>
@@ -475,17 +476,12 @@ enum {
 	INTn_2_INP_SEL_PROXIMITY,
 };
 
-enum {
-	INTERP_MAIN_PATH,
-	INTERP_MIX_PATH,
-};
-
 struct interp_sample_rate {
 	int sample_rate;
 	int rate_val;
 };
 
-static struct interp_sample_rate sr_val_tbl[] = {
+static const struct interp_sample_rate sr_val_tbl[] = {
 	{8000, 0x0},
 	{16000, 0x1},
 	{32000, 0x3},
@@ -527,7 +523,7 @@ static const struct regmap_range_cfg wcd934x_ifc_ranges[] = {
 	},
 };
 
-static struct regmap_config wcd934x_ifc_regmap_config = {
+static const struct regmap_config wcd934x_ifc_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 8,
 	.max_register = 0xffff,
@@ -571,10 +567,7 @@ struct wcd934x_codec {
 	struct mutex micb_lock;
 	u32 micb_ref[WCD934X_MAX_MICBIAS];
 	u32 pullup_ref[WCD934X_MAX_MICBIAS];
-	u32 micb1_mv;
 	u32 micb2_mv;
-	u32 micb3_mv;
-	u32 micb4_mv;
 };
 
 #define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw)
@@ -1217,7 +1210,7 @@ static const struct soc_enum cdc_if_tx13_mux_enum =
 	SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0,
 			ARRAY_SIZE(cdc_if_tx13_mux_text), cdc_if_tx13_mux_text);
 
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
 	WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD934X_ANA_MBHC_MECH, 0x80),
 	WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD934X_ANA_MBHC_MECH, 0x40),
 	WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD934X_ANA_MBHC_MECH, 0x20),
@@ -1923,8 +1916,10 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
-				   unsigned int tx_num, unsigned int *tx_slot,
-				   unsigned int rx_num, unsigned int *rx_slot)
+				   unsigned int tx_num,
+				   const unsigned int *tx_slot,
+				   unsigned int rx_num,
+				   const unsigned int *rx_slot)
 {
 	struct wcd934x_codec *wcd;
 	int i;
@@ -1958,7 +1953,7 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static int wcd934x_get_channel_map(struct snd_soc_dai *dai,
+static int wcd934x_get_channel_map(const struct snd_soc_dai *dai,
 				   unsigned int *tx_num, unsigned int *tx_slot,
 				   unsigned int *rx_num, unsigned int *rx_slot)
 {
@@ -2206,7 +2201,8 @@ static int wcd934x_get_micbias_val(struct device *dev, const char *micbias,
 		mv = WCD934X_DEF_MICBIAS_MV;
 	}
 
-	*micb_mv = mv;
+	if (micb_mv)
+		*micb_mv = mv;
 
 	return (mv - 1000) / 50;
 }
@@ -2218,17 +2214,14 @@ static int wcd934x_init_dmic(struct snd_soc_component *comp)
 	u32 def_dmic_rate, dmic_clk_drv;
 
 	vout_ctl_1 = wcd934x_get_micbias_val(comp->dev,
-					     "qcom,micbias1-microvolt",
-					     &wcd->micb1_mv);
+					     "qcom,micbias1-microvolt", NULL);
 	vout_ctl_2 = wcd934x_get_micbias_val(comp->dev,
 					     "qcom,micbias2-microvolt",
 					     &wcd->micb2_mv);
 	vout_ctl_3 = wcd934x_get_micbias_val(comp->dev,
-					     "qcom,micbias3-microvolt",
-					     &wcd->micb3_mv);
+					     "qcom,micbias3-microvolt", NULL);
 	vout_ctl_4 = wcd934x_get_micbias_val(comp->dev,
-					     "qcom,micbias4-microvolt",
-					     &wcd->micb4_mv);
+					     "qcom,micbias4-microvolt", NULL);
 
 	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1,
 				      WCD934X_MICB_VAL_MASK, vout_ctl_1);
@@ -4981,25 +4974,23 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
 	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
 	unsigned int decimator;
 	char *dec_adc_mux_name = NULL;
-	char *widget_name = NULL;
-	char *wname;
+	char *widget_name;
 	int ret = 0, amic_n;
 	u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
 	u16 tx_gain_ctl_reg;
 	char *dec;
 	u8 hpf_coff_freq;
 
-	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
-	if (!widget_name)
+	char *wname __free(kfree) = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!wname)
 		return -ENOMEM;
 
-	wname = widget_name;
+	widget_name = wname;
 	dec_adc_mux_name = strsep(&widget_name, " ");
 	if (!dec_adc_mux_name) {
 		dev_err(comp->dev, "%s: Invalid decimator = %s\n",
 			__func__, w->name);
-		ret =  -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 	dec_adc_mux_name = widget_name;
 
@@ -5007,16 +4998,14 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
 	if (!dec) {
 		dev_err(comp->dev, "%s: decimator index not found\n",
 			__func__);
-		ret =  -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	ret = kstrtouint(dec, 10, &decimator);
 	if (ret < 0) {
 		dev_err(comp->dev, "%s: Invalid decimator = %s\n",
 			__func__, wname);
-		ret =  -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator;
@@ -5109,8 +5098,7 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
 					      WCD934X_DEC_PWR_LVL_DF);
 		break;
 	}
-out:
-	kfree(wname);
+
 	return ret;
 }
 
@@ -5864,17 +5852,13 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
 	struct device_node *ifc_dev_np;
 
 	ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0);
-	if (!ifc_dev_np) {
-		dev_err(dev, "No Interface device found\n");
-		return -EINVAL;
-	}
+	if (!ifc_dev_np)
+		return dev_err_probe(dev, -EINVAL, "No Interface device found\n");
 
 	wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np);
 	of_node_put(ifc_dev_np);
-	if (!wcd->sidev) {
-		dev_err(dev, "Unable to get SLIM Interface device\n");
-		return -EINVAL;
-	}
+	if (!wcd->sidev)
+		return dev_err_probe(dev, -EINVAL, "Unable to get SLIM Interface device\n");
 
 	slim_get_logical_addr(wcd->sidev);
 	wcd->if_regmap = regmap_init_slimbus(wcd->sidev,
@@ -5920,10 +5904,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
 	mutex_init(&wcd->micb_lock);
 
 	ret = wcd934x_codec_parse_data(wcd);
-	if (ret) {
-		dev_err(wcd->dev, "Failed to get SLIM IRQ\n");
+	if (ret)
 		return ret;
-	}
 
 	/* set default rate 9P6MHz */
 	regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
new file mode 100644
index 0000000000000000000000000000000000000000..3abc8041406adc24544bb33e23b56162c0c36deb
--- /dev/null
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -0,0 +1,1137 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include "wcd937x.h"
+
+static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = {
+	WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)),
+	WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_COMP_L, WCD937X_COMP_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_COMP_R, WCD937X_COMP_PORT, BIT(1)),
+	WCD_SDW_CH(WCD937X_LO, WCD937X_LO_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_DSD_L, WCD937X_DSD_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)),
+};
+
+static const struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = {
+	WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_DMIC0, WCD937X_DMIC_0_3_MBHC_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_DMIC1, WCD937X_DMIC_0_3_MBHC_PORT, BIT(1)),
+	WCD_SDW_CH(WCD937X_MBHC, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)),
+	WCD_SDW_CH(WCD937X_DMIC2, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)),
+	WCD_SDW_CH(WCD937X_DMIC3, WCD937X_DMIC_0_3_MBHC_PORT, BIT(3)),
+	WCD_SDW_CH(WCD937X_DMIC4, WCD937X_DMIC_4_6_PORT, BIT(0)),
+	WCD_SDW_CH(WCD937X_DMIC5, WCD937X_DMIC_4_6_PORT, BIT(1)),
+	WCD_SDW_CH(WCD937X_DMIC6, WCD937X_DMIC_4_6_PORT, BIT(2)),
+};
+
+static struct sdw_dpn_prop wcd937x_dpn_prop[WCD937X_MAX_SWR_PORTS] = {
+	{
+		.num = 1,
+		.type = SDW_DPN_SIMPLE,
+		.min_ch = 1,
+		.max_ch = 8,
+		.simple_ch_prep_sm = true,
+	}, {
+		.num = 2,
+		.type = SDW_DPN_SIMPLE,
+		.min_ch = 1,
+		.max_ch = 4,
+		.simple_ch_prep_sm = true,
+	}, {
+		.num = 3,
+		.type = SDW_DPN_SIMPLE,
+		.min_ch = 1,
+		.max_ch = 4,
+		.simple_ch_prep_sm = true,
+	}, {
+		.num = 4,
+		.type = SDW_DPN_SIMPLE,
+		.min_ch = 1,
+		.max_ch = 4,
+		.simple_ch_prep_sm = true,
+	}, {
+		.num = 5,
+		.type = SDW_DPN_SIMPLE,
+		.min_ch = 1,
+		.max_ch = 4,
+		.simple_ch_prep_sm = true,
+	}
+};
+
+struct device *wcd937x_sdw_device_get(struct device_node *np)
+{
+	return bus_find_device_by_of_node(&sdw_bus_type, np);
+}
+EXPORT_SYMBOL_GPL(wcd937x_sdw_device_get);
+
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+			  struct snd_pcm_substream *substream,
+			  struct snd_pcm_hw_params *params,
+			  struct snd_soc_dai *dai)
+{
+	struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
+	unsigned long ch_mask;
+	int i, j;
+
+	wcd->sconfig.ch_count = 1;
+	wcd->active_ports = 0;
+	for (i = 0; i < WCD937X_MAX_SWR_PORTS; i++) {
+		ch_mask = wcd->port_config[i].ch_mask;
+		if (!ch_mask)
+			continue;
+
+		for_each_set_bit(j, &ch_mask, 4)
+			wcd->sconfig.ch_count++;
+
+		port_config[wcd->active_ports] = wcd->port_config[i];
+		wcd->active_ports++;
+	}
+
+	wcd->sconfig.bps = 1;
+	wcd->sconfig.frame_rate = params_rate(params);
+	wcd->sconfig.direction = wcd->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX;
+	wcd->sconfig.type = SDW_STREAM_PCM;
+
+	return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig,
+				    &port_config[0], wcd->active_ports,
+				    wcd->sruntime);
+}
+EXPORT_SYMBOL_GPL(wcd937x_sdw_hw_params);
+
+static int wcd9370_update_status(struct sdw_slave *slave, enum sdw_slave_status status)
+{
+	struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+
+	if (wcd->regmap && status == SDW_SLAVE_ATTACHED) {
+		/* Write out any cached changes that happened between probe and attach */
+		regcache_cache_only(wcd->regmap, false);
+		return regcache_sync(wcd->regmap);
+	}
+
+	return 0;
+}
+
+/*
+ * Handle Soundwire out-of-band interrupt event by triggering
+ * the first irq of the slave_irq irq domain, which then will
+ * be handled by the regmap_irq threaded irq.
+ * Looping is to ensure no interrupts were missed in the process.
+ */
+static int wcd9370_interrupt_callback(struct sdw_slave *slave,
+				      struct sdw_slave_intr_status *status)
+{
+	struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+	struct irq_domain *slave_irq = wcd->slave_irq;
+	u32 sts1, sts2, sts3;
+
+	do {
+		handle_nested_irq(irq_find_mapping(slave_irq, 0));
+		regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_0, &sts1);
+		regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_1, &sts2);
+		regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_2, &sts3);
+
+	} while (sts1 || sts2 || sts3);
+
+	return IRQ_HANDLED;
+}
+
+static const struct reg_default wcd937x_defaults[] = {
+	/* Default values except for Read-Only & Volatile registers */
+	{ WCD937X_ANA_BIAS,					0x00 },
+	{ WCD937X_ANA_RX_SUPPLIES,				0x00 },
+	{ WCD937X_ANA_HPH,					0x0c },
+	{ WCD937X_ANA_EAR,					0x00 },
+	{ WCD937X_ANA_EAR_COMPANDER_CTL,			0x02 },
+	{ WCD937X_ANA_TX_CH1,					0x20 },
+	{ WCD937X_ANA_TX_CH2,					0x00 },
+	{ WCD937X_ANA_TX_CH3,					0x20 },
+	{ WCD937X_ANA_TX_CH3_HPF,				0x00 },
+	{ WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC,			0x00 },
+	{ WCD937X_ANA_MICB3_DSP_EN_LOGIC,			0x00 },
+	{ WCD937X_ANA_MBHC_MECH,				0x39 },
+	{ WCD937X_ANA_MBHC_ELECT,				0x08 },
+	{ WCD937X_ANA_MBHC_ZDET,				0x00 },
+	{ WCD937X_ANA_MBHC_BTN0,				0x00 },
+	{ WCD937X_ANA_MBHC_BTN1,				0x10 },
+	{ WCD937X_ANA_MBHC_BTN2,				0x20 },
+	{ WCD937X_ANA_MBHC_BTN3,				0x30 },
+	{ WCD937X_ANA_MBHC_BTN4,				0x40 },
+	{ WCD937X_ANA_MBHC_BTN5,				0x50 },
+	{ WCD937X_ANA_MBHC_BTN6,				0x60 },
+	{ WCD937X_ANA_MBHC_BTN7,				0x70 },
+	{ WCD937X_ANA_MICB1,					0x10 },
+	{ WCD937X_ANA_MICB2,					0x10 },
+	{ WCD937X_ANA_MICB2_RAMP,				0x00 },
+	{ WCD937X_ANA_MICB3,					0x10 },
+	{ WCD937X_BIAS_CTL,					0x2a },
+	{ WCD937X_BIAS_VBG_FINE_ADJ,				0x55 },
+	{ WCD937X_LDOL_VDDCX_ADJUST,				0x01 },
+	{ WCD937X_LDOL_DISABLE_LDOL,				0x00 },
+	{ WCD937X_MBHC_CTL_CLK,					0x00 },
+	{ WCD937X_MBHC_CTL_ANA,					0x00 },
+	{ WCD937X_MBHC_CTL_SPARE_1,				0x00 },
+	{ WCD937X_MBHC_CTL_SPARE_2,				0x00 },
+	{ WCD937X_MBHC_CTL_BCS,					0x00 },
+	{ WCD937X_MBHC_TEST_CTL,				0x00 },
+	{ WCD937X_LDOH_MODE,					0x2b },
+	{ WCD937X_LDOH_BIAS,					0x68 },
+	{ WCD937X_LDOH_STB_LOADS,				0x00 },
+	{ WCD937X_LDOH_SLOWRAMP,				0x50 },
+	{ WCD937X_MICB1_TEST_CTL_1,				0x1a },
+	{ WCD937X_MICB1_TEST_CTL_2,				0x18 },
+	{ WCD937X_MICB1_TEST_CTL_3,				0xa4 },
+	{ WCD937X_MICB2_TEST_CTL_1,				0x1a },
+	{ WCD937X_MICB2_TEST_CTL_2,				0x18 },
+	{ WCD937X_MICB2_TEST_CTL_3,				0xa4 },
+	{ WCD937X_MICB3_TEST_CTL_1,				0x1a },
+	{ WCD937X_MICB3_TEST_CTL_2,				0x18 },
+	{ WCD937X_MICB3_TEST_CTL_3,				0xa4 },
+	{ WCD937X_TX_COM_ADC_VCM,				0x39 },
+	{ WCD937X_TX_COM_BIAS_ATEST,				0xc0 },
+	{ WCD937X_TX_COM_ADC_INT1_IB,				0x6f },
+	{ WCD937X_TX_COM_ADC_INT2_IB,				0x4f },
+	{ WCD937X_TX_COM_TXFE_DIV_CTL,				0x2e },
+	{ WCD937X_TX_COM_TXFE_DIV_START,			0x00 },
+	{ WCD937X_TX_COM_TXFE_DIV_STOP_9P6M,			0xc7 },
+	{ WCD937X_TX_COM_TXFE_DIV_STOP_12P288M,			0xff },
+	{ WCD937X_TX_1_2_TEST_EN,				0xcc },
+	{ WCD937X_TX_1_2_ADC_IB,				0x09 },
+	{ WCD937X_TX_1_2_ATEST_REFCTL,				0x0a },
+	{ WCD937X_TX_1_2_TEST_CTL,				0x38 },
+	{ WCD937X_TX_1_2_TEST_BLK_EN,				0xff },
+	{ WCD937X_TX_1_2_TXFE_CLKDIV,				0x00 },
+	{ WCD937X_TX_3_TEST_EN,					0xcc },
+	{ WCD937X_TX_3_ADC_IB,					0x09 },
+	{ WCD937X_TX_3_ATEST_REFCTL,				0x0a },
+	{ WCD937X_TX_3_TEST_CTL,				0x38 },
+	{ WCD937X_TX_3_TEST_BLK_EN,				0xff },
+	{ WCD937X_TX_3_TXFE_CLKDIV,				0x00 },
+	{ WCD937X_TX_3_SPARE_MONO,				0x00 },
+	{ WCD937X_CLASSH_MODE_1,				0x40 },
+	{ WCD937X_CLASSH_MODE_2,				0x3a },
+	{ WCD937X_CLASSH_MODE_3,				0x00 },
+	{ WCD937X_CLASSH_CTRL_VCL_1,				0x70 },
+	{ WCD937X_CLASSH_CTRL_VCL_2,				0x82 },
+	{ WCD937X_CLASSH_CTRL_CCL_1,				0x31 },
+	{ WCD937X_CLASSH_CTRL_CCL_2,				0x80 },
+	{ WCD937X_CLASSH_CTRL_CCL_3,				0x80 },
+	{ WCD937X_CLASSH_CTRL_CCL_4,				0x51 },
+	{ WCD937X_CLASSH_CTRL_CCL_5,				0x00 },
+	{ WCD937X_CLASSH_BUCK_TMUX_A_D,				0x00 },
+	{ WCD937X_CLASSH_BUCK_SW_DRV_CNTL,			0x77 },
+	{ WCD937X_CLASSH_SPARE,					0x00 },
+	{ WCD937X_FLYBACK_EN,					0x4e },
+	{ WCD937X_FLYBACK_VNEG_CTRL_1,				0x0b },
+	{ WCD937X_FLYBACK_VNEG_CTRL_2,				0x45 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_3,				0x74 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_4,				0x7f },
+	{ WCD937X_FLYBACK_VNEG_CTRL_5,				0x83 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_6,				0x98 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_7,				0xa9 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_8,				0x68 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_9,				0x64 },
+	{ WCD937X_FLYBACK_VNEGDAC_CTRL_1,			0xed },
+	{ WCD937X_FLYBACK_VNEGDAC_CTRL_2,			0xf0 },
+	{ WCD937X_FLYBACK_VNEGDAC_CTRL_3,			0xa6 },
+	{ WCD937X_FLYBACK_CTRL_1,				0x65 },
+	{ WCD937X_FLYBACK_TEST_CTL,				0x00 },
+	{ WCD937X_RX_AUX_SW_CTL,				0x00 },
+	{ WCD937X_RX_PA_AUX_IN_CONN,				0x00 },
+	{ WCD937X_RX_TIMER_DIV,					0x32 },
+	{ WCD937X_RX_OCP_CTL,					0x1f },
+	{ WCD937X_RX_OCP_COUNT,					0x77 },
+	{ WCD937X_RX_BIAS_EAR_DAC,				0xa0 },
+	{ WCD937X_RX_BIAS_EAR_AMP,				0xaa },
+	{ WCD937X_RX_BIAS_HPH_LDO,				0xa9 },
+	{ WCD937X_RX_BIAS_HPH_PA,				0xaa },
+	{ WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2,			0x8a },
+	{ WCD937X_RX_BIAS_HPH_RDAC_LDO,				0x88 },
+	{ WCD937X_RX_BIAS_HPH_CNP1,				0x82 },
+	{ WCD937X_RX_BIAS_HPH_LOWPOWER,				0x82 },
+	{ WCD937X_RX_BIAS_AUX_DAC,				0xa0 },
+	{ WCD937X_RX_BIAS_AUX_AMP,				0xaa },
+	{ WCD937X_RX_BIAS_VNEGDAC_BLEEDER,			0x50 },
+	{ WCD937X_RX_BIAS_MISC,					0x00 },
+	{ WCD937X_RX_BIAS_BUCK_RST,				0x08 },
+	{ WCD937X_RX_BIAS_BUCK_VREF_ERRAMP,			0x44 },
+	{ WCD937X_RX_BIAS_FLYB_ERRAMP,				0x40 },
+	{ WCD937X_RX_BIAS_FLYB_BUFF,				0xaa },
+	{ WCD937X_RX_BIAS_FLYB_MID_RST,				0x14 },
+	{ WCD937X_HPH_CNP_EN,					0x80 },
+	{ WCD937X_HPH_CNP_WG_CTL,				0x9a },
+	{ WCD937X_HPH_CNP_WG_TIME,				0x14 },
+	{ WCD937X_HPH_OCP_CTL,					0x28 },
+	{ WCD937X_HPH_AUTO_CHOP,				0x16 },
+	{ WCD937X_HPH_CHOP_CTL,					0x83 },
+	{ WCD937X_HPH_PA_CTL1,					0x46 },
+	{ WCD937X_HPH_PA_CTL2,					0x50 },
+	{ WCD937X_HPH_L_EN,					0x80 },
+	{ WCD937X_HPH_L_TEST,					0xe0 },
+	{ WCD937X_HPH_L_ATEST,					0x50 },
+	{ WCD937X_HPH_R_EN,					0x80 },
+	{ WCD937X_HPH_R_TEST,					0xe0 },
+	{ WCD937X_HPH_R_ATEST,					0x54 },
+	{ WCD937X_HPH_RDAC_CLK_CTL1,				0x99 },
+	{ WCD937X_HPH_RDAC_CLK_CTL2,				0x9b },
+	{ WCD937X_HPH_RDAC_LDO_CTL,				0x33 },
+	{ WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL,			0x00 },
+	{ WCD937X_HPH_REFBUFF_UHQA_CTL,				0xa8 },
+	{ WCD937X_HPH_REFBUFF_LP_CTL,				0x0e },
+	{ WCD937X_HPH_L_DAC_CTL,				0x20 },
+	{ WCD937X_HPH_R_DAC_CTL,				0x20 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL,		0x55 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_EN,			0x19 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1,			0xa0 },
+	{ WCD937X_EAR_EAR_EN_REG,				0x22 },
+	{ WCD937X_EAR_EAR_PA_CON,				0x44 },
+	{ WCD937X_EAR_EAR_SP_CON,				0xdb },
+	{ WCD937X_EAR_EAR_DAC_CON,				0x80 },
+	{ WCD937X_EAR_EAR_CNP_FSM_CON,				0xb2 },
+	{ WCD937X_EAR_TEST_CTL,					0x00 },
+	{ WCD937X_ANA_NEW_PAGE_REGISTER,			0x00 },
+	{ WCD937X_HPH_NEW_ANA_HPH2,				0x00 },
+	{ WCD937X_HPH_NEW_ANA_HPH3,				0x00 },
+	{ WCD937X_SLEEP_CTL,					0x16 },
+	{ WCD937X_SLEEP_WATCHDOG_CTL,				0x00 },
+	{ WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL,			0x00 },
+	{ WCD937X_MBHC_NEW_CTL_1,				0x02 },
+	{ WCD937X_MBHC_NEW_CTL_2,				0x05 },
+	{ WCD937X_MBHC_NEW_PLUG_DETECT_CTL,			0xe9 },
+	{ WCD937X_MBHC_NEW_ZDET_ANA_CTL,			0x0f },
+	{ WCD937X_MBHC_NEW_ZDET_RAMP_CTL,			0x00 },
+	{ WCD937X_TX_NEW_TX_CH2_SEL,				0x00 },
+	{ WCD937X_AUX_AUXPA,					0x00 },
+	{ WCD937X_LDORXTX_MODE,					0x0c },
+	{ WCD937X_LDORXTX_CONFIG,				0x10 },
+	{ WCD937X_DIE_CRACK_DIE_CRK_DET_EN,			0x00 },
+	{ WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL,			0x40 },
+	{ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,			0x81 },
+	{ WCD937X_HPH_NEW_INT_RDAC_VREF_CTL,			0x10 },
+	{ WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL,		0x00 },
+	{ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,			0x81 },
+	{ WCD937X_HPH_NEW_INT_PA_MISC1,				0x22 },
+	{ WCD937X_HPH_NEW_INT_PA_MISC2,				0x00 },
+	{ WCD937X_HPH_NEW_INT_PA_RDAC_MISC,			0x00 },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER1,			0xfe },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER2,			0x02 },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER3,			0x4e },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER4,			0x54 },
+	{ WCD937X_HPH_NEW_INT_PA_RDAC_MISC2,			0x00 },
+	{ WCD937X_HPH_NEW_INT_PA_RDAC_MISC3,			0x00 },
+	{ WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI,		0x62 },
+	{ WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP,			0x01 },
+	{ WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP,			0x11 },
+	{ WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL,		0x57 },
+	{ WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL,	0x01 },
+	{ WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT,		0x00 },
+	{ WCD937X_MBHC_NEW_INT_SPARE_2,				0x00 },
+	{ WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON,			0xa8 },
+	{ WCD937X_EAR_INT_NEW_CNP_VCM_CON1,			0x42 },
+	{ WCD937X_EAR_INT_NEW_CNP_VCM_CON2,			0x22 },
+	{ WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS,			0x00 },
+	{ WCD937X_AUX_INT_EN_REG,				0x00 },
+	{ WCD937X_AUX_INT_PA_CTRL,				0x06 },
+	{ WCD937X_AUX_INT_SP_CTRL,				0xd2 },
+	{ WCD937X_AUX_INT_DAC_CTRL,				0x80 },
+	{ WCD937X_AUX_INT_CLK_CTRL,				0x50 },
+	{ WCD937X_AUX_INT_TEST_CTRL,				0x00 },
+	{ WCD937X_AUX_INT_STATUS_REG,				0x00 },
+	{ WCD937X_AUX_INT_MISC,					0x00 },
+	{ WCD937X_LDORXTX_INT_BIAS,				0x6e },
+	{ WCD937X_LDORXTX_INT_STB_LOADS_DTEST,			0x50 },
+	{ WCD937X_LDORXTX_INT_TEST0,				0x1c },
+	{ WCD937X_LDORXTX_INT_STARTUP_TIMER,			0xff },
+	{ WCD937X_LDORXTX_INT_TEST1,				0x1f },
+	{ WCD937X_LDORXTX_INT_STATUS,				0x00 },
+	{ WCD937X_SLEEP_INT_WATCHDOG_CTL_1,			0x0a },
+	{ WCD937X_SLEEP_INT_WATCHDOG_CTL_2,			0x0a },
+	{ WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1,		0x02 },
+	{ WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2,		0x60 },
+	{ WCD937X_DIGITAL_PAGE_REGISTER,			0x00 },
+	{ WCD937X_DIGITAL_CDC_RST_CTL,				0x03 },
+	{ WCD937X_DIGITAL_TOP_CLK_CFG,				0x00 },
+	{ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,			0x00 },
+	{ WCD937X_DIGITAL_SWR_RST_EN,				0x00 },
+	{ WCD937X_DIGITAL_CDC_PATH_MODE,			0x55 },
+	{ WCD937X_DIGITAL_CDC_RX_RST,				0x00 },
+	{ WCD937X_DIGITAL_CDC_RX0_CTL,				0xfc },
+	{ WCD937X_DIGITAL_CDC_RX1_CTL,				0xfc },
+	{ WCD937X_DIGITAL_CDC_RX2_CTL,				0xfc },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA0,			0x55 },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA1,			0x55 },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA2,			0x55 },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA3,			0x01 },
+	{ WCD937X_DIGITAL_CDC_COMP_CTL_0,			0x00 },
+	{ WCD937X_DIGITAL_CDC_RX_DELAY_CTL,			0x66 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A1_0,			0x00 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A1_1,			0x01 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A2_0,			0x63 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A2_1,			0x04 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A3_0,			0xac },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A3_1,			0x04 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A4_0,			0x1a },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A4_1,			0x03 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A5_0,			0xbc },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A5_1,			0x02 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A6_0,			0xc7 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A7_0,			0xf8 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_0,			0x47 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_1,			0x43 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_2,			0xb1 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_3,			0x17 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R1,			0x4b },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R2,			0x26 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R3,			0x32 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R4,			0x57 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R5,			0x63 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R6,			0x7c },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R7,			0x57 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A1_0,			0x00 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A1_1,			0x01 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A2_0,			0x96 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A2_1,			0x09 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A3_0,			0xab },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A3_1,			0x05 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A4_0,			0x1c },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A4_1,			0x02 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A5_0,			0x17 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A5_1,			0x02 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A6_0,			0xaa },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A7_0,			0xe3 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_0,			0x69 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_1,			0x54 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_2,			0x02 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_3,			0x15 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R1,			0xa4 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R2,			0xb5 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R3,			0x86 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R4,			0x85 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R5,			0xaa },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R6,			0xe2 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R7,			0x62 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0,			0x55 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1,			0xa9 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0,			0x3d },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1,			0x2e },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2,			0x01 },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0,			0x00 },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1,			0xfc },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2,			0x01 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_EAR_PATH_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_SWR_CLH,				0x00 },
+	{ WCD937X_DIGITAL_SWR_CLH_BYP,				0x00 },
+	{ WCD937X_DIGITAL_CDC_TX0_CTL,				0x68 },
+	{ WCD937X_DIGITAL_CDC_TX1_CTL,				0x68 },
+	{ WCD937X_DIGITAL_CDC_TX2_CTL,				0x68 },
+	{ WCD937X_DIGITAL_CDC_TX_RST,				0x00 },
+	{ WCD937X_DIGITAL_CDC_REQ_CTL,				0x01 },
+	{ WCD937X_DIGITAL_CDC_AMIC_CTL,				0x07 },
+	{ WCD937X_DIGITAL_CDC_DMIC_CTL,				0x00 },
+	{ WCD937X_DIGITAL_CDC_DMIC1_CTL,			0x01 },
+	{ WCD937X_DIGITAL_CDC_DMIC2_CTL,			0x01 },
+	{ WCD937X_DIGITAL_CDC_DMIC3_CTL,			0x01 },
+	{ WCD937X_DIGITAL_EFUSE_CTL,				0x2b },
+	{ WCD937X_DIGITAL_EFUSE_PRG_CTL,			0x00 },
+	{ WCD937X_DIGITAL_EFUSE_TEST_CTL_0,			0x00 },
+	{ WCD937X_DIGITAL_EFUSE_TEST_CTL_1,			0x00 },
+	{ WCD937X_DIGITAL_PDM_WD_CTL0,				0x00 },
+	{ WCD937X_DIGITAL_PDM_WD_CTL1,				0x00 },
+	{ WCD937X_DIGITAL_PDM_WD_CTL2,				0x00 },
+	{ WCD937X_DIGITAL_INTR_MODE,				0x00 },
+	{ WCD937X_DIGITAL_INTR_MASK_0,				0xff },
+	{ WCD937X_DIGITAL_INTR_MASK_1,				0xff },
+	{ WCD937X_DIGITAL_INTR_MASK_2,				0x0f },
+	{ WCD937X_DIGITAL_INTR_CLEAR_0,				0x00 },
+	{ WCD937X_DIGITAL_INTR_CLEAR_1,				0x00 },
+	{ WCD937X_DIGITAL_INTR_CLEAR_2,				0x00 },
+	{ WCD937X_DIGITAL_INTR_LEVEL_0,				0x00 },
+	{ WCD937X_DIGITAL_INTR_LEVEL_1,				0x00 },
+	{ WCD937X_DIGITAL_INTR_LEVEL_2,				0x00 },
+	{ WCD937X_DIGITAL_INTR_SET_0,				0x00 },
+	{ WCD937X_DIGITAL_INTR_SET_1,				0x00 },
+	{ WCD937X_DIGITAL_INTR_SET_2,				0x00 },
+	{ WCD937X_DIGITAL_INTR_TEST_0,				0x00 },
+	{ WCD937X_DIGITAL_INTR_TEST_1,				0x00 },
+	{ WCD937X_DIGITAL_INTR_TEST_2,				0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_RX0_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_RX1_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_RX2_CTL,			0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_TX_CTL,			0x00 },
+	{ WCD937X_DIGITAL_LOOP_BACK_MODE,			0x00 },
+	{ WCD937X_DIGITAL_SWR_DAC_TEST,				0x00 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_RX_0,			0x40 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_TX_0,			0x40 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_RX_1,			0x00 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_TX_1,			0x00 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_RX0,			0xf1 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_RX1,			0xf1 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_TX0,			0xf1 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_TX1,			0xf1 },
+	{ WCD937X_DIGITAL_PAD_INP_DIS_0,			0x00 },
+	{ WCD937X_DIGITAL_PAD_INP_DIS_1,			0x00 },
+	{ WCD937X_DIGITAL_DRIVE_STRENGTH_0,			0x00 },
+	{ WCD937X_DIGITAL_DRIVE_STRENGTH_1,			0x00 },
+	{ WCD937X_DIGITAL_DRIVE_STRENGTH_2,			0x00 },
+	{ WCD937X_DIGITAL_RX_DATA_EDGE_CTL,			0x1f },
+	{ WCD937X_DIGITAL_TX_DATA_EDGE_CTL,			0x10 },
+	{ WCD937X_DIGITAL_GPIO_MODE,				0x00 },
+	{ WCD937X_DIGITAL_PIN_CTL_OE,				0x00 },
+	{ WCD937X_DIGITAL_PIN_CTL_DATA_0,			0x00 },
+	{ WCD937X_DIGITAL_PIN_CTL_DATA_1,			0x00 },
+	{ WCD937X_DIGITAL_DIG_DEBUG_CTL,			0x00 },
+	{ WCD937X_DIGITAL_DIG_DEBUG_EN,				0x00 },
+	{ WCD937X_DIGITAL_ANA_CSR_DBG_ADD,			0x00 },
+	{ WCD937X_DIGITAL_ANA_CSR_DBG_CTL,			0x48 },
+	{ WCD937X_DIGITAL_SSP_DBG,				0x00 },
+	{ WCD937X_DIGITAL_SPARE_0,				0x00 },
+	{ WCD937X_DIGITAL_SPARE_1,				0x00 },
+	{ WCD937X_DIGITAL_SPARE_2,				0x00 },
+};
+
+static bool wcd937x_rdwr_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WCD937X_ANA_BIAS:
+	case WCD937X_ANA_RX_SUPPLIES:
+	case WCD937X_ANA_HPH:
+	case WCD937X_ANA_EAR:
+	case WCD937X_ANA_EAR_COMPANDER_CTL:
+	case WCD937X_ANA_TX_CH1:
+	case WCD937X_ANA_TX_CH2:
+	case WCD937X_ANA_TX_CH3:
+	case WCD937X_ANA_TX_CH3_HPF:
+	case WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC:
+	case WCD937X_ANA_MICB3_DSP_EN_LOGIC:
+	case WCD937X_ANA_MBHC_MECH:
+	case WCD937X_ANA_MBHC_ELECT:
+	case WCD937X_ANA_MBHC_ZDET:
+	case WCD937X_ANA_MBHC_BTN0:
+	case WCD937X_ANA_MBHC_BTN1:
+	case WCD937X_ANA_MBHC_BTN2:
+	case WCD937X_ANA_MBHC_BTN3:
+	case WCD937X_ANA_MBHC_BTN4:
+	case WCD937X_ANA_MBHC_BTN5:
+	case WCD937X_ANA_MBHC_BTN6:
+	case WCD937X_ANA_MBHC_BTN7:
+	case WCD937X_ANA_MICB1:
+	case WCD937X_ANA_MICB2:
+	case WCD937X_ANA_MICB2_RAMP:
+	case WCD937X_ANA_MICB3:
+	case WCD937X_BIAS_CTL:
+	case WCD937X_BIAS_VBG_FINE_ADJ:
+	case WCD937X_LDOL_VDDCX_ADJUST:
+	case WCD937X_LDOL_DISABLE_LDOL:
+	case WCD937X_MBHC_CTL_CLK:
+	case WCD937X_MBHC_CTL_ANA:
+	case WCD937X_MBHC_CTL_SPARE_1:
+	case WCD937X_MBHC_CTL_SPARE_2:
+	case WCD937X_MBHC_CTL_BCS:
+	case WCD937X_MBHC_TEST_CTL:
+	case WCD937X_LDOH_MODE:
+	case WCD937X_LDOH_BIAS:
+	case WCD937X_LDOH_STB_LOADS:
+	case WCD937X_LDOH_SLOWRAMP:
+	case WCD937X_MICB1_TEST_CTL_1:
+	case WCD937X_MICB1_TEST_CTL_2:
+	case WCD937X_MICB1_TEST_CTL_3:
+	case WCD937X_MICB2_TEST_CTL_1:
+	case WCD937X_MICB2_TEST_CTL_2:
+	case WCD937X_MICB2_TEST_CTL_3:
+	case WCD937X_MICB3_TEST_CTL_1:
+	case WCD937X_MICB3_TEST_CTL_2:
+	case WCD937X_MICB3_TEST_CTL_3:
+	case WCD937X_TX_COM_ADC_VCM:
+	case WCD937X_TX_COM_BIAS_ATEST:
+	case WCD937X_TX_COM_ADC_INT1_IB:
+	case WCD937X_TX_COM_ADC_INT2_IB:
+	case WCD937X_TX_COM_TXFE_DIV_CTL:
+	case WCD937X_TX_COM_TXFE_DIV_START:
+	case WCD937X_TX_COM_TXFE_DIV_STOP_9P6M:
+	case WCD937X_TX_COM_TXFE_DIV_STOP_12P288M:
+	case WCD937X_TX_1_2_TEST_EN:
+	case WCD937X_TX_1_2_ADC_IB:
+	case WCD937X_TX_1_2_ATEST_REFCTL:
+	case WCD937X_TX_1_2_TEST_CTL:
+	case WCD937X_TX_1_2_TEST_BLK_EN:
+	case WCD937X_TX_1_2_TXFE_CLKDIV:
+	case WCD937X_TX_3_TEST_EN:
+	case WCD937X_TX_3_ADC_IB:
+	case WCD937X_TX_3_ATEST_REFCTL:
+	case WCD937X_TX_3_TEST_CTL:
+	case WCD937X_TX_3_TEST_BLK_EN:
+	case WCD937X_TX_3_TXFE_CLKDIV:
+	case WCD937X_CLASSH_MODE_1:
+	case WCD937X_CLASSH_MODE_2:
+	case WCD937X_CLASSH_MODE_3:
+	case WCD937X_CLASSH_CTRL_VCL_1:
+	case WCD937X_CLASSH_CTRL_VCL_2:
+	case WCD937X_CLASSH_CTRL_CCL_1:
+	case WCD937X_CLASSH_CTRL_CCL_2:
+	case WCD937X_CLASSH_CTRL_CCL_3:
+	case WCD937X_CLASSH_CTRL_CCL_4:
+	case WCD937X_CLASSH_CTRL_CCL_5:
+	case WCD937X_CLASSH_BUCK_TMUX_A_D:
+	case WCD937X_CLASSH_BUCK_SW_DRV_CNTL:
+	case WCD937X_CLASSH_SPARE:
+	case WCD937X_FLYBACK_EN:
+	case WCD937X_FLYBACK_VNEG_CTRL_1:
+	case WCD937X_FLYBACK_VNEG_CTRL_2:
+	case WCD937X_FLYBACK_VNEG_CTRL_3:
+	case WCD937X_FLYBACK_VNEG_CTRL_4:
+	case WCD937X_FLYBACK_VNEG_CTRL_5:
+	case WCD937X_FLYBACK_VNEG_CTRL_6:
+	case WCD937X_FLYBACK_VNEG_CTRL_7:
+	case WCD937X_FLYBACK_VNEG_CTRL_8:
+	case WCD937X_FLYBACK_VNEG_CTRL_9:
+	case WCD937X_FLYBACK_VNEGDAC_CTRL_1:
+	case WCD937X_FLYBACK_VNEGDAC_CTRL_2:
+	case WCD937X_FLYBACK_VNEGDAC_CTRL_3:
+	case WCD937X_FLYBACK_CTRL_1:
+	case WCD937X_FLYBACK_TEST_CTL:
+	case WCD937X_RX_AUX_SW_CTL:
+	case WCD937X_RX_PA_AUX_IN_CONN:
+	case WCD937X_RX_TIMER_DIV:
+	case WCD937X_RX_OCP_CTL:
+	case WCD937X_RX_OCP_COUNT:
+	case WCD937X_RX_BIAS_EAR_DAC:
+	case WCD937X_RX_BIAS_EAR_AMP:
+	case WCD937X_RX_BIAS_HPH_LDO:
+	case WCD937X_RX_BIAS_HPH_PA:
+	case WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2:
+	case WCD937X_RX_BIAS_HPH_RDAC_LDO:
+	case WCD937X_RX_BIAS_HPH_CNP1:
+	case WCD937X_RX_BIAS_HPH_LOWPOWER:
+	case WCD937X_RX_BIAS_AUX_DAC:
+	case WCD937X_RX_BIAS_AUX_AMP:
+	case WCD937X_RX_BIAS_VNEGDAC_BLEEDER:
+	case WCD937X_RX_BIAS_MISC:
+	case WCD937X_RX_BIAS_BUCK_RST:
+	case WCD937X_RX_BIAS_BUCK_VREF_ERRAMP:
+	case WCD937X_RX_BIAS_FLYB_ERRAMP:
+	case WCD937X_RX_BIAS_FLYB_BUFF:
+	case WCD937X_RX_BIAS_FLYB_MID_RST:
+	case WCD937X_HPH_CNP_EN:
+	case WCD937X_HPH_CNP_WG_CTL:
+	case WCD937X_HPH_CNP_WG_TIME:
+	case WCD937X_HPH_OCP_CTL:
+	case WCD937X_HPH_AUTO_CHOP:
+	case WCD937X_HPH_CHOP_CTL:
+	case WCD937X_HPH_PA_CTL1:
+	case WCD937X_HPH_PA_CTL2:
+	case WCD937X_HPH_L_EN:
+	case WCD937X_HPH_L_TEST:
+	case WCD937X_HPH_L_ATEST:
+	case WCD937X_HPH_R_EN:
+	case WCD937X_HPH_R_TEST:
+	case WCD937X_HPH_R_ATEST:
+	case WCD937X_HPH_RDAC_CLK_CTL1:
+	case WCD937X_HPH_RDAC_CLK_CTL2:
+	case WCD937X_HPH_RDAC_LDO_CTL:
+	case WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL:
+	case WCD937X_HPH_REFBUFF_UHQA_CTL:
+	case WCD937X_HPH_REFBUFF_LP_CTL:
+	case WCD937X_HPH_L_DAC_CTL:
+	case WCD937X_HPH_R_DAC_CTL:
+	case WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL:
+	case WCD937X_HPH_SURGE_HPHLR_SURGE_EN:
+	case WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1:
+	case WCD937X_EAR_EAR_EN_REG:
+	case WCD937X_EAR_EAR_PA_CON:
+	case WCD937X_EAR_EAR_SP_CON:
+	case WCD937X_EAR_EAR_DAC_CON:
+	case WCD937X_EAR_EAR_CNP_FSM_CON:
+	case WCD937X_EAR_TEST_CTL:
+	case WCD937X_HPH_NEW_ANA_HPH2:
+	case WCD937X_HPH_NEW_ANA_HPH3:
+	case WCD937X_SLEEP_CTL:
+	case WCD937X_SLEEP_WATCHDOG_CTL:
+	case WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL:
+	case WCD937X_MBHC_NEW_CTL_1:
+	case WCD937X_MBHC_NEW_CTL_2:
+	case WCD937X_MBHC_NEW_PLUG_DETECT_CTL:
+	case WCD937X_MBHC_NEW_ZDET_ANA_CTL:
+	case WCD937X_MBHC_NEW_ZDET_RAMP_CTL:
+	case WCD937X_TX_NEW_TX_CH2_SEL:
+	case WCD937X_AUX_AUXPA:
+	case WCD937X_LDORXTX_MODE:
+	case WCD937X_LDORXTX_CONFIG:
+	case WCD937X_DIE_CRACK_DIE_CRK_DET_EN:
+	case WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL:
+	case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L:
+	case WCD937X_HPH_NEW_INT_RDAC_VREF_CTL:
+	case WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL:
+	case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R:
+	case WCD937X_HPH_NEW_INT_PA_MISC1:
+	case WCD937X_HPH_NEW_INT_PA_MISC2:
+	case WCD937X_HPH_NEW_INT_PA_RDAC_MISC:
+	case WCD937X_HPH_NEW_INT_HPH_TIMER1:
+	case WCD937X_HPH_NEW_INT_HPH_TIMER2:
+	case WCD937X_HPH_NEW_INT_HPH_TIMER3:
+	case WCD937X_HPH_NEW_INT_HPH_TIMER4:
+	case WCD937X_HPH_NEW_INT_PA_RDAC_MISC2:
+	case WCD937X_HPH_NEW_INT_PA_RDAC_MISC3:
+	case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI:
+	case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP:
+	case WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP:
+	case WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL:
+	case WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL:
+	case WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT:
+	case WCD937X_MBHC_NEW_INT_SPARE_2:
+	case WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON:
+	case WCD937X_EAR_INT_NEW_CNP_VCM_CON1:
+	case WCD937X_EAR_INT_NEW_CNP_VCM_CON2:
+	case WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS:
+	case WCD937X_AUX_INT_EN_REG:
+	case WCD937X_AUX_INT_PA_CTRL:
+	case WCD937X_AUX_INT_SP_CTRL:
+	case WCD937X_AUX_INT_DAC_CTRL:
+	case WCD937X_AUX_INT_CLK_CTRL:
+	case WCD937X_AUX_INT_TEST_CTRL:
+	case WCD937X_AUX_INT_MISC:
+	case WCD937X_LDORXTX_INT_BIAS:
+	case WCD937X_LDORXTX_INT_STB_LOADS_DTEST:
+	case WCD937X_LDORXTX_INT_TEST0:
+	case WCD937X_LDORXTX_INT_STARTUP_TIMER:
+	case WCD937X_LDORXTX_INT_TEST1:
+	case WCD937X_SLEEP_INT_WATCHDOG_CTL_1:
+	case WCD937X_SLEEP_INT_WATCHDOG_CTL_2:
+	case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1:
+	case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2:
+	case WCD937X_DIGITAL_CDC_RST_CTL:
+	case WCD937X_DIGITAL_TOP_CLK_CFG:
+	case WCD937X_DIGITAL_CDC_ANA_CLK_CTL:
+	case WCD937X_DIGITAL_CDC_DIG_CLK_CTL:
+	case WCD937X_DIGITAL_SWR_RST_EN:
+	case WCD937X_DIGITAL_CDC_PATH_MODE:
+	case WCD937X_DIGITAL_CDC_RX_RST:
+	case WCD937X_DIGITAL_CDC_RX0_CTL:
+	case WCD937X_DIGITAL_CDC_RX1_CTL:
+	case WCD937X_DIGITAL_CDC_RX2_CTL:
+	case WCD937X_DIGITAL_DEM_BYPASS_DATA0:
+	case WCD937X_DIGITAL_DEM_BYPASS_DATA1:
+	case WCD937X_DIGITAL_DEM_BYPASS_DATA2:
+	case WCD937X_DIGITAL_DEM_BYPASS_DATA3:
+	case WCD937X_DIGITAL_CDC_COMP_CTL_0:
+	case WCD937X_DIGITAL_CDC_RX_DELAY_CTL:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A1_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A1_1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A2_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A2_1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A3_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A3_1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A4_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A4_1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A5_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A5_1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A6_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_A7_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_C_0:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_C_1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_C_2:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_C_3:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R1:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R2:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R3:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R4:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R5:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R6:
+	case WCD937X_DIGITAL_CDC_HPH_DSM_R7:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A1_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A1_1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A2_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A2_1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A3_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A3_1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A4_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A4_1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A5_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A5_1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A6_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_A7_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_C_0:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_C_1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_C_2:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_C_3:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R1:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R2:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R3:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R4:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R5:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R6:
+	case WCD937X_DIGITAL_CDC_AUX_DSM_R7:
+	case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0:
+	case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1:
+	case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0:
+	case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1:
+	case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2:
+	case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0:
+	case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1:
+	case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2:
+	case WCD937X_DIGITAL_CDC_HPH_GAIN_CTL:
+	case WCD937X_DIGITAL_CDC_AUX_GAIN_CTL:
+	case WCD937X_DIGITAL_CDC_EAR_PATH_CTL:
+	case WCD937X_DIGITAL_CDC_SWR_CLH:
+	case WCD937X_DIGITAL_SWR_CLH_BYP:
+	case WCD937X_DIGITAL_CDC_TX0_CTL:
+	case WCD937X_DIGITAL_CDC_TX1_CTL:
+	case WCD937X_DIGITAL_CDC_TX2_CTL:
+	case WCD937X_DIGITAL_CDC_TX_RST:
+	case WCD937X_DIGITAL_CDC_REQ_CTL:
+	case WCD937X_DIGITAL_CDC_AMIC_CTL:
+	case WCD937X_DIGITAL_CDC_DMIC_CTL:
+	case WCD937X_DIGITAL_CDC_DMIC1_CTL:
+	case WCD937X_DIGITAL_CDC_DMIC2_CTL:
+	case WCD937X_DIGITAL_CDC_DMIC3_CTL:
+	case WCD937X_DIGITAL_EFUSE_CTL:
+	case WCD937X_DIGITAL_EFUSE_PRG_CTL:
+	case WCD937X_DIGITAL_EFUSE_TEST_CTL_0:
+	case WCD937X_DIGITAL_EFUSE_TEST_CTL_1:
+	case WCD937X_DIGITAL_PDM_WD_CTL0:
+	case WCD937X_DIGITAL_PDM_WD_CTL1:
+	case WCD937X_DIGITAL_PDM_WD_CTL2:
+	case WCD937X_DIGITAL_INTR_MODE:
+	case WCD937X_DIGITAL_INTR_MASK_0:
+	case WCD937X_DIGITAL_INTR_MASK_1:
+	case WCD937X_DIGITAL_INTR_MASK_2:
+	case WCD937X_DIGITAL_INTR_CLEAR_0:
+	case WCD937X_DIGITAL_INTR_CLEAR_1:
+	case WCD937X_DIGITAL_INTR_CLEAR_2:
+	case WCD937X_DIGITAL_INTR_LEVEL_0:
+	case WCD937X_DIGITAL_INTR_LEVEL_1:
+	case WCD937X_DIGITAL_INTR_LEVEL_2:
+	case WCD937X_DIGITAL_INTR_SET_0:
+	case WCD937X_DIGITAL_INTR_SET_1:
+	case WCD937X_DIGITAL_INTR_SET_2:
+	case WCD937X_DIGITAL_INTR_TEST_0:
+	case WCD937X_DIGITAL_INTR_TEST_1:
+	case WCD937X_DIGITAL_INTR_TEST_2:
+	case WCD937X_DIGITAL_CDC_CONN_RX0_CTL:
+	case WCD937X_DIGITAL_CDC_CONN_RX1_CTL:
+	case WCD937X_DIGITAL_CDC_CONN_RX2_CTL:
+	case WCD937X_DIGITAL_CDC_CONN_TX_CTL:
+	case WCD937X_DIGITAL_LOOP_BACK_MODE:
+	case WCD937X_DIGITAL_SWR_DAC_TEST:
+	case WCD937X_DIGITAL_SWR_HM_TEST_RX_0:
+	case WCD937X_DIGITAL_SWR_HM_TEST_TX_0:
+	case WCD937X_DIGITAL_SWR_HM_TEST_RX_1:
+	case WCD937X_DIGITAL_SWR_HM_TEST_TX_1:
+	case WCD937X_DIGITAL_SWR_HM_TEST:
+	case WCD937X_DIGITAL_PAD_CTL_PDM_RX0:
+	case WCD937X_DIGITAL_PAD_CTL_PDM_RX1:
+	case WCD937X_DIGITAL_PAD_CTL_PDM_TX0:
+	case WCD937X_DIGITAL_PAD_CTL_PDM_TX1:
+	case WCD937X_DIGITAL_PAD_INP_DIS_0:
+	case WCD937X_DIGITAL_PAD_INP_DIS_1:
+	case WCD937X_DIGITAL_DRIVE_STRENGTH_0:
+	case WCD937X_DIGITAL_DRIVE_STRENGTH_1:
+	case WCD937X_DIGITAL_DRIVE_STRENGTH_2:
+	case WCD937X_DIGITAL_RX_DATA_EDGE_CTL:
+	case WCD937X_DIGITAL_TX_DATA_EDGE_CTL:
+	case WCD937X_DIGITAL_GPIO_MODE:
+	case WCD937X_DIGITAL_PIN_CTL_OE:
+	case WCD937X_DIGITAL_PIN_CTL_DATA_0:
+	case WCD937X_DIGITAL_PIN_CTL_DATA_1:
+	case WCD937X_DIGITAL_PIN_STATUS_0:
+	case WCD937X_DIGITAL_PIN_STATUS_1:
+	case WCD937X_DIGITAL_DIG_DEBUG_CTL:
+	case WCD937X_DIGITAL_DIG_DEBUG_EN:
+	case WCD937X_DIGITAL_ANA_CSR_DBG_ADD:
+	case WCD937X_DIGITAL_ANA_CSR_DBG_CTL:
+	case WCD937X_DIGITAL_SSP_DBG:
+	case WCD937X_DIGITAL_MODE_STATUS_0:
+	case WCD937X_DIGITAL_MODE_STATUS_1:
+	case WCD937X_DIGITAL_SPARE_0:
+	case WCD937X_DIGITAL_SPARE_1:
+	case WCD937X_DIGITAL_SPARE_2:
+		return true;
+	}
+
+	return false;
+}
+
+static bool wcd937x_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WCD937X_ANA_MBHC_RESULT_1:
+	case WCD937X_ANA_MBHC_RESULT_2:
+	case WCD937X_ANA_MBHC_RESULT_3:
+	case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS:
+	case WCD937X_TX_1_2_SAR2_ERR:
+	case WCD937X_TX_1_2_SAR1_ERR:
+	case WCD937X_TX_3_SPARE_MONO:
+	case WCD937X_TX_3_SAR1_ERR:
+	case WCD937X_HPH_L_STATUS:
+	case WCD937X_HPH_R_STATUS:
+	case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS:
+	case WCD937X_EAR_STATUS_REG_1:
+	case WCD937X_EAR_STATUS_REG_2:
+	case WCD937X_MBHC_NEW_FSM_STATUS:
+	case WCD937X_MBHC_NEW_ADC_RESULT:
+	case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT:
+	case WCD937X_AUX_INT_STATUS_REG:
+	case WCD937X_LDORXTX_INT_STATUS:
+	case WCD937X_DIGITAL_CHIP_ID0:
+	case WCD937X_DIGITAL_CHIP_ID1:
+	case WCD937X_DIGITAL_CHIP_ID2:
+	case WCD937X_DIGITAL_CHIP_ID3:
+	case WCD937X_DIGITAL_EFUSE_T_DATA_0:
+	case WCD937X_DIGITAL_EFUSE_T_DATA_1:
+	case WCD937X_DIGITAL_INTR_STATUS_0:
+	case WCD937X_DIGITAL_INTR_STATUS_1:
+	case WCD937X_DIGITAL_INTR_STATUS_2:
+	case WCD937X_DIGITAL_EFUSE_REG_0:
+	case WCD937X_DIGITAL_EFUSE_REG_1:
+	case WCD937X_DIGITAL_EFUSE_REG_2:
+	case WCD937X_DIGITAL_EFUSE_REG_3:
+	case WCD937X_DIGITAL_EFUSE_REG_4:
+	case WCD937X_DIGITAL_EFUSE_REG_5:
+	case WCD937X_DIGITAL_EFUSE_REG_6:
+	case WCD937X_DIGITAL_EFUSE_REG_7:
+	case WCD937X_DIGITAL_EFUSE_REG_8:
+	case WCD937X_DIGITAL_EFUSE_REG_9:
+	case WCD937X_DIGITAL_EFUSE_REG_10:
+	case WCD937X_DIGITAL_EFUSE_REG_11:
+	case WCD937X_DIGITAL_EFUSE_REG_12:
+	case WCD937X_DIGITAL_EFUSE_REG_13:
+	case WCD937X_DIGITAL_EFUSE_REG_14:
+	case WCD937X_DIGITAL_EFUSE_REG_15:
+	case WCD937X_DIGITAL_EFUSE_REG_16:
+	case WCD937X_DIGITAL_EFUSE_REG_17:
+	case WCD937X_DIGITAL_EFUSE_REG_18:
+	case WCD937X_DIGITAL_EFUSE_REG_19:
+	case WCD937X_DIGITAL_EFUSE_REG_20:
+	case WCD937X_DIGITAL_EFUSE_REG_21:
+	case WCD937X_DIGITAL_EFUSE_REG_22:
+	case WCD937X_DIGITAL_EFUSE_REG_23:
+	case WCD937X_DIGITAL_EFUSE_REG_24:
+	case WCD937X_DIGITAL_EFUSE_REG_25:
+	case WCD937X_DIGITAL_EFUSE_REG_26:
+	case WCD937X_DIGITAL_EFUSE_REG_27:
+	case WCD937X_DIGITAL_EFUSE_REG_28:
+	case WCD937X_DIGITAL_EFUSE_REG_29:
+	case WCD937X_DIGITAL_EFUSE_REG_30:
+	case WCD937X_DIGITAL_EFUSE_REG_31:
+		return true;
+	}
+
+	return wcd937x_rdwr_register(dev, reg);
+}
+
+static bool wcd937x_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WCD937X_ANA_MBHC_RESULT_1:
+	case WCD937X_ANA_MBHC_RESULT_2:
+	case WCD937X_ANA_MBHC_RESULT_3:
+	case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS:
+	case WCD937X_TX_1_2_SAR1_ERR:
+	case WCD937X_TX_1_2_SAR2_ERR:
+	case WCD937X_TX_3_SAR1_ERR:
+	case WCD937X_HPH_L_STATUS:
+	case WCD937X_HPH_R_STATUS:
+	case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS:
+	case WCD937X_EAR_STATUS_REG_1:
+	case WCD937X_EAR_STATUS_REG_2:
+	case WCD937X_MBHC_NEW_FSM_STATUS:
+	case WCD937X_MBHC_NEW_ADC_RESULT:
+	case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT:
+	case WCD937X_DIGITAL_INTR_STATUS_0:
+	case WCD937X_DIGITAL_INTR_STATUS_1:
+	case WCD937X_DIGITAL_INTR_STATUS_2:
+	case WCD937X_DIGITAL_SWR_HM_TEST:
+	case WCD937X_DIGITAL_PIN_STATUS_0:
+	case WCD937X_DIGITAL_PIN_STATUS_1:
+	case WCD937X_DIGITAL_MODE_STATUS_0:
+	case WCD937X_DIGITAL_MODE_STATUS_1:
+		return true;
+	}
+	return false;
+}
+
+static const struct regmap_config wcd937x_regmap_config = {
+	.name = "wcd937x_csr",
+	.reg_bits = 32,
+	.val_bits = 8,
+	.cache_type = REGCACHE_MAPLE,
+	.reg_defaults = wcd937x_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wcd937x_defaults),
+	.max_register = WCD937X_MAX_REGISTER,
+	.readable_reg = wcd937x_readable_register,
+	.writeable_reg = wcd937x_rdwr_register,
+	.volatile_reg = wcd937x_volatile_register,
+};
+
+static const struct sdw_slave_ops wcd9370_slave_ops = {
+	.update_status = wcd9370_update_status,
+	.interrupt_callback = wcd9370_interrupt_callback,
+};
+
+static int wcd937x_sdw_component_bind(struct device *dev,
+				      struct device *master, void *data)
+{
+	pm_runtime_set_autosuspend_delay(dev, 3000);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void wcd937x_sdw_component_unbind(struct device *dev,
+					 struct device *master, void *data)
+{
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_dont_use_autosuspend(dev);
+}
+
+static const struct component_ops wcd937x_sdw_component_ops = {
+	.bind = wcd937x_sdw_component_bind,
+	.unbind = wcd937x_sdw_component_unbind,
+};
+
+static int wcd9370_probe(struct sdw_slave *pdev,
+			 const struct sdw_device_id *id)
+{
+	struct device *dev = &pdev->dev;
+	struct wcd937x_sdw_priv *wcd;
+	int ret;
+
+	wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+	if (!wcd)
+		return -ENOMEM;
+
+	/* Port map index starts at 0, however the data port for this codec start at index 1 */
+	if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) {
+		wcd->is_tx = true;
+		ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping",
+						 &pdev->m_port_map[1],
+						 WCD937X_MAX_TX_SWR_PORTS);
+	} else {
+		ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping",
+						 &pdev->m_port_map[1],
+						 WCD937X_MAX_SWR_PORTS);
+	}
+	if (ret < 0)
+		dev_info(dev, "Error getting static port mapping for %s (%d)\n",
+			 wcd->is_tx ? "TX" : "RX", ret);
+
+	wcd->sdev = pdev;
+	dev_set_drvdata(dev, wcd);
+
+	pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
+				   SDW_SCP_INT1_BUS_CLASH |
+				   SDW_SCP_INT1_PARITY;
+	pdev->prop.lane_control_support = true;
+	pdev->prop.simple_clk_stop_capable = true;
+	if (wcd->is_tx) {
+		pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS, 0);
+		pdev->prop.src_dpn_prop = wcd937x_dpn_prop;
+		wcd->ch_info = &wcd937x_sdw_tx_ch_info[0];
+		pdev->prop.wake_capable = true;
+
+		wcd->regmap = devm_regmap_init_sdw(pdev, &wcd937x_regmap_config);
+		if (IS_ERR(wcd->regmap))
+			return dev_err_probe(dev, PTR_ERR(wcd->regmap),
+					     "Regmap init failed\n");
+
+		/* Start in cache-only until device is enumerated */
+		regcache_cache_only(wcd->regmap, true);
+	} else {
+		pdev->prop.sink_ports = GENMASK(WCD937X_MAX_SWR_PORTS, 0);
+		pdev->prop.sink_dpn_prop = wcd937x_dpn_prop;
+		wcd->ch_info = &wcd937x_sdw_rx_ch_info[0];
+	}
+
+
+	ret = component_add(dev, &wcd937x_sdw_component_ops);
+	if (ret)
+		return ret;
+
+	/* Set suspended until aggregate device is bind */
+	pm_runtime_set_suspended(dev);
+
+	return 0;
+}
+
+static int wcd9370_remove(struct sdw_slave *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	component_del(dev, &wcd937x_sdw_component_ops);
+
+	return 0;
+}
+
+static const struct sdw_device_id wcd9370_slave_id[] = {
+	SDW_SLAVE_ENTRY(0x0217, 0x10a, 0), /* WCD9370 RX/TX Device ID */
+	{ },
+};
+MODULE_DEVICE_TABLE(sdw, wcd9370_slave_id);
+
+static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev)
+{
+	struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+	if (wcd->regmap) {
+		regcache_cache_only(wcd->regmap, true);
+		regcache_mark_dirty(wcd->regmap);
+	}
+
+	return 0;
+}
+
+static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev)
+{
+	struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+	if (wcd->regmap) {
+		regcache_cache_only(wcd->regmap, false);
+		regcache_sync(wcd->regmap);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops wcd937x_sdw_pm_ops = {
+	SET_RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL)
+};
+
+static struct sdw_driver wcd9370_codec_driver = {
+	.probe = wcd9370_probe,
+	.remove = wcd9370_remove,
+	.ops = &wcd9370_slave_ops,
+	.id_table = wcd9370_slave_id,
+	.driver = {
+		.name = "wcd9370-codec",
+		.pm = &wcd937x_sdw_pm_ops,
+	}
+};
+module_sdw_driver(wcd9370_codec_driver);
+
+MODULE_DESCRIPTION("WCD937X SDW codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
new file mode 100644
index 0000000000000000000000000000000000000000..13926f4b0d9f16bb98c23a83908b9d9fc1c1d149
--- /dev/null
+++ b/sound/soc/codecs/wcd937x.c
@@ -0,0 +1,2971 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "wcd-clsh-v2.h"
+#include "wcd-mbhc-v2.h"
+#include "wcd937x.h"
+
+enum {
+	CHIPID_WCD9370 = 0,
+	CHIPID_WCD9375 = 5,
+};
+
+/* Z value defined in milliohm */
+#define WCD937X_ZDET_VAL_32		(32000)
+#define WCD937X_ZDET_VAL_400		(400000)
+#define WCD937X_ZDET_VAL_1200		(1200000)
+#define WCD937X_ZDET_VAL_100K		(100000000)
+/* Z floating defined in ohms */
+#define WCD937X_ZDET_FLOATING_IMPEDANCE	(0x0FFFFFFE)
+#define WCD937X_ZDET_NUM_MEASUREMENTS	(900)
+#define WCD937X_MBHC_GET_C1(c)		(((c) & 0xC000) >> 14)
+#define WCD937X_MBHC_GET_X1(x)		((x) & 0x3FFF)
+/* Z value compared in milliOhm */
+#define WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z)	(((z) > 400000) || ((z) < 32000))
+#define WCD937X_MBHC_ZDET_CONST		(86 * 16384)
+#define WCD937X_MBHC_MOISTURE_RREF	R_24_KOHM
+#define WCD_MBHC_HS_V_MAX		1600
+#define EAR_RX_PATH_AUX			1
+#define WCD937X_MBHC_MAX_BUTTONS	8
+
+#define WCD937X_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 |\
+		       SNDRV_PCM_RATE_384000)
+
+/* Fractional Rates */
+#define WCD937X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+			    SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define WCD937X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+enum {
+	ALLOW_BUCK_DISABLE,
+	HPH_COMP_DELAY,
+	HPH_PA_DELAY,
+	AMIC2_BCS_ENABLE,
+};
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	NUM_CODEC_DAIS,
+};
+
+struct wcd937x_priv {
+	struct sdw_slave *tx_sdw_dev;
+	struct wcd937x_sdw_priv *sdw_priv[NUM_CODEC_DAIS];
+	struct device *txdev;
+	struct device *rxdev;
+	struct device_node *rxnode;
+	struct device_node *txnode;
+	struct regmap *regmap;
+	/* micb setup lock */
+	struct mutex micb_lock;
+	/* mbhc module */
+	struct wcd_mbhc *wcd_mbhc;
+	struct wcd_mbhc_config mbhc_cfg;
+	struct wcd_mbhc_intr intr_ids;
+	struct wcd_clsh_ctrl *clsh_info;
+	struct irq_domain *virq;
+	struct regmap_irq_chip *wcd_regmap_irq_chip;
+	struct regmap_irq_chip_data *irq_chip;
+	struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY];
+	struct regulator *buck_supply;
+	struct snd_soc_jack *jack;
+	unsigned long status_mask;
+	s32 micb_ref[WCD937X_MAX_MICBIAS];
+	s32 pullup_ref[WCD937X_MAX_MICBIAS];
+	u32 hph_mode;
+	int ear_rx_path;
+	u32 micb1_mv;
+	u32 micb2_mv;
+	u32 micb3_mv;
+	int hphr_pdm_wd_int;
+	int hphl_pdm_wd_int;
+	int aux_pdm_wd_int;
+	bool comp1_enable;
+	bool comp2_enable;
+
+	struct gpio_desc *us_euro_gpio;
+	struct gpio_desc *reset_gpio;
+
+	atomic_t rx_clk_cnt;
+	atomic_t ana_clk_count;
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+struct wcd937x_mbhc_zdet_param {
+	u16 ldo_ctl;
+	u16 noff;
+	u16 nshift;
+	u16 btn5;
+	u16 btn6;
+	u16 btn7;
+};
+
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+	WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD937X_ANA_MBHC_MECH, 0x80),
+	WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD937X_ANA_MBHC_MECH, 0x40),
+	WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD937X_ANA_MBHC_MECH, 0x20),
+	WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x30),
+	WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD937X_ANA_MBHC_ELECT, 0x08),
+	WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F),
+	WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD937X_ANA_MBHC_MECH, 0x04),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x10),
+	WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x08),
+	WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD937X_ANA_MBHC_MECH, 0x01),
+	WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD937X_ANA_MBHC_ELECT, 0x06),
+	WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD937X_ANA_MBHC_ELECT, 0x80),
+	WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F),
+	WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD937X_MBHC_NEW_CTL_1, 0x03),
+	WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD937X_MBHC_NEW_CTL_2, 0x03),
+	WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x08),
+	WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD937X_ANA_MBHC_RESULT_3, 0x10),
+	WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x20),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x80),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x40),
+	WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD937X_HPH_OCP_CTL, 0x10),
+	WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x07),
+	WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD937X_ANA_MBHC_ELECT, 0x70),
+	WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0xFF),
+	WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD937X_ANA_MICB2, 0xC0),
+	WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD937X_HPH_CNP_WG_TIME, 0xFF),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD937X_ANA_HPH, 0x40),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD937X_ANA_HPH, 0x80),
+	WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD937X_ANA_HPH, 0xC0),
+	WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD937X_ANA_MBHC_RESULT_3, 0x10),
+	WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD937X_MBHC_CTL_BCS, 0x02),
+	WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x01),
+	WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD937X_MBHC_NEW_CTL_2, 0x70),
+	WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x20),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD937X_HPH_PA_CTL2, 0x40),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD937X_HPH_PA_CTL2, 0x10),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD937X_HPH_L_TEST, 0x01),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD937X_HPH_R_TEST, 0x01),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x80),
+	WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x20),
+	WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD937X_MBHC_NEW_CTL_1, 0x08),
+	WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD937X_MBHC_NEW_FSM_STATUS, 0x40),
+	WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD937X_MBHC_NEW_FSM_STATUS, 0x80),
+	WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD937X_MBHC_NEW_ADC_RESULT, 0xFF),
+	WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD937X_ANA_MICB2, 0x3F),
+	WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD937X_MBHC_NEW_CTL_1, 0x10),
+	WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD937X_MBHC_NEW_CTL_1, 0x04),
+	WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD937X_ANA_MBHC_ZDET, 0x02),
+};
+
+static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = {
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, BIT(0)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, BIT(1)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, 0, BIT(2)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, BIT(3)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_SW_DET, 0, BIT(4)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_OCP_INT, 0, BIT(5)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_CNP_INT, 0, BIT(6)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_OCP_INT, 0, BIT(7)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_CNP_INT, 1, BIT(0)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_EAR_CNP_INT, 1, BIT(1)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_EAR_SCD_INT, 1, BIT(2)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_AUX_CNP_INT, 1, BIT(3)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_AUX_SCD_INT, 1, BIT(4)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_PDM_WD_INT, 1, BIT(5)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_PDM_WD_INT, 1, BIT(6)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_AUX_PDM_WD_INT, 1, BIT(7)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_LDORT_SCD_INT, 2, BIT(0)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_MOISTURE_INT, 2, BIT(1)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_SURGE_DET_INT, 2, BIT(2)),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_SURGE_DET_INT, 2, BIT(3)),
+};
+
+static int wcd937x_handle_post_irq(void *data)
+{
+	struct wcd937x_priv *wcd937x;
+
+	if (data)
+		wcd937x = (struct wcd937x_priv *)data;
+	else
+		return IRQ_HANDLED;
+
+	regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_0, 0);
+	regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_1, 0);
+	regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_2, 0);
+
+	return IRQ_HANDLED;
+}
+
+static const u32 wcd937x_config_regs[] = {
+	WCD937X_DIGITAL_INTR_LEVEL_0,
+};
+
+static const struct regmap_irq_chip wcd937x_regmap_irq_chip = {
+	.name = "wcd937x",
+	.irqs = wcd937x_irqs,
+	.num_irqs = ARRAY_SIZE(wcd937x_irqs),
+	.num_regs = 3,
+	.status_base = WCD937X_DIGITAL_INTR_STATUS_0,
+	.mask_base = WCD937X_DIGITAL_INTR_MASK_0,
+	.ack_base = WCD937X_DIGITAL_INTR_CLEAR_0,
+	.use_ack = 1,
+	.clear_ack = 1,
+	.config_base = wcd937x_config_regs,
+	.num_config_bases = ARRAY_SIZE(wcd937x_config_regs),
+	.num_config_regs = 1,
+	.runtime_pm = true,
+	.handle_post_irq = wcd937x_handle_post_irq,
+	.irq_drv_data = NULL,
+};
+
+static void wcd937x_reset(struct wcd937x_priv *wcd937x)
+{
+	usleep_range(20, 30);
+
+	gpiod_set_value(wcd937x->reset_gpio, 1);
+
+	usleep_range(20, 30);
+}
+
+static void wcd937x_io_init(struct regmap *regmap)
+{
+	u32 val = 0, temp = 0, temp1 = 0;
+
+	regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_29, &val);
+
+	val = val & 0x0F;
+
+	regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &temp);
+	regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_17, &temp1);
+
+	if (temp == 0x02 || temp1 > 0x09)
+		regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0E, val);
+	else
+		regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0e, 0x0e);
+
+	regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x80, 0x80);
+	usleep_range(1000, 1010);
+
+	regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x40, 0x40);
+	usleep_range(1000, 1010);
+
+	regmap_update_bits(regmap, WCD937X_LDORXTX_CONFIG, BIT(4), 0x00);
+	regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xf0, BIT(7));
+	regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(7), BIT(7));
+	regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), BIT(6));
+	usleep_range(10000, 10010);
+
+	regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), 0x00);
+	regmap_update_bits(regmap, WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xff, 0xd9);
+	regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_1, 0xff, 0xfa);
+	regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_1, 0xff, 0xfa);
+	regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_1, 0xff, 0xfa);
+
+	regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_2, 0x38, 0x00);
+	regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_2, 0x38, 0x00);
+	regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_2, 0x38, 0x00);
+
+	/* Set Bandgap Fine Adjustment to +5mV for Tanggu SMIC part */
+	regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &val);
+	if (val == 0x01) {
+		regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+	} else if (val == 0x02) {
+		regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x1F, 0x04);
+		regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x1F, 0x04);
+		regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+		regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xF0, 0x50);
+	}
+}
+
+static int wcd937x_rx_clk_enable(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	if (atomic_read(&wcd937x->rx_clk_cnt))
+		return 0;
+
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(3), BIT(3));
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), BIT(0));
+	snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), BIT(0));
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX0_CTL, BIT(6), 0x00);
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX1_CTL, BIT(6), 0x00);
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX2_CTL, BIT(6), 0x00);
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), BIT(1));
+
+	atomic_inc(&wcd937x->rx_clk_cnt);
+
+	return 0;
+}
+
+static int wcd937x_rx_clk_disable(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	if (!atomic_read(&wcd937x->rx_clk_cnt)) {
+		dev_err(component->dev, "clk already disabled\n");
+		return 0;
+	}
+
+	atomic_dec(&wcd937x->rx_clk_cnt);
+
+	snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), 0x00);
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), 0x00);
+	snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), 0x00);
+
+	return 0;
+}
+
+static int wcd937x_codec_hphl_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(0), BIT(0));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+					      BIT(2), BIT(2));
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_RDAC_CLK_CTL1,
+					      BIT(7), 0x00);
+		set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+						      0x0f, BIT(1));
+		else if (hph_mode == CLS_H_LOHIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+						      0x0f, 0x06);
+
+		if (wcd937x->comp1_enable) {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+						      BIT(1), BIT(1));
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_L_EN,
+						      BIT(5), 0x00);
+
+			if (wcd937x->comp2_enable) {
+				snd_soc_component_update_bits(component,
+							      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+							      BIT(0), BIT(0));
+				snd_soc_component_update_bits(component,
+							      WCD937X_HPH_R_EN, BIT(5), 0x00);
+			}
+
+			if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+				usleep_range(5000, 5110);
+				clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+			}
+		} else {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+						      BIT(1), 0x00);
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_L_EN,
+						      BIT(5), BIT(5));
+		}
+
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_NEW_INT_HPH_TIMER1,
+					      BIT(1), 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+					      0x0f, BIT(0));
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_hphr_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(1), BIT(1));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, BIT(3), BIT(3));
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_RDAC_CLK_CTL1, BIT(7), 0x00);
+		set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+						      0x0f, BIT(1));
+		else if (hph_mode == CLS_H_LOHIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+						      0x0f, 0x06);
+		if (wcd937x->comp2_enable) {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+						      BIT(0), BIT(0));
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_R_EN, BIT(5), 0x00);
+			if (wcd937x->comp1_enable) {
+				snd_soc_component_update_bits(component,
+							      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+							      BIT(1), BIT(1));
+				snd_soc_component_update_bits(component,
+							      WCD937X_HPH_L_EN,
+							      BIT(5), 0x00);
+			}
+
+			if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+				usleep_range(5000, 5110);
+				clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+			}
+		} else {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+						      BIT(0), 0x00);
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_R_EN,
+						      BIT(5), BIT(5));
+		}
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_NEW_INT_HPH_TIMER1,
+					      BIT(1), 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+					      0x0f, BIT(0));
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_ear_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+					      BIT(2), BIT(2));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(0), BIT(0));
+
+		if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+						      0x0f, BIT(1));
+		else if (hph_mode == CLS_H_LOHIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+						      0x0f, 0x06);
+		if (wcd937x->comp1_enable)
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+						      BIT(1), BIT(1));
+		usleep_range(5000, 5010);
+
+		snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, BIT(2), 0x00);
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_EAR,
+					hph_mode);
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_LOHIFI ||
+		    hph_mode == CLS_H_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+						      0x0f, BIT(0));
+		if (wcd937x->comp1_enable)
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_COMP_CTL_0,
+						      BIT(1), 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_aux_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+					      BIT(2), BIT(2));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(2), BIT(2));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,
+					      BIT(0), BIT(0));
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_AUX,
+					hph_mode);
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+					      BIT(2), 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_hphr_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_HPHR,
+					hph_mode);
+		snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+					      BIT(4), BIT(4));
+		usleep_range(100, 110);
+		set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_PDM_WD_CTL1,
+					      0x07, 0x03);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+			if (wcd937x->comp2_enable)
+				usleep_range(7000, 7100);
+			else
+				usleep_range(20000, 20100);
+			clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		}
+
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_NEW_INT_HPH_TIMER1,
+					      BIT(1), BIT(1));
+		if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_ANA_RX_SUPPLIES,
+						      BIT(1), BIT(1));
+		enable_irq(wcd937x->hphr_pdm_wd_int);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+		set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHR_PA_OFF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+			if (wcd937x->comp2_enable)
+				usleep_range(7000, 7100);
+			else
+				usleep_range(20000, 20100);
+			clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		}
+
+		wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHR_PA_OFF);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00);
+		snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+					      BIT(4), 0x00);
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_POST_PA,
+					WCD_CLSH_STATE_HPHR,
+					hph_mode);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_hphl_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_HPHL,
+					hph_mode);
+		snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+					      BIT(5), BIT(5));
+		usleep_range(100, 110);
+		set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+			if (!wcd937x->comp1_enable)
+				usleep_range(20000, 20100);
+			else
+				usleep_range(7000, 7100);
+			clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		}
+
+		snd_soc_component_update_bits(component,
+					      WCD937X_HPH_NEW_INT_HPH_TIMER1,
+					      BIT(1), BIT(1));
+		if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_ANA_RX_SUPPLIES,
+						      BIT(1), BIT(1));
+		enable_irq(wcd937x->hphl_pdm_wd_int);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+		set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+			if (!wcd937x->comp1_enable)
+				usleep_range(20000, 20100);
+			else
+				usleep_range(7000, 7100);
+			clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+		}
+
+		wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHL_PA_OFF);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00);
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_HPH, BIT(5), 0x00);
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_POST_PA,
+					WCD_CLSH_STATE_HPHL,
+					hph_mode);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_aux_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_PDM_WD_CTL2,
+					      BIT(0), BIT(0));
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1010);
+		if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_ANA_RX_SUPPLIES,
+						      BIT(1), BIT(1));
+		enable_irq(wcd937x->aux_pdm_wd_int);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(2000, 2010);
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_POST_PA,
+					WCD_CLSH_STATE_AUX,
+					hph_mode);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_PDM_WD_CTL2,
+					      BIT(0), 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_ear_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int hph_mode = wcd937x->hph_mode;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable watchdog interrupt for HPHL or AUX depending on mux value */
+		wcd937x->ear_rx_path = snd_soc_component_read(component,
+							      WCD937X_DIGITAL_CDC_EAR_PATH_CTL);
+
+		if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_PDM_WD_CTL2,
+						      BIT(0), BIT(0));
+		else
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_PDM_WD_CTL0,
+						      0x07, 0x03);
+		if (!wcd937x->comp1_enable)
+			snd_soc_component_update_bits(component,
+						      WCD937X_ANA_EAR_COMPANDER_CTL,
+						      BIT(7), BIT(7));
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(6000, 6010);
+		if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+			snd_soc_component_update_bits(component,
+						      WCD937X_ANA_RX_SUPPLIES,
+						      BIT(1), BIT(1));
+
+		if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+			enable_irq(wcd937x->aux_pdm_wd_int);
+		else
+			enable_irq(wcd937x->hphl_pdm_wd_int);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+			disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+		else
+			disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (!wcd937x->comp1_enable)
+			snd_soc_component_update_bits(component,
+						      WCD937X_ANA_EAR_COMPANDER_CTL,
+						      BIT(7), 0x00);
+		usleep_range(7000, 7010);
+		wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+					WCD_CLSH_EVENT_POST_PA,
+					WCD_CLSH_STATE_EAR,
+					hph_mode);
+		snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN,
+					      BIT(2), BIT(2));
+
+		if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_PDM_WD_CTL2,
+						      BIT(0), 0x00);
+		else
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_PDM_WD_CTL0,
+						      0x07, 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_enable_rx1(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol,
+			      int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	if (event == SND_SOC_DAPM_POST_PMD) {
+		wcd937x_rx_clk_disable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(0), 0x00);
+	}
+
+	return 0;
+}
+
+static int wcd937x_enable_rx2(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	if (event == SND_SOC_DAPM_POST_PMD) {
+		wcd937x_rx_clk_disable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(1), 0x00);
+	}
+
+	return 0;
+}
+
+static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol,
+			      int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	if (event == SND_SOC_DAPM_POST_PMD) {
+		usleep_range(6000, 6010);
+		wcd937x_rx_clk_disable(component);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(2), 0x00);
+	}
+
+	return 0;
+}
+
+static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv)
+{
+	if (micb_mv < 1000 || micb_mv > 2850) {
+		pr_err("Unsupported micbias voltage (%u mV)\n", micb_mv);
+		return -EINVAL;
+	}
+
+	return (micb_mv - 1000) / 50;
+}
+
+static int wcd937x_tx_swr_ctrl(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	bool use_amic3 = snd_soc_component_read(component, WCD937X_TX_NEW_TX_CH2_SEL) & BIT(7);
+
+	/* Enable BCS for Headset mic */
+	if (event == SND_SOC_DAPM_PRE_PMU && strnstr(w->name, "ADC", sizeof("ADC")))
+		if (w->shift == 1 && !use_amic3)
+			set_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_adc(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		atomic_inc(&wcd937x->ana_clk_count);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(7), BIT(7));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), BIT(3));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(4), BIT(4));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (w->shift == 1 && test_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask))
+			clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_enable_req(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_REQ_CTL, BIT(1), BIT(1));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_REQ_CTL, BIT(0), 0x00);
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH2, BIT(6), BIT(6));
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH3_HPF, BIT(6), BIT(6));
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70);
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH1, BIT(7), BIT(7));
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH2, BIT(6), 0x00);
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH2, BIT(7), BIT(7));
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH3, BIT(7), BIT(7));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH1, BIT(7), 0x00);
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH2, BIT(7), 0x00);
+		snd_soc_component_update_bits(component,
+					      WCD937X_ANA_TX_CH3, BIT(7), 0x00);
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(4), 0x00);
+
+		atomic_dec(&wcd937x->ana_clk_count);
+		if (atomic_read(&wcd937x->ana_clk_count) <= 0) {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+						      BIT(4), 0x00);
+			atomic_set(&wcd937x->ana_clk_count, 0);
+		}
+
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(7), 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_dmic(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 dmic_clk_reg;
+
+	switch (w->shift) {
+	case 0:
+	case 1:
+		dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC1_CTL;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC2_CTL;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC3_CTL;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DMIC Selection\n");
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+					      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+					      BIT(7), BIT(7));
+		snd_soc_component_update_bits(component,
+					      dmic_clk_reg, 0x07, BIT(1));
+		snd_soc_component_update_bits(component,
+					      dmic_clk_reg, BIT(3), BIT(3));
+		snd_soc_component_update_bits(component,
+					      dmic_clk_reg, 0x70, BIT(5));
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_micbias_control(struct snd_soc_component *component,
+				   int micb_num, int req, bool is_dapm)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int micb_index = micb_num - 1;
+	u16 micb_reg;
+
+	if (micb_index < 0 || (micb_index > WCD937X_MAX_MICBIAS - 1)) {
+		dev_err(component->dev, "Invalid micbias index, micb_ind:%d\n", micb_index);
+		return -EINVAL;
+	}
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD937X_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD937X_ANA_MICB2;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD937X_ANA_MICB3;
+		break;
+	default:
+		dev_err(component->dev, "Invalid micbias number: %d\n", micb_num);
+		return -EINVAL;
+	}
+
+	mutex_lock(&wcd937x->micb_lock);
+	switch (req) {
+	case MICB_PULLUP_ENABLE:
+		wcd937x->pullup_ref[micb_index]++;
+		if (wcd937x->pullup_ref[micb_index] == 1 &&
+		    wcd937x->micb_ref[micb_index] == 0)
+			snd_soc_component_update_bits(component, micb_reg,
+						      0xc0, BIT(7));
+		break;
+	case MICB_PULLUP_DISABLE:
+		if (wcd937x->pullup_ref[micb_index] > 0)
+			wcd937x->pullup_ref[micb_index]++;
+		if (wcd937x->pullup_ref[micb_index] == 0 &&
+		    wcd937x->micb_ref[micb_index] == 0)
+			snd_soc_component_update_bits(component, micb_reg,
+						      0xc0, 0x00);
+		break;
+	case MICB_ENABLE:
+		wcd937x->micb_ref[micb_index]++;
+		atomic_inc(&wcd937x->ana_clk_count);
+		if (wcd937x->micb_ref[micb_index] == 1) {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+						      0xf0, 0xf0);
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+						      BIT(4), BIT(4));
+			snd_soc_component_update_bits(component,
+						      WCD937X_MICB1_TEST_CTL_2,
+						      BIT(0), BIT(0));
+			snd_soc_component_update_bits(component,
+						      WCD937X_MICB2_TEST_CTL_2,
+						      BIT(0), BIT(0));
+			snd_soc_component_update_bits(component,
+						      WCD937X_MICB3_TEST_CTL_2,
+						      BIT(0), BIT(0));
+			snd_soc_component_update_bits(component,
+						      micb_reg, 0xc0, BIT(6));
+
+			if (micb_num == MIC_BIAS_2)
+				wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+						      WCD_EVENT_POST_MICBIAS_2_ON);
+
+			if (micb_num == MIC_BIAS_2 && is_dapm)
+				wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+						      WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
+		}
+		break;
+	case MICB_DISABLE:
+		atomic_dec(&wcd937x->ana_clk_count);
+		if (wcd937x->micb_ref[micb_index] > 0)
+			wcd937x->micb_ref[micb_index]--;
+		if (wcd937x->micb_ref[micb_index] == 0 &&
+		    wcd937x->pullup_ref[micb_index] > 0)
+			snd_soc_component_update_bits(component, micb_reg,
+						      0xc0, BIT(7));
+		else if (wcd937x->micb_ref[micb_index] == 0 &&
+			 wcd937x->pullup_ref[micb_index] == 0) {
+			if (micb_num == MIC_BIAS_2)
+				wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+						      WCD_EVENT_PRE_MICBIAS_2_OFF);
+
+			snd_soc_component_update_bits(component, micb_reg,
+						      0xc0, 0x00);
+			if (micb_num == MIC_BIAS_2)
+				wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+						      WCD_EVENT_POST_MICBIAS_2_OFF);
+		}
+
+		if (is_dapm && micb_num == MIC_BIAS_2)
+			wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+					      WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
+		if (atomic_read(&wcd937x->ana_clk_count) <= 0) {
+			snd_soc_component_update_bits(component,
+						      WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+						      BIT(4), 0x00);
+			atomic_set(&wcd937x->ana_clk_count, 0);
+		}
+		break;
+	}
+	mutex_unlock(&wcd937x->micb_lock);
+
+	return 0;
+}
+
+static int __wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int micb_num = w->shift;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_micbias_control(component, micb_num,
+					MICB_ENABLE, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_micbias_control(component, micb_num,
+					MICB_DISABLE, true);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	return __wcd937x_codec_enable_micbias(w, event);
+}
+
+static int __wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+						 int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int micb_num = w->shift;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_micbias_control(component, micb_num, MICB_PULLUP_ENABLE, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_micbias_control(component, micb_num, MICB_PULLUP_DISABLE, true);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+					       struct snd_kcontrol *kcontrol,
+					       int event)
+{
+	return __wcd937x_codec_enable_micbias_pullup(w, event);
+}
+
+static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch_id, bool enable)
+{
+	struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1];
+	const struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id];
+	u8 port_num = ch_info->port_num;
+	u8 ch_mask = ch_info->ch_mask;
+
+	port_config->num = port_num;
+
+	if (enable)
+		port_config->ch_mask |= ch_mask;
+	else
+		port_config->ch_mask &= ~ch_mask;
+
+	return 0;
+}
+
+static int wcd937x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wcd937x->hph_mode;
+	return 0;
+}
+
+static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	u32 mode_val;
+
+	mode_val = ucontrol->value.enumerated.item[0];
+
+	if (!mode_val)
+		mode_val = CLS_AB;
+
+	if (mode_val == wcd937x->hph_mode)
+		return 0;
+
+	switch (mode_val) {
+	case CLS_H_NORMAL:
+	case CLS_H_HIFI:
+	case CLS_H_LP:
+	case CLS_AB:
+	case CLS_H_LOHIFI:
+	case CLS_H_ULP:
+	case CLS_AB_LP:
+	case CLS_AB_HIFI:
+		wcd937x->hph_mode = mode_val;
+		return 1;
+	}
+
+	dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__);
+	return -EINVAL;
+}
+
+static int wcd937x_get_compander(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc;
+	bool hphr;
+
+	mc = (struct soc_mixer_control *)(kcontrol->private_value);
+	hphr = mc->shift;
+
+	ucontrol->value.integer.value[0] = hphr ? wcd937x->comp2_enable :
+						  wcd937x->comp1_enable;
+	return 0;
+}
+
+static int wcd937x_set_compander(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[AIF1_PB];
+	int value = ucontrol->value.integer.value[0];
+	struct soc_mixer_control *mc;
+	int portidx;
+	bool hphr;
+
+	mc = (struct soc_mixer_control *)(kcontrol->private_value);
+	hphr = mc->shift;
+
+	if (hphr) {
+		if (value == wcd937x->comp2_enable)
+			return 0;
+
+		wcd937x->comp2_enable = value;
+	} else {
+		if (value == wcd937x->comp1_enable)
+			return 0;
+
+		wcd937x->comp1_enable = value;
+	}
+
+	portidx = wcd->ch_info[mc->reg].port_num;
+
+	if (value)
+		wcd937x_connect_port(wcd, portidx, mc->reg, true);
+	else
+		wcd937x_connect_port(wcd, portidx, mc->reg, false);
+
+	return 1;
+}
+
+static int wcd937x_get_swr_port(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp);
+	struct wcd937x_sdw_priv *wcd;
+	int dai_id = mixer->shift;
+	int ch_idx = mixer->reg;
+	int portidx;
+
+	wcd = wcd937x->sdw_priv[dai_id];
+	portidx = wcd->ch_info[ch_idx].port_num;
+
+	ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
+
+	return 0;
+}
+
+static int wcd937x_set_swr_port(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp);
+	struct wcd937x_sdw_priv *wcd;
+	int dai_id = mixer->shift;
+	int ch_idx = mixer->reg;
+	int portidx;
+	bool enable;
+
+	wcd = wcd937x->sdw_priv[dai_id];
+
+	portidx = wcd->ch_info[ch_idx].port_num;
+
+	enable = ucontrol->value.integer.value[0];
+
+	if (enable == wcd->port_enable[portidx]) {
+		wcd937x_connect_port(wcd, portidx, ch_idx, enable);
+		return 0;
+	}
+
+	wcd->port_enable[portidx] = enable;
+	wcd937x_connect_port(wcd, portidx, ch_idx, enable);
+
+	return 1;
+}
+
+static const char * const rx_hph_mode_mux_text[] = {
+	"CLS_H_NORMAL", "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB",
+	"CLS_H_LOHIFI", "CLS_H_ULP", "CLS_AB_LP", "CLS_AB_HIFI",
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text);
+
+/* MBHC related */
+static void wcd937x_mbhc_clk_setup(struct snd_soc_component *component,
+				   bool enable)
+{
+	snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_1,
+				      WCD937X_MBHC_CTL_RCO_EN_MASK, enable);
+}
+
+static void wcd937x_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+					   bool enable)
+{
+	snd_soc_component_write_field(component, WCD937X_ANA_MBHC_ELECT,
+				      WCD937X_ANA_MBHC_BIAS_EN, enable);
+}
+
+static void wcd937x_mbhc_program_btn_thr(struct snd_soc_component *component,
+					 int *btn_low, int *btn_high,
+					 int num_btn, bool is_micbias)
+{
+	int i, vth;
+
+	if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+		dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+			__func__, num_btn);
+		return;
+	}
+
+	for (i = 0; i < num_btn; i++) {
+		vth = ((btn_high[i] * 2) / 25) & 0x3F;
+		snd_soc_component_write_field(component, WCD937X_ANA_MBHC_BTN0 + i,
+					      WCD937X_MBHC_BTN_VTH_MASK, vth);
+	}
+}
+
+static bool wcd937x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
+{
+	u8 val;
+
+	if (micb_num == MIC_BIAS_2) {
+		val = snd_soc_component_read_field(component,
+						   WCD937X_ANA_MICB2,
+						   WCD937X_ANA_MICB2_ENABLE_MASK);
+		if (val == WCD937X_MICB_ENABLE)
+			return true;
+	}
+	return false;
+}
+
+static void wcd937x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component,
+					       int pull_up_cur)
+{
+	/* Default pull up current to 2uA */
+	if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA)
+		pull_up_cur = HS_PULLUP_I_2P0_UA;
+
+	snd_soc_component_write_field(component,
+				      WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT,
+				      WCD937X_HSDET_PULLUP_C_MASK, pull_up_cur);
+}
+
+static int wcd937x_mbhc_request_micbias(struct snd_soc_component *component,
+					int micb_num, int req)
+{
+	return wcd937x_micbias_control(component, micb_num, req, false);
+}
+
+static void wcd937x_mbhc_micb_ramp_control(struct snd_soc_component *component,
+					   bool enable)
+{
+	if (enable) {
+		snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+					      WCD937X_RAMP_SHIFT_CTRL_MASK, 0x0C);
+		snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+					      WCD937X_RAMP_EN_MASK, 1);
+	} else {
+		snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+					      WCD937X_RAMP_EN_MASK, 0);
+		snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+					      WCD937X_RAMP_SHIFT_CTRL_MASK, 0);
+	}
+}
+
+static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+					    int req_volt, int micb_num)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD937X_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD937X_ANA_MICB2;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD937X_ANA_MICB3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mutex_lock(&wcd937x->micb_lock);
+	/*
+	 * If requested micbias voltage is same as current micbias
+	 * voltage, then just return. Otherwise, adjust voltage as
+	 * per requested value. If micbias is already enabled, then
+	 * to avoid slow micbias ramp-up or down enable pull-up
+	 * momentarily, change the micbias value and then re-enable
+	 * micbias.
+	 */
+	micb_en = snd_soc_component_read_field(component, micb_reg,
+					       WCD937X_MICB_EN_MASK);
+	cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
+						    WCD937X_MICB_VOUT_MASK);
+
+	req_vout_ctl = wcd937x_get_micb_vout_ctl_val(req_volt);
+	if (req_vout_ctl < 0) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (cur_vout_ctl == req_vout_ctl) {
+		ret = 0;
+		goto exit;
+	}
+
+	if (micb_en == WCD937X_MICB_ENABLE)
+		snd_soc_component_write_field(component, micb_reg,
+					      WCD937X_MICB_EN_MASK,
+					      WCD937X_MICB_PULL_UP);
+
+	snd_soc_component_write_field(component, micb_reg,
+				      WCD937X_MICB_VOUT_MASK,
+				      req_vout_ctl);
+
+	if (micb_en == WCD937X_MICB_ENABLE) {
+		snd_soc_component_write_field(component, micb_reg,
+					      WCD937X_MICB_EN_MASK,
+					      WCD937X_MICB_ENABLE);
+		/*
+		 * Add 2ms delay as per HW requirement after enabling
+		 * micbias
+		 */
+		usleep_range(2000, 2100);
+	}
+exit:
+	mutex_unlock(&wcd937x->micb_lock);
+	return ret;
+}
+
+static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
+						int micb_num, bool req_en)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int micb_mv;
+
+	if (micb_num != MIC_BIAS_2)
+		return -EINVAL;
+	/*
+	 * If device tree micbias level is already above the minimum
+	 * voltage needed to detect threshold microphone, then do
+	 * not change the micbias, just return.
+	 */
+	if (wcd937x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+		return 0;
+
+	micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd937x->micb2_mv;
+
+	return wcd937x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+}
+
+static void wcd937x_mbhc_get_result_params(struct snd_soc_component *component,
+					   s16 *d1_a, u16 noff,
+					   int32_t *zdet)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	int i;
+	int val, val1;
+	s16 c1;
+	s32 x1, d1;
+	s32 denom;
+	static const int minCode_param[] = {
+		3277, 1639, 820, 410, 205, 103, 52, 26
+	};
+
+	regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x20);
+	for (i = 0; i < WCD937X_ZDET_NUM_MEASUREMENTS; i++) {
+		regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val);
+		if (val & 0x80)
+			break;
+	}
+	val = val << 0x8;
+	regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val1);
+	val |= val1;
+	regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x00);
+	x1 = WCD937X_MBHC_GET_X1(val);
+	c1 = WCD937X_MBHC_GET_C1(val);
+	/* If ramp is not complete, give additional 5ms */
+	if (c1 < 2 && x1)
+		usleep_range(5000, 5050);
+
+	if (!c1 || !x1) {
+		dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n",
+			c1, x1);
+		goto ramp_down;
+	}
+	d1 = d1_a[c1];
+	denom = (x1 * d1) - (1 << (14 - noff));
+	if (denom > 0)
+		*zdet = (WCD937X_MBHC_ZDET_CONST * 1000) / denom;
+	else if (x1 < minCode_param[noff])
+		*zdet = WCD937X_ZDET_FLOATING_IMPEDANCE;
+
+	dev_err(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n",
+		__func__, d1, c1, x1, *zdet);
+ramp_down:
+	i = 0;
+	while (x1) {
+		regmap_read(wcd937x->regmap,
+			    WCD937X_ANA_MBHC_RESULT_1, &val);
+		regmap_read(wcd937x->regmap,
+			    WCD937X_ANA_MBHC_RESULT_2, &val1);
+		val = val << 0x08;
+		val |= val1;
+		x1 = WCD937X_MBHC_GET_X1(val);
+		i++;
+		if (i == WCD937X_ZDET_NUM_MEASUREMENTS)
+			break;
+	}
+}
+
+static void wcd937x_mbhc_zdet_ramp(struct snd_soc_component *component,
+				   struct wcd937x_mbhc_zdet_param *zdet_param,
+				   s32 *zl, s32 *zr, s16 *d1_a)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	s32 zdet = 0;
+
+	snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL,
+				      WCD937X_ZDET_MAXV_CTL_MASK, zdet_param->ldo_ctl);
+	snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN5,
+				      WCD937X_VTH_MASK, zdet_param->btn5);
+	snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN6,
+				      WCD937X_VTH_MASK, zdet_param->btn6);
+	snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN7,
+				      WCD937X_VTH_MASK, zdet_param->btn7);
+	snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL,
+				      WCD937X_ZDET_RANGE_CTL_MASK, zdet_param->noff);
+	snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_RAMP_CTL,
+				      0x0F, zdet_param->nshift);
+
+	if (!zl)
+		goto z_right;
+	/* Start impedance measurement for HPH_L */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x80, 0x80);
+	wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x80, 0x00);
+
+	*zl = zdet;
+
+z_right:
+	if (!zr)
+		return;
+	/* Start impedance measurement for HPH_R */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x40, 0x40);
+	wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x40, 0x00);
+
+	*zr = zdet;
+}
+
+static void wcd937x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+				       s32 *z_val, int flag_l_r)
+{
+	s16 q1;
+	int q1_cal;
+
+	if (*z_val < (WCD937X_ZDET_VAL_400 / 1000))
+		q1 = snd_soc_component_read(component,
+					    WCD937X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+	else
+		q1 = snd_soc_component_read(component,
+					    WCD937X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
+	if (q1 & 0x80)
+		q1_cal = (10000 - ((q1 & 0x7F) * 25));
+	else
+		q1_cal = (10000 + (q1 * 25));
+	if (q1_cal > 0)
+		*z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void wcd937x_wcd_mbhc_calc_impedance(struct snd_soc_component *component,
+					    u32 *zl, u32 *zr)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	s16 reg0, reg1, reg2, reg3, reg4;
+	s32 z1l, z1r, z1ls;
+	int zMono, z_diff1, z_diff2;
+	bool is_fsm_disable = false;
+	struct wcd937x_mbhc_zdet_param zdet_param[] = {
+		{4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+		{2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+		{1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+		{1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+	};
+	struct wcd937x_mbhc_zdet_param *zdet_param_ptr = NULL;
+	s16 d1_a[][4] = {
+		{0, 30, 90, 30},
+		{0, 30, 30, 5},
+		{0, 30, 30, 5},
+		{0, 30, 30, 5},
+	};
+	s16 *d1 = NULL;
+
+	reg0 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN5);
+	reg1 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN6);
+	reg2 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN7);
+	reg3 = snd_soc_component_read(component, WCD937X_MBHC_CTL_CLK);
+	reg4 = snd_soc_component_read(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL);
+
+	if (snd_soc_component_read(component, WCD937X_ANA_MBHC_ELECT) & 0x80) {
+		is_fsm_disable = true;
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_ELECT, 0x80, 0x00);
+	}
+
+	/* For NO-jack, disable L_DET_EN before Z-det measurements */
+	if (wcd937x->mbhc_cfg.hphl_swh)
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_MECH, 0x80, 0x00);
+
+	/* Turn off 100k pull down on HPHL */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_MECH, 0x01, 0x00);
+
+	/* Disable surge protection before impedance detection.
+	 * This is done to give correct value for high impedance.
+	 */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+	/* 1ms delay needed after disable surge protection */
+	usleep_range(1000, 1010);
+
+	/* First get impedance on Left */
+	d1 = d1_a[1];
+	zdet_param_ptr = &zdet_param[1];
+	wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1);
+
+	if (!WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1l))
+		goto left_ch_impedance;
+
+	/* Second ramp for left ch */
+	if (z1l < WCD937X_ZDET_VAL_32) {
+		zdet_param_ptr = &zdet_param[0];
+		d1 = d1_a[0];
+	} else if ((z1l > WCD937X_ZDET_VAL_400) &&
+		  (z1l <= WCD937X_ZDET_VAL_1200)) {
+		zdet_param_ptr = &zdet_param[2];
+		d1 = d1_a[2];
+	} else if (z1l > WCD937X_ZDET_VAL_1200) {
+		zdet_param_ptr = &zdet_param[3];
+		d1 = d1_a[3];
+	}
+	wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1);
+
+left_ch_impedance:
+	if (z1l == WCD937X_ZDET_FLOATING_IMPEDANCE ||
+	    z1l > WCD937X_ZDET_VAL_100K) {
+		*zl = WCD937X_ZDET_FLOATING_IMPEDANCE;
+		zdet_param_ptr = &zdet_param[1];
+		d1 = d1_a[1];
+	} else {
+		*zl = z1l / 1000;
+		wcd937x_wcd_mbhc_qfuse_cal(component, zl, 0);
+	}
+
+	/* Start of right impedance ramp and calculation */
+	wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1);
+	if (WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1r)) {
+		if ((z1r > WCD937X_ZDET_VAL_1200 &&
+		     zdet_param_ptr->noff == 0x6) ||
+		     ((*zl) != WCD937X_ZDET_FLOATING_IMPEDANCE))
+			goto right_ch_impedance;
+		/* Second ramp for right ch */
+		if (z1r < WCD937X_ZDET_VAL_32) {
+			zdet_param_ptr = &zdet_param[0];
+			d1 = d1_a[0];
+		} else if ((z1r > WCD937X_ZDET_VAL_400) &&
+			(z1r <= WCD937X_ZDET_VAL_1200)) {
+			zdet_param_ptr = &zdet_param[2];
+			d1 = d1_a[2];
+		} else if (z1r > WCD937X_ZDET_VAL_1200) {
+			zdet_param_ptr = &zdet_param[3];
+			d1 = d1_a[3];
+		}
+		wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1);
+	}
+right_ch_impedance:
+	if (z1r == WCD937X_ZDET_FLOATING_IMPEDANCE ||
+	    z1r > WCD937X_ZDET_VAL_100K) {
+		*zr = WCD937X_ZDET_FLOATING_IMPEDANCE;
+	} else {
+		*zr = z1r / 1000;
+		wcd937x_wcd_mbhc_qfuse_cal(component, zr, 1);
+	}
+
+	/* Mono/stereo detection */
+	if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) &&
+	    (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE)) {
+		dev_err(component->dev,
+			"%s: plug type is invalid or extension cable\n",
+			__func__);
+		goto zdet_complete;
+	}
+	if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+	    (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+	    ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+	    ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+		wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+		goto zdet_complete;
+	}
+	snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST,
+				      WCD937X_HPHPA_GND_OVR_MASK, 1);
+	snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+				      WCD937X_HPHPA_GND_R_MASK, 1);
+	if (*zl < (WCD937X_ZDET_VAL_32 / 1000))
+		wcd937x_mbhc_zdet_ramp(component, &zdet_param[0], &z1ls, NULL, d1);
+	else
+		wcd937x_mbhc_zdet_ramp(component, &zdet_param[1], &z1ls, NULL, d1);
+	snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+				      WCD937X_HPHPA_GND_R_MASK, 0);
+	snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST,
+				      WCD937X_HPHPA_GND_OVR_MASK, 0);
+	z1ls /= 1000;
+	wcd937x_wcd_mbhc_qfuse_cal(component, &z1ls, 0);
+	/* Parallel of left Z and 9 ohm pull down resistor */
+	zMono = ((*zl) * 9) / ((*zl) + 9);
+	z_diff1 = (z1ls > zMono) ? (z1ls - zMono) : (zMono - z1ls);
+	z_diff2 = ((*zl) > z1ls) ? ((*zl) - z1ls) : (z1ls - (*zl));
+	if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + zMono)))
+		wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_STEREO);
+	else
+		wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+
+	/* Enable surge protection again after impedance detection */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
+zdet_complete:
+	snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN5, reg0);
+	snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN6, reg1);
+	snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN7, reg2);
+	/* Turn on 100k pull down on HPHL */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_MECH, 0x01, 0x01);
+
+	/* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+	if (wcd937x->mbhc_cfg.hphl_swh)
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_MECH, 0x80, 0x80);
+
+	snd_soc_component_write(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+	snd_soc_component_write(component, WCD937X_MBHC_CTL_CLK, reg3);
+	if (is_fsm_disable)
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+
+static void wcd937x_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+				      bool enable)
+{
+	if (enable) {
+		snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+					      WCD937X_MBHC_HSG_PULLUP_COMP_EN, 1);
+		snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+					      WCD937X_MBHC_GND_DET_EN_MASK, 1);
+	} else {
+		snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+					      WCD937X_MBHC_GND_DET_EN_MASK, 0);
+		snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+					      WCD937X_MBHC_HSG_PULLUP_COMP_EN, 0);
+	}
+}
+
+static void wcd937x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+					    bool enable)
+{
+	snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+				      WCD937X_HPHPA_GND_R_MASK, enable);
+	snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+				      WCD937X_HPHPA_GND_L_MASK, enable);
+}
+
+static void wcd937x_mbhc_moisture_config(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+					      WCD937X_M_RTH_CTL_MASK, R_OFF);
+		return;
+	}
+
+	/* Do not enable moisture detection if jack type is NC */
+	if (!wcd937x->mbhc_cfg.hphl_swh) {
+		dev_err(component->dev, "%s: disable moisture detection for NC\n",
+			__func__);
+		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+					      WCD937X_M_RTH_CTL_MASK, R_OFF);
+		return;
+	}
+
+	snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+				      WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref);
+}
+
+static void wcd937x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	if (enable)
+		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+					      WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref);
+	else
+		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+					      WCD937X_M_RTH_CTL_MASK, R_OFF);
+}
+
+static bool wcd937x_mbhc_get_moisture_status(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	bool ret = false;
+
+	if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+					      WCD937X_M_RTH_CTL_MASK, R_OFF);
+		goto done;
+	}
+
+	/* Do not enable moisture detection if jack type is NC */
+	if (!wcd937x->mbhc_cfg.hphl_swh) {
+		dev_err(component->dev, "%s: disable moisture detection for NC\n",
+			__func__);
+		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+					      WCD937X_M_RTH_CTL_MASK, R_OFF);
+		goto done;
+	}
+
+	/*
+	 * If moisture_en is already enabled, then skip to plug type
+	 * detection.
+	 */
+	if (snd_soc_component_read_field(component, WCD937X_MBHC_NEW_CTL_2, WCD937X_M_RTH_CTL_MASK))
+		goto done;
+
+	wcd937x_mbhc_moisture_detect_en(component, true);
+	/* Read moisture comparator status */
+	ret = ((snd_soc_component_read(component, WCD937X_MBHC_NEW_FSM_STATUS)
+				       & 0x20) ? 0 : 1);
+done:
+	return ret;
+}
+
+static void wcd937x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component,
+					       bool enable)
+{
+	snd_soc_component_write_field(component,
+				      WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL,
+				      WCD937X_MOISTURE_EN_POLLING_MASK, enable);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+	.clk_setup = wcd937x_mbhc_clk_setup,
+	.mbhc_bias = wcd937x_mbhc_mbhc_bias_control,
+	.set_btn_thr = wcd937x_mbhc_program_btn_thr,
+	.micbias_enable_status = wcd937x_mbhc_micb_en_status,
+	.hph_pull_up_control_v2 = wcd937x_mbhc_hph_l_pull_up_control,
+	.mbhc_micbias_control = wcd937x_mbhc_request_micbias,
+	.mbhc_micb_ramp_control = wcd937x_mbhc_micb_ramp_control,
+	.mbhc_micb_ctrl_thr_mic = wcd937x_mbhc_micb_ctrl_threshold_mic,
+	.compute_impedance = wcd937x_wcd_mbhc_calc_impedance,
+	.mbhc_gnd_det_ctrl = wcd937x_mbhc_gnd_det_ctrl,
+	.hph_pull_down_ctrl = wcd937x_mbhc_hph_pull_down_ctrl,
+	.mbhc_moisture_config = wcd937x_mbhc_moisture_config,
+	.mbhc_get_moisture_status = wcd937x_mbhc_get_moisture_status,
+	.mbhc_moisture_polling_ctrl = wcd937x_mbhc_moisture_polling_ctrl,
+	.mbhc_moisture_detect_en = wcd937x_mbhc_moisture_detect_en,
+};
+
+static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd937x->wcd_mbhc);
+
+	return 0;
+}
+
+static int wcd937x_hph_impedance_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	u32 zl, zr;
+	bool hphr;
+	struct soc_mixer_control *mc;
+	struct snd_soc_component *component =
+					snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	mc = (struct soc_mixer_control *)(kcontrol->private_value);
+	hphr = mc->shift;
+	wcd_mbhc_get_impedance(wcd937x->wcd_mbhc, &zl, &zr);
+	ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+	SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0,
+		       wcd937x_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0,
+		       wcd937x_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0,
+		       wcd937x_hph_impedance_get, NULL),
+};
+
+static int wcd937x_mbhc_init(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	struct wcd_mbhc_intr *intr_ids = &wcd937x->intr_ids;
+
+	intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+						     WCD937X_IRQ_MBHC_SW_DET);
+	intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+							    WCD937X_IRQ_MBHC_BUTTON_PRESS_DET);
+	intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+							      WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET);
+	intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+							 WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET);
+	intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+							 WCD937X_IRQ_MBHC_ELECT_INS_REM_DET);
+	intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
+						     WCD937X_IRQ_HPHL_OCP_INT);
+	intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
+						      WCD937X_IRQ_HPHR_OCP_INT);
+
+	wcd937x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+	if (IS_ERR(wcd937x->wcd_mbhc))
+		return PTR_ERR(wcd937x->wcd_mbhc);
+
+	snd_soc_add_component_controls(component, impedance_detect_controls,
+				       ARRAY_SIZE(impedance_detect_controls));
+	snd_soc_add_component_controls(component, hph_type_detect_controls,
+				       ARRAY_SIZE(hph_type_detect_controls));
+
+	return 0;
+}
+
+static void wcd937x_mbhc_deinit(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	wcd_mbhc_deinit(wcd937x->wcd_mbhc);
+}
+
+/* END MBHC */
+
+static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
+	SOC_SINGLE_TLV("EAR_PA Volume", WCD937X_ANA_EAR_COMPANDER_CTL,
+		       2, 0x10, 0, ear_pa_gain),
+	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+		     wcd937x_rx_hph_mode_get, wcd937x_rx_hph_mode_put),
+
+	SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+		       wcd937x_get_compander, wcd937x_set_compander),
+	SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0,
+		       wcd937x_get_compander, wcd937x_set_compander),
+
+	SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain),
+	SOC_SINGLE_TLV("ADC1 Volume", WCD937X_ANA_TX_CH1, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", WCD937X_ANA_TX_CH2, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", WCD937X_ANA_TX_CH3, 0, 20, 0, analog_gain),
+
+	SOC_SINGLE_EXT("HPHL Switch", WCD937X_HPH_L, 0, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("HPHR Switch", WCD937X_HPH_R, 0, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+
+	SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("ADC3 Switch", WCD937X_ADC3, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("DMIC0 Switch", WCD937X_DMIC0, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("DMIC1 Switch", WCD937X_DMIC1, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("MBHC Switch", WCD937X_MBHC, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("DMIC2 Switch", WCD937X_DMIC2, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("DMIC3 Switch", WCD937X_DMIC3, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("DMIC4 Switch", WCD937X_DMIC4, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+	SOC_SINGLE_EXT("DMIC5 Switch", WCD937X_DMIC5, 1, 1, 0,
+		       wcd937x_get_swr_port, wcd937x_set_swr_port),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc3_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic3_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic4_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic5_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic6_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new aux_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+	"INP2", "INP3"
+};
+
+static const char * const rdac3_mux_text[] = {
+	"RX1", "RX3"
+};
+
+static const struct soc_enum adc2_enum =
+	SOC_ENUM_SINGLE(WCD937X_TX_NEW_TX_CH2_SEL, 7,
+			ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum rdac3_enum =
+	SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0,
+			ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+
+static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
+
+static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = {
+	/* Input widgets */
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_INPUT("IN1_HPHL"),
+	SND_SOC_DAPM_INPUT("IN2_HPHR"),
+	SND_SOC_DAPM_INPUT("IN3_AUX"),
+
+	/* TX widgets */
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+			   wcd937x_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0,
+			   wcd937x_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0,
+			     NULL, 0, wcd937x_enable_req,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 0, 0,
+			     NULL, 0, wcd937x_enable_req,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+	/* TX mixers */
+	SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+			     adc1_switch, ARRAY_SIZE(adc1_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 1, 0,
+			     adc2_switch, ARRAY_SIZE(adc2_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+
+	/* MIC_BIAS widgets */
+	SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+			    wcd937x_codec_enable_micbias,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+			    wcd937x_codec_enable_micbias,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+			    wcd937x_codec_enable_micbias,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* RX widgets */
+	SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0,
+			   wcd937x_codec_enable_ear_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0,
+			   wcd937x_codec_enable_aux_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0,
+			   wcd937x_codec_enable_hphl_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0,
+			   wcd937x_codec_enable_hphr_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+			   wcd937x_codec_hphl_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+			   wcd937x_codec_hphr_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+			   wcd937x_codec_ear_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0,
+			   wcd937x_codec_aux_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux),
+
+	SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+			     wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+			     wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0,
+			     wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+
+	/* RX mixer widgets*/
+	SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+			   ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+	SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0,
+			   aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)),
+	SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+			   hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+	SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+			   hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+	/* TX output widgets */
+	SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("WCD_TX_OUTPUT"),
+
+	/* RX output widgets */
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("AUX"),
+	SND_SOC_DAPM_OUTPUT("HPHL"),
+	SND_SOC_DAPM_OUTPUT("HPHR"),
+
+	/* MIC_BIAS pull up widgets */
+	SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+			    wcd937x_codec_enable_micbias_pullup,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+			    wcd937x_codec_enable_micbias_pullup,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+			    wcd937x_codec_enable_micbias_pullup,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = {
+	/* Input widgets */
+	SND_SOC_DAPM_INPUT("AMIC4"),
+
+	/* TX widgets */
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0,
+			   wcd937x_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0,
+			     NULL, 0, wcd937x_enable_req,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+			   wcd937x_codec_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0,
+			   wcd937x_codec_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0,
+			   wcd937x_codec_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0,
+			   wcd937x_codec_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0,
+			   wcd937x_codec_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0,
+			   wcd937x_codec_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* TX mixer widgets */
+	SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0,
+			     0, dmic1_switch, ARRAY_SIZE(dmic1_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 1,
+			     0, dmic2_switch, ARRAY_SIZE(dmic2_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 2,
+			     0, dmic3_switch, ARRAY_SIZE(dmic3_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 3,
+			     0, dmic4_switch, ARRAY_SIZE(dmic4_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 4,
+			     0, dmic5_switch, ARRAY_SIZE(dmic5_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 5,
+			     0, dmic6_switch, ARRAY_SIZE(dmic6_switch),
+			     wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 2, 0, adc3_switch,
+			     ARRAY_SIZE(adc3_switch), wcd937x_tx_swr_ctrl,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Output widgets */
+	SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route wcd937x_audio_map[] = {
+	{ "ADC1_OUTPUT", NULL, "ADC1_MIXER" },
+	{ "ADC1_MIXER", "Switch", "ADC1 REQ" },
+	{ "ADC1 REQ", NULL, "ADC1" },
+	{ "ADC1", NULL, "AMIC1" },
+
+	{ "ADC2_OUTPUT", NULL, "ADC2_MIXER" },
+	{ "ADC2_MIXER", "Switch", "ADC2 REQ" },
+	{ "ADC2 REQ", NULL, "ADC2" },
+	{ "ADC2", NULL, "ADC2 MUX" },
+	{ "ADC2 MUX", "INP3", "AMIC3" },
+	{ "ADC2 MUX", "INP2", "AMIC2" },
+
+	{ "IN1_HPHL", NULL, "VDD_BUCK" },
+	{ "IN1_HPHL", NULL, "CLS_H_PORT" },
+	{ "RX1", NULL, "IN1_HPHL" },
+	{ "RDAC1", NULL, "RX1" },
+	{ "HPHL_RDAC", "Switch", "RDAC1" },
+	{ "HPHL PGA", NULL, "HPHL_RDAC" },
+	{ "HPHL", NULL, "HPHL PGA" },
+
+	{ "IN2_HPHR", NULL, "VDD_BUCK" },
+	{ "IN2_HPHR", NULL, "CLS_H_PORT" },
+	{ "RX2", NULL, "IN2_HPHR" },
+	{ "RDAC2", NULL, "RX2" },
+	{ "HPHR_RDAC", "Switch", "RDAC2" },
+	{ "HPHR PGA", NULL, "HPHR_RDAC" },
+	{ "HPHR", NULL, "HPHR PGA" },
+
+	{ "IN3_AUX", NULL, "VDD_BUCK" },
+	{ "IN3_AUX", NULL, "CLS_H_PORT" },
+	{ "RX3", NULL, "IN3_AUX" },
+	{ "RDAC4", NULL, "RX3" },
+	{ "AUX_RDAC", "Switch", "RDAC4" },
+	{ "AUX PGA", NULL, "AUX_RDAC" },
+	{ "AUX", NULL, "AUX PGA" },
+
+	{ "RDAC3_MUX", "RX3", "RX3" },
+	{ "RDAC3_MUX", "RX1", "RX1" },
+	{ "RDAC3", NULL, "RDAC3_MUX" },
+	{ "EAR_RDAC", "Switch", "RDAC3" },
+	{ "EAR PGA", NULL, "EAR_RDAC" },
+	{ "EAR", NULL, "EAR PGA" },
+};
+
+static const struct snd_soc_dapm_route wcd9375_audio_map[] = {
+	{ "ADC3_OUTPUT", NULL, "ADC3_MIXER" },
+	{ "ADC3_OUTPUT", NULL, "ADC3_MIXER" },
+	{ "ADC3_MIXER", "Switch", "ADC3 REQ" },
+	{ "ADC3 REQ", NULL, "ADC3" },
+	{ "ADC3", NULL, "AMIC4" },
+
+	{ "DMIC1_OUTPUT", NULL, "DMIC1_MIXER" },
+	{ "DMIC1_MIXER", "Switch", "DMIC1" },
+
+	{ "DMIC2_OUTPUT", NULL, "DMIC2_MIXER" },
+	{ "DMIC2_MIXER", "Switch", "DMIC2" },
+
+	{ "DMIC3_OUTPUT", NULL, "DMIC3_MIXER" },
+	{ "DMIC3_MIXER", "Switch", "DMIC3" },
+
+	{ "DMIC4_OUTPUT", NULL, "DMIC4_MIXER" },
+	{ "DMIC4_MIXER", "Switch", "DMIC4" },
+
+	{ "DMIC5_OUTPUT", NULL, "DMIC5_MIXER" },
+	{ "DMIC5_MIXER", "Switch", "DMIC5" },
+
+	{ "DMIC6_OUTPUT", NULL, "DMIC6_MIXER" },
+	{ "DMIC6_MIXER", "Switch", "DMIC6" },
+};
+
+static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x)
+{
+	int vout_ctl[3];
+
+	/* Set micbias voltage */
+	vout_ctl[0] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb1_mv);
+	vout_ctl[1] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb2_mv);
+	vout_ctl[2] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb3_mv);
+	if ((vout_ctl[0] | vout_ctl[1] | vout_ctl[2]) < 0)
+		return -EINVAL;
+
+	regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB1, WCD937X_ANA_MICB_VOUT, vout_ctl[0]);
+	regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB2, WCD937X_ANA_MICB_VOUT, vout_ctl[1]);
+	regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB3, WCD937X_ANA_MICB_VOUT, vout_ctl[2]);
+
+	return 0;
+}
+
+static irqreturn_t wcd937x_wd_handle_irq(int irq, void *data)
+{
+	return IRQ_HANDLED;
+}
+
+static const struct irq_chip wcd_irq_chip = {
+	.name = "WCD937x",
+};
+
+static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq,
+			    irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq);
+	irq_set_nested_thread(virq, 1);
+	irq_set_noprobe(virq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops wcd_domain_ops = {
+	.map = wcd_irq_chip_map,
+};
+
+static int wcd937x_irq_init(struct wcd937x_priv *wcd, struct device *dev)
+{
+	wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL);
+	if (!(wcd->virq)) {
+		dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
+		return -EINVAL;
+	}
+
+	return devm_regmap_add_irq_chip(dev, wcd->regmap,
+					irq_create_mapping(wcd->virq, 0),
+					IRQF_ONESHOT, 0, &wcd937x_regmap_irq_chip,
+					&wcd->irq_chip);
+}
+
+static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	struct sdw_slave *tx_sdw_dev = wcd937x->tx_sdw_dev;
+	struct device *dev = component->dev;
+	unsigned long time_left;
+	int i, ret;
+	u32 chipid;
+
+	time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete,
+						msecs_to_jiffies(5000));
+	if (!time_left) {
+		dev_err(dev, "soundwire device init timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	snd_soc_component_init_regmap(component, wcd937x->regmap);
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0)
+		return ret;
+
+	chipid = (snd_soc_component_read(component,
+					 WCD937X_DIGITAL_EFUSE_REG_0) & 0x1e) >> 1;
+	if (chipid != CHIPID_WCD9370 && chipid != CHIPID_WCD9375) {
+		dev_err(dev, "Got unknown chip id: 0x%x\n", chipid);
+		pm_runtime_put(dev);
+		return -EINVAL;
+	}
+
+	wcd937x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD937X);
+	if (IS_ERR(wcd937x->clsh_info)) {
+		pm_runtime_put(dev);
+		return PTR_ERR(wcd937x->clsh_info);
+	}
+
+	wcd937x_io_init(wcd937x->regmap);
+	/* Set all interrupts as edge triggered */
+	for (i = 0; i < wcd937x_regmap_irq_chip.num_regs; i++)
+		regmap_write(wcd937x->regmap, (WCD937X_DIGITAL_INTR_LEVEL_0 + i), 0);
+
+	pm_runtime_put(dev);
+
+	wcd937x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+						       WCD937X_IRQ_HPHR_PDM_WD_INT);
+	wcd937x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+						       WCD937X_IRQ_HPHL_PDM_WD_INT);
+	wcd937x->aux_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+						      WCD937X_IRQ_AUX_PDM_WD_INT);
+
+	/* Request for watchdog interrupt */
+	ret = devm_request_threaded_irq(dev, wcd937x->hphr_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+					"HPHR PDM WDOG INT", wcd937x);
+	if (ret)
+		dev_err(dev, "Failed to request HPHR watchdog interrupt (%d)\n", ret);
+
+	ret = devm_request_threaded_irq(dev, wcd937x->hphl_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+					"HPHL PDM WDOG INT", wcd937x);
+	if (ret)
+		dev_err(dev, "Failed to request HPHL watchdog interrupt (%d)\n", ret);
+
+	ret = devm_request_threaded_irq(dev, wcd937x->aux_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+					"AUX PDM WDOG INT", wcd937x);
+	if (ret)
+		dev_err(dev, "Failed to request Aux watchdog interrupt (%d)\n", ret);
+
+	/* Disable watchdog interrupt for HPH and AUX */
+	disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+	disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+	disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+
+	if (chipid == CHIPID_WCD9375) {
+		ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets,
+						ARRAY_SIZE(wcd9375_dapm_widgets));
+		if (ret < 0) {
+			dev_err(component->dev, "Failed to add snd_ctls\n");
+			return ret;
+		}
+
+		ret = snd_soc_dapm_add_routes(dapm, wcd9375_audio_map,
+					      ARRAY_SIZE(wcd9375_audio_map));
+		if (ret < 0) {
+			dev_err(component->dev, "Failed to add routes\n");
+			return ret;
+		}
+	}
+
+	ret = wcd937x_mbhc_init(component);
+	if (ret)
+		dev_err(component->dev, "mbhc initialization failed\n");
+
+	return ret;
+}
+
+static void wcd937x_soc_codec_remove(struct snd_soc_component *component)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	wcd937x_mbhc_deinit(component);
+	free_irq(wcd937x->aux_pdm_wd_int, wcd937x);
+	free_irq(wcd937x->hphl_pdm_wd_int, wcd937x);
+	free_irq(wcd937x->hphr_pdm_wd_int, wcd937x);
+
+	wcd_clsh_ctrl_free(wcd937x->clsh_info);
+}
+
+static int wcd937x_codec_set_jack(struct snd_soc_component *comp,
+				  struct snd_soc_jack *jack, void *data)
+{
+	struct wcd937x_priv *wcd = dev_get_drvdata(comp->dev);
+	int ret = 0;
+
+	if (jack)
+		ret = wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack);
+	else
+		wcd_mbhc_stop(wcd->wcd_mbhc);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_wcd937x = {
+	.name = "wcd937x_codec",
+	.probe = wcd937x_soc_codec_probe,
+	.remove = wcd937x_soc_codec_remove,
+	.controls = wcd937x_snd_controls,
+	.num_controls = ARRAY_SIZE(wcd937x_snd_controls),
+	.dapm_widgets = wcd937x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets),
+	.dapm_routes = wcd937x_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map),
+	.set_jack = wcd937x_codec_set_jack,
+	.endianness = 1,
+};
+
+static void wcd937x_dt_parse_micbias_info(struct device *dev, struct wcd937x_priv *wcd)
+{
+	struct device_node *np = dev->of_node;
+	u32 prop_val = 0;
+	int ret = 0;
+
+	ret = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val);
+	if (!ret)
+		wcd->micb1_mv = prop_val / 1000;
+	else
+		dev_warn(dev, "Micbias1 DT property not found\n");
+
+	ret = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val);
+	if (!ret)
+		wcd->micb2_mv = prop_val / 1000;
+	else
+		dev_warn(dev, "Micbias2 DT property not found\n");
+
+	ret = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val);
+	if (!ret)
+		wcd->micb3_mv = prop_val / 1000;
+	else
+		dev_warn(dev, "Micbias3 DT property not found\n");
+}
+
+static bool wcd937x_swap_gnd_mic(struct snd_soc_component *component, bool active)
+{
+	int value;
+	struct wcd937x_priv *wcd937x;
+
+	wcd937x = snd_soc_component_get_drvdata(component);
+
+	value = gpiod_get_value(wcd937x->us_euro_gpio);
+	gpiod_set_value(wcd937x->us_euro_gpio, !value);
+
+	return true;
+}
+
+static int wcd937x_codec_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+	struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+	return wcd937x_sdw_hw_params(wcd, substream, params, dai);
+}
+
+static int wcd937x_codec_free(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+	struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+	return sdw_stream_remove_slave(wcd->sdev, wcd->sruntime);
+}
+
+static int wcd937x_codec_set_sdw_stream(struct snd_soc_dai *dai,
+					void *stream, int direction)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+	struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+	wcd->sruntime = stream;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wcd937x_sdw_dai_ops = {
+	.hw_params = wcd937x_codec_hw_params,
+	.hw_free = wcd937x_codec_free,
+	.set_stream = wcd937x_codec_set_sdw_stream,
+};
+
+static struct snd_soc_dai_driver wcd937x_dais[] = {
+	[0] = {
+		.name = "wcd937x-sdw-rx",
+		.playback = {
+			.stream_name = "WCD AIF Playback",
+			.rates = WCD937X_RATES | WCD937X_FRAC_RATES,
+			.formats = WCD937X_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 384000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd937x_sdw_dai_ops,
+	},
+	[1] = {
+		.name = "wcd937x-sdw-tx",
+		.capture = {
+			.stream_name = "WCD AIF Capture",
+			.rates = WCD937X_RATES,
+			.formats = WCD937X_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd937x_sdw_dai_ops,
+	},
+};
+
+static int wcd937x_bind(struct device *dev)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+	int ret;
+
+	/* Give the SDW subdevices some more time to settle */
+	usleep_range(5000, 5010);
+
+	ret = component_bind_all(dev, wcd937x);
+	if (ret) {
+		dev_err(dev, "Slave bind failed, ret = %d\n", ret);
+		return ret;
+	}
+
+	wcd937x->rxdev = wcd937x_sdw_device_get(wcd937x->rxnode);
+	if (!wcd937x->rxdev) {
+		dev_err(dev, "could not find slave with matching of node\n");
+		return -EINVAL;
+	}
+
+	wcd937x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd937x->rxdev);
+	wcd937x->sdw_priv[AIF1_PB]->wcd937x = wcd937x;
+
+	wcd937x->txdev = wcd937x_sdw_device_get(wcd937x->txnode);
+	if (!wcd937x->txdev) {
+		dev_err(dev, "could not find txslave with matching of node\n");
+		return -EINVAL;
+	}
+
+	wcd937x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd937x->txdev);
+	wcd937x->sdw_priv[AIF1_CAP]->wcd937x = wcd937x;
+	wcd937x->tx_sdw_dev = dev_to_sdw_dev(wcd937x->txdev);
+	if (!wcd937x->tx_sdw_dev) {
+		dev_err(dev, "could not get txslave with matching of dev\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * As TX is the main CSR reg interface, which should not be suspended first.
+	 * expicilty add the dependency link
+	 */
+	if (!device_link_add(wcd937x->rxdev, wcd937x->txdev,
+			     DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+		dev_err(dev, "Could not devlink TX and RX\n");
+		return -EINVAL;
+	}
+
+	if (!device_link_add(dev, wcd937x->txdev,
+			     DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+		dev_err(dev, "Could not devlink WCD and TX\n");
+		return -EINVAL;
+	}
+
+	if (!device_link_add(dev, wcd937x->rxdev,
+			     DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+		dev_err(dev, "Could not devlink WCD and RX\n");
+		return -EINVAL;
+	}
+
+	wcd937x->regmap = dev_get_regmap(&wcd937x->tx_sdw_dev->dev, NULL);
+	if (!wcd937x->regmap) {
+		dev_err(dev, "could not get TX device regmap\n");
+		return -EINVAL;
+	}
+
+	ret = wcd937x_irq_init(wcd937x, dev);
+	if (ret) {
+		dev_err(dev, "IRQ init failed: %d\n", ret);
+		return ret;
+	}
+
+	wcd937x->sdw_priv[AIF1_PB]->slave_irq = wcd937x->virq;
+	wcd937x->sdw_priv[AIF1_CAP]->slave_irq = wcd937x->virq;
+
+	ret = wcd937x_set_micbias_data(wcd937x);
+	if (ret < 0) {
+		dev_err(dev, "Bad micbias pdata\n");
+		return ret;
+	}
+
+	ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x,
+					 wcd937x_dais, ARRAY_SIZE(wcd937x_dais));
+	if (ret)
+		dev_err(dev, "Codec registration failed\n");
+
+	return ret;
+}
+
+static void wcd937x_unbind(struct device *dev)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+	snd_soc_unregister_component(dev);
+	device_link_remove(dev, wcd937x->txdev);
+	device_link_remove(dev, wcd937x->rxdev);
+	device_link_remove(wcd937x->rxdev, wcd937x->txdev);
+	component_unbind_all(dev, wcd937x);
+	mutex_destroy(&wcd937x->micb_lock);
+}
+
+static const struct component_master_ops wcd937x_comp_ops = {
+	.bind = wcd937x_bind,
+	.unbind = wcd937x_unbind,
+};
+
+static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x,
+					struct device *dev,
+					struct component_match **matchptr)
+{
+	struct device_node *np = dev->of_node;
+
+	wcd937x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0);
+	if (!wcd937x->rxnode) {
+		dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n");
+		return -ENODEV;
+	}
+	of_node_get(wcd937x->rxnode);
+	component_match_add_release(dev, matchptr, component_release_of,
+				    component_compare_of, wcd937x->rxnode);
+
+	wcd937x->txnode = of_parse_phandle(np, "qcom,tx-device", 0);
+	if (!wcd937x->txnode) {
+		dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n");
+			return -ENODEV;
+	}
+	of_node_get(wcd937x->txnode);
+	component_match_add_release(dev, matchptr, component_release_of,
+				    component_compare_of, wcd937x->txnode);
+
+	return 0;
+}
+
+static int wcd937x_probe(struct platform_device *pdev)
+{
+	struct component_match *match = NULL;
+	struct device *dev = &pdev->dev;
+	struct wcd937x_priv *wcd937x;
+	struct wcd_mbhc_config *cfg;
+	int ret;
+
+	wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL);
+	if (!wcd937x)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, wcd937x);
+	mutex_init(&wcd937x->micb_lock);
+
+	wcd937x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(wcd937x->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(wcd937x->reset_gpio),
+				     "failed to reset wcd gpio\n");
+
+	wcd937x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", GPIOD_OUT_LOW);
+	if (IS_ERR(wcd937x->us_euro_gpio))
+		return dev_err_probe(dev, PTR_ERR(wcd937x->us_euro_gpio),
+				"us-euro swap Control GPIO not found\n");
+
+	cfg = &wcd937x->mbhc_cfg;
+	cfg->swap_gnd_mic = wcd937x_swap_gnd_mic;
+
+	wcd937x->supplies[0].supply = "vdd-rxtx";
+	wcd937x->supplies[1].supply = "vdd-px";
+	wcd937x->supplies[2].supply = "vdd-mic-bias";
+	wcd937x->supplies[3].supply = "vdd-buck";
+
+	ret = devm_regulator_bulk_get(dev, WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+	ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+	if (ret) {
+		regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+		return dev_err_probe(dev, ret, "Failed to enable supplies\n");
+	}
+
+	wcd937x_dt_parse_micbias_info(dev, wcd937x);
+
+	cfg->mbhc_micbias = MIC_BIAS_2;
+	cfg->anc_micbias = MIC_BIAS_2;
+	cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
+	cfg->num_btn = WCD937X_MBHC_MAX_BUTTONS;
+	cfg->micb_mv = wcd937x->micb2_mv;
+	cfg->linein_th = 5000;
+	cfg->hs_thr = 1700;
+	cfg->hph_thr = 50;
+
+	wcd_dt_parse_mbhc_data(dev, &wcd937x->mbhc_cfg);
+
+	ret = wcd937x_add_slave_components(wcd937x, dev, &match);
+	if (ret)
+		goto err_disable_regulators;
+
+	wcd937x_reset(wcd937x);
+
+	ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match);
+	if (ret)
+		goto err_disable_regulators;
+
+	pm_runtime_set_autosuspend_delay(dev, 1000);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	return 0;
+
+err_disable_regulators:
+	regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+	regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+
+	return ret;
+}
+
+static void wcd937x_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+	component_master_del(&pdev->dev, &wcd937x_comp_ops);
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_dont_use_autosuspend(dev);
+
+	regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+	regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id wcd937x_of_match[] = {
+	{ .compatible = "qcom,wcd9370-codec" },
+	{ .compatible = "qcom,wcd9375-codec" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wcd937x_of_match);
+#endif
+
+static struct platform_driver wcd937x_codec_driver = {
+	.probe = wcd937x_probe,
+	.remove_new = wcd937x_remove,
+	.driver = {
+		.name = "wcd937x_codec",
+		.of_match_table = of_match_ptr(wcd937x_of_match),
+		.suppress_bind_attrs = true,
+	},
+};
+
+module_platform_driver(wcd937x_codec_driver);
+MODULE_DESCRIPTION("WCD937X Codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h
new file mode 100644
index 0000000000000000000000000000000000000000..37bff16e88ddd553f43d36bbb68915fdeafe69b6
--- /dev/null
+++ b/sound/soc/codecs/wcd937x.h
@@ -0,0 +1,624 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _WCD937X_REGISTERS_H
+#define _WCD937X_REGISTERS_H
+
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+
+#define WCD937X_BASE_ADDRESS			0x3000
+#define WCD937X_ANA_BIAS			0x3001
+#define WCD937X_ANA_RX_SUPPLIES			0x3008
+#define WCD937X_ANA_HPH				0x3009
+#define WCD937X_ANA_EAR				0x300A
+#define WCD937X_ANA_EAR_COMPANDER_CTL		0x300B
+#define WCD937X_EAR_GAIN_MASK			GENMASK(6, 2)
+#define WCD937X_ANA_TX_CH1			0x300E
+#define WCD937X_ANA_TX_CH2			0x300F
+#define WCD937X_ANA_TX_CH3			0x3010
+#define WCD937X_ANA_TX_CH3_HPF			0x3011
+#define WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC	0x3012
+#define WCD937X_ANA_MICB3_DSP_EN_LOGIC		0x3013
+#define WCD937X_ANA_MBHC_MECH			0x3014
+#define WCD937X_MBHC_L_DET_EN_MASK		BIT(7)
+#define WCD937X_MBHC_L_DET_EN			BIT(7)
+#define WCD937X_MBHC_GND_DET_EN_MASK		BIT(6)
+#define WCD937X_MBHC_MECH_DETECT_TYPE_MASK	BIT(5)
+#define WCD937X_MBHC_MECH_DETECT_TYPE_INS	1
+#define WCD937X_MBHC_HPHL_PLUG_TYPE_MASK	BIT(4)
+#define WCD937X_MBHC_HPHL_PLUG_TYPE_NO		1
+#define WCD937X_MBHC_GND_PLUG_TYPE_MASK		BIT(3)
+#define WCD937X_MBHC_GND_PLUG_TYPE_NO		1
+#define WCD937X_MBHC_HSL_PULLUP_COMP_EN		BIT(2)
+#define WCD937X_MBHC_HSG_PULLUP_COMP_EN		BIT(1)
+#define WCD937X_MBHC_HPHL_100K_TO_GND_EN	BIT(0)
+#define WCD937X_ANA_MBHC_ELECT			0x3015
+#define WCD937X_ANA_MBHC_BD_ISRC_CTL_MASK	GENMASK(6, 4)
+#define WCD937X_ANA_MBHC_BD_ISRC_100UA		GENMASK(5, 4)
+#define WCD937X_ANA_MBHC_BD_ISRC_OFF		0
+#define WCD937X_ANA_MBHC_BIAS_EN_MASK		BIT(0)
+#define WCD937X_ANA_MBHC_BIAS_EN		BIT(0)
+#define WCD937X_ANA_MBHC_ZDET			0x3016
+#define WCD937X_ANA_MBHC_RESULT_1		0x3017
+#define WCD937X_ANA_MBHC_RESULT_2		0x3018
+#define WCD937X_ANA_MBHC_RESULT_3		0x3019
+#define WCD937X_MBHC_BTN_RESULT_MASK		GENMASK(2, 0)
+#define WCD937X_ANA_MBHC_BTN0			0x301A
+#define WCD937X_MBHC_BTN_VTH_MASK		GENMASK(7, 2)
+#define WCD937X_ANA_MBHC_BTN1			0x301B
+#define WCD937X_ANA_MBHC_BTN2			0x301C
+#define WCD937X_ANA_MBHC_BTN3			0x301D
+#define WCD937X_ANA_MBHC_BTN4			0x301E
+#define WCD937X_ANA_MBHC_BTN5			0x301F
+#define WCD937X_VTH_MASK			GENMASK(7, 2)
+#define WCD937X_ANA_MBHC_BTN6			0x3020
+#define WCD937X_ANA_MBHC_BTN7			0x3021
+#define WCD937X_ANA_MICB1			0x3022
+#define WCD937X_MICB_VOUT_MASK			GENMASK(5, 0)
+#define WCD937X_MICB_EN_MASK			GENMASK(7, 6)
+#define WCD937X_MICB_DISABLE			0
+#define WCD937X_MICB_ENABLE			1
+#define WCD937X_MICB_PULL_UP			2
+#define WCD937X_MICB_PULL_DOWN			3
+#define WCD937X_ANA_MICB2			0x3023
+#define WCD937X_ANA_MICB2_ENABLE		BIT(6)
+#define WCD937X_ANA_MICB2_ENABLE_MASK		GENMASK(7, 6)
+#define WCD937X_ANA_MICB2_VOUT_MASK		GENMASK(5, 0)
+#define WCD937X_ANA_MICB2_RAMP			0x3024
+#define WCD937X_RAMP_EN_MASK			BIT(7)
+#define WCD937X_RAMP_SHIFT_CTRL_MASK		GENMASK(4, 2)
+#define WCD937X_ANA_MICB3			0x3025
+#define WCD937X_ANA_MICB_EN			GENMASK(7, 6)
+#define WCD937X_MICB_DISABLE			0
+#define WCD937X_MICB_ENABLE			1
+#define WCD937X_MICB_PULL_UP			2
+#define WCD937X_ANA_MICB_VOUT			GENMASK(5, 0)
+#define WCD937X_BIAS_CTL			0x3028
+#define WCD937X_BIAS_VBG_FINE_ADJ		0x3029
+#define WCD937X_LDOL_VDDCX_ADJUST		0x3040
+#define WCD937X_LDOL_DISABLE_LDOL		0x3041
+#define WCD937X_MBHC_CTL_CLK			0x3056
+#define WCD937X_MBHC_CTL_ANA			0x3057
+#define WCD937X_MBHC_CTL_SPARE_1		0x3058
+#define WCD937X_MBHC_CTL_SPARE_2		0x3059
+#define WCD937X_MBHC_CTL_BCS			0x305A
+#define WCD937X_MBHC_MOISTURE_DET_FSM_STATUS	0x305B
+#define WCD937X_MBHC_TEST_CTL			0x305C
+#define WCD937X_LDOH_MODE			0x3067
+#define WCD937X_LDOH_BIAS			0x3068
+#define WCD937X_LDOH_STB_LOADS			0x3069
+#define WCD937X_LDOH_SLOWRAMP			0x306A
+#define WCD937X_MICB1_TEST_CTL_1		0x306B
+#define WCD937X_MICB1_TEST_CTL_2		0x306C
+#define WCD937X_MICB1_TEST_CTL_3		0x306D
+#define WCD937X_MICB2_TEST_CTL_1		0x306E
+#define WCD937X_MICB2_TEST_CTL_2		0x306F
+#define WCD937X_MICB2_TEST_CTL_3		0x3070
+#define WCD937X_MICB3_TEST_CTL_1		0x3071
+#define WCD937X_MICB3_TEST_CTL_2		0x3072
+#define WCD937X_MICB3_TEST_CTL_3		0x3073
+#define WCD937X_TX_COM_ADC_VCM			0x3077
+#define WCD937X_TX_COM_BIAS_ATEST		0x3078
+#define WCD937X_TX_COM_ADC_INT1_IB		0x3079
+#define WCD937X_TX_COM_ADC_INT2_IB		0x307A
+#define WCD937X_TX_COM_TXFE_DIV_CTL		0x307B
+#define WCD937X_TX_COM_TXFE_DIV_START		0x307C
+#define WCD937X_TX_COM_TXFE_DIV_STOP_9P6M	0x307D
+#define WCD937X_TX_COM_TXFE_DIV_STOP_12P288M	0x307E
+#define WCD937X_TX_1_2_TEST_EN			0x307F
+#define WCD937X_TX_1_2_ADC_IB			0x3080
+#define WCD937X_TX_1_2_ATEST_REFCTL		0x3081
+#define WCD937X_TX_1_2_TEST_CTL			0x3082
+#define WCD937X_TX_1_2_TEST_BLK_EN		0x3083
+#define WCD937X_TX_1_2_TXFE_CLKDIV		0x3084
+#define WCD937X_TX_1_2_SAR2_ERR			0x3085
+#define WCD937X_TX_1_2_SAR1_ERR			0x3086
+#define WCD937X_TX_3_TEST_EN			0x3087
+#define WCD937X_TX_3_ADC_IB			0x3088
+#define WCD937X_TX_3_ATEST_REFCTL		0x3089
+#define WCD937X_TX_3_TEST_CTL			0x308A
+#define WCD937X_TX_3_TEST_BLK_EN		0x308B
+#define WCD937X_TX_3_TXFE_CLKDIV		0x308C
+#define WCD937X_TX_3_SPARE_MONO			0x308D
+#define WCD937X_TX_3_SAR1_ERR			0x308E
+#define WCD937X_CLASSH_MODE_1			0x3097
+#define WCD937X_CLASSH_MODE_2			0x3098
+#define WCD937X_CLASSH_MODE_3			0x3099
+#define WCD937X_CLASSH_CTRL_VCL_1		0x309A
+#define WCD937X_CLASSH_CTRL_VCL_2		0x309B
+#define WCD937X_CLASSH_CTRL_CCL_1		0x309C
+#define WCD937X_CLASSH_CTRL_CCL_2		0x309D
+#define WCD937X_CLASSH_CTRL_CCL_3		0x309E
+#define WCD937X_CLASSH_CTRL_CCL_4		0x309F
+#define WCD937X_CLASSH_CTRL_CCL_5		0x30A0
+#define WCD937X_CLASSH_BUCK_TMUX_A_D		0x30A1
+#define WCD937X_CLASSH_BUCK_SW_DRV_CNTL		0x30A2
+#define WCD937X_CLASSH_SPARE			0x30A3
+#define WCD937X_FLYBACK_EN			0x30A4
+#define WCD937X_FLYBACK_VNEG_CTRL_1		0x30A5
+#define WCD937X_FLYBACK_VNEG_CTRL_2		0x30A6
+#define WCD937X_FLYBACK_VNEG_CTRL_3		0x30A7
+#define WCD937X_FLYBACK_VNEG_CTRL_4		0x30A8
+#define WCD937X_FLYBACK_VNEG_CTRL_5		0x30A9
+#define WCD937X_FLYBACK_VNEG_CTRL_6		0x30AA
+#define WCD937X_FLYBACK_VNEG_CTRL_7		0x30AB
+#define WCD937X_FLYBACK_VNEG_CTRL_8		0x30AC
+#define WCD937X_FLYBACK_VNEG_CTRL_9		0x30AD
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_1		0x30AE
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_2		0x30AF
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_3		0x30B0
+#define WCD937X_FLYBACK_CTRL_1			0x30B1
+#define WCD937X_FLYBACK_TEST_CTL		0x30B2
+#define WCD937X_RX_AUX_SW_CTL			0x30B3
+#define WCD937X_RX_PA_AUX_IN_CONN		0x30B4
+#define WCD937X_RX_TIMER_DIV			0x30B5
+#define WCD937X_RX_OCP_CTL			0x30B6
+#define WCD937X_RX_OCP_COUNT			0x30B7
+#define WCD937X_RX_BIAS_EAR_DAC			0x30B8
+#define WCD937X_RX_BIAS_EAR_AMP			0x30B9
+#define WCD937X_RX_BIAS_HPH_LDO			0x30BA
+#define WCD937X_RX_BIAS_HPH_PA			0x30BB
+#define WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2	0x30BC
+#define WCD937X_RX_BIAS_HPH_RDAC_LDO		0x30BD
+#define WCD937X_RX_BIAS_HPH_CNP1		0x30BE
+#define WCD937X_RX_BIAS_HPH_LOWPOWER		0x30BF
+#define WCD937X_RX_BIAS_AUX_DAC			0x30C0
+#define WCD937X_RX_BIAS_AUX_AMP			0x30C1
+#define WCD937X_RX_BIAS_VNEGDAC_BLEEDER		0x30C2
+#define WCD937X_RX_BIAS_MISC			0x30C3
+#define WCD937X_RX_BIAS_BUCK_RST		0x30C4
+#define WCD937X_RX_BIAS_BUCK_VREF_ERRAMP	0x30C5
+#define WCD937X_RX_BIAS_FLYB_ERRAMP		0x30C6
+#define WCD937X_RX_BIAS_FLYB_BUFF		0x30C7
+#define WCD937X_RX_BIAS_FLYB_MID_RST		0x30C8
+#define WCD937X_HPH_L_STATUS			0x30C9
+#define WCD937X_HPH_R_STATUS			0x30CA
+#define WCD937X_HPH_CNP_EN			0x30CB
+#define WCD937X_HPH_CNP_WG_CTL			0x30CC
+#define WCD937X_HPH_CNP_WG_TIME			0x30CD
+#define WCD937X_HPH_OCP_CTL			0x30CE
+#define WCD937X_HPH_AUTO_CHOP			0x30CF
+#define WCD937X_HPH_CHOP_CTL			0x30D0
+#define WCD937X_HPH_PA_CTL1			0x30D1
+#define WCD937X_HPH_PA_CTL2			0x30D2
+#define WCD937X_HPHPA_GND_R_MASK		BIT(6)
+#define WCD937X_HPHPA_GND_L_MASK		BIT(4)
+#define WCD937X_HPH_L_EN			0x30D3
+#define WCD937X_HPH_L_TEST			0x30D4
+#define WCD937X_HPH_L_ATEST			0x30D5
+#define WCD937X_HPH_R_EN			0x30D6
+#define WCD937X_GAIN_SRC_SEL_MASK		BIT(5)
+#define WCD937X_GAIN_SRC_SEL_REGISTER		1
+#define WCD937X_HPH_R_TEST			0x30D7
+#define WCD937X_HPH_R_ATEST			0x30D8
+#define WCD937X_HPH_RDAC_CLK_CTL1		0x30D9
+#define WCD937X_HPHPA_GND_OVR_MASK		BIT(1)
+#define WCD937X_CHOP_CLK_EN_MASK		BIT(7)
+#define WCD937X_HPH_RDAC_CLK_CTL2		0x30DA
+#define WCD937X_HPH_RDAC_LDO_CTL		0x30DB
+#define WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL	0x30DC
+#define WCD937X_HPH_REFBUFF_UHQA_CTL		0x30DD
+#define WCD937X_HPH_REFBUFF_LP_CTL		0x30DE
+#define WCD937X_PREREF_FLIT_BYPASS_MASK		BIT(0)
+#define WCD937X_HPH_L_DAC_CTL			0x30DF
+#define WCD937X_HPH_R_DAC_CTL			0x30E0
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL	0x30E1
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_EN	0x30E2
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1	0x30E3
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS	0x30E4
+#define WCD937X_EAR_EAR_EN_REG			0x30E9
+#define WCD937X_EAR_EAR_PA_CON			0x30EA
+#define WCD937X_EAR_EAR_SP_CON			0x30EB
+#define WCD937X_EAR_EAR_DAC_CON			0x30EC
+#define WCD937X_EAR_EAR_CNP_FSM_CON		0x30ED
+#define WCD937X_EAR_TEST_CTL			0x30EE
+#define WCD937X_EAR_STATUS_REG_1		0x30EF
+#define WCD937X_EAR_STATUS_REG_2		0x30F0
+#define WCD937X_ANA_NEW_PAGE_REGISTER		0x3100
+#define WCD937X_HPH_NEW_ANA_HPH2		0x3101
+#define WCD937X_HPH_NEW_ANA_HPH3		0x3102
+#define WCD937X_SLEEP_CTL			0x3103
+#define WCD937X_SLEEP_WATCHDOG_CTL		0x3104
+#define WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL	0x311F
+#define WCD937X_MBHC_NEW_CTL_1			0x3120
+#define WCD937X_MBHC_CTL_RCO_EN_MASK		BIT(7)
+#define WCD937X_MBHC_CTL_RCO_EN			BIT(7)
+#define WCD937X_MBHC_BTN_DBNC_MASK		GENMASK(1, 0)
+#define WCD937X_MBHC_BTN_DBNC_T_16_MS		0x2
+#define WCD937X_MBHC_NEW_CTL_2			0x3121
+#define WCD937X_MBHC_NEW_PLUG_DETECT_CTL	0x3122
+#define WCD937X_MBHC_NEW_ZDET_ANA_CTL		0x3123
+#define WCD937X_M_RTH_CTL_MASK			GENMASK(3, 2)
+#define WCD937X_MBHC_HS_VREF_CTL_MASK		GENMASK(1, 0)
+#define WCD937X_MBHC_HS_VREF_1P5_V		0x1
+#define WCD937X_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS	0x6
+#define WCD937X_ZDET_RANGE_CTL_MASK		GENMASK(3, 0)
+#define WCD937X_ZDET_MAXV_CTL_MASK		GENMASK(6, 4)
+#define WCD937X_MBHC_NEW_ZDET_RAMP_CTL		0x3124
+#define WCD937X_MBHC_NEW_FSM_STATUS		0x3125
+#define WCD937X_MBHC_NEW_ADC_RESULT		0x3126
+#define WCD937X_TX_NEW_TX_CH2_SEL		0x3127
+#define WCD937X_AUX_AUXPA			0x3128
+#define WCD937X_AUXPA_CLK_EN_MASK		BIT(4)
+#define WCD937X_AUXPA_CLK_EN_MASK		BIT(4)
+#define WCD937X_LDORXTX_MODE			0x3129
+#define WCD937X_LDORXTX_CONFIG			0x312A
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_EN	0x312C
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_OUT	0x312D
+#define WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL	0x3132
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L	0x3133
+#define WCD937X_HPH_NEW_INT_RDAC_VREF_CTL	0x3134
+#define WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL	0x3135
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R	0x3136
+#define WCD937X_HPH_NEW_INT_PA_MISC1		0x3137
+#define WCD937X_HPH_NEW_INT_PA_MISC2		0x3138
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC	0x3139
+#define WCD937X_HPH_NEW_INT_HPH_TIMER1		0x313A
+#define WCD937X_HPH_NEW_INT_HPH_TIMER2		0x313B
+#define WCD937X_HPH_NEW_INT_HPH_TIMER3		0x313C
+#define WCD937X_HPH_NEW_INT_HPH_TIMER4		0x313D
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC2	0x313E
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC3	0x313F
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI	0x3145
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP	0x3146
+#define WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP	0x3147
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL			0x31AF
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL			0x31B0
+#define WCD937X_MOISTURE_EN_POLLING_MASK	BIT(2)
+#define WCD937X_HSDET_PULLUP_C_MASK		GENMASK(4, 0)
+#define WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT	0x31B1
+#define WCD937X_MBHC_NEW_INT_SPARE_2		0x31B2
+#define WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON	0x31B7
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON1	0x31B8
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON2	0x31B9
+#define WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS	0x31BA
+#define WCD937X_AUX_INT_EN_REG			0x31BD
+#define WCD937X_AUX_INT_PA_CTRL			0x31BE
+#define WCD937X_AUX_INT_SP_CTRL			0x31BF
+#define WCD937X_AUX_INT_DAC_CTRL		0x31C0
+#define WCD937X_AUX_INT_CLK_CTRL		0x31C1
+#define WCD937X_AUX_INT_TEST_CTRL		0x31C2
+#define WCD937X_AUX_INT_STATUS_REG		0x31C3
+#define WCD937X_AUX_INT_MISC			0x31C4
+#define WCD937X_LDORXTX_INT_BIAS		0x31C5
+#define WCD937X_LDORXTX_INT_STB_LOADS_DTEST	0x31C6
+#define WCD937X_LDORXTX_INT_TEST0		0x31C7
+#define WCD937X_LDORXTX_INT_STARTUP_TIMER	0x31C8
+#define WCD937X_LDORXTX_INT_TEST1		0x31C9
+#define WCD937X_LDORXTX_INT_STATUS		0x31CA
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_1	0x31D0
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_2	0x31D1
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1	0x31D3
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2	0x31D4
+#define WCD937X_DIGITAL_PAGE_REGISTER		0x3400
+#define WCD937X_DIGITAL_CHIP_ID0		0x3401
+#define WCD937X_DIGITAL_CHIP_ID1		0x3402
+#define WCD937X_DIGITAL_CHIP_ID2		0x3403
+#define WCD937X_DIGITAL_CHIP_ID3		0x3404
+#define WCD937X_DIGITAL_CDC_RST_CTL		0x3406
+#define WCD937X_DIGITAL_TOP_CLK_CFG		0x3407
+#define WCD937X_DIGITAL_CDC_ANA_CLK_CTL		0x3408
+#define WCD937X_DIGITAL_CDC_DIG_CLK_CTL		0x3409
+#define WCD937X_DIGITAL_SWR_RST_EN		0x340A
+#define WCD937X_DIGITAL_CDC_PATH_MODE		0x340B
+#define WCD937X_DIGITAL_CDC_RX_RST		0x340C
+#define WCD937X_DIGITAL_CDC_RX0_CTL		0x340D
+#define WCD937X_DIGITAL_CDC_RX1_CTL		0x340E
+#define WCD937X_DIGITAL_CDC_RX2_CTL		0x340F
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA0	0x3410
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA1	0x3411
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA2	0x3412
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA3	0x3413
+#define WCD937X_DIGITAL_CDC_COMP_CTL_0		0x3414
+#define WCD937X_DIGITAL_CDC_RX_DELAY_CTL	0x3417
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_0	0x3418
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_1	0x3419
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_0	0x341A
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_1	0x341B
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_0	0x341C
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_1	0x341D
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_0	0x341E
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_1	0x341F
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_0	0x3420
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_1	0x3421
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A6_0	0x3422
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A7_0	0x3423
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_0		0x3424
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_1		0x3425
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_2		0x3426
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_3		0x3427
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R1		0x3428
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R2		0x3429
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R3		0x342A
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R4		0x342B
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R5		0x342C
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R6		0x342D
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R7		0x342E
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_0	0x342F
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_1	0x3430
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_0	0x3431
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_1	0x3432
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_0	0x3433
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_1	0x3434
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_0	0x3435
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_1	0x3436
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_0	0x3437
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_1	0x3438
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A6_0	0x3439
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A7_0	0x343A
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_0		0x343B
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_1		0x343C
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_2		0x343D
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_3		0x343E
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R1		0x343F
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R2		0x3440
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R3		0x3441
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R4		0x3442
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R5		0x3443
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R6		0x3444
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R7		0x3445
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0	0x3446
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1	0x3447
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0	0x3448
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1	0x3449
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2	0x344A
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0	0x344B
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1	0x344C
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2	0x344D
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_CTL	0x344E
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_CTL	0x344F
+#define WCD937X_DIGITAL_CDC_EAR_PATH_CTL	0x3450
+#define WCD937X_DIGITAL_CDC_SWR_CLH		0x3451
+#define WCD937X_DIGITAL_SWR_CLH_BYP		0x3452
+#define WCD937X_DIGITAL_CDC_TX0_CTL		0x3453
+#define WCD937X_DIGITAL_CDC_TX1_CTL		0x3454
+#define WCD937X_DIGITAL_CDC_TX2_CTL		0x3455
+#define WCD937X_DIGITAL_CDC_TX_RST		0x3456
+#define WCD937X_DIGITAL_CDC_REQ_CTL		0x3457
+#define WCD937X_DIGITAL_CDC_AMIC_CTL		0x345A
+#define WCD937X_DIGITAL_CDC_DMIC_CTL		0x345B
+#define WCD937X_DIGITAL_CDC_DMIC1_CTL		0x345C
+#define WCD937X_DIGITAL_CDC_DMIC2_CTL		0x345D
+#define WCD937X_DIGITAL_CDC_DMIC3_CTL		0x345E
+#define WCD937X_DIGITAL_EFUSE_CTL		0x345F
+#define WCD937X_DIGITAL_EFUSE_PRG_CTL		0x3460
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_0	0x3461
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_1	0x3462
+#define WCD937X_DIGITAL_EFUSE_T_DATA_0		0x3463
+#define WCD937X_DIGITAL_EFUSE_T_DATA_1		0x3464
+#define WCD937X_DIGITAL_PDM_WD_CTL0		0x3465
+#define WCD937X_DIGITAL_PDM_WD_CTL1		0x3466
+#define WCD937X_DIGITAL_PDM_WD_CTL2		0x3467
+#define WCD937X_DIGITAL_INTR_MODE		0x346A
+#define WCD937X_DIGITAL_INTR_MASK_0		0x346B
+#define WCD937X_DIGITAL_INTR_MASK_1		0x346C
+#define WCD937X_DIGITAL_INTR_MASK_2		0x346D
+#define WCD937X_DIGITAL_INTR_STATUS_0		0x346E
+#define WCD937X_DIGITAL_INTR_STATUS_1		0x346F
+#define WCD937X_DIGITAL_INTR_STATUS_2		0x3470
+#define WCD937X_DIGITAL_INTR_CLEAR_0		0x3471
+#define WCD937X_DIGITAL_INTR_CLEAR_1		0x3472
+#define WCD937X_DIGITAL_INTR_CLEAR_2		0x3473
+#define WCD937X_DIGITAL_INTR_LEVEL_0		0x3474
+#define WCD937X_DIGITAL_INTR_LEVEL_1		0x3475
+#define WCD937X_DIGITAL_INTR_LEVEL_2		0x3476
+#define WCD937X_DIGITAL_INTR_SET_0		0x3477
+#define WCD937X_DIGITAL_INTR_SET_1		0x3478
+#define WCD937X_DIGITAL_INTR_SET_2		0x3479
+#define WCD937X_DIGITAL_INTR_TEST_0		0x347A
+#define WCD937X_DIGITAL_INTR_TEST_1		0x347B
+#define WCD937X_DIGITAL_INTR_TEST_2		0x347C
+#define WCD937X_DIGITAL_CDC_CONN_RX0_CTL	0x347F
+#define WCD937X_DIGITAL_CDC_CONN_RX1_CTL	0x3480
+#define WCD937X_DIGITAL_CDC_CONN_RX2_CTL	0x3481
+#define WCD937X_DIGITAL_CDC_CONN_TX_CTL		0x3482
+#define WCD937X_DIGITAL_LOOP_BACK_MODE		0x3483
+#define WCD937X_DIGITAL_SWR_DAC_TEST		0x3484
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_0	0x3485
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_0	0x3491
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_1	0x3492
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_1	0x3493
+#define WCD937X_DIGITAL_SWR_HM_TEST		0x3494
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX0		0x3495
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX1		0x3496
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX0		0x3497
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX1		0x3498
+#define WCD937X_DIGITAL_PAD_INP_DIS_0		0x3499
+#define WCD937X_DIGITAL_PAD_INP_DIS_1		0x349A
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_0	0x349B
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_1	0x349C
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_2	0x349D
+#define WCD937X_DIGITAL_RX_DATA_EDGE_CTL	0x349E
+#define WCD937X_DIGITAL_TX_DATA_EDGE_CTL	0x349F
+#define WCD937X_DIGITAL_GPIO_MODE		0x34A0
+#define WCD937X_DIGITAL_PIN_CTL_OE		0x34A1
+#define WCD937X_DIGITAL_PIN_CTL_DATA_0		0x34A2
+#define WCD937X_DIGITAL_PIN_CTL_DATA_1		0x34A3
+#define WCD937X_DIGITAL_PIN_STATUS_0		0x34A4
+#define WCD937X_DIGITAL_PIN_STATUS_1		0x34A5
+#define WCD937X_DIGITAL_DIG_DEBUG_CTL		0x34A6
+#define WCD937X_DIGITAL_DIG_DEBUG_EN		0x34A7
+#define WCD937X_DIGITAL_ANA_CSR_DBG_ADD		0x34A8
+#define WCD937X_DIGITAL_ANA_CSR_DBG_CTL		0x34A9
+#define WCD937X_DIGITAL_SSP_DBG			0x34AA
+#define WCD937X_DIGITAL_MODE_STATUS_0		0x34AB
+#define WCD937X_DIGITAL_MODE_STATUS_1		0x34AC
+#define WCD937X_DIGITAL_SPARE_0			0x34AD
+#define WCD937X_DIGITAL_SPARE_1			0x34AE
+#define WCD937X_DIGITAL_SPARE_2			0x34AF
+#define WCD937X_DIGITAL_EFUSE_REG_0		0x34B0
+#define WCD937X_DIGITAL_EFUSE_REG_1		0x34B1
+#define WCD937X_DIGITAL_EFUSE_REG_2		0x34B2
+#define WCD937X_DIGITAL_EFUSE_REG_3		0x34B3
+#define WCD937X_DIGITAL_EFUSE_REG_4		0x34B4
+#define WCD937X_DIGITAL_EFUSE_REG_5		0x34B5
+#define WCD937X_DIGITAL_EFUSE_REG_6		0x34B6
+#define WCD937X_DIGITAL_EFUSE_REG_7		0x34B7
+#define WCD937X_DIGITAL_EFUSE_REG_8		0x34B8
+#define WCD937X_DIGITAL_EFUSE_REG_9		0x34B9
+#define WCD937X_DIGITAL_EFUSE_REG_10		0x34BA
+#define WCD937X_DIGITAL_EFUSE_REG_11		0x34BB
+#define WCD937X_DIGITAL_EFUSE_REG_12		0x34BC
+#define WCD937X_DIGITAL_EFUSE_REG_13		0x34BD
+#define WCD937X_DIGITAL_EFUSE_REG_14		0x34BE
+#define WCD937X_DIGITAL_EFUSE_REG_15		0x34BF
+#define WCD937X_DIGITAL_EFUSE_REG_16		0x34C0
+#define WCD937X_DIGITAL_EFUSE_REG_17		0x34C1
+#define WCD937X_DIGITAL_EFUSE_REG_18		0x34C2
+#define WCD937X_DIGITAL_EFUSE_REG_19		0x34C3
+#define WCD937X_DIGITAL_EFUSE_REG_20		0x34C4
+#define WCD937X_DIGITAL_EFUSE_REG_21		0x34C5
+#define WCD937X_DIGITAL_EFUSE_REG_22		0x34C6
+#define WCD937X_DIGITAL_EFUSE_REG_23		0x34C7
+#define WCD937X_DIGITAL_EFUSE_REG_24		0x34C8
+#define WCD937X_DIGITAL_EFUSE_REG_25		0x34C9
+#define WCD937X_DIGITAL_EFUSE_REG_26		0x34CA
+#define WCD937X_DIGITAL_EFUSE_REG_27		0x34CB
+#define WCD937X_DIGITAL_EFUSE_REG_28		0x34CC
+#define WCD937X_DIGITAL_EFUSE_REG_29		0x34CD
+#define WCD937X_DIGITAL_EFUSE_REG_30		0x34CE
+#define WCD937X_DIGITAL_EFUSE_REG_31		0x34CF
+#define WCD937X_MAX_REGISTER			(WCD937X_DIGITAL_EFUSE_REG_31)
+
+#define WCD937X_MAX_MICBIAS			3
+#define WCD937X_MAX_BULK_SUPPLY			4
+#define WCD937X_MAX_TX_SWR_PORTS		4
+#define WCD937X_MAX_SWR_PORTS			5
+#define WCD937X_MAX_SWR_CH_IDS			15
+
+struct wcd937x_sdw_ch_info {
+	int port_num;
+	unsigned int ch_mask;
+};
+
+#define WCD_SDW_CH(id, pn, cmask)	\
+	[id] = {			\
+		.port_num = pn,		\
+		.ch_mask = cmask,	\
+	}
+
+struct wcd937x_priv;
+struct wcd937x_sdw_priv {
+	struct sdw_slave *sdev;
+	struct sdw_stream_config sconfig;
+	struct sdw_stream_runtime *sruntime;
+	struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
+	const struct wcd937x_sdw_ch_info *ch_info;
+	bool port_enable[WCD937X_MAX_SWR_CH_IDS];
+	int active_ports;
+	bool is_tx;
+	struct wcd937x_priv *wcd937x;
+	struct irq_domain *slave_irq;
+	struct regmap *regmap;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD937X_SDW)
+int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd,
+		     struct snd_pcm_substream *substream,
+		     struct snd_soc_dai *dai);
+int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd,
+			       struct snd_soc_dai *dai,
+			       void *stream, int direction);
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+			  struct snd_pcm_substream *substream,
+			  struct snd_pcm_hw_params *params,
+			  struct snd_soc_dai *dai);
+
+struct device *wcd937x_sdw_device_get(struct device_node *np);
+
+#else
+int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd,
+		     struct snd_pcm_substream *substream,
+		     struct snd_soc_dai *dai)
+{
+	return -EOPNOTSUPP;
+}
+
+int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd,
+			       struct snd_soc_dai *dai,
+			       void *stream, int direction)
+{
+	return -EOPNOTSUPP;
+}
+
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+			  struct snd_pcm_substream *substream,
+			  struct snd_pcm_hw_params *params,
+			  struct snd_soc_dai *dai)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
+enum {
+	/* INTR_CTRL_INT_MASK_0 */
+	WCD937X_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+	WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET,
+	WCD937X_IRQ_MBHC_ELECT_INS_REM_DET,
+	WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	WCD937X_IRQ_MBHC_SW_DET,
+	WCD937X_IRQ_HPHR_OCP_INT,
+	WCD937X_IRQ_HPHR_CNP_INT,
+	WCD937X_IRQ_HPHL_OCP_INT,
+
+	/* INTR_CTRL_INT_MASK_1 */
+	WCD937X_IRQ_HPHL_CNP_INT,
+	WCD937X_IRQ_EAR_CNP_INT,
+	WCD937X_IRQ_EAR_SCD_INT,
+	WCD937X_IRQ_AUX_CNP_INT,
+	WCD937X_IRQ_AUX_SCD_INT,
+	WCD937X_IRQ_HPHL_PDM_WD_INT,
+	WCD937X_IRQ_HPHR_PDM_WD_INT,
+	WCD937X_IRQ_AUX_PDM_WD_INT,
+
+	/* INTR_CTRL_INT_MASK_2 */
+	WCD937X_IRQ_LDORT_SCD_INT,
+	WCD937X_IRQ_MBHC_MOISTURE_INT,
+	WCD937X_IRQ_HPHL_SURGE_DET_INT,
+	WCD937X_IRQ_HPHR_SURGE_DET_INT,
+	WCD937X_NUM_IRQS,
+};
+
+enum wcd937x_tx_sdw_ports {
+	WCD937X_ADC_1_PORT = 1,
+	WCD937X_ADC_2_3_PORT,
+	WCD937X_DMIC_0_3_MBHC_PORT,
+	WCD937X_DMIC_4_6_PORT,
+};
+
+enum wcd937x_tx_sdw_channels {
+	WCD937X_ADC1,
+	WCD937X_ADC2,
+	WCD937X_ADC3,
+	WCD937X_DMIC0,
+	WCD937X_DMIC1,
+	WCD937X_MBHC,
+	WCD937X_DMIC2,
+	WCD937X_DMIC3,
+	WCD937X_DMIC4,
+	WCD937X_DMIC5,
+	WCD937X_DMIC6,
+};
+
+enum wcd937x_rx_sdw_ports {
+	WCD937X_HPH_PORT = 1,
+	WCD937X_CLSH_PORT,
+	WCD937X_COMP_PORT,
+	WCD937X_LO_PORT,
+	WCD937X_DSD_PORT,
+};
+
+enum wcd937x_rx_sdw_channels {
+	WCD937X_HPH_L,
+	WCD937X_HPH_R,
+	WCD937X_CLSH,
+	WCD937X_COMP_L,
+	WCD937X_COMP_R,
+	WCD937X_LO,
+	WCD937X_DSD_R,
+	WCD937X_DSD_L,
+};
+
+#endif
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index a1f04010da95f60278071292254d4f3489a40bba..c995bcc59eadb4f2c726267b48044bb3dc6e8c93 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -21,7 +21,7 @@
 
 #define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
 
-static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
+static const struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
 	WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
 	WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
 	WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
@@ -32,7 +32,7 @@ static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
 	WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
 };
 
-static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
+static const struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
 	WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
 	WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
 	WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 6021aa5a56891969b04db64ac019bafb0766c701..12b32d5dc5807bedd3d9fc5800ffc45d77e11510 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -206,7 +206,6 @@ struct wcd938x_priv {
 	bool comp1_enable;
 	bool comp2_enable;
 	bool ldoh;
-	bool bcs_dis;
 };
 
 static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
@@ -222,7 +221,7 @@ struct wcd938x_mbhc_zdet_param {
 	u16 btn7;
 };
 
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
 	WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD938X_ANA_MBHC_MECH, 0x80),
 	WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD938X_ANA_MBHC_MECH, 0x40),
 	WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD938X_ANA_MBHC_MECH, 0x20),
@@ -419,7 +418,7 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
 
 }
 
-static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
+static int wcd938x_sdw_connect_port(const struct wcd938x_sdw_ch_info *ch_info,
 				    struct sdw_port_config *port_config,
 				    u8 enable)
 {
@@ -1650,31 +1649,6 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
-	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
-	ucontrol->value.integer.value[0] = wcd938x->bcs_dis;
-
-	return 0;
-}
-
-static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
-	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
-	if (wcd938x->bcs_dis == ucontrol->value.integer.value[0])
-		return 0;
-
-	wcd938x->bcs_dis = ucontrol->value.integer.value[0];
-
-	return 1;
-}
-
 static const char * const tx_mode_mux_text_wcd9380[] = {
 	"ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
 };
@@ -1982,7 +1956,7 @@ static bool wcd938x_mbhc_micb_en_status(struct snd_soc_component *component, int
 	if (micb_num == MIC_BIAS_2) {
 		val = snd_soc_component_read_field(component,
 						   WCD938X_ANA_MICB2,
-						   WCD938X_ANA_MICB2_ENABLE_MASK);
+						   WCD938X_MICB_EN_MASK);
 		if (val == WCD938X_MICB_ENABLE)
 			return true;
 	}
@@ -2695,8 +2669,6 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
 		       wcd938x_get_swr_port, wcd938x_set_swr_port),
 	SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0,
 		       wcd938x_ldoh_get, wcd938x_ldoh_put),
-	SOC_SINGLE_EXT("ADC2_BCS Disable Switch", SND_SOC_NOPM, 0, 1, 0,
-		       wcd938x_bcs_get, wcd938x_bcs_put),
 
 	SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain),
@@ -3055,7 +3027,7 @@ static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static struct irq_chip wcd_irq_chip = {
+static const struct irq_chip wcd_irq_chip = {
 	.name = "WCD938x",
 };
 
diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h
index 74b1498fec38b621a2561de95648379f9acb5993..b2ad98026ae2cd302bb1336ddc4474d4795952c5 100644
--- a/sound/soc/codecs/wcd938x.h
+++ b/sound/soc/codecs/wcd938x.h
@@ -75,9 +75,6 @@
 #define WCD938X_MICB_PULL_UP			2
 #define WCD938X_MICB_PULL_DOWN			3
 #define WCD938X_ANA_MICB2                       (0x3023)
-#define WCD938X_ANA_MICB2_ENABLE		BIT(6)
-#define WCD938X_ANA_MICB2_ENABLE_MASK		GENMASK(7, 6)
-#define WCD938X_ANA_MICB2_VOUT_MASK		GENMASK(5, 0)
 #define WCD938X_ANA_MICB2_RAMP                  (0x3024)
 #define WCD938X_RAMP_EN_MASK			BIT(7)
 #define WCD938X_RAMP_SHIFT_CTRL_MASK		GENMASK(4, 2)
@@ -645,10 +642,6 @@ enum wcd938x_rx_sdw_channels {
 	WCD938X_DSD_R,
 	WCD938X_DSD_L,
 };
-enum {
-	WCD938X_SDW_DIR_RX,
-	WCD938X_SDW_DIR_TX,
-};
 
 struct wcd938x_priv;
 struct wcd938x_sdw_priv {
@@ -656,10 +649,9 @@ struct wcd938x_sdw_priv {
 	struct sdw_stream_config sconfig;
 	struct sdw_stream_runtime *sruntime;
 	struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS];
-	struct wcd938x_sdw_ch_info *ch_info;
+	const struct wcd938x_sdw_ch_info *ch_info;
 	bool port_enable[WCD938X_MAX_SWR_CH_IDS];
 	int active_ports;
-	int num_ports;
 	bool is_tx;
 	struct wcd938x_priv *wcd938x;
 	struct irq_domain *slave_irq;
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
index 8acb5651c5bca84c8a57836300ddc59fa3e91289..94b1e99a3ca0ecdb16a8dd73b2b07ee54564dd50 100644
--- a/sound/soc/codecs/wcd939x-sdw.c
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -23,7 +23,7 @@
 
 #define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
 
-static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
+static const struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
 	WCD_SDW_CH(WCD939X_HPH_L, WCD939X_HPH_PORT, BIT(0)),
 	WCD_SDW_CH(WCD939X_HPH_R, WCD939X_HPH_PORT, BIT(1)),
 	WCD_SDW_CH(WCD939X_CLSH, WCD939X_CLSH_PORT, BIT(0)),
@@ -36,7 +36,7 @@ static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
 	WCD_SDW_CH(WCD939X_HIFI_PCM_R, WCD939X_HIFI_PCM_PORT, BIT(1)),
 };
 
-static struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = {
+static const struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = {
 	WCD_SDW_CH(WCD939X_ADC1, WCD939X_ADC_1_4_PORT, BIT(0)),
 	WCD_SDW_CH(WCD939X_ADC2, WCD939X_ADC_1_4_PORT, BIT(1)),
 	WCD_SDW_CH(WCD939X_ADC3, WCD939X_ADC_1_4_PORT, BIT(2)),
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index c49894aad8a543e83647e33b780db16ce5cbd9ac..68fc591670dc84b340be5bb89e16e4ab45c40591 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -85,7 +85,6 @@ enum {
 #define WCD939X_MBHC_GET_X1(x)		((x) & 0x3FFF)
 
 /* Z value compared in milliOhm */
-#define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false
 #define WCD939X_ANA_MBHC_ZDET_CONST	(1018 * 1024)
 
 enum {
@@ -182,8 +181,6 @@ struct wcd939x_priv {
 	/* typec handling */
 	bool typec_analog_mux;
 #if IS_ENABLED(CONFIG_TYPEC)
-	struct typec_mux_dev *typec_mux;
-	struct typec_switch_dev *typec_sw;
 	enum typec_orientation typec_orientation;
 	unsigned long typec_mode;
 	struct typec_switch *typec_switch;
@@ -221,7 +218,7 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
 
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
 	WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80),
 	WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40),
 	WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20),
@@ -292,7 +289,7 @@ static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = {
 	REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
 };
 
-static struct regmap_irq_chip wcd939x_regmap_irq_chip = {
+static const struct regmap_irq_chip wcd939x_regmap_irq_chip = {
 	.name = "wcd939x",
 	.irqs = wcd939x_irqs,
 	.num_irqs = ARRAY_SIZE(wcd939x_irqs),
@@ -415,7 +412,7 @@ static int wcd939x_io_init(struct snd_soc_component *component)
 	return 0;
 }
 
-static int wcd939x_sdw_connect_port(struct wcd939x_sdw_ch_info *ch_info,
+static int wcd939x_sdw_connect_port(const struct wcd939x_sdw_ch_info *ch_info,
 				    struct sdw_port_config *port_config,
 				    u8 enable)
 {
@@ -525,7 +522,7 @@ static int wcd939x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
 						      WCD939X_DIGITAL_CDC_COMP_CTL_0,
 						      WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN,
 						      true);
-			 /* 5msec compander delay as per HW requirement */
+			/* 5msec compander delay as per HW requirement */
 			if (!wcd939x->comp2_enable ||
 			    snd_soc_component_read_field(component,
 							 WCD939X_DIGITAL_CDC_COMP_CTL_0,
@@ -1268,25 +1265,20 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
 {
 	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
 	int micb_index = micb_num - 1;
-	u16 micb_field;
 	u16 micb_reg;
 
 	switch (micb_num) {
 	case MIC_BIAS_1:
 		micb_reg = WCD939X_ANA_MICB1;
-		micb_field = WCD939X_MICB1_ENABLE;
 		break;
 	case MIC_BIAS_2:
 		micb_reg = WCD939X_ANA_MICB2;
-		micb_field = WCD939X_MICB2_ENABLE;
 		break;
 	case MIC_BIAS_3:
 		micb_reg = WCD939X_ANA_MICB3;
-		micb_field = WCD939X_MICB3_ENABLE;
 		break;
 	case MIC_BIAS_4:
 		micb_reg = WCD939X_ANA_MICB4;
-		micb_field = WCD939X_MICB4_ENABLE;
 		break;
 	default:
 		dev_err(component->dev, "%s: Invalid micbias number: %d\n",
@@ -1300,7 +1292,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
 		if (wcd939x->pullup_ref[micb_index] == 1 &&
 		    wcd939x->micb_ref[micb_index] == 0)
 			snd_soc_component_write_field(component, micb_reg,
-						      micb_field, MICB_BIAS_PULL_UP);
+						      WCD939X_MICB_ENABLE,
+						      MICB_BIAS_PULL_UP);
 		break;
 	case MICB_PULLUP_DISABLE:
 		if (wcd939x->pullup_ref[micb_index] > 0)
@@ -1308,7 +1301,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
 		if (wcd939x->pullup_ref[micb_index] == 0 &&
 		    wcd939x->micb_ref[micb_index] == 0)
 			snd_soc_component_write_field(component, micb_reg,
-						      micb_field, MICB_BIAS_DISABLE);
+						      WCD939X_MICB_ENABLE,
+						      MICB_BIAS_DISABLE);
 		break;
 	case MICB_ENABLE:
 		wcd939x->micb_ref[micb_index]++;
@@ -1345,7 +1339,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
 			snd_soc_component_write_field(component,
 						WCD939X_MICB4_TEST_CTL_2,
 						WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true);
-			snd_soc_component_write_field(component, micb_reg, micb_field,
+			snd_soc_component_write_field(component, micb_reg,
+						      WCD939X_MICB_ENABLE,
 						      MICB_BIAS_ENABLE);
 			if (micb_num == MIC_BIAS_2)
 				wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
@@ -1362,7 +1357,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
 		if (wcd939x->micb_ref[micb_index] == 0 &&
 		    wcd939x->pullup_ref[micb_index] > 0)
 			snd_soc_component_write_field(component, micb_reg,
-						      micb_field, MICB_BIAS_PULL_UP);
+						      WCD939X_MICB_ENABLE,
+						      MICB_BIAS_PULL_UP);
 		else if (wcd939x->micb_ref[micb_index] == 0 &&
 			 wcd939x->pullup_ref[micb_index] == 0) {
 			if (micb_num  == MIC_BIAS_2)
@@ -1370,7 +1366,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
 						      WCD_EVENT_PRE_MICBIAS_2_OFF);
 
 			snd_soc_component_write_field(component, micb_reg,
-						      micb_field, MICB_BIAS_DISABLE);
+						      WCD939X_MICB_ENABLE,
+						      MICB_BIAS_DISABLE);
 			if (micb_num  == MIC_BIAS_2)
 				wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
 						      WCD_EVENT_POST_MICBIAS_2_OFF);
@@ -1869,11 +1866,10 @@ static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component,
 
 static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
 {
-
 	if (micb_num == MIC_BIAS_2) {
 		u8 val;
 
-		val = FIELD_GET(WCD939X_MICB2_ENABLE,
+		val = FIELD_GET(WCD939X_MICB_ENABLE,
 				snd_soc_component_read(component, WCD939X_ANA_MICB2));
 		if (val == MICB_BIAS_ENABLE)
 			return true;
@@ -1935,7 +1931,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
 					    int req_volt, int micb_num)
 {
 	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
-	unsigned int micb_en_field, micb_vout_ctl_field;
 	unsigned int micb_reg, cur_vout_ctl, micb_en;
 	int req_vout_ctl;
 	int ret = 0;
@@ -1943,23 +1938,15 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
 	switch (micb_num) {
 	case MIC_BIAS_1:
 		micb_reg = WCD939X_ANA_MICB1;
-		micb_en_field = WCD939X_MICB1_ENABLE;
-		micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL;
 		break;
 	case MIC_BIAS_2:
 		micb_reg = WCD939X_ANA_MICB2;
-		micb_en_field = WCD939X_MICB2_ENABLE;
-		micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL;
 		break;
 	case MIC_BIAS_3:
 		micb_reg = WCD939X_ANA_MICB3;
-		micb_en_field = WCD939X_MICB3_ENABLE;
-		micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL;
 		break;
 	case MIC_BIAS_4:
 		micb_reg = WCD939X_ANA_MICB4;
-		micb_en_field = WCD939X_MICB4_ENABLE;
-		micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL;
 		break;
 	default:
 		return -EINVAL;
@@ -1975,9 +1962,9 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
 	 * micbias.
 	 */
 	micb_en = snd_soc_component_read_field(component, micb_reg,
-					       micb_en_field);
+					       WCD939X_MICB_ENABLE);
 	cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
-						    micb_vout_ctl_field);
+						    WCD939X_MICB_VOUT_CTL);
 
 	req_vout_ctl = wcd939x_get_micb_vout_ctl_val(req_volt);
 	if (req_vout_ctl < 0) {
@@ -1996,14 +1983,16 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
 
 	if (micb_en == MICB_BIAS_ENABLE)
 		snd_soc_component_write_field(component, micb_reg,
-					      micb_en_field, MICB_BIAS_PULL_DOWN);
+					      WCD939X_MICB_ENABLE,
+					      MICB_BIAS_PULL_DOWN);
 
 	snd_soc_component_write_field(component, micb_reg,
-				      micb_vout_ctl_field, req_vout_ctl);
+				      WCD939X_MICB_VOUT_CTL, req_vout_ctl);
 
 	if (micb_en == MICB_BIAS_ENABLE) {
 		snd_soc_component_write_field(component, micb_reg,
-					      micb_en_field, MICB_BIAS_ENABLE);
+					      WCD939X_MICB_ENABLE,
+					      MICB_BIAS_ENABLE);
 		/*
 		 * Add 2ms delay as per HW requirement after enabling
 		 * micbias
@@ -2916,13 +2905,13 @@ static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x)
 		return -EINVAL;
 
 	regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1,
-			   WCD939X_MICB1_VOUT_CTL, vout_ctl_1);
+			   WCD939X_MICB_VOUT_CTL, vout_ctl_1);
 	regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2,
-			   WCD939X_MICB2_VOUT_CTL, vout_ctl_2);
+			   WCD939X_MICB_VOUT_CTL, vout_ctl_2);
 	regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3,
-			   WCD939X_MICB3_VOUT_CTL, vout_ctl_3);
+			   WCD939X_MICB_VOUT_CTL, vout_ctl_3);
 	regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4,
-			   WCD939X_MICB4_VOUT_CTL, vout_ctl_4);
+			   WCD939X_MICB_VOUT_CTL, vout_ctl_4);
 
 	return 0;
 }
@@ -2966,7 +2955,7 @@ static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data)
  *     \- regmap_irq_thread()
  *         \- handle_nested_irq(i)
  */
-static struct irq_chip wcd_irq_chip = {
+static const struct irq_chip wcd_irq_chip = {
 	.name = "WCD939x",
 };
 
@@ -3528,6 +3517,68 @@ static const struct component_master_ops wcd939x_comp_ops = {
 	.unbind = wcd939x_unbind,
 };
 
+static void __maybe_unused wcd939x_typec_mux_unregister(void *data)
+{
+	struct typec_mux_dev *typec_mux = data;
+
+	typec_mux_unregister(typec_mux);
+}
+
+static void __maybe_unused wcd939x_typec_switch_unregister(void *data)
+{
+	struct typec_switch_dev *typec_sw = data;
+
+	typec_switch_unregister(typec_sw);
+}
+
+static int wcd939x_add_typec(struct wcd939x_priv *wcd939x, struct device *dev)
+{
+#if IS_ENABLED(CONFIG_TYPEC)
+	int ret;
+	struct typec_mux_dev *typec_mux;
+	struct typec_switch_dev *typec_sw;
+	struct typec_mux_desc mux_desc = {
+		.drvdata = wcd939x,
+		.fwnode = dev_fwnode(dev),
+		.set = wcd939x_typec_mux_set,
+	};
+	struct typec_switch_desc sw_desc = {
+		.drvdata = wcd939x,
+		.fwnode = dev_fwnode(dev),
+		.set = wcd939x_typec_switch_set,
+	};
+
+	/*
+	 * Is USBSS is used to mux analog lines,
+	 * register a typec mux/switch to get typec events
+	 */
+	if (!wcd939x->typec_analog_mux)
+		return 0;
+
+	typec_mux = typec_mux_register(dev, &mux_desc);
+	if (IS_ERR(typec_mux))
+		return dev_err_probe(dev, PTR_ERR(typec_mux),
+				     "failed to register typec mux\n");
+
+	ret = devm_add_action_or_reset(dev, wcd939x_typec_mux_unregister,
+				       typec_mux);
+	if (ret)
+		return ret;
+
+	typec_sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(typec_sw))
+		return dev_err_probe(dev, PTR_ERR(typec_sw),
+				     "failed to register typec switch\n");
+
+	ret = devm_add_action_or_reset(dev, wcd939x_typec_switch_unregister,
+				       typec_sw);
+	if (ret)
+		return ret;
+#endif
+
+	return 0;
+}
+
 static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x,
 					struct device *dev,
 					struct component_match **matchptr)
@@ -3576,42 +3627,13 @@ static int wcd939x_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-#if IS_ENABLED(CONFIG_TYPEC)
-	/*
-	 * Is USBSS is used to mux analog lines,
-	 * register a typec mux/switch to get typec events
-	 */
-	if (wcd939x->typec_analog_mux) {
-		struct typec_mux_desc mux_desc = {
-			.drvdata = wcd939x,
-			.fwnode = dev_fwnode(dev),
-			.set = wcd939x_typec_mux_set,
-		};
-		struct typec_switch_desc sw_desc = {
-			.drvdata = wcd939x,
-			.fwnode = dev_fwnode(dev),
-			.set = wcd939x_typec_switch_set,
-		};
-
-		wcd939x->typec_mux = typec_mux_register(dev, &mux_desc);
-		if (IS_ERR(wcd939x->typec_mux)) {
-			ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux),
-					    "failed to register typec mux\n");
-			goto err_disable_regulators;
-		}
-
-		wcd939x->typec_sw = typec_switch_register(dev, &sw_desc);
-		if (IS_ERR(wcd939x->typec_sw)) {
-			ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw),
-					    "failed to register typec switch\n");
-			goto err_unregister_typec_mux;
-		}
-	}
-#endif /* CONFIG_TYPEC */
+	ret = wcd939x_add_typec(wcd939x, dev);
+	if (ret)
+		goto err_disable_regulators;
 
 	ret = wcd939x_add_slave_components(wcd939x, dev, &match);
 	if (ret)
-		goto err_unregister_typec_switch;
+		goto err_disable_regulators;
 
 	wcd939x_reset(wcd939x);
 
@@ -3628,18 +3650,6 @@ static int wcd939x_probe(struct platform_device *pdev)
 
 	return 0;
 
-#if IS_ENABLED(CONFIG_TYPEC)
-err_unregister_typec_mux:
-	if (wcd939x->typec_analog_mux)
-		typec_mux_unregister(wcd939x->typec_mux);
-#endif /* CONFIG_TYPEC */
-
-err_unregister_typec_switch:
-#if IS_ENABLED(CONFIG_TYPEC)
-	if (wcd939x->typec_analog_mux)
-		typec_switch_unregister(wcd939x->typec_sw);
-#endif /* CONFIG_TYPEC */
-
 err_disable_regulators:
 	regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies);
 	regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies);
diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h
index 807cf3113d204afd141c73abbb5773cf40a7a0a9..1571c2120cfcb521e2232719444a9a86971e9ad6 100644
--- a/sound/soc/codecs/wcd939x.h
+++ b/sound/soc/codecs/wcd939x.h
@@ -91,11 +91,9 @@
 #define WCD939X_ANA_MBHC_BTN7				   (0x3021)
 #define WCD939X_MBHC_BTN7_VTH	GENMASK(7, 2)
 #define WCD939X_ANA_MICB1				   (0x3022)
-#define WCD939X_MICB1_ENABLE	GENMASK(7, 6)
-#define WCD939X_MICB1_VOUT_CTL	GENMASK(5, 0)
+#define WCD939X_MICB_ENABLE	GENMASK(7, 6)
+#define WCD939X_MICB_VOUT_CTL	GENMASK(5, 0)
 #define WCD939X_ANA_MICB2				   (0x3023)
-#define WCD939X_MICB2_ENABLE	GENMASK(7, 6)
-#define WCD939X_MICB2_VOUT_CTL	GENMASK(5, 0)
 #define WCD939X_ANA_MICB2_RAMP				   (0x3024)
 #define WCD939X_MICB2_RAMP_RAMP_ENABLE	BIT(7)
 #define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE	BIT(6)
@@ -103,11 +101,7 @@
 #define WCD939X_MICB2_RAMP_SHIFT_CTL	GENMASK(4, 2)
 #define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP	GENMASK(1, 0)
 #define WCD939X_ANA_MICB3				   (0x3025)
-#define WCD939X_MICB3_ENABLE	GENMASK(7, 6)
-#define WCD939X_MICB3_VOUT_CTL	GENMASK(5, 0)
 #define WCD939X_ANA_MICB4				   (0x3026)
-#define WCD939X_MICB4_ENABLE	GENMASK(7, 6)
-#define WCD939X_MICB4_VOUT_CTL	GENMASK(5, 0)
 #define WCD939X_BIAS_CTL				   (0x3028)
 #define WCD939X_BIAS_VBG_FINE_ADJ			   (0x3029)
 #define WCD939X_LDOL_VDDCX_ADJUST			   (0x3040)
@@ -909,21 +903,15 @@ enum wcd939x_rx_sdw_channels {
 	WCD939X_HIFI_PCM_R,
 };
 
-enum {
-	WCD939X_SDW_DIR_RX,
-	WCD939X_SDW_DIR_TX,
-};
-
 struct wcd939x_priv;
 struct wcd939x_sdw_priv {
 	struct sdw_slave *sdev;
 	struct sdw_stream_config sconfig;
 	struct sdw_stream_runtime *sruntime;
 	struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS];
-	struct wcd939x_sdw_ch_info *ch_info;
+	const struct wcd939x_sdw_ch_info *ch_info;
 	bool port_enable[WCD939X_MAX_SWR_CH_IDS];
 	int active_ports;
-	int num_ports;
 	bool is_tx;
 	struct wcd939x_priv *wcd939x;
 	struct irq_domain *slave_irq;
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 8f862729a2ca6d671198debfbe989d5ef1cd4658..edd2cb185c42cfd3ac446b32ca7577e636744b76 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -115,14 +115,6 @@ struct wm0010_priv {
 	struct completion boot_completion;
 };
 
-struct wm0010_spi_msg {
-	struct spi_message m;
-	struct spi_transfer t;
-	u8 *tx_buf;
-	u8 *rx_buf;
-	size_t len;
-};
-
 static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("CLKIN",  SND_SOC_NOPM, 0, 0, NULL, 0),
 };
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 68d2d6444533f5d2f602dbe81fbf54b00979c4c2..9f8549b34e30254dc9831300b1495e58f2158d5c 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -601,7 +601,7 @@ static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
 		return -EINVAL;
 	}
 
-	switch (cs_dsp->fw_ver) {
+	switch (cs_dsp->wmfw_ver) {
 	case 0:
 	case 1:
 		ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 1253695bebd863cab4accfef0616250fb3006830..0478599d0f359f2fbd64bc353e7b179b90adafd2 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -634,7 +634,7 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
 	}
 }
 
-static struct regmap_config wsa881x_regmap_config = {
+static const struct regmap_config wsa881x_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 8,
 	.cache_type = REGCACHE_MAPLE,
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index a2e86ef7d18f5981b4604372e4b20930695aa5c4..d0ab4e2290b6a9f049a95534cbe7673b9c1ae594 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -9,7 +9,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/printk.h>
 #include <linux/regmap.h>
@@ -935,7 +934,7 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
 	return wsa883x_readonly_register(dev, reg);
 }
 
-static struct regmap_config wsa883x_regmap_config = {
+static const struct regmap_config wsa883x_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 8,
 	.cache_type = REGCACHE_MAPLE,
@@ -1399,6 +1398,14 @@ static int wsa883x_probe(struct sdw_slave *pdev,
 	wsa883x->sconfig.direction = SDW_DATA_DIR_RX;
 	wsa883x->sconfig.type = SDW_STREAM_PDM;
 
+	/**
+	 * Port map index starts with 0, however the data port for this codec
+	 * are from index 1
+	 */
+	if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1],
+					WSA883X_MAX_SWR_PORTS))
+		dev_dbg(dev, "Static Port mapping not specified\n");
+
 	pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0);
 	pdev->prop.simple_clk_stop_capable = true;
 	pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index a9767ef0e39d158a1a58929f6e85762499530568..d17ae17b2938b40ee4bb50bbacaad834e6ff4751 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -1319,7 +1319,7 @@ static bool wsa884x_volatile_register(struct device *dev, unsigned int reg)
 	return wsa884x_readonly_register(dev, reg);
 }
 
-static struct regmap_config wsa884x_regmap_config = {
+static const struct regmap_config wsa884x_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 8,
 	.cache_type = REGCACHE_MAPLE,
@@ -1887,6 +1887,14 @@ static int wsa884x_probe(struct sdw_slave *pdev,
 	wsa884x->sconfig.direction = SDW_DATA_DIR_RX;
 	wsa884x->sconfig.type = SDW_STREAM_PDM;
 
+	/**
+	 * Port map index starts with 0, however the data port for this codec
+	 * are from index 1
+	 */
+	if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1],
+					WSA884X_MAX_SWR_PORTS))
+		dev_dbg(dev, "Static Port mapping not specified\n");
+
 	pdev->prop.sink_ports = GENMASK(WSA884X_MAX_SWR_PORTS, 0);
 	pdev->prop.simple_clk_stop_capable = true;
 	pdev->prop.sink_dpn_prop = wsa884x_sink_dpn_prop;
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 270726c134b3d0aa09ede9c36248ccfc1b78b70e..e283751abfefe897aae87217a2c9804869e2e420 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -103,6 +103,7 @@ config SND_SOC_FSL_XCVR
 	select REGMAP_MMIO
 	select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
 	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select SND_SOC_FSL_UTILS
 	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,
@@ -130,6 +131,13 @@ config SND_SOC_FSL_RPMSG
 	  This option is only useful for out-of-tree drivers since
 	  in-tree drivers select it automatically.
 
+config SND_SOC_FSL_LPC3XXX
+	tristate "SoC Audio for NXP LPC32XX CPUs"
+	depends on ARCH_LPC32XX || COMPILE_TEST
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y or M if you want to add support for the LPC3XXX I2S interface.
+
 config SND_SOC_IMX_PCM_DMA
 	tristate
 	select SND_SOC_GENERIC_DMAENGINE_PCM
@@ -295,15 +303,6 @@ config SND_SOC_IMX_SGTL5000
 	  SND_SOC_FSL_ASOC_CARD and SND_SOC_SGTL5000 to use the newer
 	  driver.
 
-config SND_SOC_IMX_SPDIF
-	tristate "SoC Audio support for i.MX boards with S/PDIF"
-	select SND_SOC_IMX_PCM_DMA
-	select SND_SOC_FSL_SPDIF
-	help
-	  SoC Audio support for i.MX boards with S/PDIF
-	  Say Y if you want to add support for SoC audio on an i.MX board with
-	  a S/DPDIF.
-
 config SND_SOC_FSL_ASOC_CARD
 	tristate "Generic ASoC Sound Card with ASRC support"
 	depends on OF && I2C
@@ -315,6 +314,7 @@ config SND_SOC_FSL_ASOC_CARD
 	select SND_SOC_FSL_ESAI
 	select SND_SOC_FSL_SAI
 	select SND_SOC_FSL_SSI
+	select SND_SOC_FSL_SPDIF
 	select SND_SOC_TLV320AIC31XX
 	select SND_SOC_WM8994
 	select MFD_WM8994
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 2fe78eed3a4893e8bb51dc4ffab73b88401edacb..ad97244b5cc3bbc2bd1a2aec3bebb0f4062e1714 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 snd-soc-fsl-audmix-y := fsl_audmix.o
 snd-soc-fsl-asoc-card-y := fsl-asoc-card.o
 snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o
+snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o
 snd-soc-fsl-sai-y := fsl_sai.o
 snd-soc-fsl-ssi-y := fsl_ssi.o
 snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
@@ -29,6 +30,7 @@ snd-soc-fsl-qmc-audio-y := fsl_qmc_audio.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
 obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
+obj-$(CONFIG_SND_SOC_FSL_LPC3XXX) += snd-soc-fsl-lpc3xxx.o
 obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
 obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
@@ -65,7 +67,6 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_RPMSG) += imx-pcm-rpmsg.o
 snd-soc-eukrea-tlv320-y := eukrea-tlv320.o
 snd-soc-imx-es8328-y := imx-es8328.o
 snd-soc-imx-sgtl5000-y := imx-sgtl5000.o
-snd-soc-imx-spdif-y := imx-spdif.o
 snd-soc-imx-audmix-y := imx-audmix.o
 snd-soc-imx-hdmi-y := imx-hdmi.o
 snd-soc-imx-rpmsg-y := imx-rpmsg.o
@@ -74,7 +75,6 @@ snd-soc-imx-card-y := imx-card.o
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.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_AUDMIX) += snd-soc-imx-audmix.o
 obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
 obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index eb67689dcd6e62f8756c3ec74bd9f01d06f98417..82df887b3af5ed4236904cffc880f54982673bf4 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -99,7 +99,7 @@ struct fsl_asoc_card_priv {
 	struct simple_util_jack hp_jack;
 	struct simple_util_jack mic_jack;
 	struct platform_device *pdev;
-	struct codec_priv codec_priv;
+	struct codec_priv codec_priv[2];
 	struct cpu_priv cpu_priv;
 	struct snd_soc_card card;
 	u8 streams;
@@ -172,10 +172,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-	struct codec_priv *codec_priv = &priv->codec_priv;
+	struct codec_priv *codec_priv;
+	struct snd_soc_dai *codec_dai;
 	struct cpu_priv *cpu_priv = &priv->cpu_priv;
 	struct device *dev = rtd->card->dev;
 	unsigned int pll_out;
+	int codec_idx;
 	int ret;
 
 	priv->sample_rate = params_rate(params);
@@ -208,28 +210,32 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* Specific configuration for PLL */
-	if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
-		if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
-			pll_out = priv->sample_rate * 384;
-		else
-			pll_out = priv->sample_rate * 256;
+	for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+		codec_priv = &priv->codec_priv[codec_idx];
 
-		ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0),
-					  codec_priv->pll_id,
-					  codec_priv->mclk_id,
-					  codec_priv->mclk_freq, pll_out);
-		if (ret) {
-			dev_err(dev, "failed to start FLL: %d\n", ret);
-			goto fail;
-		}
+		if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
+			if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
+				pll_out = priv->sample_rate * 384;
+			else
+				pll_out = priv->sample_rate * 256;
 
-		ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0),
-					     codec_priv->fll_id,
-					     pll_out, SND_SOC_CLOCK_IN);
+			ret = snd_soc_dai_set_pll(codec_dai,
+						codec_priv->pll_id,
+						codec_priv->mclk_id,
+						codec_priv->mclk_freq, pll_out);
+			if (ret) {
+				dev_err(dev, "failed to start FLL: %d\n", ret);
+				goto fail;
+			}
 
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dev, "failed to set SYSCLK: %d\n", ret);
-			goto fail;
+			ret = snd_soc_dai_set_sysclk(codec_dai,
+						codec_priv->fll_id,
+						pll_out, SND_SOC_CLOCK_IN);
+
+			if (ret && ret != -ENOTSUPP) {
+				dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+				goto fail;
+			}
 		}
 	}
 
@@ -244,28 +250,34 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
-	struct codec_priv *codec_priv = &priv->codec_priv;
+	struct codec_priv *codec_priv;
+	struct snd_soc_dai *codec_dai;
 	struct device *dev = rtd->card->dev;
+	int codec_idx;
 	int ret;
 
 	priv->streams &= ~BIT(substream->stream);
 
-	if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
-		/* Force freq to be free_freq to avoid error message in codec */
-		ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0),
-					     codec_priv->mclk_id,
-					     codec_priv->free_freq,
-					     SND_SOC_CLOCK_IN);
-		if (ret) {
-			dev_err(dev, "failed to switch away from FLL: %d\n", ret);
-			return ret;
-		}
+	for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+		codec_priv = &priv->codec_priv[codec_idx];
 
-		ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0),
-					  codec_priv->pll_id, 0, 0, 0);
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dev, "failed to stop FLL: %d\n", ret);
-			return ret;
+		if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
+			/* Force freq to be free_freq to avoid error message in codec */
+			ret = snd_soc_dai_set_sysclk(codec_dai,
+						codec_priv->mclk_id,
+						codec_priv->free_freq,
+						SND_SOC_CLOCK_IN);
+			if (ret) {
+				dev_err(dev, "failed to switch away from FLL: %d\n", ret);
+				return ret;
+			}
+
+			ret = snd_soc_dai_set_pll(codec_dai,
+						codec_priv->pll_id, 0, 0, 0);
+			if (ret && ret != -ENOTSUPP) {
+				dev_err(dev, "failed to stop FLL: %d\n", ret);
+				return ret;
+			}
 		}
 	}
 
@@ -296,7 +308,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 
 SND_SOC_DAILINK_DEFS(hifi,
 	DAILINK_COMP_ARRAY(COMP_EMPTY()),
-	DAILINK_COMP_ARRAY(COMP_EMPTY()),
+	DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY()),
 	DAILINK_COMP_ARRAY(COMP_EMPTY()));
 
 SND_SOC_DAILINK_DEFS(hifi_fe,
@@ -306,7 +318,7 @@ SND_SOC_DAILINK_DEFS(hifi_fe,
 
 SND_SOC_DAILINK_DEFS(hifi_be,
 	DAILINK_COMP_ARRAY(COMP_EMPTY()),
-	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+	DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY()));
 
 static const struct snd_soc_dai_link fsl_asoc_card_dai[] = {
 	/* Default ASoC DAI Link*/
@@ -465,6 +477,75 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
 	return 0;
 }
 
+static int fsl_asoc_card_spdif_init(struct device_node *codec_np[],
+				    struct device_node *cpu_np,
+				    const char *codec_dai_name[],
+				    struct fsl_asoc_card_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+	struct device_node *np = dev->of_node;
+
+	if (!of_node_name_eq(cpu_np, "spdif")) {
+		dev_err(dev, "CPU phandle invalid, should be an SPDIF device\n");
+		return -EINVAL;
+	}
+
+	priv->dai_link[0].playback_only = true;
+	priv->dai_link[0].capture_only = true;
+
+	for (int i = 0; i < 2; i++) {
+		if (!codec_np[i])
+			break;
+
+		if (of_device_is_compatible(codec_np[i], "linux,spdif-dit")) {
+			priv->dai_link[0].capture_only = false;
+			codec_dai_name[i] = "dit-hifi";
+		} else if (of_device_is_compatible(codec_np[i], "linux,spdif-dir")) {
+			priv->dai_link[0].playback_only = false;
+			codec_dai_name[i] = "dir-hifi";
+		}
+	}
+
+	// Old SPDIF DT binding
+	if (!codec_np[0]) {
+		codec_dai_name[0] = snd_soc_dummy_dlc.dai_name;
+		if (of_property_read_bool(np, "spdif-out"))
+			priv->dai_link[0].capture_only = false;
+		if (of_property_read_bool(np, "spdif-in"))
+			priv->dai_link[0].playback_only = false;
+	}
+
+	if (priv->dai_link[0].playback_only && priv->dai_link[0].capture_only) {
+		dev_err(dev, "no enabled S/PDIF DAI link\n");
+		return -EINVAL;
+	}
+
+	if (priv->dai_link[0].playback_only) {
+		priv->dai_link[1].dpcm_capture = false;
+		priv->dai_link[2].dpcm_capture = false;
+		priv->card.dapm_routes = audio_map_tx;
+		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
+	} else if (priv->dai_link[0].capture_only) {
+		priv->dai_link[1].dpcm_playback = false;
+		priv->dai_link[2].dpcm_playback = false;
+		priv->card.dapm_routes = audio_map_rx;
+		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
+	}
+
+	// No DAPM routes with old bindings and dummy codec
+	if (!codec_np[0]) {
+		priv->card.dapm_routes = NULL;
+		priv->card.num_dapm_routes = 0;
+	}
+
+	if (codec_np[0] && codec_np[1]) {
+		priv->dai_link[0].num_codecs = 2;
+		priv->dai_link[2].num_codecs = 2;
+	}
+
+	return 0;
+}
+
 static int hp_jack_event(struct notifier_block *nb, unsigned long event,
 			 void *data)
 {
@@ -504,9 +585,10 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
 	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
 	struct snd_soc_pcm_runtime *rtd = list_first_entry(
 			&card->rtd_list, struct snd_soc_pcm_runtime, list);
-	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
-	struct codec_priv *codec_priv = &priv->codec_priv;
+	struct snd_soc_dai *codec_dai;
+	struct codec_priv *codec_priv;
 	struct device *dev = card->dev;
+	int codec_idx;
 	int ret;
 
 	if (fsl_asoc_card_is_ac97(priv)) {
@@ -526,32 +608,39 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
 		return 0;
 	}
 
-	ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
-				     codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
-	if (ret && ret != -ENOTSUPP) {
-		dev_err(dev, "failed to set sysclk in %s\n", __func__);
-		return ret;
-	}
+	for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+		codec_priv = &priv->codec_priv[codec_idx];
 
-	if (!IS_ERR_OR_NULL(codec_priv->mclk))
-		clk_prepare_enable(codec_priv->mclk);
+		ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+					codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
+		if (ret && ret != -ENOTSUPP) {
+			dev_err(dev, "failed to set sysclk in %s\n", __func__);
+			return ret;
+		}
+
+		if (!IS_ERR_OR_NULL(codec_priv->mclk))
+			clk_prepare_enable(codec_priv->mclk);
+	}
 
 	return 0;
 }
 
 static int fsl_asoc_card_probe(struct platform_device *pdev)
 {
-	struct device_node *cpu_np, *codec_np, *asrc_np;
+	struct device_node *cpu_np, *asrc_np;
+	struct snd_soc_dai_link_component *codec_comp;
+	struct device_node *codec_np[2];
 	struct device_node *np = pdev->dev.of_node;
 	struct platform_device *asrc_pdev = NULL;
 	struct device_node *bitclkprovider = NULL;
 	struct device_node *frameprovider = NULL;
 	struct platform_device *cpu_pdev;
 	struct fsl_asoc_card_priv *priv;
-	struct device *codec_dev = NULL;
-	const char *codec_dai_name;
-	const char *codec_dev_name;
+	struct device *codec_dev[2] = { NULL, NULL };
+	const char *codec_dai_name[2];
+	const char *codec_dev_name[2];
 	u32 asrc_fmt = 0;
+	int codec_idx;
 	u32 width;
 	int ret;
 
@@ -562,9 +651,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 	priv->pdev = pdev;
 
 	cpu_np = of_parse_phandle(np, "audio-cpu", 0);
-	/* Give a chance to old DT binding */
+	/* Give a chance to old DT bindings */
 	if (!cpu_np)
 		cpu_np = of_parse_phandle(np, "ssi-controller", 0);
+	if (!cpu_np)
+		cpu_np = of_parse_phandle(np, "spdif-controller", 0);
 	if (!cpu_np) {
 		dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
 		ret = -EINVAL;
@@ -578,21 +669,25 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		goto fail;
 	}
 
-	codec_np = of_parse_phandle(np, "audio-codec", 0);
-	if (codec_np) {
-		struct platform_device *codec_pdev;
-		struct i2c_client *codec_i2c;
+	codec_np[0] = of_parse_phandle(np, "audio-codec", 0);
+	codec_np[1] = of_parse_phandle(np, "audio-codec", 1);
 
-		codec_i2c = of_find_i2c_device_by_node(codec_np);
-		if (codec_i2c) {
-			codec_dev = &codec_i2c->dev;
-			codec_dev_name = codec_i2c->name;
-		}
-		if (!codec_dev) {
-			codec_pdev = of_find_device_by_node(codec_np);
-			if (codec_pdev) {
-				codec_dev = &codec_pdev->dev;
-				codec_dev_name = codec_pdev->name;
+	for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+		if (codec_np[codec_idx]) {
+			struct platform_device *codec_pdev;
+			struct i2c_client *codec_i2c;
+
+			codec_i2c = of_find_i2c_device_by_node(codec_np[codec_idx]);
+			if (codec_i2c) {
+				codec_dev[codec_idx] = &codec_i2c->dev;
+				codec_dev_name[codec_idx] = codec_i2c->name;
+			}
+			if (!codec_dev[codec_idx]) {
+				codec_pdev = of_find_device_by_node(codec_np[codec_idx]);
+				if (codec_pdev) {
+					codec_dev[codec_idx] = &codec_pdev->dev;
+					codec_dev_name[codec_idx] = codec_pdev->name;
+				}
 			}
 		}
 	}
@@ -602,12 +697,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		asrc_pdev = of_find_device_by_node(asrc_np);
 
 	/* Get the MCLK rate only, and leave it controlled by CODEC drivers */
-	if (codec_dev) {
-		struct clk *codec_clk = clk_get(codec_dev, NULL);
+	for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+		if (codec_dev[codec_idx]) {
+			struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL);
 
-		if (!IS_ERR(codec_clk)) {
-			priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
-			clk_put(codec_clk);
+			if (!IS_ERR(codec_clk)) {
+				priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk);
+				clk_put(codec_clk);
+			}
 		}
 	}
 
@@ -620,36 +717,40 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 
 	memcpy(priv->dai_link, fsl_asoc_card_dai,
 	       sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
+	priv->dai_link[0].num_codecs = 1;
+	priv->dai_link[2].num_codecs = 1;
 
 	priv->card.dapm_routes = audio_map;
 	priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
 	priv->card.driver_name = DRIVER_NAME;
 
-	priv->codec_priv.fll_id = -1;
-	priv->codec_priv.pll_id = -1;
+	for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+		priv->codec_priv[codec_idx].fll_id = -1;
+		priv->codec_priv[codec_idx].pll_id = -1;
+	}
 
 	/* Diversify the card configurations */
 	if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
-		codec_dai_name = "cs42888";
-		priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
-		priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
+		codec_dai_name[0] = "cs42888";
+		priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv[0].mclk_freq;
+		priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv[0].mclk_freq;
 		priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
 		priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
 		priv->cpu_priv.slot_width = 32;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) {
-		codec_dai_name = "cs4271-hifi";
-		priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK;
+		codec_dai_name[0] = "cs4271-hifi";
+		priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
-		codec_dai_name = "sgtl5000";
-		priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
+		codec_dai_name[0] = "sgtl5000";
+		priv->codec_priv[0].mclk_id = SGTL5000_SYSCLK;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) {
-		codec_dai_name = "tlv320aic32x4-hifi";
+		codec_dai_name[0] = "tlv320aic32x4-hifi";
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) {
-		codec_dai_name = "tlv320dac31xx-hifi";
+		codec_dai_name[0] = "tlv320dac31xx-hifi";
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
 		priv->dai_link[1].dpcm_capture = 0;
 		priv->dai_link[2].dpcm_capture = 0;
@@ -658,23 +759,23 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		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-wm8962")) {
-		codec_dai_name = "wm8962";
-		priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
-		priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
-		priv->codec_priv.pll_id = WM8962_FLL;
+		codec_dai_name[0] = "wm8962";
+		priv->codec_priv[0].mclk_id = WM8962_SYSCLK_MCLK;
+		priv->codec_priv[0].fll_id = WM8962_SYSCLK_FLL;
+		priv->codec_priv[0].pll_id = WM8962_FLL;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
-		codec_dai_name = "wm8960-hifi";
-		priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
-		priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
+		codec_dai_name[0] = "wm8960-hifi";
+		priv->codec_priv[0].fll_id = WM8960_SYSCLK_AUTO;
+		priv->codec_priv[0].pll_id = WM8960_SYSCLK_AUTO;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
-		codec_dai_name = "ac97-hifi";
+		codec_dai_name[0] = "ac97-hifi";
 		priv->dai_fmt = SND_SOC_DAIFMT_AC97;
 		priv->card.dapm_routes = audio_map_ac97;
 		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97);
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) {
-		codec_dai_name = "fsl-mqs-dai";
+		codec_dai_name[0] = "fsl-mqs-dai";
 		priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
 				SND_SOC_DAIFMT_CBC_CFC |
 				SND_SOC_DAIFMT_NB_NF;
@@ -683,7 +784,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		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-wm8524")) {
-		codec_dai_name = "wm8524-hifi";
+		codec_dai_name[0] = "wm8524-hifi";
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
 		priv->dai_link[1].dpcm_capture = 0;
 		priv->dai_link[2].dpcm_capture = 0;
@@ -691,33 +792,37 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		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";
+		codec_dai_name[0] = "si476x-codec";
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
 		priv->card.dapm_routes = audio_map_rx;
 		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) {
-		codec_dai_name = "wm8994-aif1";
+		codec_dai_name[0] = "wm8994-aif1";
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
-		priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1;
-		priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1;
-		priv->codec_priv.pll_id = WM8994_FLL1;
-		priv->codec_priv.free_freq = priv->codec_priv.mclk_freq;
+		priv->codec_priv[0].mclk_id = WM8994_FLL_SRC_MCLK1;
+		priv->codec_priv[0].fll_id = WM8994_SYSCLK_FLL1;
+		priv->codec_priv[0].pll_id = WM8994_FLL1;
+		priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq;
 		priv->card.dapm_routes = NULL;
 		priv->card.num_dapm_routes = 0;
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) {
-		codec_dai_name = "nau8822-hifi";
-		priv->codec_priv.mclk_id = NAU8822_CLK_MCLK;
-		priv->codec_priv.fll_id = NAU8822_CLK_PLL;
-		priv->codec_priv.pll_id = NAU8822_CLK_PLL;
+		codec_dai_name[0] = "nau8822-hifi";
+		priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK;
+		priv->codec_priv[0].fll_id = NAU8822_CLK_PLL;
+		priv->codec_priv[0].pll_id = NAU8822_CLK_PLL;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
-		if (codec_dev)
-			priv->codec_priv.mclk = devm_clk_get(codec_dev, NULL);
+		if (codec_dev[0])
+			priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL);
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) {
-		codec_dai_name = "wm8904-hifi";
-		priv->codec_priv.mclk_id = WM8904_FLL_MCLK;
-		priv->codec_priv.fll_id = WM8904_CLK_FLL;
-		priv->codec_priv.pll_id = WM8904_FLL_MCLK;
+		codec_dai_name[0] = "wm8904-hifi";
+		priv->codec_priv[0].mclk_id = WM8904_FLL_MCLK;
+		priv->codec_priv[0].fll_id = WM8904_CLK_FLL;
+		priv->codec_priv[0].pll_id = WM8904_FLL_MCLK;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
+	} else if (of_device_is_compatible(np, "fsl,imx-audio-spdif")) {
+		ret = fsl_asoc_card_spdif_init(codec_np, cpu_np, codec_dai_name, priv);
+		if (ret)
+			goto asrc_fail;
 	} else {
 		dev_err(&pdev->dev, "unknown Device Tree compatible\n");
 		ret = -EINVAL;
@@ -728,18 +833,30 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 	 * Allow setting mclk-id from the device-tree node. Otherwise, the
 	 * default value for each card configuration is used.
 	 */
-	of_property_read_u32(np, "mclk-id", &priv->codec_priv.mclk_id);
+	for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+		of_property_read_u32_index(np, "mclk-id", codec_idx,
+					&priv->codec_priv[codec_idx].mclk_id);
+	}
 
 	/* Format info from DT is optional. */
 	snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider);
 	if (bitclkprovider || frameprovider) {
 		unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL);
+		bool codec_bitclkprovider = false;
+		bool codec_frameprovider = false;
+
+		for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+			if (bitclkprovider && codec_np[codec_idx] == bitclkprovider)
+				codec_bitclkprovider = true;
+			if (frameprovider && codec_np[codec_idx] == frameprovider)
+				codec_frameprovider = true;
+		}
 
-		if (codec_np == bitclkprovider)
-			daifmt |= (codec_np == frameprovider) ?
+		if (codec_bitclkprovider)
+			daifmt |= (codec_frameprovider) ?
 				SND_SOC_DAIFMT_CBP_CFP : SND_SOC_DAIFMT_CBP_CFC;
 		else
-			daifmt |= (codec_np == frameprovider) ?
+			daifmt |= (codec_frameprovider) ?
 				SND_SOC_DAIFMT_CBC_CFP : SND_SOC_DAIFMT_CBC_CFC;
 
 		/* Override dai_fmt with value from DT */
@@ -755,7 +872,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 	of_node_put(bitclkprovider);
 	of_node_put(frameprovider);
 
-	if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) {
+	if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]
+	    && codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) {
 		dev_dbg(&pdev->dev, "failed to find codec device\n");
 		ret = -EPROBE_DEFER;
 		goto asrc_fail;
@@ -794,7 +912,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 	ret = snd_soc_of_parse_card_name(&priv->card, "model");
 	if (ret) {
 		snprintf(priv->name, sizeof(priv->name), "%s-audio",
-			 fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name);
+			 fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name[0]);
 		priv->card.name = priv->name;
 	}
 	priv->card.dai_link = priv->dai_link;
@@ -816,11 +934,19 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 
 	/* Normal DAI Link */
 	priv->dai_link[0].cpus->of_node = cpu_np;
-	priv->dai_link[0].codecs->dai_name = codec_dai_name;
+	for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+		codec_comp->dai_name = codec_dai_name[codec_idx];
+	}
+
+	// Old SPDIF DT binding support
+	if (codec_dai_name[0] == snd_soc_dummy_dlc.dai_name)
+		priv->dai_link[0].codecs[0].name = snd_soc_dummy_dlc.name;
 
-	if (!fsl_asoc_card_is_ac97(priv))
-		priv->dai_link[0].codecs->of_node = codec_np;
-	else {
+	if (!fsl_asoc_card_is_ac97(priv)) {
+		for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+			codec_comp->of_node = codec_np[codec_idx];
+		}
+	} else {
 		u32 idx;
 
 		ret = of_property_read_u32(cpu_np, "cell-index", &idx);
@@ -830,11 +956,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 			goto asrc_fail;
 		}
 
-		priv->dai_link[0].codecs->name =
+		priv->dai_link[0].codecs[0].name =
 				devm_kasprintf(&pdev->dev, GFP_KERNEL,
 					       "ac97-codec.%u",
 					       (unsigned int)idx);
-		if (!priv->dai_link[0].codecs->name) {
+		if (!priv->dai_link[0].codecs[0].name) {
 			ret = -ENOMEM;
 			goto asrc_fail;
 		}
@@ -848,10 +974,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		/* DPCM DAI Links only if ASRC exists */
 		priv->dai_link[1].cpus->of_node = asrc_np;
 		priv->dai_link[1].platforms->of_node = asrc_np;
-		priv->dai_link[2].codecs->dai_name = codec_dai_name;
-		priv->dai_link[2].codecs->of_node = codec_np;
-		priv->dai_link[2].codecs->name =
-				priv->dai_link[0].codecs->name;
+		for_each_link_codecs((&(priv->dai_link[2])), codec_idx, codec_comp) {
+			codec_comp->dai_name = priv->dai_link[0].codecs[codec_idx].dai_name;
+			codec_comp->of_node = priv->dai_link[0].codecs[codec_idx].of_node;
+			codec_comp->name = priv->dai_link[0].codecs[codec_idx].name;
+		}
 		priv->dai_link[2].cpus->of_node = cpu_np;
 		priv->dai_link[2].dai_fmt = priv->dai_fmt;
 		priv->card.num_links = 3;
@@ -921,7 +1048,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 
 asrc_fail:
 	of_node_put(asrc_np);
-	of_node_put(codec_np);
+	of_node_put(codec_np[0]);
+	of_node_put(codec_np[1]);
 	put_device(&cpu_pdev->dev);
 fail:
 	of_node_put(cpu_np);
@@ -944,6 +1072,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
 	{ .compatible = "fsl,imx-audio-wm8958", },
 	{ .compatible = "fsl,imx-audio-nau8822", },
 	{ .compatible = "fsl,imx-audio-wm8904", },
+	{ .compatible = "fsl,imx-audio-spdif", },
 	{}
 };
 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
index ee2f6ad1f800756bea0b05e75585cb9dabd95eee..a6cbaa6364c7fb9b51a0bd32ed87c29426b69fc7 100644
--- a/sound/soc/fsl/fsl_aud2htx.c
+++ b/sound/soc/fsl/fsl_aud2htx.c
@@ -261,7 +261,7 @@ static void fsl_aud2htx_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
-static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
+static int fsl_aud2htx_runtime_suspend(struct device *dev)
 {
 	struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
 
@@ -271,7 +271,7 @@ static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
+static int fsl_aud2htx_runtime_resume(struct device *dev)
 {
 	struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
 	int ret;
@@ -288,9 +288,8 @@ static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
-	SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend,
-			   fsl_aud2htx_runtime_resume,
-			   NULL)
+	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)
 };
@@ -300,7 +299,7 @@ static struct platform_driver fsl_aud2htx_driver = {
 	.remove_new = fsl_aud2htx_remove,
 	.driver = {
 		.name = "fsl-aud2htx",
-		.pm = &fsl_aud2htx_pm_ops,
+		.pm = pm_ptr(&fsl_aud2htx_pm_ops),
 		.of_match_table = fsl_aud2htx_dt_ids,
 	},
 };
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 0ab2c19621175e8c951393fb44b8594fd52eb0ac..1671a3037c6048adbedf32853b64125a7bb029fc 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -326,15 +326,6 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = {
 			.rates = SNDRV_PCM_RATE_8000_96000,
 			.formats = FSL_AUDMIX_FORMATS,
 		},
-		.capture = {
-			.stream_name = "AUDMIX-Capture-0",
-			.channels_min = 8,
-			.channels_max = 8,
-			.rate_min = 8000,
-			.rate_max = 96000,
-			.rates = SNDRV_PCM_RATE_8000_96000,
-			.formats = FSL_AUDMIX_FORMATS,
-		},
 		.ops = &fsl_audmix_dai_ops,
 	},
 	{
@@ -349,8 +340,13 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = {
 			.rates = SNDRV_PCM_RATE_8000_96000,
 			.formats = FSL_AUDMIX_FORMATS,
 		},
+		.ops = &fsl_audmix_dai_ops,
+	},
+	{
+		.id   = 2,
+		.name = "audmix-2",
 		.capture = {
-			.stream_name = "AUDMIX-Capture-1",
+			.stream_name = "AUDMIX-Capture-0",
 			.channels_min = 8,
 			.channels_max = 8,
 			.rate_min = 8000,
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index ec53bda46a467df6e24274d7c771d5d159a34fca..962f30912091893a2eb9ee4892f7c080756ba7eb 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1988,7 +1988,7 @@ static void fsl_easrc_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
-static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev)
+static int fsl_easrc_runtime_suspend(struct device *dev)
 {
 	struct fsl_asrc *easrc = dev_get_drvdata(dev);
 	struct fsl_easrc_priv *easrc_priv = easrc->private;
@@ -2005,7 +2005,7 @@ static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static __maybe_unused int fsl_easrc_runtime_resume(struct device *dev)
+static int fsl_easrc_runtime_resume(struct device *dev)
 {
 	struct fsl_asrc *easrc = dev_get_drvdata(dev);
 	struct fsl_easrc_priv *easrc_priv = easrc->private;
@@ -2086,9 +2086,7 @@ static __maybe_unused int fsl_easrc_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops fsl_easrc_pm_ops = {
-	SET_RUNTIME_PM_OPS(fsl_easrc_runtime_suspend,
-			   fsl_easrc_runtime_resume,
-			   NULL)
+	RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL)
 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 				pm_runtime_force_resume)
 };
@@ -2098,7 +2096,7 @@ static struct platform_driver fsl_easrc_driver = {
 	.remove_new = fsl_easrc_remove,
 	.driver = {
 		.name = "fsl-easrc",
-		.pm = &fsl_easrc_pm_ops,
+		.pm = pm_ptr(&fsl_easrc_pm_ops),
 		.of_match_table = fsl_easrc_dt_ids,
 	},
 };
diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c
index 60929c36a0e3bf407a2d2291d22a025475875732..c95b84a54dc464221d1bfeeebca7e7f798b68a2b 100644
--- a/sound/soc/fsl/fsl_mqs.c
+++ b/sound/soc/fsl/fsl_mqs.c
@@ -28,10 +28,16 @@
 #define MQS_CLK_DIV_MASK		(0xFF << 0)
 #define MQS_CLK_DIV_SHIFT		(0)
 
+enum reg_type {
+	TYPE_REG_OWN,  /* module own register space */
+	TYPE_REG_GPR,  /* register in GPR space */
+	TYPE_REG_SM,   /* System Manager controls the register */
+};
+
 /**
  * struct fsl_mqs_soc_data - soc specific data
  *
- * @use_gpr: control register is in General Purpose Register group
+ * @type: control register space type
  * @ctrl_off: control register offset
  * @en_mask: enable bit mask
  * @en_shift: enable bit shift
@@ -43,7 +49,7 @@
  * @div_shift: clock divider bit shift
  */
 struct fsl_mqs_soc_data {
-	bool use_gpr;
+	enum reg_type type;
 	int  ctrl_off;
 	int  en_mask;
 	int  en_shift;
@@ -200,7 +206,7 @@ static int fsl_mqs_probe(struct platform_device *pdev)
 	 */
 	mqs_priv->soc = of_device_get_match_data(&pdev->dev);
 
-	if (mqs_priv->soc->use_gpr) {
+	if (mqs_priv->soc->type == TYPE_REG_GPR) {
 		gpr_np = of_parse_phandle(np, "gpr", 0);
 		if (!gpr_np) {
 			dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
@@ -304,7 +310,7 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = {
 };
 
 static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
-	.use_gpr = false,
+	.type = TYPE_REG_OWN,
 	.ctrl_off = REG_MQS_CTRL,
 	.en_mask  = MQS_EN_MASK,
 	.en_shift = MQS_EN_SHIFT,
@@ -317,7 +323,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
 };
 
 static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
-	.use_gpr = true,
+	.type = TYPE_REG_GPR,
 	.ctrl_off = IOMUXC_GPR2,
 	.en_mask  = IMX6SX_GPR2_MQS_EN_MASK,
 	.en_shift = IMX6SX_GPR2_MQS_EN_SHIFT,
@@ -330,7 +336,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
 };
 
 static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
-	.use_gpr = true,
+	.type = TYPE_REG_GPR,
 	.ctrl_off = 0x20,
 	.en_mask  = BIT(1),
 	.en_shift = 1,
@@ -342,10 +348,38 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
 	.div_shift = 8,
 };
 
+static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = {
+	.type = TYPE_REG_SM,
+	.ctrl_off = 0x88,
+	.en_mask  = BIT(1),
+	.en_shift = 1,
+	.rst_mask = BIT(2),
+	.rst_shift = 2,
+	.osr_mask = BIT(3),
+	.osr_shift = 3,
+	.div_mask = GENMASK(15, 8),
+	.div_shift = 8,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx95_netc_data = {
+	.type = TYPE_REG_GPR,
+	.ctrl_off = 0x0,
+	.en_mask  = BIT(2),
+	.en_shift = 2,
+	.rst_mask = BIT(3),
+	.rst_shift = 3,
+	.osr_mask = BIT(4),
+	.osr_shift = 4,
+	.div_mask = GENMASK(16, 9),
+	.div_shift = 9,
+};
+
 static const struct of_device_id fsl_mqs_dt_ids[] = {
 	{ .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data },
 	{ .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data },
 	{ .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data },
+	{ .compatible = "fsl,imx95-aonmix-mqs", .data = &fsl_mqs_imx95_aon_data },
+	{ .compatible = "fsl,imx95-netcmix-mqs", .data = &fsl_mqs_imx95_netc_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index bfaaa451735b8fdba399db20038d88860d12fd54..8668abd352080064ba53095dc8ab5d35c6a75116 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -17,13 +17,23 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
+struct qmc_dai_chan {
+	struct qmc_dai_prtd *prtd_tx;
+	struct qmc_dai_prtd *prtd_rx;
+	struct qmc_chan *qmc_chan;
+};
+
 struct qmc_dai {
 	char *name;
 	int id;
 	struct device *dev;
-	struct qmc_chan *qmc_chan;
 	unsigned int nb_tx_ts;
 	unsigned int nb_rx_ts;
+
+	unsigned int nb_chans_avail;
+	unsigned int nb_chans_used_tx;
+	unsigned int nb_chans_used_rx;
+	struct qmc_dai_chan *chans;
 };
 
 struct qmc_audio {
@@ -35,11 +45,19 @@ struct qmc_audio {
 
 struct qmc_dai_prtd {
 	struct qmc_dai *qmc_dai;
-	dma_addr_t dma_buffer_start;
-	dma_addr_t period_ptr_submitted;
-	dma_addr_t period_ptr_ended;
-	dma_addr_t dma_buffer_end;
-	size_t period_size;
+
+	snd_pcm_uframes_t buffer_ended;
+	snd_pcm_uframes_t buffer_size;
+	snd_pcm_uframes_t period_size;
+
+	dma_addr_t ch_dma_addr_start;
+	dma_addr_t ch_dma_addr_current;
+	dma_addr_t ch_dma_addr_end;
+	size_t ch_dma_size;
+	size_t ch_dma_offset;
+
+	unsigned int channels;
+	DECLARE_BITMAP(chans_pending, 64);
 	struct snd_pcm_substream *substream;
 };
 
@@ -54,10 +72,22 @@ static int qmc_audio_pcm_construct(struct snd_soc_component *component,
 		return ret;
 
 	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
-				       64*1024, 64*1024);
+				       64 * 1024, 64 * 1024);
 	return 0;
 }
 
+static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access)
+{
+	switch (access) {
+	case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
+	case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
+		return true;
+	default:
+		break;
+	}
+	return false;
+}
+
 static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
 				   struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params)
@@ -65,66 +95,143 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
 
-	prtd->dma_buffer_start = runtime->dma_addr;
-	prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params);
-	prtd->period_size = params_period_bytes(params);
-	prtd->period_ptr_submitted = prtd->dma_buffer_start;
-	prtd->period_ptr_ended = prtd->dma_buffer_start;
+	/*
+	 * In interleaved mode, the driver uses one QMC channel for all audio
+	 * channels whereas in non-interleaved mode, it uses one QMC channel per
+	 * audio channel.
+	 */
+	prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ?
+				1 : params_channels(params);
+
 	prtd->substream = substream;
 
+	prtd->buffer_ended = 0;
+	prtd->buffer_size = params_buffer_size(params);
+	prtd->period_size = params_period_size(params);
+
+	prtd->ch_dma_addr_start = runtime->dma_addr;
+	prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels;
+	prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset;
+	prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+	prtd->ch_dma_size = params_period_bytes(params) / prtd->channels;
+
 	return 0;
 }
 
-static void qmc_audio_pcm_write_complete(void *context)
+static void qmc_audio_pcm_write_complete(void *context);
+
+static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
 {
-	struct qmc_dai_prtd *prtd = context;
+	unsigned int i;
 	int ret;
 
-	prtd->period_ptr_ended += prtd->period_size;
-	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
-		prtd->period_ptr_ended = prtd->dma_buffer_start;
-
-	prtd->period_ptr_submitted += prtd->period_size;
-	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
-		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+	for (i = 0; i < prtd->channels; i++) {
+		bitmap_set(prtd->chans_pending, i, 1);
 
-	ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
-		prtd->period_ptr_submitted, prtd->period_size,
-		qmc_audio_pcm_write_complete, prtd);
-	if (ret) {
-		dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n",
-			ret);
+		ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,
+					    prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
+					    prtd->ch_dma_size,
+					    qmc_audio_pcm_write_complete,
+					    &prtd->qmc_dai->chans[i]);
+		if (ret) {
+			dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",
+				i, ret);
+			bitmap_clear(prtd->chans_pending, i, 1);
+			return ret;
+		}
 	}
 
+	return 0;
+}
+
+static void qmc_audio_pcm_write_complete(void *context)
+{
+	struct qmc_dai_chan *chan = context;
+	struct qmc_dai_prtd *prtd;
+
+	prtd = chan->prtd_tx;
+
+	/* Mark the current channel as completed */
+	bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);
+
+	/*
+	 * All QMC channels involved must have completed their transfer before
+	 * submitting a new one.
+	 */
+	if (!bitmap_empty(prtd->chans_pending, 64))
+		return;
+
+	prtd->buffer_ended += prtd->period_size;
+	if (prtd->buffer_ended >= prtd->buffer_size)
+		prtd->buffer_ended = 0;
+
+	prtd->ch_dma_addr_current += prtd->ch_dma_size;
+	if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+		prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+
+	qmc_audio_pcm_write_submit(prtd);
+
 	snd_pcm_period_elapsed(prtd->substream);
 }
 
-static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
+static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags);
+
+static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
 {
-	struct qmc_dai_prtd *prtd = context;
+	unsigned int i;
 	int ret;
 
-	if (length != prtd->period_size) {
-		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
-			length, prtd->period_size);
+	for (i = 0; i < prtd->channels; i++) {
+		bitmap_set(prtd->chans_pending, i, 1);
+
+		ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,
+					   prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
+					   prtd->ch_dma_size,
+					   qmc_audio_pcm_read_complete,
+					   &prtd->qmc_dai->chans[i]);
+		if (ret) {
+			dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",
+				i, ret);
+			bitmap_clear(prtd->chans_pending, i, 1);
+			return ret;
+		}
 	}
 
-	prtd->period_ptr_ended += prtd->period_size;
-	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
-		prtd->period_ptr_ended = prtd->dma_buffer_start;
+	return 0;
+}
+
+static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
+{
+	struct qmc_dai_chan *chan = context;
+	struct qmc_dai_prtd *prtd;
+
+	prtd = chan->prtd_rx;
 
-	prtd->period_ptr_submitted += prtd->period_size;
-	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
-		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+	/* Mark the current channel as completed */
+	bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);
 
-	ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
-		prtd->period_ptr_submitted, prtd->period_size,
-		qmc_audio_pcm_read_complete, prtd);
-	if (ret) {
-		dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n",
-			ret);
+	if (length != prtd->ch_dma_size) {
+		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
+			length, prtd->ch_dma_size);
 	}
 
+	/*
+	 * All QMC channels involved must have completed their transfer before
+	 * submitting a new one.
+	 */
+	if (!bitmap_empty(prtd->chans_pending, 64))
+		return;
+
+	prtd->buffer_ended += prtd->period_size;
+	if (prtd->buffer_ended >= prtd->buffer_size)
+		prtd->buffer_ended = 0;
+
+	prtd->ch_dma_addr_current += prtd->ch_dma_size;
+	if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+		prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+
+	qmc_audio_pcm_read_submit(prtd);
+
 	snd_pcm_period_elapsed(prtd->substream);
 }
 
@@ -132,6 +239,7 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
 				 struct snd_pcm_substream *substream, int cmd)
 {
 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	unsigned int i;
 	int ret;
 
 	if (!prtd->qmc_dai) {
@@ -141,56 +249,43 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+		bitmap_zero(prtd->chans_pending, 64);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			for (i = 0; i < prtd->channels; i++)
+				prtd->qmc_dai->chans[i].prtd_tx = prtd;
+
 			/* Submit first chunk ... */
-			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
-				prtd->period_ptr_submitted, prtd->period_size,
-				qmc_audio_pcm_write_complete, prtd);
-			if (ret) {
-				dev_err(component->dev, "write_submit failed %d\n",
-					ret);
+			ret = qmc_audio_pcm_write_submit(prtd);
+			if (ret)
 				return ret;
-			}
 
 			/* ... prepare next one ... */
-			prtd->period_ptr_submitted += prtd->period_size;
-			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
-				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+			prtd->ch_dma_addr_current += prtd->ch_dma_size;
+			if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+				prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
 
 			/* ... and send it */
-			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
-				prtd->period_ptr_submitted, prtd->period_size,
-				qmc_audio_pcm_write_complete, prtd);
-			if (ret) {
-				dev_err(component->dev, "write_submit failed %d\n",
-					ret);
+			ret = qmc_audio_pcm_write_submit(prtd);
+			if (ret)
 				return ret;
-			}
 		} else {
+			for (i = 0; i < prtd->channels; i++)
+				prtd->qmc_dai->chans[i].prtd_rx = prtd;
+
 			/* Submit first chunk ... */
-			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
-				prtd->period_ptr_submitted, prtd->period_size,
-				qmc_audio_pcm_read_complete, prtd);
-			if (ret) {
-				dev_err(component->dev, "read_submit failed %d\n",
-					ret);
+			ret = qmc_audio_pcm_read_submit(prtd);
+			if (ret)
 				return ret;
-			}
 
 			/* ... prepare next one ... */
-			prtd->period_ptr_submitted += prtd->period_size;
-			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
-				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+			prtd->ch_dma_addr_current += prtd->ch_dma_size;
+			if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+				prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
 
 			/* ... and send it */
-			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
-				prtd->period_ptr_submitted, prtd->period_size,
-				qmc_audio_pcm_read_complete, prtd);
-			if (ret) {
-				dev_err(component->dev, "write_submit failed %d\n",
-					ret);
+			ret = qmc_audio_pcm_read_submit(prtd);
+			if (ret)
 				return ret;
-			}
 		}
 		break;
 
@@ -215,13 +310,12 @@ static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *compone
 {
 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
 
-	return bytes_to_frames(substream->runtime,
-			       prtd->period_ptr_ended - prtd->dma_buffer_start);
+	return prtd->buffer_ended;
 }
 
 static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
-					const struct of_phandle_args *args,
-					const char **dai_name)
+				       const struct of_phandle_args *args,
+				       const char **dai_name)
 {
 	struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
 	struct snd_soc_dai_driver *dai_driver;
@@ -243,12 +337,13 @@ static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
 				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_NONINTERLEAVED |
 				  SNDRV_PCM_INFO_PAUSE,
 	.period_bytes_min	= 32,
-	.period_bytes_max	= 64*1024,
+	.period_bytes_max	= 64 * 1024,
 	.periods_min		= 2,
-	.periods_max		= 2*1024,
-	.buffer_bytes_max	= 64*1024,
+	.periods_max		= 2 * 1024,
+	.buffer_bytes_max	= 64 * 1024,
 };
 
 static int qmc_audio_pcm_open(struct snd_soc_component *component,
@@ -266,7 +361,7 @@ static int qmc_audio_pcm_open(struct snd_soc_component *component,
 		return ret;
 
 	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
-	if (prtd == NULL)
+	if (!prtd)
 		return -ENOMEM;
 
 	runtime->private_data = prtd;
@@ -329,13 +424,13 @@ static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai,
 		ch.max = nb_ts;
 		break;
 	case 16:
-		ch.max = nb_ts/2;
+		ch.max = nb_ts / 2;
 		break;
 	case 32:
-		ch.max = nb_ts/4;
+		ch.max = nb_ts / 4;
 		break;
 	case 64:
-		ch.max = nb_ts/8;
+		ch.max = nb_ts / 8;
 		break;
 	default:
 		dev_err(qmc_dai->dev, "format physical width %u not supported\n",
@@ -356,9 +451,8 @@ static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params
 	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
 }
 
-static int qmc_dai_hw_rule_capture_channels_by_format(
-			struct snd_pcm_hw_params *params,
-			struct snd_pcm_hw_rule *rule)
+static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
+						      struct snd_pcm_hw_rule *rule)
 {
 	struct qmc_dai *qmc_dai = rule->private;
 
@@ -394,42 +488,31 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
 	return snd_mask_refine(f_old, &f_new);
 }
 
-static int qmc_dai_hw_rule_playback_format_by_channels(
-			struct snd_pcm_hw_params *params,
-			struct snd_pcm_hw_rule *rule)
+static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
+						       struct snd_pcm_hw_rule *rule)
 {
 	struct qmc_dai *qmc_dai = rule->private;
 
 	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
 }
 
-static int qmc_dai_hw_rule_capture_format_by_channels(
-			struct snd_pcm_hw_params *params,
-			struct snd_pcm_hw_rule *rule)
+static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
+						      struct snd_pcm_hw_rule *rule)
 {
 	struct qmc_dai *qmc_dai = rule->private;
 
 	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
 }
 
-static int qmc_dai_startup(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai)
+static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,
+					   struct qmc_dai *qmc_dai)
 {
-	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
 	snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
 	snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
-	struct qmc_dai *qmc_dai;
 	unsigned int frame_bits;
+	u64 access;
 	int ret;
 
-	qmc_dai = qmc_dai_get_data(dai);
-	if (!qmc_dai) {
-		dev_err(dai->dev, "Invalid dai\n");
-		return -EINVAL;
-	}
-
-	prtd->qmc_dai = qmc_dai;
-
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
 		hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
@@ -444,7 +527,7 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream,
 				  hw_rule_channels_by_format, qmc_dai,
 				  SNDRV_PCM_HW_PARAM_FORMAT, -1);
 	if (ret) {
-		dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret);
+		dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret);
 		return ret;
 	}
 
@@ -452,27 +535,86 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream,
 				  hw_rule_format_by_channels, qmc_dai,
 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 	if (ret) {
-		dev_err(dai->dev, "Failed to add format rule (%d)\n", ret);
+		dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_pcm_hw_constraint_single(substream->runtime,
+					   SNDRV_PCM_HW_PARAM_FRAME_BITS,
+					   frame_bits);
+	if (ret < 0) {
+		dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+		return ret;
+	}
+
+	access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
+		 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+	ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
+					   access);
+	if (ret) {
+		dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);
 		return ret;
 	}
 
+	return 0;
+}
+
+static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream,
+					      struct qmc_dai *qmc_dai)
+{
+	unsigned int frame_bits;
+	u64 access;
+	int ret;
+
+	frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ?
+			qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8;
 	ret = snd_pcm_hw_constraint_single(substream->runtime,
 					   SNDRV_PCM_HW_PARAM_FRAME_BITS,
 					   frame_bits);
 	if (ret < 0) {
-		dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+		dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+		return ret;
+	}
+
+	access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
+		 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
+	ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
+					   access);
+	if (ret) {
+		dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
+static int qmc_dai_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	struct qmc_dai *qmc_dai;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	prtd->qmc_dai = qmc_dai;
+
+	return qmc_dai->nb_chans_avail > 1 ?
+		qmc_dai_constraints_noninterleaved(substream, qmc_dai) :
+		qmc_dai_constraints_interleaved(substream, qmc_dai);
+}
+
 static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
 	struct qmc_chan_param chan_param = {0};
+	unsigned int nb_chans_used;
 	struct qmc_dai *qmc_dai;
+	unsigned int i;
 	int ret;
 
 	qmc_dai = qmc_dai_get_data(dai);
@@ -481,15 +623,34 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
+	/*
+	 * In interleaved mode, the driver uses one QMC channel for all audio
+	 * channels whereas in non-interleaved mode, it uses one QMC channel per
+	 * audio channel.
+	 */
+	nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ?
+				1 : params_channels(params);
+
+	if (nb_chans_used > qmc_dai->nb_chans_avail) {
+		dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n",
+			nb_chans_used, qmc_dai->nb_chans_avail);
+		return -EINVAL;
+	}
+
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		chan_param.mode = QMC_TRANSPARENT;
-		chan_param.transp.max_rx_buf_size = params_period_bytes(params);
-		ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param);
-		if (ret) {
-			dev_err(dai->dev, "set param failed %d\n",
-				ret);
-			return ret;
+		chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;
+		for (i = 0; i < nb_chans_used; i++) {
+			ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);
+			if (ret) {
+				dev_err(dai->dev, "chans[%u], set param failed %d\n",
+					i, ret);
+				return ret;
+			}
 		}
+		qmc_dai->nb_chans_used_rx = nb_chans_used;
+	} else {
+		qmc_dai->nb_chans_used_tx = nb_chans_used;
 	}
 
 	return 0;
@@ -498,9 +659,12 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
 static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 			   struct snd_soc_dai *dai)
 {
+	unsigned int nb_chans_used;
 	struct qmc_dai *qmc_dai;
+	unsigned int i;
 	int direction;
-	int ret;
+	int ret = 0;
+	int ret_tmp;
 
 	qmc_dai = qmc_dai_get_data(dai);
 	if (!qmc_dai) {
@@ -508,30 +672,50 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 		return -EINVAL;
 	}
 
-	direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-		    QMC_CHAN_WRITE : QMC_CHAN_READ;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		direction = QMC_CHAN_WRITE;
+		nb_chans_used = qmc_dai->nb_chans_used_tx;
+	} else {
+		direction = QMC_CHAN_READ;
+		nb_chans_used = qmc_dai->nb_chans_used_rx;
+	}
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		ret = qmc_chan_start(qmc_dai->qmc_chan, direction);
-		if (ret)
-			return ret;
+		for (i = 0; i < nb_chans_used; i++) {
+			ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);
+			if (ret)
+				goto err_stop;
+		}
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
-		if (ret)
-			return ret;
-		ret = qmc_chan_reset(qmc_dai->qmc_chan, direction);
+		/* Stop and reset all QMC channels and return the first error encountered */
+		for (i = 0; i < nb_chans_used; i++) {
+			ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
+			if (!ret)
+				ret = ret_tmp;
+			if (ret_tmp)
+				continue;
+
+			ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
+			if (!ret)
+				ret = ret_tmp;
+		}
 		if (ret)
 			return ret;
 		break;
 
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		/* Stop all QMC channels and return the first error encountered */
+		for (i = 0; i < nb_chans_used; i++) {
+			ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
+			if (!ret)
+				ret = ret_tmp;
+		}
 		if (ret)
 			return ret;
 		break;
@@ -541,6 +725,13 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 	}
 
 	return 0;
+
+err_stop:
+	while (i--) {
+		qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
+		qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
+	}
+	return ret;
 }
 
 static const struct snd_soc_dai_ops qmc_dai_ops = {
@@ -549,7 +740,7 @@ static const struct snd_soc_dai_ops qmc_dai_ops = {
 	.hw_params	= qmc_dai_hw_params,
 };
 
-static u64 qmc_audio_formats(u8 nb_ts)
+static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved)
 {
 	unsigned int format_width;
 	unsigned int chan_width;
@@ -581,15 +772,29 @@ static u64 qmc_audio_formats(u8 nb_ts)
 		if (format_width > chan_width || chan_width % format_width)
 			continue;
 
+		/*
+		 * In non interleaved mode, we can only support formats that
+		 * can fit only 1 time in the channel
+		 */
+		if (is_noninterleaved && format_width != chan_width)
+			continue;
+
 		formats_mask |= pcm_format_to_bits(format);
 	}
 	return formats_mask;
 }
 
 static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
-	struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver)
+			       struct qmc_dai *qmc_dai,
+			       struct snd_soc_dai_driver *qmc_soc_dai_driver)
 {
 	struct qmc_chan_info info;
+	unsigned long rx_fs_rate;
+	unsigned long tx_fs_rate;
+	unsigned int nb_tx_ts;
+	unsigned int nb_rx_ts;
+	unsigned int i;
+	int count;
 	u32 val;
 	int ret;
 
@@ -604,57 +809,108 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
 
 	qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
 				       np->parent->name, qmc_dai->id);
+	if (!qmc_dai->name)
+		return -ENOMEM;
 
-	qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
-							"fsl,qmc-chan");
-	if (IS_ERR(qmc_dai->qmc_chan)) {
-		ret = PTR_ERR(qmc_dai->qmc_chan);
-		return dev_err_probe(qmc_audio->dev, ret,
-				     "dai %d get QMC channel failed\n", qmc_dai->id);
-	}
+	count = qmc_chan_count_phandles(np, "fsl,qmc-chan");
+	if (count < 0)
+		return dev_err_probe(qmc_audio->dev, count,
+				     "dai %d get number of QMC channel failed\n", qmc_dai->id);
+	if (!count)
+		return dev_err_probe(qmc_audio->dev, -EINVAL,
+				     "dai %d no QMC channel defined\n", qmc_dai->id);
 
-	qmc_soc_dai_driver->id = qmc_dai->id;
-	qmc_soc_dai_driver->name = qmc_dai->name;
+	qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);
+	if (!qmc_dai->chans)
+		return -ENOMEM;
 
-	ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
-	if (ret) {
-		dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
-			qmc_dai->id, ret);
-		return ret;
-	}
-	dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
-		 qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
+	for (i = 0; i < count; i++) {
+		qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
+										"fsl,qmc-chan", i);
+		if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {
+			return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),
+					     "dai %d get QMC channel %d failed\n", qmc_dai->id, i);
+		}
 
-	if (info.mode != QMC_TRANSPARENT) {
-		dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
-			qmc_dai->id, info.mode);
-		return -EINVAL;
+		ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);
+		if (ret) {
+			dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
+				qmc_dai->id, i, ret);
+			return ret;
+		}
+		dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
+			 qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts);
+
+		if (info.mode != QMC_TRANSPARENT) {
+			dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n",
+				qmc_dai->id, i, info.mode);
+			return -EINVAL;
+		}
+
+		/*
+		 * All channels must have the same number of Tx slots and the
+		 * same numbers of Rx slots.
+		 */
+		if (i == 0) {
+			nb_tx_ts = info.nb_tx_ts;
+			nb_rx_ts = info.nb_rx_ts;
+			tx_fs_rate = info.tx_fs_rate;
+			rx_fs_rate = info.rx_fs_rate;
+		} else {
+			if (nb_tx_ts != info.nb_tx_ts) {
+				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n",
+					qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts);
+				return -EINVAL;
+			}
+			if (nb_rx_ts != info.nb_rx_ts) {
+				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n",
+					qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts);
+				return -EINVAL;
+			}
+			if (tx_fs_rate != info.tx_fs_rate) {
+				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n",
+					qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate);
+				return -EINVAL;
+			}
+			if (rx_fs_rate != info.rx_fs_rate) {
+				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n",
+					qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate);
+				return -EINVAL;
+			}
+		}
 	}
-	qmc_dai->nb_tx_ts = info.nb_tx_ts;
-	qmc_dai->nb_rx_ts = info.nb_rx_ts;
+
+	qmc_dai->nb_chans_avail = count;
+	qmc_dai->nb_tx_ts = nb_tx_ts * count;
+	qmc_dai->nb_rx_ts = nb_rx_ts * count;
+
+	qmc_soc_dai_driver->id = qmc_dai->id;
+	qmc_soc_dai_driver->name = qmc_dai->name;
 
 	qmc_soc_dai_driver->playback.channels_min = 0;
 	qmc_soc_dai_driver->playback.channels_max = 0;
-	if (qmc_dai->nb_tx_ts) {
+	if (nb_tx_ts) {
 		qmc_soc_dai_driver->playback.channels_min = 1;
-		qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
+		qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;
 	}
-	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
+	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,
+								 count > 1 ? true : false);
 
 	qmc_soc_dai_driver->capture.channels_min = 0;
 	qmc_soc_dai_driver->capture.channels_max = 0;
-	if (qmc_dai->nb_rx_ts) {
+	if (nb_rx_ts) {
 		qmc_soc_dai_driver->capture.channels_min = 1;
-		qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
+		qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;
 	}
-	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
+	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,
+								count > 1 ? true : false);
 
-	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
-	qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
-	qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
-	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
-	qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
-	qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
+	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate);
+	qmc_soc_dai_driver->playback.rate_min = tx_fs_rate;
+	qmc_soc_dai_driver->playback.rate_max = tx_fs_rate;
+	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate);
+	qmc_soc_dai_driver->capture.rate_min = rx_fs_rate;
+	qmc_soc_dai_driver->capture.rate_max = rx_fs_rate;
 
 	qmc_soc_dai_driver->ops = &qmc_dai_ops;
 
@@ -702,7 +958,6 @@ static int qmc_audio_probe(struct platform_device *pdev)
 		i++;
 	}
 
-
 	platform_set_drvdata(pdev, qmc_audio);
 
 	ret = devm_snd_soc_register_component(qmc_audio->dev,
diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c
index bc41a06668566d72c915a507a96351e9f4a64b3d..467d6bc9f956675fc3bf2b11411dd47c4ed9ac0b 100644
--- a/sound/soc/fsl/fsl_rpmsg.c
+++ b/sound/soc/fsl/fsl_rpmsg.c
@@ -175,6 +175,14 @@ static const struct fsl_rpmsg_soc_data imx93_data = {
 		   SNDRV_PCM_FMTBIT_S32_LE,
 };
 
+static const struct fsl_rpmsg_soc_data imx95_data = {
+	.rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |
+		 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+		 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+		   SNDRV_PCM_FMTBIT_S32_LE,
+};
+
 static const struct of_device_id fsl_rpmsg_ids[] = {
 	{ .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data},
 	{ .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data},
@@ -182,6 +190,7 @@ static const struct of_device_id fsl_rpmsg_ids[] = {
 	{ .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data},
 	{ .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data},
 	{ .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data},
+	{ .compatible = "fsl,imx95-rpmsg-audio", .data = &imx95_data},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 0e2c3143967083a32046de0f8d5a88dbd61fd144..d03b0172b8ad240ad2903e04cf8d6119fe6e77e2 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -357,18 +357,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
 	case SND_SOC_DAIFMT_BP_FP:
 		val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
 		val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
-		sai->is_consumer_mode = false;
+		sai->is_consumer_mode[tx] = false;
 		break;
 	case SND_SOC_DAIFMT_BC_FC:
-		sai->is_consumer_mode = true;
+		sai->is_consumer_mode[tx] = true;
 		break;
 	case SND_SOC_DAIFMT_BP_FC:
 		val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
-		sai->is_consumer_mode = false;
+		sai->is_consumer_mode[tx] = false;
 		break;
 	case SND_SOC_DAIFMT_BC_FP:
 		val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
-		sai->is_consumer_mode = true;
+		sai->is_consumer_mode[tx] = true;
 		break;
 	default:
 		return -EINVAL;
@@ -400,6 +400,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	return ret;
 }
 
+static int fsl_sai_set_dai_fmt_tx(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true);
+}
+
+static int fsl_sai_set_dai_fmt_rx(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false);
+}
+
 static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
 {
 	struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
@@ -412,7 +422,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
 	bool support_1_1_ratio = sai->verid.version >= 0x0301;
 
 	/* Don't apply to consumer mode */
-	if (sai->is_consumer_mode)
+	if (sai->is_consumer_mode[tx])
 		return 0;
 
 	/*
@@ -575,7 +585,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	if (!sai->is_consumer_mode) {
+	if (!sai->is_consumer_mode[tx]) {
 		ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
 		if (ret)
 			return ret;
@@ -613,7 +623,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 	 * RCR5(TCR5) for playback(capture), or there will be sync error.
 	 */
 
-	if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) {
+	if (!sai->is_consumer_mode[tx] && fsl_sai_dir_is_synced(sai, adir)) {
 		regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
 				   FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
 				   FSL_SAI_CR4_CHMOD_MASK,
@@ -683,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 	 * FSD_MSTR bit for this specific case.
 	 */
 	if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
-	    !sai->is_consumer_mode)
+	    !sai->is_consumer_mode[tx])
 		regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
 				   FSL_SAI_CR4_FSD_MSTR, 0);
 
@@ -697,7 +707,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 
 	/* Enable FSD_MSTR after configuring word width */
 	if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
-	    !sai->is_consumer_mode)
+	    !sai->is_consumer_mode[tx])
 		regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
 				   FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR);
 
@@ -720,8 +730,8 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
 	regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
 			   FSL_SAI_CR3_TRCE_MASK, 0);
 
-	if (!sai->is_consumer_mode &&
-			sai->mclk_streams & BIT(substream->stream)) {
+	if (!sai->is_consumer_mode[tx] &&
+	    sai->mclk_streams & BIT(substream->stream)) {
 		clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
 		sai->mclk_streams &= ~BIT(substream->stream);
 	}
@@ -759,7 +769,7 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
 	 * This is a hardware bug, and will be fix in the
 	 * next sai version.
 	 */
-	if (!sai->is_consumer_mode) {
+	if (!sai->is_consumer_mode[tx]) {
 		/* Software Reset */
 		regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
 		/* Clear SR bit to finish the reset */
@@ -914,6 +924,30 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
 	.startup	= fsl_sai_startup,
 };
 
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_ops = {
+	.probe		= fsl_sai_dai_probe,
+	.set_bclk_ratio	= fsl_sai_set_dai_bclk_ratio,
+	.set_sysclk	= fsl_sai_set_dai_sysclk,
+	.set_fmt	= fsl_sai_set_dai_fmt_tx,
+	.set_tdm_slot	= fsl_sai_set_dai_tdm_slot,
+	.hw_params	= fsl_sai_hw_params,
+	.hw_free	= fsl_sai_hw_free,
+	.trigger	= fsl_sai_trigger,
+	.startup	= fsl_sai_startup,
+};
+
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_ops = {
+	.probe		= fsl_sai_dai_probe,
+	.set_bclk_ratio	= fsl_sai_set_dai_bclk_ratio,
+	.set_sysclk	= fsl_sai_set_dai_sysclk,
+	.set_fmt	= fsl_sai_set_dai_fmt_rx,
+	.set_tdm_slot	= fsl_sai_set_dai_tdm_slot,
+	.hw_params	= fsl_sai_hw_params,
+	.hw_free	= fsl_sai_hw_free,
+	.trigger	= fsl_sai_trigger,
+	.startup	= fsl_sai_startup,
+};
+
 static int fsl_sai_dai_resume(struct snd_soc_component *component)
 {
 	struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
@@ -931,26 +965,55 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
 	return 0;
 }
 
-static struct snd_soc_dai_driver fsl_sai_dai_template = {
-	.playback = {
-		.stream_name = "CPU-Playback",
-		.channels_min = 1,
-		.channels_max = 32,
-		.rate_min = 8000,
-		.rate_max = 2822400,
-		.rates = SNDRV_PCM_RATE_KNOT,
-		.formats = FSL_SAI_FORMATS,
+static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
+	{
+		.name = "sai-tx-rx",
+		.playback = {
+			.stream_name = "CPU-Playback",
+			.channels_min = 1,
+			.channels_max = 32,
+			.rate_min = 8000,
+			.rate_max = 2822400,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = FSL_SAI_FORMATS,
+		},
+		.capture = {
+			.stream_name = "CPU-Capture",
+			.channels_min = 1,
+			.channels_max = 32,
+			.rate_min = 8000,
+			.rate_max = 2822400,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = FSL_SAI_FORMATS,
+		},
+		.ops = &fsl_sai_pcm_dai_ops,
+	},
+	{
+		.name = "sai-tx",
+		.playback = {
+			.stream_name = "CPU-Playback",
+			.channels_min = 1,
+			.channels_max = 32,
+				.rate_min = 8000,
+			.rate_max = 2822400,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = FSL_SAI_FORMATS,
+		},
+		.ops = &fsl_sai_pcm_dai_tx_ops,
 	},
-	.capture = {
-		.stream_name = "CPU-Capture",
-		.channels_min = 1,
-		.channels_max = 32,
-		.rate_min = 8000,
-		.rate_max = 2822400,
-		.rates = SNDRV_PCM_RATE_KNOT,
-		.formats = FSL_SAI_FORMATS,
+	{
+		.name = "sai-rx",
+		.capture = {
+			.stream_name = "CPU-Capture",
+			.channels_min = 1,
+			.channels_max = 32,
+			.rate_min = 8000,
+			.rate_max = 2822400,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = FSL_SAI_FORMATS,
+		},
+		.ops = &fsl_sai_pcm_dai_rx_ops,
 	},
-	.ops = &fsl_sai_pcm_dai_ops,
 };
 
 static const struct snd_soc_component_driver fsl_component = {
@@ -1399,15 +1462,15 @@ static int fsl_sai_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template,
-	       sizeof(fsl_sai_dai_template));
+	memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template,
+	       sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template));
 
 	/* Sync Tx with Rx as default by following old DT binding */
 	sai->synchronous[RX] = true;
 	sai->synchronous[TX] = false;
-	sai->cpu_dai_drv.symmetric_rate = 1;
-	sai->cpu_dai_drv.symmetric_channels = 1;
-	sai->cpu_dai_drv.symmetric_sample_bits = 1;
+	sai->cpu_dai_drv[0].symmetric_rate = 1;
+	sai->cpu_dai_drv[0].symmetric_channels = 1;
+	sai->cpu_dai_drv[0].symmetric_sample_bits = 1;
 
 	if (of_property_read_bool(np, "fsl,sai-synchronous-rx") &&
 	    of_property_read_bool(np, "fsl,sai-asynchronous")) {
@@ -1424,9 +1487,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
 		/* Discard all settings for asynchronous mode */
 		sai->synchronous[RX] = false;
 		sai->synchronous[TX] = false;
-		sai->cpu_dai_drv.symmetric_rate = 0;
-		sai->cpu_dai_drv.symmetric_channels = 0;
-		sai->cpu_dai_drv.symmetric_sample_bits = 0;
+		sai->cpu_dai_drv[0].symmetric_rate = 0;
+		sai->cpu_dai_drv[0].symmetric_channels = 0;
+		sai->cpu_dai_drv[0].symmetric_sample_bits = 0;
 	}
 
 	sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output");
@@ -1505,7 +1568,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
 	}
 
 	ret = devm_snd_soc_register_component(dev, &fsl_component,
-					      &sai->cpu_dai_drv, 1);
+					      sai->cpu_dai_drv, ARRAY_SIZE(fsl_sai_dai_template));
 	if (ret)
 		goto err_pm_get_sync;
 
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 550df87b6a068c0dcb5d7dd331c876641736eaf3..dadbd16ee3945768ad4b95adf5902b62d5def483 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -282,7 +282,7 @@ struct fsl_sai {
 	struct clk *pll11k_clk;
 	struct resource *res;
 
-	bool is_consumer_mode;
+	bool is_consumer_mode[2];
 	bool is_lsb_first;
 	bool is_dsp_mode;
 	bool is_pdm_mode;
@@ -299,7 +299,7 @@ struct fsl_sai {
 	unsigned int bclk_ratio;
 
 	const struct fsl_sai_soc_data *soc_data;
-	struct snd_soc_dai_driver cpu_dai_drv;
+	struct snd_soc_dai_driver cpu_dai_drv[3];
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 	struct fsl_sai_verid verid;
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index c46f64557a7ffd268716e852dfe4411251da08cc..bf9a4e90978ef16d62d0fbad09011dc10310b4cc 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -15,14 +15,22 @@
 #include <sound/pcm_params.h>
 
 #include "fsl_xcvr.h"
+#include "fsl_utils.h"
 #include "imx-pcm.h"
 
 #define FSL_XCVR_CAPDS_SIZE	256
 
+enum fsl_xcvr_pll_verison {
+	PLL_MX8MP,
+	PLL_MX95,
+};
+
 struct fsl_xcvr_soc_data {
 	const char *fw_name;
 	bool spdif_only;
 	bool use_edma;
+	bool use_phy;
+	enum fsl_xcvr_pll_verison pll_ver;
 };
 
 struct fsl_xcvr {
@@ -33,6 +41,8 @@ struct fsl_xcvr {
 	struct clk *pll_ipg_clk;
 	struct clk *phy_clk;
 	struct clk *spba_clk;
+	struct clk *pll8k_clk;
+	struct clk *pll11k_clk;
 	struct reset_control *reset;
 	u8 streams;
 	u32 mode;
@@ -262,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
 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;
+	u32 i, div = 0, log2, val;
 	int ret;
 
-	if (xcvr->soc_data->spdif_only)
+	if (!xcvr->soc_data->use_phy)
 		return 0;
 
 	for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
@@ -288,45 +298,62 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
 		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 */
+	switch (xcvr->soc_data->pll_ver) {
+	case PLL_MX8MP:
+		/* 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_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);
+				  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);
+		}
+		break;
+	case PLL_MX95:
+		val = fsl_xcvr_pll_cfg[i].mfi << FSL_XCVR_GP_PLL_DIV_MFI_SHIFT | div;
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DIV, val, 0);
+		val = fsl_xcvr_pll_cfg[i].mfn << FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT;
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_NUMERATOR, val, 0);
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DENOMINATOR,
+				  fsl_xcvr_pll_cfg[i].mfd, 0);
+		val = FSL_XCVR_GP_PLL_CTRL_POWERUP | FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN;
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_CTRL, val, 0);
+		break;
+	default:
+		dev_err(dev, "Error for PLL version %d\n", xcvr->soc_data->pll_ver);
+		return -EINVAL;
 	}
 
 	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
@@ -362,6 +389,8 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
 
 	freq = xcvr->soc_data->spdif_only ? freq / 5 : freq;
 	clk_disable_unprepare(xcvr->phy_clk);
+	fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk,
+				     xcvr->pll8k_clk, xcvr->pll11k_clk, freq);
 	ret = clk_set_rate(xcvr->phy_clk, freq);
 	if (ret < 0) {
 		dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
@@ -373,7 +402,7 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
 		return ret;
 	}
 
-	if (xcvr->soc_data->spdif_only)
+	if (!xcvr->soc_data->use_phy)
 		return 0;
 	/* Release AI interface from reset */
 	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
@@ -500,16 +529,6 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
 		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;
-	}
-
-	/* set DPATH RESET */
-	m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
-	v_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);
@@ -650,6 +669,15 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/* set DPATH RESET */
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
+					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
+			return ret;
+		}
+
 		if (tx) {
 			switch (xcvr->mode) {
 			case FSL_XCVR_MODE_EARC:
@@ -682,6 +710,13 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
 			return ret;
 		}
 
+		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 */
 		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
 					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
@@ -704,6 +739,13 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
 			return ret;
 		}
 
+		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 clear IER0: %d\n", ret);
+			return ret;
+		}
+
 		if (tx) {
 			switch (xcvr->mode) {
 			case FSL_XCVR_MODE_SPDIF:
@@ -1017,7 +1059,7 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
 {
 	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
 
-	if (xcvr->soc_data->spdif_only)
+	if (!xcvr->soc_data->use_phy)
 		if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) ||
 		    reg > FSL_XCVR_TX_DPTH_BCRR)
 			return false;
@@ -1090,7 +1132,7 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
 {
 	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
 
-	if (xcvr->soc_data->spdif_only)
+	if (!xcvr->soc_data->use_phy)
 		if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA)
 			return false;
 	switch (reg) {
@@ -1234,6 +1276,8 @@ static irqreturn_t irq0_isr(int irq, void *devid)
 
 static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
 	.fw_name = "imx/xcvr/xcvr-imx8mp.bin",
+	.use_phy = true,
+	.pll_ver = PLL_MX8MP,
 };
 
 static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
@@ -1241,9 +1285,17 @@ static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
 	.use_edma = true,
 };
 
+static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = {
+	.spdif_only = true,
+	.use_phy = true,
+	.use_edma = true,
+	.pll_ver = PLL_MX95,
+};
+
 static const struct of_device_id fsl_xcvr_dt_ids[] = {
 	{ .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
 	{ .compatible = "fsl,imx93-xcvr", .data = &fsl_xcvr_imx93_data},
+	{ .compatible = "fsl,imx95-xcvr", .data = &fsl_xcvr_imx95_data},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
@@ -1287,6 +1339,9 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
 		return PTR_ERR(xcvr->pll_ipg_clk);
 	}
 
+	fsl_asoc_get_pll_clocks(dev, &xcvr->pll8k_clk,
+				&xcvr->pll11k_clk);
+
 	xcvr->ram_addr = devm_platform_ioremap_resource_byname(pdev, "ram");
 	if (IS_ERR(xcvr->ram_addr))
 		return PTR_ERR(xcvr->ram_addr);
@@ -1364,21 +1419,11 @@ static void fsl_xcvr_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
-static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
+static int fsl_xcvr_runtime_suspend(struct device *dev)
 {
 	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
 	int ret;
 
-	/*
-	 * Clear interrupts, when streams starts or resumes after
-	 * suspend, interrupts are enabled in prepare(), so no need
-	 * to enable interrupts in resume().
-	 */
-	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
-				 FSL_XCVR_IRQ_EARC_ALL, 0);
-	if (ret < 0)
-		dev_err(dev, "Failed to clear IER0: %d\n", ret);
-
 	if (!xcvr->soc_data->spdif_only) {
 		/* Assert M0+ reset */
 		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
@@ -1398,7 +1443,7 @@ static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev)
+static int fsl_xcvr_runtime_resume(struct device *dev)
 {
 	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
 	int ret;
@@ -1483,9 +1528,7 @@ static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops fsl_xcvr_pm_ops = {
-	SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend,
-			   fsl_xcvr_runtime_resume,
-			   NULL)
+	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)
 };
@@ -1494,7 +1537,7 @@ static struct platform_driver fsl_xcvr_driver = {
 	.probe = fsl_xcvr_probe,
 	.driver = {
 		.name = "fsl,imx8mp-audio-xcvr",
-		.pm = &fsl_xcvr_pm_ops,
+		.pm = pm_ptr(&fsl_xcvr_pm_ops),
 		.of_match_table = fsl_xcvr_dt_ids,
 	},
 	.remove_new = fsl_xcvr_remove,
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
index 044058fc6aa24c74bb0a7bf487b34d48d23b34de..882428592e1ad6876a6d9268be0f90ee8a9fb12f 100644
--- a/sound/soc/fsl/fsl_xcvr.h
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -291,4 +291,95 @@
 #define FSL_XCVR_RX_CS_BUFF_1		0xA0 /* Second RX CS buffer */
 #define FSL_XCVR_CAP_DATA_STR		0x300 /* Capabilities data structure */
 
+/* GP PLL Registers */
+#define FSL_XCVR_GP_PLL_CTRL			0x00
+#define FSL_XCVR_GP_PLL_CTRL_SET		0x04
+#define FSL_XCVR_GP_PLL_CTRL_CLR		0x08
+#define FSL_XCVR_GP_PLL_CTRL_TOG		0x0C
+#define FSL_XCVR_GP_PLL_ANA_PRG			0x10
+#define FSL_XCVR_GP_PLL_ANA_PRG_SET		0x14
+#define FSL_XCVR_GP_PLL_ANA_PRG_CLR		0x18
+#define FSL_XCVR_GP_PLL_ANA_PRG_TOG		0x1C
+#define FSL_XCVR_GP_PLL_TEST			0x20
+#define FSL_XCVR_GP_PLL_TEST_SET		0x24
+#define FSL_XCVR_GP_PLL_TEST_CLR		0x28
+#define FSL_XCVR_GP_PLL_TEST_TOG		0x2C
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM		0x30
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_SET	0x34
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_CLR	0x38
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_TOG	0x3C
+#define FSL_XCVR_GP_PLL_NUMERATOR		0x40
+#define FSL_XCVR_GP_PLL_NUMERATOR_SET		0x44
+#define FSL_XCVR_GP_PLL_NUMERATOR_CLR		0x48
+#define FSL_XCVR_GP_PLL_NUMERATOR_TOG		0x4C
+#define FSL_XCVR_GP_PLL_DENOMINATOR		0x50
+#define FSL_XCVR_GP_PLL_DENOMINATOR_SET		0x54
+#define FSL_XCVR_GP_PLL_DENOMINATOR_CLR		0x58
+#define FSL_XCVR_GP_PLL_DENOMINATOR_TOG		0x5C
+#define FSL_XCVR_GP_PLL_DIV			0x60
+#define FSL_XCVR_GP_PLL_DIV_SET			0x64
+#define FSL_XCVR_GP_PLL_DIV_CLR			0x68
+#define FSL_XCVR_GP_PLL_DIV_TOG			0x6C
+#define FSL_XCVR_GP_PLL_DFS_CTRL0		0x70
+#define FSL_XCVR_GP_PLL_DFS_CTRL0_SET		0x74
+#define FSL_XCVR_GP_PLL_DFS_CTRL0_CLR		0x78
+#define FSL_XCVR_GP_PLL_DFS_CTRL0_TOG		0x7C
+#define FSL_XCVR_GP_PLL_DFS_DIV0		0x80
+#define FSL_XCVR_GP_PLL_DFS_DIV0_SET		0x84
+#define FSL_XCVR_GP_PLL_DFS_DIV0_CLR		0x88
+#define FSL_XCVR_GP_PLL_DFS_DIV0_TOG		0x8C
+#define FSL_XCVR_GP_PLL_DFS_CTRL1		0x90
+#define FSL_XCVR_GP_PLL_DFS_CTRL1_SET		0x94
+#define FSL_XCVR_GP_PLL_DFS_CTRL1_CLR		0x98
+#define FSL_XCVR_GP_PLL_DFS_CTRL1_TOG		0x9C
+#define FSL_XCVR_GP_PLL_DFS_DIV1		0xA0
+#define FSL_XCVR_GP_PLL_DFS_DIV1_SET		0xA4
+#define FSL_XCVR_GP_PLL_DFS_DIV1_CLR		0xA8
+#define FSL_XCVR_GP_PLL_DFS_DIV1_TOG		0xAC
+#define FSL_XCVR_GP_PLL_DFS_CTRL2		0xB0
+#define FSL_XCVR_GP_PLL_DFS_CTRL2_SET		0xB4
+#define FSL_XCVR_GP_PLL_DFS_CTRL2_CLR		0xB8
+#define FSL_XCVR_GP_PLL_DFS_CTRL2_TOG		0xBC
+#define FSL_XCVR_GP_PLL_DFS_DIV2		0xC0
+#define FSL_XCVR_GP_PLL_DFS_DIV2_SET		0xC4
+#define FSL_XCVR_GP_PLL_DFS_DIV2_CLR		0xC8
+#define FSL_XCVR_GP_PLL_DFS_DIV2_TOG		0xCC
+#define FSL_XCVR_GP_PLL_DFS_CTRL3		0xD0
+#define FSL_XCVR_GP_PLL_DFS_CTRL3_SET		0xD4
+#define FSL_XCVR_GP_PLL_DFS_CTRL3_CLR		0xD8
+#define FSL_XCVR_GP_PLL_DFS_CTRL3_TOG		0xDC
+#define FSL_XCVR_GP_PLL_DFS_DIV3		0xE0
+#define FSL_XCVR_GP_PLL_DFS_DIV3_SET		0xE4
+#define FSL_XCVR_GP_PLL_DFS_DIV3_CLR		0xE8
+#define FSL_XCVR_GP_PLL_DFS_DIV3_TOG		0xEC
+#define FSL_XCVR_GP_PLL_STATUS			0xF0
+#define FSL_XCVR_GP_PLL_STATUS_SET		0xF4
+#define FSL_XCVR_GP_PLL_STATUS_CLR		0xF8
+#define FSL_XCVR_GP_PLL_STATUS_TOG		0xFC
+
+/* GP PLL Control Register */
+#define FSL_XCVR_GP_PLL_CTRL_LBYPASS		BIT(31)
+#define FSL_XCVR_GP_PLL_CTRL_HCS		BIT(16)
+#define FSL_XCVR_GP_PLL_CTRL_MSD		BIT(12)
+#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN3		BIT(11)
+#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN2		BIT(10)
+#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN1		BIT(9)
+#define FSL_XCVR_GP_PLL_CTRL_SPREADCTL		BIT(8)
+#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_BYPASS	BIT(2)
+#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN		BIT(1)
+#define FSL_XCVR_GP_PLL_CTRL_POWERUP		BIT(0)
+
+/* GP PLL Numerator Register */
+#define FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT	2
+#define FSL_XCVR_GP_PLL_NUMERATOR_MFN		GENMASK(31, 2)
+
+/* GP PLL Denominator Register */
+#define FSL_XCVR_GP_PLL_DENOMINATOR_MFD		GENMASK(29, 0)
+
+/* GP PLL Dividers Register */
+#define FSL_XCVR_GP_PLL_DIV_MFI_SHIFT		16
+#define FSL_XCVR_GP_PLL_DIV_MFI			GENMASK(24, 16)
+#define FSL_XCVR_GP_PLL_DIV_RDIV		GENMASK(15, 13)
+#define FSL_XCVR_GP_PLL_DIV_ODIV		GENMASK(7, 0)
+
 #endif /* __FSL_XCVR_H */
diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
index 2aeb18397bcb21986a74b1df623e366088595031..6fbcf33fd0dea6373b0a104d1654013882e274ca 100644
--- a/sound/soc/fsl/imx-audmix.c
+++ b/sound/soc/fsl/imx-audmix.c
@@ -140,6 +140,13 @@ static const struct snd_soc_ops imx_audmix_be_ops = {
 	.hw_params = imx_audmix_be_hw_params,
 };
 
+static const char *name[][3] = {
+	{"HiFi-AUDMIX-FE-0", "HiFi-AUDMIX-FE-1", "HiFi-AUDMIX-FE-2"},
+	{"sai-tx", "sai-tx", "sai-rx"},
+	{"AUDMIX-Playback-0", "AUDMIX-Playback-1", "CPU-Capture"},
+	{"CPU-Playback", "CPU-Playback", "AUDMIX-Capture-0"},
+};
+
 static int imx_audmix_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -150,7 +157,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
 	struct imx_audmix *priv;
 	int i, num_dai, ret;
 	const char *fe_name_pref = "HiFi-AUDMIX-FE-";
-	char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name;
+	char *be_name, *dai_name;
 
 	if (pdev->dev.parent) {
 		audmix_np = pdev->dev.parent->of_node;
@@ -183,6 +190,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
 	if (!priv)
 		return -ENOMEM;
 
+	num_dai += 1;
 	priv->num_dai = 2 * num_dai;
 	priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai,
 				 sizeof(struct snd_soc_dai_link), GFP_KERNEL);
@@ -196,7 +204,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
 	if (!priv->dai_conf)
 		return -ENOMEM;
 
-	priv->num_dapm_routes = 3 * num_dai;
+	priv->num_dapm_routes = num_dai;
 	priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes,
 					 sizeof(struct snd_soc_dapm_route),
 					 GFP_KERNEL);
@@ -211,8 +219,12 @@ static int imx_audmix_probe(struct platform_device *pdev)
 		if (!dlc)
 			return -ENOMEM;
 
-		ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i,
-						 &args);
+		if (i == num_dai - 1)
+			ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, 0,
+							 &args);
+		else
+			ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i,
+							 &args);
 		if (ret < 0) {
 			dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n");
 			return ret;
@@ -226,20 +238,14 @@ static int imx_audmix_probe(struct platform_device *pdev)
 		put_device(&cpu_pdev->dev);
 
 		dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s",
-					  fe_name_pref, args.np->full_name + 1);
+					  fe_name_pref, args.np->full_name);
 		if (!dai_name)
 			return -ENOMEM;
 
 		dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name);
 
-		if (i == 0) {
+		if (i == num_dai - 1)
 			out_cpu_np = args.np;
-			capture_dai_name =
-				devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
-					       dai_name, "CPU-Capture");
-			if (!capture_dai_name)
-				return -ENOMEM;
-		}
 
 		/*
 		 * CPU == Platform
@@ -252,27 +258,23 @@ static int imx_audmix_probe(struct platform_device *pdev)
 		priv->dai[i].num_cpus = 1;
 		priv->dai[i].num_codecs = 1;
 		priv->dai[i].num_platforms = 1;
-
-		priv->dai[i].name = dai_name;
+		priv->dai[i].name = name[0][i];
 		priv->dai[i].stream_name = "HiFi-AUDMIX-FE";
 		priv->dai[i].cpus->of_node = args.np;
-		priv->dai[i].cpus->dai_name = dev_name(&cpu_pdev->dev);
+		priv->dai[i].cpus->dai_name = name[1][i];
+
 		priv->dai[i].dynamic = 1;
 		priv->dai[i].dpcm_playback = 1;
-		priv->dai[i].dpcm_capture = (i == 0 ? 1 : 0);
+		if (i == num_dai - 1) {
+			priv->dai[i].dpcm_capture = 1;
+			priv->dai[i].dpcm_playback = 0;
+		}
 		priv->dai[i].ignore_pmdown_time = 1;
 		priv->dai[i].ops = &imx_audmix_fe_ops;
 
 		/* Add AUDMIX Backend */
 		be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
 					 "audmix-%d", i);
-		be_pb = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-				       "AUDMIX-Playback-%d", i);
-		be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-				       "AUDMIX-Capture-%d", i);
-		if (!be_name || !be_pb || !be_cp)
-			return -ENOMEM;
-
 		priv->dai[num_dai + i].cpus	= &dlc[1];
 		priv->dai[num_dai + i].codecs	= &snd_soc_dummy_dlc;
 
@@ -284,24 +286,33 @@ static int imx_audmix_probe(struct platform_device *pdev)
 		priv->dai[num_dai + i].cpus->dai_name = be_name;
 		priv->dai[num_dai + i].no_pcm = 1;
 		priv->dai[num_dai + i].dpcm_playback = 1;
-		priv->dai[num_dai + i].dpcm_capture  = 1;
+		if (i == num_dai - 1) {
+			priv->dai[num_dai + i].dpcm_capture  = 1;
+			priv->dai[num_dai + i].dpcm_playback  = 0;
+		}
 		priv->dai[num_dai + i].ignore_pmdown_time = 1;
 		priv->dai[num_dai + i].ops = &imx_audmix_be_ops;
 
 		priv->dai_conf[i].dlc.of_node = args.np;
 		priv->dai_conf[i].name_prefix = dai_name;
 
-		priv->dapm_routes[i].source =
-			devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
-				       dai_name, "CPU-Playback");
-		if (!priv->dapm_routes[i].source)
-			return -ENOMEM;
+		if (i == num_dai - 1) {
+			priv->dapm_routes[i].sink =
+				devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
+					       dai_name, name[2][i]);
+			if (!priv->dapm_routes[i].sink)
+				return -ENOMEM;
 
-		priv->dapm_routes[i].sink = be_pb;
-		priv->dapm_routes[num_dai + i].source   = be_pb;
-		priv->dapm_routes[num_dai + i].sink     = be_cp;
-		priv->dapm_routes[2 * num_dai + i].source = be_cp;
-		priv->dapm_routes[2 * num_dai + i].sink   = capture_dai_name;
+			priv->dapm_routes[i].source = name[3][i];
+		} else {
+			priv->dapm_routes[i].source =
+				devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
+					       dai_name, name[3][i]);
+			if (!priv->dapm_routes[i].source)
+				return -ENOMEM;
+
+			priv->dapm_routes[i].sink = name[2][i];
+		}
 	}
 
 	cpu_pdev = of_find_device_by_node(out_cpu_np);
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 5b9648f3b087f488ae2fc18d2cb6e33ee290b07b..3ef92f6dfc6bb18ff3ac9db63212289b66574af9 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -8,7 +8,6 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/i2c.h>
-#include <linux/of_gpio.h>
 #include <sound/soc.h>
 #include <sound/jack.h>
 
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 0d124002678ebdf2e6e8ec4da78c39d76b97fa53..3391430e425327bd09ff1a5cc175fd5c6a7e9b58 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -319,4 +319,5 @@ void imx_pcm_fiq_exit(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
 
+MODULE_DESCRIPTION("Freescale i.MX PCM FIQ handler");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index 0f1ad7ad7d270cfd5f90185ff59d3c45c3d36ab9..ce98d2288193bc99016ab12baf6fc7137272ff4b 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -5,9 +5,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/i2c.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
 #include <linux/clk.h>
 #include <sound/soc.h>
 #include <sound/jack.h>
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
deleted file mode 100644
index 1e57939a7e29f7de22d171deed1e49bf8b76db9a..0000000000000000000000000000000000000000
--- a/sound/soc/fsl/imx-spdif.c
+++ /dev/null
@@ -1,103 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// Copyright (C) 2013 Freescale Semiconductor, Inc.
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <sound/soc.h>
-
-struct imx_spdif_data {
-	struct snd_soc_dai_link dai;
-	struct snd_soc_card card;
-};
-
-static int imx_spdif_audio_probe(struct platform_device *pdev)
-{
-	struct device_node *spdif_np, *np = pdev->dev.of_node;
-	struct imx_spdif_data *data;
-	struct snd_soc_dai_link_component *comp;
-	int ret = 0;
-
-	spdif_np = of_parse_phandle(np, "spdif-controller", 0);
-	if (!spdif_np) {
-		dev_err(&pdev->dev, "failed to find spdif-controller\n");
-		ret = -EINVAL;
-		goto end;
-	}
-
-	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-	comp = devm_kzalloc(&pdev->dev, sizeof(*comp), GFP_KERNEL);
-	if (!data || !comp) {
-		ret = -ENOMEM;
-		goto end;
-	}
-
-	/*
-	 * CPU == Platform
-	 * platform is using soc-generic-dmaengine-pcm
-	 */
-	data->dai.cpus		=
-	data->dai.platforms	= comp;
-	data->dai.codecs	= &snd_soc_dummy_dlc;
-
-	data->dai.num_cpus	= 1;
-	data->dai.num_codecs	= 1;
-	data->dai.num_platforms	= 1;
-
-	data->dai.name = "S/PDIF PCM";
-	data->dai.stream_name = "S/PDIF PCM";
-	data->dai.cpus->of_node = spdif_np;
-	data->dai.playback_only = true;
-	data->dai.capture_only = true;
-
-	if (of_property_read_bool(np, "spdif-out"))
-		data->dai.capture_only = false;
-
-	if (of_property_read_bool(np, "spdif-in"))
-		data->dai.playback_only = false;
-
-	if (data->dai.playback_only && data->dai.capture_only) {
-		dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
-		goto end;
-	}
-
-	data->card.dev = &pdev->dev;
-	data->card.dai_link = &data->dai;
-	data->card.num_links = 1;
-	data->card.owner = THIS_MODULE;
-
-	ret = snd_soc_of_parse_card_name(&data->card, "model");
-	if (ret)
-		goto end;
-
-	ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
-	if (ret)
-		dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
-
-end:
-	of_node_put(spdif_np);
-
-	return ret;
-}
-
-static const struct of_device_id imx_spdif_dt_ids[] = {
-	{ .compatible = "fsl,imx-audio-spdif", },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
-
-static struct platform_driver imx_spdif_driver = {
-	.driver = {
-		.name = "imx-spdif",
-		.pm = &snd_soc_pm_ops,
-		.of_match_table = imx_spdif_dt_ids,
-	},
-	.probe = imx_spdif_audio_probe,
-};
-
-module_platform_driver(imx_spdif_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:imx-spdif");
diff --git a/sound/soc/fsl/lpc3xxx-i2s.c b/sound/soc/fsl/lpc3xxx-i2s.c
new file mode 100644
index 0000000000000000000000000000000000000000..af995ca081a37efb9604aa803ebdf1d0b81fd3f1
--- /dev/null
+++ b/sound/soc/fsl/lpc3xxx-i2s.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Author: Kevin Wells <kevin.wells@nxp.com>
+//
+// Copyright (C) 2008 NXP Semiconductors
+// Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "lpc3xxx-i2s.h"
+
+#define I2S_PLAYBACK_FLAG 0x1
+#define I2S_CAPTURE_FLAG 0x2
+
+#define LPC3XXX_I2S_RATES ( \
+	SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+	SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+#define LPC3XXX_I2S_FORMATS ( \
+	SNDRV_PCM_FMTBIT_S8 | \
+	SNDRV_PCM_FMTBIT_S16_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u32 clkrate)
+{
+	u32 i2srate;
+	u32 idxx, idyy;
+	u32 savedbitclkrate, diff, trate, baseclk;
+
+	/* Adjust rate for sample size (bits) and 2 channels and offset for
+	 * divider in clock output
+	 */
+	i2srate = (freq / 100) * 2 * (8 * xbytes);
+	i2srate = i2srate << 1;
+	clkrate = clkrate / 100;
+	baseclk = clkrate;
+	*clkx = 1;
+	*clky = 1;
+
+	/* Find the best divider */
+	*clkx = *clky = 0;
+	savedbitclkrate = 0;
+	diff = ~0;
+	for (idxx = 1; idxx < 0xFF; idxx++) {
+		for (idyy = 1; idyy < 0xFF; idyy++) {
+			trate = (baseclk * idxx) / idyy;
+			if (abs(trate - i2srate) < diff) {
+				diff = abs(trate - i2srate);
+				savedbitclkrate = trate;
+				*clkx = idxx;
+				*clky = idyy;
+			}
+		}
+	}
+}
+
+static int lpc3xxx_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+	struct device *dev = i2s_info_p->dev;
+	u32 flag;
+	int ret = 0;
+
+	guard(mutex)(&i2s_info_p->lock);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		flag = I2S_PLAYBACK_FLAG;
+	else
+		flag = I2S_CAPTURE_FLAG;
+
+	if (flag & i2s_info_p->streams_in_use) {
+		dev_warn(dev, "I2S channel is busy\n");
+		ret = -EBUSY;
+		return ret;
+	}
+
+	if (i2s_info_p->streams_in_use == 0) {
+		ret = clk_prepare_enable(i2s_info_p->clk);
+		if (ret) {
+			dev_err(dev, "Can't enable clock, err=%d\n", ret);
+			return ret;
+		}
+	}
+
+	i2s_info_p->streams_in_use |= flag;
+	return 0;
+}
+
+static void lpc3xxx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+	struct regmap *regs = i2s_info_p->regs;
+	const u32 stop_bits = (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP);
+	u32 flag;
+
+	guard(mutex)(&i2s_info_p->lock);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		flag = I2S_PLAYBACK_FLAG;
+		regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, 0);
+		regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, stop_bits, stop_bits);
+	} else {
+		flag = I2S_CAPTURE_FLAG;
+		regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, 0);
+		regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, stop_bits, stop_bits);
+	}
+	i2s_info_p->streams_in_use &= ~flag;
+
+	if (i2s_info_p->streams_in_use == 0)
+		clk_disable_unprepare(i2s_info_p->clk);
+}
+
+static int lpc3xxx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+				      int clk_id, unsigned int freq, int dir)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+
+	/* Will use in HW params later */
+	i2s_info_p->freq = freq;
+
+	return 0;
+}
+
+static int lpc3xxx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+	struct device *dev = i2s_info_p->dev;
+
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_warn(dev, "unsupported bus format %d\n", fmt);
+		return -EINVAL;
+	}
+
+	if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) {
+		dev_warn(dev, "unsupported clock provider %d\n", fmt);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+	struct device *dev = i2s_info_p->dev;
+	struct regmap *regs = i2s_info_p->regs;
+	int xfersize;
+	u32 tmp, clkx, clky;
+
+	tmp = LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		tmp |= LPC3XXX_I2S_WW8 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW8_HP);
+		xfersize = 1;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+		tmp |= LPC3XXX_I2S_WW16 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW16_HP);
+		xfersize = 2;
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		tmp |= LPC3XXX_I2S_WW32 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW32_HP);
+		xfersize = 4;
+		break;
+
+	default:
+		dev_warn(dev, "Unsupported audio data format %d\n", params_format(params));
+		return -EINVAL;
+	}
+
+	if (params_channels(params) == 1)
+		tmp |= LPC3XXX_I2S_MONO;
+
+	__lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, i2s_info_p->clkrate);
+
+	dev_dbg(dev, "Stream                : %s\n",
+		substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
+	dev_dbg(dev, "Desired clock rate    : %d\n", i2s_info_p->freq);
+	dev_dbg(dev, "Base clock rate       : %d\n", i2s_info_p->clkrate);
+	dev_dbg(dev, "Transfer size (bytes) : %d\n", xfersize);
+	dev_dbg(dev, "Clock divider (x)     : %d\n", clkx);
+	dev_dbg(dev, "Clock divider (y)     : %d\n", clky);
+	dev_dbg(dev, "Channels              : %d\n", params_channels(params));
+	dev_dbg(dev, "Data format           : %s\n", "I2S");
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_write(regs, LPC3XXX_REG_I2S_DMA1,
+			     LPC3XXX_I2S_DMA1_TX_EN | LPC3XXX_I2S_DMA0_TX_DEPTH(4));
+		regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, (clkx << 8) | clky);
+		regmap_write(regs, LPC3XXX_REG_I2S_DAO, tmp);
+	} else {
+		regmap_write(regs, LPC3XXX_REG_I2S_DMA0,
+			     LPC3XXX_I2S_DMA0_RX_EN | LPC3XXX_I2S_DMA1_RX_DEPTH(4));
+		regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, (clkx << 8) | clky);
+		regmap_write(regs, LPC3XXX_REG_I2S_DAI, tmp);
+	}
+
+	return 0;
+}
+
+static int lpc3xxx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *cpu_dai)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+	struct regmap *regs = i2s_info_p->regs;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO,
+					   LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP);
+		else
+			regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI,
+					   LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP);
+		break;
+
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO,
+					   (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0);
+		else
+			regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI,
+					   (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int lpc3xxx_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+	struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &i2s_info_p->playback_dma_config,
+				  &i2s_info_p->capture_dma_config);
+	return 0;
+}
+
+const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = {
+	.probe	= lpc3xxx_i2s_dai_probe,
+	.startup = lpc3xxx_i2s_startup,
+	.shutdown = lpc3xxx_i2s_shutdown,
+	.trigger = lpc3xxx_i2s_trigger,
+	.hw_params = lpc3xxx_i2s_hw_params,
+	.set_sysclk = lpc3xxx_i2s_set_dai_sysclk,
+	.set_fmt = lpc3xxx_i2s_set_dai_fmt,
+};
+
+struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = {
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = LPC3XXX_I2S_RATES,
+		.formats = LPC3XXX_I2S_FORMATS,
+		},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = LPC3XXX_I2S_RATES,
+		.formats = LPC3XXX_I2S_FORMATS,
+		},
+	.ops = &lpc3xxx_i2s_dai_ops,
+	.symmetric_rate = 1,
+	.symmetric_channels = 1,
+	.symmetric_sample_bits = 1,
+};
+
+static const struct snd_soc_component_driver lpc32xx_i2s_component = {
+	.name = "lpc32xx-i2s",
+	.legacy_dai_naming = 1,
+};
+
+static const struct regmap_config lpc32xx_i2s_regconfig = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = LPC3XXX_REG_I2S_RX_RATE,
+};
+
+static int lpc32xx_i2s_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lpc3xxx_i2s_info *i2s_info_p;
+	struct resource *res;
+	void __iomem *iomem;
+	int ret;
+
+	i2s_info_p = devm_kzalloc(dev, sizeof(*i2s_info_p), GFP_KERNEL);
+	if (!i2s_info_p)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, i2s_info_p);
+	i2s_info_p->dev = dev;
+
+	iomem = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(iomem))
+		return dev_err_probe(dev, PTR_ERR(iomem), "Can't map registers\n");
+
+	i2s_info_p->regs = devm_regmap_init_mmio(dev, iomem, &lpc32xx_i2s_regconfig);
+	if (IS_ERR(i2s_info_p->regs))
+		return dev_err_probe(dev, PTR_ERR(i2s_info_p->regs),
+				     "failed to init register map: %pe\n", i2s_info_p->regs);
+
+	i2s_info_p->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(i2s_info_p->clk))
+		return dev_err_probe(dev, PTR_ERR(i2s_info_p->clk), "Can't get clock\n");
+
+	i2s_info_p->clkrate = clk_get_rate(i2s_info_p->clk);
+	if (i2s_info_p->clkrate == 0)
+		return dev_err_probe(dev, -EINVAL, "Invalid returned clock rate\n");
+
+	mutex_init(&i2s_info_p->lock);
+
+	ret = devm_snd_soc_register_component(dev, &lpc32xx_i2s_component,
+					      &lpc3xxx_i2s_dai_driver, 1);
+	if (ret)
+		return dev_err_probe(dev, ret, "Can't register cpu_dai component\n");
+
+	i2s_info_p->playback_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_TX_FIFO);
+	i2s_info_p->playback_dma_config.maxburst = 4;
+
+	i2s_info_p->capture_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_RX_FIFO);
+	i2s_info_p->capture_dma_config.maxburst = 4;
+
+	ret = lpc3xxx_pcm_register(pdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Can't register pcm component\n");
+
+	return 0;
+}
+
+static const struct of_device_id lpc32xx_i2s_match[] = {
+	{ .compatible = "nxp,lpc3220-i2s" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_i2s_match);
+
+static struct platform_driver lpc32xx_i2s_driver = {
+	.probe = lpc32xx_i2s_probe,
+	.driver		= {
+		.name	= "lpc3xxx-i2s",
+		.of_match_table = lpc32xx_i2s_match,
+	},
+};
+
+module_platform_driver(lpc32xx_i2s_driver);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>");
+MODULE_DESCRIPTION("ASoC LPC3XXX I2S interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/lpc3xxx-i2s.h b/sound/soc/fsl/lpc3xxx-i2s.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6657853017a314a2914631c5b8da37bfa06234e
--- /dev/null
+++ b/sound/soc/fsl/lpc3xxx-i2s.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2008 NXP Semiconductors
+ * Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com>
+ */
+
+#ifndef __SOUND_SOC_LPC3XXX_I2S_H
+#define __SOUND_SOC_LPC3XXX_I2S_H
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+#include <linux/regmap.h>
+
+struct lpc3xxx_i2s_info {
+	struct device *dev;
+	struct clk *clk;
+	struct mutex lock; /* To serialize user-space access */
+	struct regmap *regs;
+	u32 streams_in_use;
+	u32 clkrate;
+	int freq;
+	struct snd_dmaengine_dai_dma_data playback_dma_config;
+	struct snd_dmaengine_dai_dma_data capture_dma_config;
+};
+
+int lpc3xxx_pcm_register(struct platform_device *pdev);
+
+/* I2S controller register offsets */
+#define LPC3XXX_REG_I2S_DAO		0x00
+#define LPC3XXX_REG_I2S_DAI		0x04
+#define LPC3XXX_REG_I2S_TX_FIFO	0x08
+#define LPC3XXX_REG_I2S_RX_FIFO	0x0C
+#define LPC3XXX_REG_I2S_STAT	0x10
+#define LPC3XXX_REG_I2S_DMA0	0x14
+#define LPC3XXX_REG_I2S_DMA1	0x18
+#define LPC3XXX_REG_I2S_IRQ		0x1C
+#define LPC3XXX_REG_I2S_TX_RATE	0x20
+#define LPC3XXX_REG_I2S_RX_RATE	0x24
+
+/* i2s_daO i2s_dai register definitions */
+#define LPC3XXX_I2S_WW8      FIELD_PREP(0x3, 0) /* Word width is 8bit */
+#define LPC3XXX_I2S_WW16     FIELD_PREP(0x3, 1) /* Word width is 16bit */
+#define LPC3XXX_I2S_WW32     FIELD_PREP(0x3, 3) /* Word width is 32bit */
+#define LPC3XXX_I2S_MONO     BIT(2)   /* Mono */
+#define LPC3XXX_I2S_STOP     BIT(3)   /* Stop, diables the access to FIFO, mutes the channel */
+#define LPC3XXX_I2S_RESET    BIT(4)   /* Reset the channel */
+#define LPC3XXX_I2S_WS_SEL   BIT(5)   /* Channel Master(0) or slave(1) mode select */
+#define LPC3XXX_I2S_WS_HP(s) FIELD_PREP(0x7FC0, s) /* Word select half period - 1 */
+#define LPC3XXX_I2S_MUTE     BIT(15)  /* Mute the channel, Transmit channel only */
+
+#define LPC3XXX_I2S_WW32_HP  0x1f /* Word select half period for 32bit word width */
+#define LPC3XXX_I2S_WW16_HP  0x0f /* Word select half period for 16bit word width */
+#define LPC3XXX_I2S_WW8_HP   0x7  /* Word select half period for 8bit word width */
+
+/* i2s_stat register definitions */
+#define LPC3XXX_I2S_IRQ_STAT     BIT(0)
+#define LPC3XXX_I2S_DMA0_REQ     BIT(1)
+#define LPC3XXX_I2S_DMA1_REQ     BIT(2)
+
+/* i2s_dma0 Configuration register definitions */
+#define LPC3XXX_I2S_DMA0_RX_EN     BIT(0)       /* Enable RX DMA1 */
+#define LPC3XXX_I2S_DMA0_TX_EN     BIT(1)       /* Enable TX DMA1 */
+#define LPC3XXX_I2S_DMA0_RX_DEPTH(s) FIELD_PREP(0xF00, s)  /* Set the DMA1 RX Request level */
+#define LPC3XXX_I2S_DMA0_TX_DEPTH(s) FIELD_PREP(0xF0000, s) /* Set the DMA1 TX Request level */
+
+/* i2s_dma1 Configuration register definitions */
+#define LPC3XXX_I2S_DMA1_RX_EN     BIT(0)       /* Enable RX DMA1 */
+#define LPC3XXX_I2S_DMA1_TX_EN     BIT(1)       /* Enable TX DMA1 */
+#define LPC3XXX_I2S_DMA1_RX_DEPTH(s) FIELD_PREP(0x700, s) /* Set the DMA1 RX Request level */
+#define LPC3XXX_I2S_DMA1_TX_DEPTH(s) FIELD_PREP(0x70000, s) /* Set the DMA1 TX Request level */
+
+/* i2s_irq register definitions */
+#define LPC3XXX_I2S_RX_IRQ_EN     BIT(0)       /* Enable RX IRQ */
+#define LPC3XXX_I2S_TX_IRQ_EN     BIT(1)       /* Enable TX IRQ */
+#define LPC3XXX_I2S_IRQ_RX_DEPTH(s)  FIELD_PREP(0xFF00, s)  /* valid values ar 0 to 7 */
+#define LPC3XXX_I2S_IRQ_TX_DEPTH(s)  FIELD_PREP(0xFF0000, s) /* valid values ar 0 to 7 */
+
+#endif
diff --git a/sound/soc/fsl/lpc3xxx-pcm.c b/sound/soc/fsl/lpc3xxx-pcm.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0d499b9b8ba440ac99168521d099deeb584b819
--- /dev/null
+++ b/sound/soc/fsl/lpc3xxx-pcm.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Author: Kevin Wells <kevin.wells@nxp.com>
+//
+// Copyright (C) 2008 NXP Semiconductors
+// Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/pl08x.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+
+#include "lpc3xxx-i2s.h"
+
+#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
+			SNDRV_PCM_FMTBIT_U8 | \
+			SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_U16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_U24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE | \
+			SNDRV_PCM_FMTBIT_U32_LE | \
+			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
+
+static const struct snd_pcm_hardware lpc3xxx_pcm_hardware = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_PAUSE |
+		 SNDRV_PCM_INFO_RESUME),
+	.formats = STUB_FORMATS,
+	.period_bytes_min = 128,
+	.period_bytes_max = 2048,
+	.periods_min = 2,
+	.periods_max = 1024,
+	.buffer_bytes_max = 128 * 1024
+};
+
+static const struct snd_dmaengine_pcm_config lpc3xxx_dmaengine_pcm_config = {
+	.pcm_hardware = &lpc3xxx_pcm_hardware,
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.compat_filter_fn = pl08x_filter_id,
+	.prealloc_buffer_size = 128 * 1024,
+};
+
+const struct snd_soc_component_driver lpc3xxx_soc_platform_driver = {
+	.name = "lpc32xx-pcm",
+};
+
+int lpc3xxx_pcm_register(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &lpc3xxx_dmaengine_pcm_config, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register dmaengine: %d\n", ret);
+		return ret;
+	}
+
+	return devm_snd_soc_register_component(&pdev->dev, &lpc3xxx_soc_platform_driver,
+					       NULL, 0);
+}
+EXPORT_SYMBOL(lpc3xxx_pcm_register);
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 83e3ba773fbd6e3d21db903cc273476042f1953d..3425fbbcbd7e9c6a580b8eb0739462bf21dfc051 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -7,6 +7,7 @@
 //
 // based on ${LINUX}/sound/soc/generic/simple-card.c
 
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
@@ -19,6 +20,18 @@
 
 #define DPCM_SELECTABLE 1
 
+#define ep_to_port(ep)	of_get_parent(ep)
+static struct device_node *port_to_ports(struct device_node *port)
+{
+	struct device_node *ports = of_get_parent(port);
+
+	if (!of_node_name_eq(ports, "ports")) {
+		of_node_put(ports);
+		return NULL;
+	}
+	return ports;
+}
+
 static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol,
 			      int event)
@@ -68,13 +81,12 @@ static void graph_parse_convert(struct device *dev,
 				struct simple_util_data *adata)
 {
 	struct device_node *top = dev->of_node;
-	struct device_node *port = of_get_parent(ep);
-	struct device_node *ports = of_get_parent(port);
+	struct device_node *port = ep_to_port(ep);
+	struct device_node *ports = port_to_ports(port);
 	struct device_node *node = of_graph_get_port_parent(ep);
 
 	simple_util_parse_convert(top,   NULL,   adata);
-	if (of_node_name_eq(ports, "ports"))
-		simple_util_parse_convert(ports, NULL, adata);
+	simple_util_parse_convert(ports, NULL,   adata);
 	simple_util_parse_convert(port,  NULL,   adata);
 	simple_util_parse_convert(ep,    NULL,   adata);
 
@@ -83,30 +95,12 @@ static void graph_parse_convert(struct device *dev,
 	of_node_put(node);
 }
 
-static void graph_parse_mclk_fs(struct device_node *top,
-				struct device_node *ep,
-				struct simple_dai_props *props)
-{
-	struct device_node *port	= of_get_parent(ep);
-	struct device_node *ports	= of_get_parent(port);
-
-	of_property_read_u32(top,	"mclk-fs", &props->mclk_fs);
-	if (of_node_name_eq(ports, "ports"))
-		of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
-	of_property_read_u32(port,	"mclk-fs", &props->mclk_fs);
-	of_property_read_u32(ep,	"mclk-fs", &props->mclk_fs);
-
-	of_node_put(port);
-	of_node_put(ports);
-}
-
 static int graph_parse_node(struct simple_util_priv *priv,
 			    struct device_node *ep,
 			    struct link_info *li,
 			    int *cpu)
 {
 	struct device *dev = simple_priv_to_dev(priv);
-	struct device_node *top = dev->of_node;
 	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 snd_soc_dai_link_component *dlc;
@@ -121,8 +115,6 @@ static int graph_parse_node(struct simple_util_priv *priv,
 		dai = simple_props_to_dai_codec(dai_props, 0);
 	}
 
-	graph_parse_mclk_fs(top, ep, dai_props);
-
 	ret = graph_util_parse_dai(dev, ep, dlc, cpu);
 	if (ret < 0)
 		return ret;
@@ -139,26 +131,70 @@ static int graph_parse_node(struct simple_util_priv *priv,
 }
 
 static int graph_link_init(struct simple_util_priv *priv,
-			   struct device_node *cpu_ep,
-			   struct device_node *codec_ep,
+			   struct device_node *ep_cpu,
+			   struct device_node *ep_codec,
 			   struct link_info *li,
 			   char *name)
 {
 	struct device *dev = simple_priv_to_dev(priv);
+	struct device_node *top = dev->of_node;
 	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 *port_cpu = ep_to_port(ep_cpu);
+	struct device_node *port_codec = ep_to_port(ep_codec);
+	struct device_node *ports_cpu = port_to_ports(port_cpu);
+	struct device_node *ports_codec = port_to_ports(port_codec);
+	enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
+	enum snd_soc_trigger_order trigger_stop  = SND_SOC_TRIGGER_ORDER_DEFAULT;
+	bool playback_only = 0, capture_only = 0;
 	int ret;
 
-	ret = simple_util_parse_daifmt(dev, cpu_ep, codec_ep,
+	ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec,
 				       NULL, &dai_link->dai_fmt);
 	if (ret < 0)
-		return ret;
+		goto init_end;
+
+	graph_util_parse_link_direction(top,		&playback_only, &capture_only);
+	graph_util_parse_link_direction(port_cpu,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(port_codec,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(ep_cpu,		&playback_only, &capture_only);
+	graph_util_parse_link_direction(ep_codec,	&playback_only, &capture_only);
+
+	of_property_read_u32(top,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ports_cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ports_codec,	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(port_cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(port_codec,	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ep_cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ep_codec,		"mclk-fs", &dai_props->mclk_fs);
+
+	graph_util_parse_trigger_order(priv, top,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ports_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ports_codec,	&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, port_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, port_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ep_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ep_codec,		&trigger_start, &trigger_stop);
+
+	dai_link->playback_only	= playback_only;
+	dai_link->capture_only	= capture_only;
+
+	dai_link->trigger_start	= trigger_start;
+	dai_link->trigger_stop	= trigger_stop;
 
 	dai_link->init		= simple_util_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
 
-	return simple_util_set_dailink_name(dev, dai_link, name);
+	ret = simple_util_set_dailink_name(dev, dai_link, name);
+init_end:
+	of_node_put(ports_cpu);
+	of_node_put(ports_codec);
+	of_node_put(port_cpu);
+	of_node_put(port_codec);
+
+	return ret;
 }
 
 static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
@@ -231,14 +267,11 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
 			 "be.%pOFP.%s", codecs->of_node, codecs->dai_name);
 
 		/* check "prefix" from top node */
-		port = of_get_parent(ep);
-		ports = of_get_parent(port);
-		snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
-					      "prefix");
-		if (of_node_name_eq(ports, "ports"))
-			snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
-		snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
-					     "prefix");
+		port  = ep_to_port(ep);
+		ports = port_to_ports(port);
+		snd_soc_of_parse_node_prefix(top,   cconf, codecs->of_node, "prefix");
+		snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
+		snd_soc_of_parse_node_prefix(port,  cconf, codecs->of_node, "prefix");
 
 		of_node_put(ports);
 		of_node_put(port);
@@ -350,7 +383,7 @@ static int __graph_for_each_link(struct simple_util_priv *priv,
 
 			/* get codec */
 			codec_ep = of_graph_get_remote_endpoint(cpu_ep);
-			codec_port = of_get_parent(codec_ep);
+			codec_port = ep_to_port(codec_ep);
 
 			/* get convert-xxx property */
 			memset(&adata, 0, sizeof(adata));
@@ -541,10 +574,9 @@ static int graph_get_dais_count(struct simple_util_priv *priv,
 int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
 {
 	struct snd_soc_card *card = simple_priv_to_card(priv);
-	struct link_info *li;
 	int ret;
 
-	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+	struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
 	if (!li)
 		return -ENOMEM;
 
@@ -596,7 +628,6 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
 	if (ret < 0)
 		goto err;
 
-	devm_kfree(dev, li);
 	return 0;
 
 err:
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c
index 1b6ccd2de9647b5465b1d629815a15b8d212c8c9..8e5a510984902eb637a9f592212ec88b498218ed 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.c
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.c
@@ -5,8 +5,9 @@
 // Copyright (C) 2020 Renesas Electronics Corp.
 // Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 //
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <sound/graph_card.h>
 
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 81e84095107edbcdc47b26bec3854bd4679abf3c..56f7f946882e831cc4474c86b31f69e15de1549a 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -236,6 +236,18 @@ enum graph_type {
 
 #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint")
 
+#define ep_to_port(ep)	of_get_parent(ep)
+static struct device_node *port_to_ports(struct device_node *port)
+{
+	struct device_node *ports = of_get_parent(port);
+
+	if (!of_node_name_eq(ports, "ports")) {
+		of_node_put(ports);
+		return NULL;
+	}
+	return ports;
+}
+
 static enum graph_type __graph_get_type(struct device_node *lnk)
 {
 	struct device_node *np, *parent_np;
@@ -320,7 +332,7 @@ static int graph_lnk_is_multi(struct device_node *lnk)
 
 static struct device_node *graph_get_next_multi_ep(struct device_node **port)
 {
-	struct device_node *ports = of_get_parent(*port);
+	struct device_node *ports = port_to_ports(*port);
 	struct device_node *ep = NULL;
 	struct device_node *rep = NULL;
 
@@ -365,12 +377,11 @@ static const struct snd_soc_ops graph_ops = {
 static void graph_parse_convert(struct device_node *ep,
 				struct simple_dai_props *props)
 {
-	struct device_node *port = of_get_parent(ep);
-	struct device_node *ports = of_get_parent(port);
+	struct device_node *port = ep_to_port(ep);
+	struct device_node *ports = port_to_ports(port);
 	struct simple_util_data *adata = &props->adata;
 
-	if (of_node_name_eq(ports, "ports"))
-		simple_util_parse_convert(ports, NULL, adata);
+	simple_util_parse_convert(ports, NULL, adata);
 	simple_util_parse_convert(port, NULL, adata);
 	simple_util_parse_convert(ep,   NULL, adata);
 
@@ -378,21 +389,6 @@ static void graph_parse_convert(struct device_node *ep,
 	of_node_put(ports);
 }
 
-static void graph_parse_mclk_fs(struct device_node *ep,
-				struct simple_dai_props *props)
-{
-	struct device_node *port	= of_get_parent(ep);
-	struct device_node *ports	= of_get_parent(port);
-
-	if (of_node_name_eq(ports, "ports"))
-		of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
-	of_property_read_u32(port,	"mclk-fs", &props->mclk_fs);
-	of_property_read_u32(ep,	"mclk-fs", &props->mclk_fs);
-
-	of_node_put(port);
-	of_node_put(ports);
-}
-
 static int __graph_parse_node(struct simple_util_priv *priv,
 			      enum graph_type gtype,
 			      struct device_node *ep,
@@ -414,8 +410,6 @@ static int __graph_parse_node(struct simple_util_priv *priv,
 		dai = simple_props_to_dai_codec(dai_props, idx);
 	}
 
-	graph_parse_mclk_fs(ep, dai_props);
-
 	ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links);
 	if (ret < 0)
 		return ret;
@@ -481,11 +475,10 @@ static int __graph_parse_node(struct simple_util_priv *priv,
 	if (!is_cpu && gtype == GRAPH_DPCM) {
 		struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
 		struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx);
-		struct device_node *rport  = of_get_parent(ep);
-		struct device_node *rports = of_get_parent(rport);
+		struct device_node *rport  = ep_to_port(ep);
+		struct device_node *rports = port_to_ports(rport);
 
-		if (of_node_name_eq(rports, "ports"))
-			snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
+		snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
 		snd_soc_of_parse_node_prefix(rport,  cconf, codecs->of_node, "prefix");
 
 		of_node_put(rport);
@@ -539,11 +532,11 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
 	 */
 	struct device_node *mcpu_ep		= port_to_endpoint(mcpu_port);
 	struct device_node *mcpu_ep_n		= mcpu_ep;
-	struct device_node *mcpu_port_top	= of_get_next_child(of_get_parent(mcpu_port), NULL);
+	struct device_node *mcpu_port_top	= of_get_next_child(port_to_ports(mcpu_port), NULL);
 	struct device_node *mcpu_ep_top		= port_to_endpoint(mcpu_port_top);
 	struct device_node *mcodec_ep_top	= of_graph_get_remote_endpoint(mcpu_ep_top);
-	struct device_node *mcodec_port_top	= of_get_parent(mcodec_ep_top);
-	struct device_node *mcodec_ports	= of_get_parent(mcodec_port_top);
+	struct device_node *mcodec_port_top	= ep_to_port(mcodec_ep_top);
+	struct device_node *mcodec_ports	= port_to_ports(mcodec_port_top);
 	int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
 	int ret = -EINVAL;
 
@@ -566,9 +559,9 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
 		}
 
 		mcodec_ep_n	= of_graph_get_remote_endpoint(mcpu_ep_n);
-		mcodec_port	= of_get_parent(mcodec_ep_n);
+		mcodec_port	= ep_to_port(mcodec_ep_n);
 
-		if (mcodec_ports != of_get_parent(mcodec_port))
+		if (mcodec_ports != port_to_ports(mcodec_port))
 			goto mcpu_err;
 
 		codec_idx = 0;
@@ -705,6 +698,9 @@ static void graph_parse_daifmt(struct device_node *node,
 {
 	unsigned int fmt;
 
+	if (!node)
+		return;
+
 	/*
 	 * see also above "daifmt" explanation
 	 * and samples.
@@ -751,43 +747,74 @@ static void graph_parse_daifmt(struct device_node *node,
 }
 
 static void graph_link_init(struct simple_util_priv *priv,
-			    struct device_node *port,
+			    struct device_node *lnk,
+			    struct device_node *port_cpu,
+			    struct device_node *port_codec,
 			    struct link_info *li,
 			    int is_cpu_node)
 {
 	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
-	struct device_node *ep;
-	struct device_node *ports;
+	struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
+	struct device_node *ep_cpu, *ep_codec;
+	struct device_node *ports_cpu, *ports_codec;
 	unsigned int daifmt = 0, daiclk = 0;
 	bool playback_only = 0, capture_only = 0;
+	enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
+	enum snd_soc_trigger_order trigger_stop  = SND_SOC_TRIGGER_ORDER_DEFAULT;
 	unsigned int bit_frame = 0;
 
-	if (graph_lnk_is_multi(port)) {
-		of_node_get(port);
-		ep = graph_get_next_multi_ep(&port);
-		port = of_get_parent(ep);
+	of_node_get(port_cpu);
+	if (graph_lnk_is_multi(port_cpu)) {
+		ep_cpu = graph_get_next_multi_ep(&port_cpu);
+		of_node_put(port_cpu);
+		port_cpu = ep_to_port(ep_cpu);
 	} else {
-		ep = port_to_endpoint(port);
+		ep_cpu = port_to_endpoint(port_cpu);
 	}
+	ports_cpu = port_to_ports(port_cpu);
 
-	ports = of_get_parent(port);
-
-	/*
-	 *	ports {
-	 * (A)
-	 *		port {
-	 * (B)
-	 *			endpoint {
-	 * (C)
-	 *			};
-	 *		};
-	 *	};
-	 * };
-	 */
-	graph_parse_daifmt(ep,    &daifmt, &bit_frame);		/* (C) */
-	graph_parse_daifmt(port,  &daifmt, &bit_frame);		/* (B) */
-	if (of_node_name_eq(ports, "ports"))
-		graph_parse_daifmt(ports, &daifmt, &bit_frame);	/* (A) */
+	of_node_get(port_codec);
+	if (graph_lnk_is_multi(port_codec)) {
+		ep_codec = graph_get_next_multi_ep(&port_codec);
+		of_node_put(port_cpu);
+		port_codec = ep_to_port(ep_codec);
+	} else {
+		ep_codec = port_to_endpoint(port_codec);
+	}
+	ports_codec = port_to_ports(port_codec);
+
+
+	graph_parse_daifmt(ep_cpu,	&daifmt, &bit_frame);
+	graph_parse_daifmt(ep_codec,	&daifmt, &bit_frame);
+	graph_parse_daifmt(port_cpu,	&daifmt, &bit_frame);
+	graph_parse_daifmt(port_codec,	&daifmt, &bit_frame);
+	graph_parse_daifmt(ports_cpu,	&daifmt, &bit_frame);
+	graph_parse_daifmt(ports_codec,	&daifmt, &bit_frame);
+	graph_parse_daifmt(lnk,		&daifmt, &bit_frame);
+
+	graph_util_parse_link_direction(lnk,		&playback_only, &capture_only);
+	graph_util_parse_link_direction(ports_cpu,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(ports_codec,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(port_cpu,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(port_codec,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(ep_cpu,		&playback_only, &capture_only);
+	graph_util_parse_link_direction(ep_codec,	&playback_only, &capture_only);
+
+	of_property_read_u32(lnk,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ports_cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ports_codec,	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(port_cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(port_codec,	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ep_cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(ep_codec,		"mclk-fs", &dai_props->mclk_fs);
+
+	graph_util_parse_trigger_order(priv, lnk,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ports_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ports_codec,	&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, port_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, port_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ep_cpu,		&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, ep_codec,		&trigger_start, &trigger_stop);
 
 	/*
 	 * convert bit_frame
@@ -798,16 +825,24 @@ static void graph_link_init(struct simple_util_priv *priv,
 	if (is_cpu_node)
 		daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk);
 
-	graph_util_parse_link_direction(port, &playback_only, &capture_only);
+	dai_link->playback_only	= playback_only;
+	dai_link->capture_only	= capture_only;
 
-	dai_link->playback_only = playback_only;
-	dai_link->capture_only = capture_only;
+	dai_link->trigger_start	= trigger_start;
+	dai_link->trigger_stop	= trigger_stop;
 
 	dai_link->dai_fmt	= daifmt | daiclk;
 	dai_link->init		= simple_util_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
+
+	of_node_put(ports_cpu);
+	of_node_put(ports_codec);
+	of_node_put(port_cpu);
+	of_node_put(port_codec);
+	of_node_put(ep_cpu);
+	of_node_put(ep_codec);
 }
 
 int audio_graph2_link_normal(struct simple_util_priv *priv,
@@ -835,7 +870,7 @@ int audio_graph2_link_normal(struct simple_util_priv *priv,
 	if (ret < 0)
 		goto err;
 
-	graph_link_init(priv, cpu_port, li, 1);
+	graph_link_init(priv, lnk, cpu_port, codec_port, li, 1);
 err:
 	of_node_put(codec_port);
 	of_node_put(cpu_ep);
@@ -850,13 +885,16 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
 {
 	struct device_node *ep = port_to_endpoint(lnk);
 	struct device_node *rep = of_graph_get_remote_endpoint(ep);
-	struct device_node *rport = of_graph_get_remote_port(ep);
+	struct device_node *cpu_port = NULL;
+	struct device_node *codec_port = NULL;
 	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);
 	int is_cpu = graph_util_is_ports0(lnk);
 	int ret;
 
 	if (is_cpu) {
+		cpu_port = of_graph_get_remote_port(ep); /* rport */
+
 		/*
 		 * dpcm {
 		 *	// Front-End
@@ -884,10 +922,13 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
 		dai_link->dynamic		= 1;
 		dai_link->dpcm_merged_format	= 1;
 
-		ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 1);
+		ret = graph_parse_node(priv, GRAPH_DPCM, cpu_port, li, 1);
 		if (ret)
 			goto err;
+
 	} else {
+		codec_port = of_graph_get_remote_port(ep); /* rport */
+
 		/*
 		 * dpcm {
 		 *	// Front-End
@@ -917,7 +958,7 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
 		dai_link->no_pcm		= 1;
 		dai_link->be_hw_params_fixup	= simple_util_be_hw_params_fixup;
 
-		ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 0);
+		ret = graph_parse_node(priv, GRAPH_DPCM, codec_port, li, 0);
 		if (ret < 0)
 			goto err;
 	}
@@ -927,11 +968,12 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
 
 	snd_soc_dai_link_set_capabilities(dai_link);
 
-	graph_link_init(priv, rport, li, is_cpu);
+	graph_link_init(priv, lnk, cpu_port, codec_port, li, is_cpu);
 err:
 	of_node_put(ep);
 	of_node_put(rep);
-	of_node_put(rport);
+	of_node_put(cpu_port);
+	of_node_put(codec_port);
 
 	return ret;
 }
@@ -966,7 +1008,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
 	 */
 	of_node_get(lnk);
 	port0 = lnk;
-	ports = of_get_parent(port0);
+	ports = port_to_ports(port0);
 	port1 = of_get_next_child(ports, lnk);
 
 	/*
@@ -1019,7 +1061,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
 	if (ret < 0)
 		goto err2;
 
-	graph_link_init(priv, codec0_port, li, 1);
+	graph_link_init(priv, lnk, codec0_port, codec1_port, li, 1);
 err2:
 	of_node_put(ep0);
 	of_node_put(ep1);
@@ -1098,7 +1140,7 @@ static int graph_counter(struct device_node *lnk)
 	 * ignore first lnk part
 	 */
 	if (graph_lnk_is_multi(lnk)) {
-		struct device_node *ports = of_get_parent(lnk);
+		struct device_node *ports = port_to_ports(lnk);
 		struct device_node *port = NULL;
 		int cnt = 0;
 
@@ -1195,7 +1237,7 @@ static int graph_count_c2c(struct simple_util_priv *priv,
 			   struct device_node *lnk,
 			   struct link_info *li)
 {
-	struct device_node *ports = of_get_parent(lnk);
+	struct device_node *ports = port_to_ports(lnk);
 	struct device_node *port0 = lnk;
 	struct device_node *port1 = of_get_next_child(ports, of_node_get(lnk));
 	struct device_node *ep0 = port_to_endpoint(port0);
@@ -1308,10 +1350,9 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
 			  struct graph2_custom_hooks *hooks)
 {
 	struct snd_soc_card *card = simple_priv_to_card(priv);
-	struct link_info *li;
 	int ret;
 
-	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+	struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
 	if (!li)
 		return -ENOMEM;
 
@@ -1369,10 +1410,12 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
 
 	simple_util_debug_info(priv);
 
+	ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
+	if (ret < 0)
+		goto err;
+
 	ret = devm_snd_soc_register_card(dev, card);
 err:
-	devm_kfree(dev, li);
-
 	if (ret < 0)
 		dev_err_probe(dev, ret, "parse error\n");
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index b4876b4f259ddda34d31459992d83a930b960168..fedae7f6f70cc52317af13ce8134a3d44d92f625 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -4,6 +4,8 @@
 //
 // Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
+#include <dt-bindings/sound/audio-graph.h>
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
@@ -13,12 +15,11 @@
 #include <sound/pcm_params.h>
 #include <sound/simple_card_utils.h>
 
-static void simple_fixup_sample_fmt(struct simple_util_data *data,
-					 struct snd_pcm_hw_params *params)
+int simple_util_get_sample_fmt(struct simple_util_data *data)
 {
 	int i;
-	struct snd_mask *mask = hw_param_mask(params,
-					      SNDRV_PCM_HW_PARAM_FORMAT);
+	int val = -EINVAL;
+
 	struct {
 		char *fmt;
 		u32 val;
@@ -33,11 +34,26 @@ static void simple_fixup_sample_fmt(struct simple_util_data *data,
 	for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) {
 		if (!strcmp(data->convert_sample_format,
 			    of_sample_fmt_table[i].fmt)) {
-			snd_mask_none(mask);
-			snd_mask_set(mask, of_sample_fmt_table[i].val);
+			val = of_sample_fmt_table[i].val;
 			break;
 		}
 	}
+	return val;
+}
+EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt);
+
+static void simple_fixup_sample_fmt(struct simple_util_data *data,
+				    struct snd_pcm_hw_params *params)
+{
+	int val;
+	struct snd_mask *mask = hw_param_mask(params,
+					      SNDRV_PCM_HW_PARAM_FORMAT);
+
+	val = simple_util_get_sample_fmt(data);
+	if (val >= 0) {
+		snd_mask_none(mask);
+		snd_mask_set(mask, val);
+	}
 }
 
 void simple_util_parse_convert(struct device_node *np,
@@ -46,6 +62,9 @@ void simple_util_parse_convert(struct device_node *np,
 {
 	char prop[128];
 
+	if (!np)
+		return;
+
 	if (!prefix)
 		prefix = "";
 
@@ -117,8 +136,8 @@ EXPORT_SYMBOL_GPL(simple_util_parse_daifmt);
 int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np,
 				    struct simple_util_dai *dai)
 {
-	u32 *array_values, *p;
 	int n, i, ret;
+	u32 *p;
 
 	if (!of_property_read_bool(np, "dai-tdm-slot-width-map"))
 		return 0;
@@ -133,14 +152,15 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np,
 	if (!dai->tdm_width_map)
 		return -ENOMEM;
 
-	array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
+	u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values),
+						  GFP_KERNEL);
 	if (!array_values)
 		return -ENOMEM;
 
 	ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
 	if (ret < 0) {
 		dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
-		goto out;
+		return ret;
 	}
 
 	p = array_values;
@@ -151,11 +171,8 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np,
 	}
 
 	dai->n_tdm_widths = i;
-	ret = 0;
-out:
-	kfree(array_values);
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map);
 
@@ -1126,24 +1143,88 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep,
 }
 EXPORT_SYMBOL_GPL(graph_util_parse_dai);
 
-int graph_util_parse_link_direction(struct device_node *np,
+void graph_util_parse_link_direction(struct device_node *np,
 				    bool *playback_only, bool *capture_only)
 {
-	bool is_playback_only = false;
-	bool is_capture_only = false;
+	bool is_playback_only = of_property_read_bool(np, "playback-only");
+	bool is_capture_only  = of_property_read_bool(np, "capture-only");
 
-	is_playback_only = of_property_read_bool(np, "playback-only");
-	is_capture_only = of_property_read_bool(np, "capture-only");
+	if (is_playback_only)
+		*playback_only = is_playback_only;
+	if (is_capture_only)
+		*capture_only = is_capture_only;
+}
+EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
 
-	if (is_playback_only && is_capture_only)
-		return -EINVAL;
+static enum snd_soc_trigger_order
+__graph_util_parse_trigger_order(struct simple_util_priv *priv,
+				 struct device_node *np,
+				 const char *prop)
+{
+	u32 val[SND_SOC_TRIGGER_SIZE];
+	int ret;
 
-	*playback_only = is_playback_only;
-	*capture_only = is_capture_only;
+	ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE);
+	if (ret == 0) {
+		struct device *dev = simple_priv_to_dev(priv);
+		u32 order =	(val[0] << 8) +
+			(val[1] << 4) +
+			(val[2]);
+
+		switch (order) {
+		case	(SND_SOC_TRIGGER_LINK		<< 8) +
+			(SND_SOC_TRIGGER_COMPONENT	<< 4) +
+			(SND_SOC_TRIGGER_DAI):
+			return SND_SOC_TRIGGER_ORDER_DEFAULT;
+
+		case	(SND_SOC_TRIGGER_LINK		<< 8) +
+			(SND_SOC_TRIGGER_DAI		<< 4) +
+			(SND_SOC_TRIGGER_COMPONENT):
+			return SND_SOC_TRIGGER_ORDER_LDC;
+
+		default:
+			dev_err(dev, "unsupported trigger order [0x%x]\n", order);
+		}
+	}
 
-	return 0;
+	/* SND_SOC_TRIGGER_ORDER_MAX means error */
+	return SND_SOC_TRIGGER_ORDER_MAX;
 }
-EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
+
+void graph_util_parse_trigger_order(struct simple_util_priv *priv,
+				    struct device_node *np,
+				    enum snd_soc_trigger_order *trigger_start,
+				    enum snd_soc_trigger_order *trigger_stop)
+{
+	static enum snd_soc_trigger_order order;
+
+	/*
+	 * We can use it like below
+	 *
+	 * #include <dt-bindings/sound/audio-graph.h>
+	 *
+	 * link-trigger-order = <SND_SOC_TRIGGER_LINK
+	 *			 SND_SOC_TRIGGER_COMPONENT
+	 *			 SND_SOC_TRIGGER_DAI>;
+	 */
+
+	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order");
+	if (order < SND_SOC_TRIGGER_ORDER_MAX) {
+		*trigger_start = order;
+		*trigger_stop  = order;
+	}
+
+	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start");
+	if (order < SND_SOC_TRIGGER_ORDER_MAX)
+		*trigger_start = order;
+
+	order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop");
+	if (order < SND_SOC_TRIGGER_ORDER_MAX)
+		*trigger_stop  = order;
+
+	return;
+}
+EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order);
 
 /* Module information */
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 9c79ff6a568f025b21eaf01e48742ee043d529f3..d2588f1ea54e52a0784b11ebd8d3be2a1b1fe857 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -5,6 +5,7 @@
 // Copyright (C) 2012 Renesas Solutions Corp.
 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/module.h>
@@ -129,24 +130,6 @@ static void simple_parse_convert(struct device *dev,
 	of_node_put(node);
 }
 
-static void simple_parse_mclk_fs(struct device_node *top,
-				 struct device_node *np,
-				 struct simple_dai_props *props,
-				 char *prefix)
-{
-	struct device_node *node = of_get_parent(np);
-	char prop[128];
-
-	snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
-	of_property_read_u32(top,	prop, &props->mclk_fs);
-
-	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
-	of_property_read_u32(node,	prop, &props->mclk_fs);
-	of_property_read_u32(np,	prop, &props->mclk_fs);
-
-	of_node_put(node);
-}
-
 static int simple_parse_node(struct simple_util_priv *priv,
 			     struct device_node *np,
 			     struct link_info *li,
@@ -154,7 +137,6 @@ static int simple_parse_node(struct simple_util_priv *priv,
 			     int *cpu)
 {
 	struct device *dev = simple_priv_to_dev(priv);
-	struct device_node *top = dev->of_node;
 	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 snd_soc_dai_link_component *dlc;
@@ -169,8 +151,6 @@ static int simple_parse_node(struct simple_util_priv *priv,
 		dai = simple_props_to_dai_codec(dai_props, 0);
 	}
 
-	simple_parse_mclk_fs(top, np, dai_props, prefix);
-
 	ret = simple_parse_dai(dev, np, dlc, cpu);
 	if (ret)
 		return ret;
@@ -187,24 +167,59 @@ static int simple_parse_node(struct simple_util_priv *priv,
 }
 
 static int simple_link_init(struct simple_util_priv *priv,
-			    struct device_node *node,
+			    struct device_node *cpu,
 			    struct device_node *codec,
 			    struct link_info *li,
 			    char *prefix, char *name)
 {
 	struct device *dev = simple_priv_to_dev(priv);
+	struct device_node *top = dev->of_node;
 	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 *node = of_get_parent(cpu);
+	enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
+	enum snd_soc_trigger_order trigger_stop  = SND_SOC_TRIGGER_ORDER_DEFAULT;
+	bool playback_only = 0, capture_only = 0;
 	int ret;
 
 	ret = simple_util_parse_daifmt(dev, node, codec,
 				       prefix, &dai_link->dai_fmt);
 	if (ret < 0)
-		return 0;
+		goto init_end;
+
+	graph_util_parse_link_direction(top,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(node,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(cpu,	&playback_only, &capture_only);
+	graph_util_parse_link_direction(codec,	&playback_only, &capture_only);
+
+	of_property_read_u32(top,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(top,	PREFIX	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(node,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(node,	PREFIX	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(cpu,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(cpu,	PREFIX	"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(codec,		"mclk-fs", &dai_props->mclk_fs);
+	of_property_read_u32(codec,	PREFIX	"mclk-fs", &dai_props->mclk_fs);
+
+	graph_util_parse_trigger_order(priv, top,	&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, node,	&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, cpu,	&trigger_start, &trigger_stop);
+	graph_util_parse_trigger_order(priv, codec,	&trigger_start, &trigger_stop);
+
+	dai_link->playback_only		= playback_only;
+	dai_link->capture_only		= capture_only;
+
+	dai_link->trigger_start		= trigger_start;
+	dai_link->trigger_stop		= trigger_stop;
 
 	dai_link->init			= simple_util_dai_init;
 	dai_link->ops			= &simple_ops;
 
-	return simple_util_set_dailink_name(dev, dai_link, name);
+	ret = simple_util_set_dailink_name(dev, dai_link, name);
+init_end:
+	of_node_put(node);
+
+	return ret;
 }
 
 static int simple_dai_link_of_dpcm(struct simple_util_priv *priv,
@@ -278,7 +293,7 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv,
 
 	snd_soc_dai_link_set_capabilities(dai_link);
 
-	ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
+	ret = simple_link_init(priv, np, codec, li, prefix, dai_name);
 
 out_put_node:
 	li->link++;
@@ -336,7 +351,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv,
 	simple_util_canonicalize_cpu(cpus, single_cpu);
 	simple_util_canonicalize_platform(platforms, cpus);
 
-	ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
+	ret = simple_link_init(priv, cpu, codec, li, prefix, dai_name);
 
 dai_link_of_err:
 	of_node_put(plat);
@@ -713,7 +728,6 @@ static int simple_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct snd_soc_card *card;
-	struct link_info *li;
 	int ret;
 
 	/* Allocate the private data and the DAI link array */
@@ -727,7 +741,7 @@ static int simple_probe(struct platform_device *pdev)
 	card->probe		= simple_soc_probe;
 	card->driver_name       = "simple-card";
 
-	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+	struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
 	if (!li)
 		return -ENOMEM;
 
@@ -804,7 +818,6 @@ static int simple_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err;
 
-	devm_kfree(dev, li);
 	return 0;
 err:
 	simple_util_clean_reference(card);
diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c
index e4967540a2e1923e42c6ddbca2940331c9e5b52d..e9e5e235a8a659cabffee7acd747a68bd45f177f 100644
--- a/sound/soc/generic/test-component.c
+++ b/sound/soc/generic/test-component.c
@@ -189,7 +189,7 @@ static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static u64 test_dai_formats =
+static const u64 test_dai_formats =
 	/*
 	 * Select below from Sound Card, not auto
 	 *	SND_SOC_POSSIBLE_DAIFMT_BP_FP
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
index 3bf37a8fd6e65350d5d6712de6cf52c76f4e6620..c8522e2430f8af4cac8f095e67f34b7585c3c8ad 100644
--- a/sound/soc/intel/avs/boards/es8336.c
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -18,7 +18,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
-#include <asm/intel-family.h>
+#include <asm/cpu_device_id.h>
 #include "../utils.h"
 
 #define ES8336_CODEC_DAI	"ES8316 HiFi"
@@ -153,9 +153,9 @@ static int avs_es8336_hw_params(struct snd_pcm_substream *substream,
 	int clk_freq;
 	int ret;
 
-	switch (boot_cpu_data.x86_model) {
-	case INTEL_FAM6_KABYLAKE_L:
-	case INTEL_FAM6_KABYLAKE:
+	switch (boot_cpu_data.x86_vfm) {
+	case INTEL_KABYLAKE_L:
+	case INTEL_KABYLAKE:
 		clk_freq = 24000000;
 		break;
 	default:
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 88e711875004866a473c50203b94c79d635e4114..c76b86254a8b4dafd4767ec3f8b224456f45aec0 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -341,7 +341,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
 {
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_stream *stream_info;
+	const struct snd_soc_pcm_stream *stream_info;
 	struct hdac_ext_stream *link_stream;
 	struct hdac_ext_link *link;
 	struct avs_dma_data *data;
@@ -637,7 +637,7 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so
 static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_stream *stream_info;
+	const struct snd_soc_pcm_stream *stream_info;
 	struct avs_dma_data *data;
 	struct hdac_ext_stream *host_stream;
 	unsigned int format_val;
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index b6c5d94a15548281bff4c237ded9fa4361bf8212..5cda527020c7bfd7cf522f2ae11deac3dbff3c8b 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -1900,7 +1900,7 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
 	return 0;
 }
 
-static struct snd_soc_tplg_ops avs_tplg_ops = {
+static const struct snd_soc_tplg_ops avs_tplg_ops = {
 	.io_ops			= avs_control_ops,
 	.io_ops_count		= ARRAY_SIZE(avs_control_ops),
 	.control_load		= avs_control_load,
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 4e0586034de4b2f0700324615844655ef42e6e43..f1faa5dd2a4fc958d50346432ca8339c5f8e809b 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -677,6 +677,8 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
 	select SND_SOC_CS42L43_SDW
 	select MFD_CS42L43
 	select MFD_CS42L43_SDW
+	select PINCTRL_CS42L43
+	select SPI_CS42L43
 	select SND_SOC_CS35L56_SPI
 	select SND_SOC_CS35L56_SDW
 	select SND_SOC_DMIC
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index 3ae26f21458f332019c69f6f39328b50a6aa00f6..3c7cee03a02e6485c833fffa14c49d0fa3193967 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -131,7 +131,7 @@ static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops bdw_rt5650_ops = {
+static const struct snd_soc_ops bdw_rt5650_ops = {
 	.hw_params = bdw_rt5650_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c
index 686e603212243d6802c16f53dc882f79c4fa40af..26289e8fdd873e76e6ff6f6626c73aeb662e2e36 100644
--- a/sound/soc/intel/boards/ehl_rt5660.c
+++ b/sound/soc/intel/boards/ehl_rt5660.c
@@ -132,7 +132,7 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops rt5660_ops = {
+static const struct snd_soc_ops rt5660_ops = {
 	.hw_params = rt5660_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 9dbc15f9d1c9b69f64360399dc5cf8a08461f487..154f6a74ed151f9318d2c6f3f13550f503b559d8 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -354,7 +354,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
 			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops kabylake_dmic_ops = {
+static const struct snd_soc_ops kabylake_dmic_ops = {
 	.startup = kabylake_dmic_startup,
 };
 
@@ -388,7 +388,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
 					&constraints_16000);
 }
 
-static struct snd_soc_ops skylake_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
 	.startup = kabylake_refcap_startup,
 };
 
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index e662da5af83b591e6cf648ebebd3479202a6a1e9..02ed77a07e23d69be91899ec27cdaa1f62f4072c 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -288,7 +288,7 @@ static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd)
 	return 0;
 }
 
-static struct snd_soc_ops kabylake_ssp0_ops = {
+static const struct snd_soc_ops kabylake_ssp0_ops = {
 	.hw_params = kabylake_ssp0_hw_params,
 	.trigger = kabylake_ssp0_trigger,
 };
@@ -535,7 +535,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
 			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops kabylake_dmic_ops = {
+static const struct snd_soc_ops kabylake_dmic_ops = {
 	.startup = kabylake_dmic_startup,
 };
 
@@ -569,7 +569,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
 }
 
 
-static struct snd_soc_ops skylake_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
 	.startup = kabylake_refcap_startup,
 };
 
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
index 894d127c482a3beacba85b6b24434ac31213144c..66885cb36f2489a07de5c0ecebc39bcbe0f44b59 100644
--- a/sound/soc/intel/boards/kbl_rt5660.c
+++ b/sound/soc/intel/boards/kbl_rt5660.c
@@ -277,7 +277,7 @@ static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops kabylake_rt5660_ops = {
+static const struct snd_soc_ops kabylake_rt5660_ops = {
 	.hw_params = kabylake_rt5660_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index e16c42e81ecaa8b62ad603ce26d1b1fefa923b1c..9da89436a917b02a36d7dfd7a2ca3a2e7ed7060e 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -489,7 +489,7 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops kabylake_rt5663_ops = {
+static const struct snd_soc_ops kabylake_rt5663_ops = {
 	.hw_params = kabylake_rt5663_hw_params,
 };
 
@@ -539,7 +539,7 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops kabylake_ssp0_ops = {
+static const struct snd_soc_ops kabylake_ssp0_ops = {
 	.hw_params = kabylake_ssp0_hw_params,
 };
 
@@ -575,7 +575,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
 			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops kabylake_dmic_ops = {
+static const struct snd_soc_ops kabylake_dmic_ops = {
 	.startup = kabylake_dmic_startup,
 };
 
@@ -609,7 +609,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
 				&constraints_16000);
 }
 
-static struct snd_soc_ops skylake_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
 	.startup = kabylake_refcap_startup,
 };
 
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index a9501cd106ff2c4b1819a880e237a8797b7796a5..a32ce8f972f39888e66fdf44a4388c6bc01bf66e 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -424,7 +424,7 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops kabylake_rt5663_ops = {
+static const struct snd_soc_ops kabylake_rt5663_ops = {
 	.hw_params = kabylake_rt5663_hw_params,
 };
 
@@ -469,7 +469,7 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops kabylake_ssp0_ops = {
+static const struct snd_soc_ops kabylake_ssp0_ops = {
 	.hw_params = kabylake_ssp0_hw_params,
 };
 
@@ -508,7 +508,7 @@ static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
 			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops kabylake_dmic_ops = {
+static const struct snd_soc_ops kabylake_dmic_ops = {
 	.startup = kabylake_dmic_startup,
 };
 
diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h
index dfcc2c5c25cc1a58390bd56816a39e3d3743685c..faba847bb7c9901e25558d7de64b4c6cc0e5855f 100644
--- a/sound/soc/intel/boards/sof_board_helpers.h
+++ b/sound/soc/intel/boards/sof_board_helpers.h
@@ -86,12 +86,10 @@ enum {
 /*
  * sof_da7219_private: private data for da7219 machine driver
  *
- * @is_jsl_board: true for JSL boards
  * @mclk_en: true for mclk pin is connected
  * @pll_bypass: true for PLL bypass mode
  */
 struct sof_da7219_private {
-	bool is_jsl_board;
 	bool mclk_en;
 	bool pll_bypass;
 };
diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c
index 886771e9b9d694e52e62f52f2f0fc12f86665f19..fa1f7d2d82787ea4f6beca1f3767b2f2b38100a4 100644
--- a/sound/soc/intel/boards/sof_da7219.c
+++ b/sound/soc/intel/boards/sof_da7219.c
@@ -178,42 +178,21 @@ static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
 	snd_soc_component_set_jack(component, NULL, NULL);
 }
 
-static int max98373_hw_params(struct snd_pcm_substream *substream,
-			      struct snd_pcm_hw_params *params)
+static int card_late_probe(struct snd_soc_card *card)
 {
-	struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
-	int ret, j;
-
-	for (j = 0; j < runtime->dai_link->num_codecs; j++) {
-		struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, j);
-
-		if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
-			/* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */
-			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16);
-			if (ret < 0) {
-				dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
-				return ret;
-			}
-		}
-		if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
-			/* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */
-			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16);
-			if (ret < 0) {
-				dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
-				return ret;
-			}
-		}
+	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dapm_context *dapm = &card->dapm;
+	int err;
+
+	if (ctx->amp_type == CODEC_MAX98373) {
+		/* Disable Left and Right Spk pin after boot */
+		snd_soc_dapm_disable_pin(dapm, "Left Spk");
+		snd_soc_dapm_disable_pin(dapm, "Right Spk");
+		err = snd_soc_dapm_sync(dapm);
+		if (err < 0)
+			return err;
 	}
 
-	return 0;
-}
-
-static const struct snd_soc_ops max98373_ops = {
-	.hw_params = max98373_hw_params,
-};
-
-static int card_late_probe(struct snd_soc_card *card)
-{
 	return sof_intel_board_card_late_probe(card);
 }
 
@@ -276,14 +255,6 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
 		break;
 	case CODEC_MAX98373:
 		max_98373_dai_link(dev, ctx->amp_link);
-
-		if (ctx->da7219.is_jsl_board) {
-			ctx->amp_link->ops = &max98373_ops; /* use local ops */
-		} else {
-			/* TBD: implement the amp for later platform */
-			dev_err(dev, "max98373 not support yet\n");
-			return -EINVAL;
-		}
 		break;
 	case CODEC_MAX98390:
 		max_98390_dai_link(dev, ctx->amp_link);
@@ -388,8 +359,6 @@ static int audio_probe(struct platform_device *pdev)
 			break;
 		}
 	} else if (board_quirk & SOF_DA7219_JSL_BOARD) {
-		ctx->da7219.is_jsl_board = true;
-
 		/* overwrite the DAI link order for JSL boards */
 		ctx->link_order_overwrite = JSL_LINK_ORDER;
 
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index c1fcc156a5752c24909afb0326205528fdbdc0bb..2a88efaa6d26bd1d553c4b4919091663e979100a 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -371,7 +371,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream,
 }
 
 /* machine stream operations */
-static struct snd_soc_ops sof_es8336_ops = {
+static const struct snd_soc_ops sof_es8336_ops = {
 	.hw_params = sof_es8336_hw_params,
 	.trigger = sof_8336_trigger,
 };
diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c
index 6c40ecc04723c8856787057d9785b825bcafe671..fcc3b95e57a4f3a1f59eb9608efc9b1705774a7f 100644
--- a/sound/soc/intel/boards/sof_maxim_common.c
+++ b/sound/soc/intel/boards/sof_maxim_common.c
@@ -9,6 +9,7 @@
 #include <sound/soc-acpi.h>
 #include <sound/soc-dai.h>
 #include <sound/soc-dapm.h>
+#include <sound/sof.h>
 #include <uapi/sound/asound.h>
 #include "../common/soc-intel-quirks.h"
 #include "sof_maxim_common.h"
@@ -72,26 +73,115 @@ static struct snd_soc_dai_link_component max_98373_components[] = {
 	},
 };
 
+/*
+ * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask
+ * should choose two channels from TDM slots, the LSB of rx mask is left channel
+ * and the other one is right channel.
+ */
+static const struct {
+	unsigned int rx;
+} max_98373_tdm_mask[] = {
+	{.rx = 0x3},
+	{.rx = 0x3},
+};
+
+/*
+ * The tx mask indicates which channel(s) contains output IV-sense data and
+ * others should set to Hi-Z. Here we get the channel number from codec's ACPI
+ * device property "maxim,vmon-slot-no" and "maxim,imon-slot-no" to generate the
+ * mask. Refer to the max98373_slot_config() function in max98373.c codec driver.
+ */
+static unsigned int max_98373_get_tx_mask(struct device *dev)
+{
+	int vmon_slot;
+	int imon_slot;
+
+	if (device_property_read_u32(dev, "maxim,vmon-slot-no", &vmon_slot))
+		vmon_slot = 0;
+
+	if (device_property_read_u32(dev, "maxim,imon-slot-no", &imon_slot))
+		imon_slot = 1;
+
+	dev_dbg(dev, "vmon_slot %d imon_slot %d\n", vmon_slot, imon_slot);
+
+	return (0x1 << vmon_slot) | (0x1 << imon_slot);
+}
+
 static int max_98373_hw_params(struct snd_pcm_substream *substream,
 			       struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_dai_link *dai_link = rtd->dai_link;
 	struct snd_soc_dai *codec_dai;
+	int i;
+	int tdm_slots;
+	unsigned int tx_mask;
+	unsigned int tx_mask_used = 0x0;
 	int ret = 0;
-	int j;
 
-	for_each_rtd_codec_dais(rtd, j, codec_dai) {
-		if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
-			/* DEV0 tdm slot configuration */
-			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
-		} else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
-			/* DEV1 tdm slot configuration */
-			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
+	for_each_rtd_codec_dais(rtd, i, codec_dai) {
+		if (i >= ARRAY_SIZE(max_98373_tdm_mask)) {
+			dev_err(codec_dai->dev, "only 2 amps are supported\n");
+			return -EINVAL;
 		}
-		if (ret < 0) {
-			dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
-				ret);
-			return ret;
+
+		switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_DSP_A:
+		case SND_SOC_DAIFMT_DSP_B:
+			/* get the tplg configured tdm slot number */
+			tdm_slots = sof_dai_get_tdm_slots(rtd);
+			if (tdm_slots <= 0) {
+				dev_err(rtd->dev, "invalid tdm slots %d\n",
+					tdm_slots);
+				return -EINVAL;
+			}
+
+			/* get the tx mask from ACPI device properties */
+			tx_mask = max_98373_get_tx_mask(codec_dai->dev);
+			if (!tx_mask)
+				return -EINVAL;
+
+			if (tx_mask & tx_mask_used) {
+				dev_err(codec_dai->dev, "invalid tx mask 0x%x, used 0x%x\n",
+					tx_mask, tx_mask_used);
+				return -EINVAL;
+			}
+
+			tx_mask_used |= tx_mask;
+
+			/*
+			 * check if tdm slot number is too small for channel
+			 * allocation
+			 */
+			if (fls(tx_mask) > tdm_slots) {
+				dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n",
+					fls(tx_mask), tdm_slots);
+				return -EINVAL;
+			}
+
+			if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) {
+				dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n",
+					fls(max_98373_tdm_mask[i].rx), tdm_slots);
+				return -EINVAL;
+			}
+
+			dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n",
+				tx_mask, max_98373_tdm_mask[i].rx,
+				tdm_slots, params_width(params));
+
+			ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask,
+						       max_98373_tdm_mask[i].rx,
+						       tdm_slots,
+						       params_width(params));
+			if (ret < 0) {
+				dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+					ret);
+				return ret;
+			}
+			break;
+		default:
+			dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
+			break;
 		}
 	}
 	return 0;
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index c08b4eef0bcbe6847c80b6962a871a4bce533e10..bfe17acbc161f7fab277b635c9ca2b11fae698ef 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -115,7 +115,7 @@ static int sof_nau8825_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops sof_nau8825_ops = {
+static const struct snd_soc_ops sof_nau8825_ops = {
 	.hw_params = sof_nau8825_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
index dda346e0f7374ee6f2c9edc99aa58ee48e0379e2..f52e25083905882fc8f1f424d497173e290cfed0 100644
--- a/sound/soc/intel/boards/sof_realtek_common.c
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -452,7 +452,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops rt1015_ops = {
+static const struct snd_soc_ops rt1015_ops = {
 	.hw_params = rt1015_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 6fc6eb0c5172ca4916a221d89a24f56f2d2882e2..23a40b913290a2f871d23e7fc4dd2af2b68da9df 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -397,7 +397,7 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops sof_rt5682_ops = {
+static const struct snd_soc_ops sof_rt5682_ops = {
 	.hw_params = sof_rt5682_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index e41b0d95e0ff77856951a1e211e1d8d81638cc91..e5feaef669d145c49070141f875c588783655b4a 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -277,6 +277,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 					SOF_BT_OFFLOAD_SSP(2) |
 					SOF_SSP_BT_OFFLOAD_PRESENT),
 	},
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"),
+		},
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					RT711_JD2_100K),
+	},
 	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
@@ -397,6 +406,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 		/* No Jack */
 		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 	},
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"),
+		},
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					RT711_JD2),
+	},
 	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
@@ -505,6 +523,22 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 		},
 		.driver_data = (void *)(RT711_JD2),
 	},
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3")
+		},
+		.driver_data = (void *)(SOF_SIDECAR_AMPS),
+	},
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4")
+		},
+		.driver_data = (void *)(SOF_SIDECAR_AMPS),
+	},
 	{}
 };
 
@@ -559,24 +593,6 @@ static const struct snd_kcontrol_new rt700_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Speaker"),
 };
 
-struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd,
-					  const char * const dai_name[],
-					  int num_dais)
-{
-	struct snd_soc_dai *dai;
-	int index;
-	int i;
-
-	for (index = 0; index < num_dais; index++)
-		for_each_rtd_codec_dais(rtd, i, dai)
-			if (strstr(dai->name, dai_name[index])) {
-				dev_dbg(rtd->card->dev, "get dai %s\n", dai->name);
-				return dai;
-			}
-
-	return NULL;
-}
-
 /* these wrappers are only needed to avoid typecast compilation errors */
 int sdw_startup(struct snd_pcm_substream *substream)
 {
@@ -1077,6 +1093,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {
 				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
 				.init = sof_sdw_cs_amp_init,
 				.rtd_init = cs_spk_rtd_init,
+				.controls = generic_spk_controls,
+				.num_controls = ARRAY_SIZE(generic_spk_controls),
 				.widgets = generic_spk_widgets,
 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
 			},
@@ -1112,6 +1130,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {
 				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 				.rtd_init = cs42l43_hs_rtd_init,
+				.controls = generic_jack_controls,
+				.num_controls = ARRAY_SIZE(generic_jack_controls),
 				.widgets = generic_jack_widgets,
 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
 			},
@@ -1137,6 +1157,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {
 				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 				.init = sof_sdw_cs42l43_spk_init,
 				.rtd_init = cs42l43_spk_rtd_init,
+				.controls = generic_spk_controls,
+				.num_controls = ARRAY_SIZE(generic_spk_controls),
 				.widgets = generic_spk_widgets,
 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
 				.quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS,
@@ -2114,9 +2136,9 @@ static int mc_probe(struct platform_device *pdev)
 
 	card = &ctx->card;
 	card->dev = &pdev->dev;
-	card->name = "soundwire",
-	card->owner = THIS_MODULE,
-	card->late_probe = sof_sdw_card_late_probe,
+	card->name = "soundwire";
+	card->owner = THIS_MODULE;
+	card->late_probe = sof_sdw_card_late_probe;
 
 	snd_soc_card_set_drvdata(card, ctx);
 
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index 3dfba6f6b95dc64ef493892193b9dae1af414205..2a3145d1feb61da389e4423b1109ceee87f36643 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -134,10 +134,6 @@ struct mc_private {
 
 extern unsigned long sof_sdw_quirk;
 
-struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd,
-					  const char * const dai_name[],
-					  int num_dais);
-
 int sdw_startup(struct snd_pcm_substream *substream);
 int sdw_prepare(struct snd_pcm_substream *substream);
 int sdw_trigger(struct snd_pcm_substream *substream, int cmd);
@@ -169,7 +165,7 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
 int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
 
 /* RT1308 I2S support */
-extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
+extern const struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
 
 /* generic amp support */
 int sof_sdw_rt_amp_init(struct snd_soc_card *card,
diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/intel/boards/sof_sdw_cs42l42.c
index fdb75fc71c2649d92c8eb44256a32e341a572038..fc18e4aa3dbe9fec68b391cd3e84a98dc00688c8 100644
--- a/sound/soc/intel/boards/sof_sdw_cs42l42.c
+++ b/sound/soc/intel/boards/sof_sdw_cs42l42.c
@@ -36,24 +36,15 @@ static struct snd_soc_jack_pin cs42l42_jack_pins[] = {
 	},
 };
 
-static const char * const jack_codecs[] = {
-	"cs42l42"
-};
-
 int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
 	struct snd_soc_card *card = rtd->card;
 	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai;
 	struct snd_soc_component *component;
 	struct snd_soc_jack *jack;
 	int ret;
 
-	codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs));
-	if (!codec_dai)
-		return -EINVAL;
-
-	component = codec_dai->component;
+	component = dai->component;
 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 					  "%s hs:cs42l42",
 					  card->components);
diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c
index 96f1937985407537df1aa33cd1adeca303be255e..67737815d016ea3517fd4a2e5af575fb422f2695 100644
--- a/sound/soc/intel/boards/sof_sdw_rt5682.c
+++ b/sound/soc/intel/boards/sof_sdw_rt5682.c
@@ -35,24 +35,15 @@ static struct snd_soc_jack_pin rt5682_jack_pins[] = {
 	},
 };
 
-static const char * const jack_codecs[] = {
-	"rt5682"
-};
-
 int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
 	struct snd_soc_card *card = rtd->card;
 	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai;
 	struct snd_soc_component *component;
 	struct snd_soc_jack *jack;
 	int ret;
 
-	codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs));
-	if (!codec_dai)
-		return -EINVAL;
-
-	component = codec_dai->component;
+	component = dai->component;
 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 					  "%s hs:rt5682",
 					  card->components);
diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c
index f9575db9d99ca6a851853b3eea8fbe500376b023..0db730071be23657fc729f72d8e43b2b4c557471 100644
--- a/sound/soc/intel/boards/sof_sdw_rt700.c
+++ b/sound/soc/intel/boards/sof_sdw_rt700.c
@@ -33,24 +33,15 @@ static struct snd_soc_jack_pin rt700_jack_pins[] = {
 	},
 };
 
-static const char * const jack_codecs[] = {
-	"rt700"
-};
-
 int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
 	struct snd_soc_card *card = rtd->card;
 	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai;
 	struct snd_soc_component *component;
 	struct snd_soc_jack *jack;
 	int ret;
 
-	codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs));
-	if (!codec_dai)
-		return -EINVAL;
-
-	component = codec_dai->component;
+	component = dai->component;
 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 					  "%s hs:rt700",
 					  card->components);
diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c
index d49e5aa786c3bcce3c4eae04afed574bed68ec79..60ff4d88e2dc781f13836f3b087f3692d010cf21 100644
--- a/sound/soc/intel/boards/sof_sdw_rt711.c
+++ b/sound/soc/intel/boards/sof_sdw_rt711.c
@@ -59,24 +59,15 @@ static struct snd_soc_jack_pin rt711_jack_pins[] = {
 	},
 };
 
-static const char * const jack_codecs[] = {
-	"rt711"
-};
-
 int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
 	struct snd_soc_card *card = rtd->card;
 	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai;
 	struct snd_soc_component *component;
 	struct snd_soc_jack *jack;
 	int ret;
 
-	codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs));
-	if (!codec_dai)
-		return -EINVAL;
-
-	component = codec_dai->component;
+	component = dai->component;
 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 					  "%s hs:rt711",
 					  card->components);
diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c
index 797ea9ffa77afd6d17e7f85479c655e24f0e5ae3..d1c0f91ce5897909b7fae3c9a63e7d35aa827d70 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_amp.c
+++ b/sound/soc/intel/boards/sof_sdw_rt_amp.c
@@ -233,7 +233,7 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream,
 }
 
 /* machine stream operations */
-struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
+const struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
 	.hw_params = rt1308_i2s_hw_params,
 };
 
diff --git a/sound/soc/intel/boards/sof_sdw_rt_dmic.c b/sound/soc/intel/boards/sof_sdw_rt_dmic.c
index b8b493d5c6ec6f6e51a7aec0cc21aed31d978dae..ea7c1a4bc5661e88493c90d015de083107a6d824 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_dmic.c
+++ b/sound/soc/intel/boards/sof_sdw_rt_dmic.c
@@ -12,25 +12,13 @@
 #include "sof_board_helpers.h"
 #include "sof_sdw_common.h"
 
-static const char * const dmics[] = {
-	"rt715",
-	"rt715-sdca",
-	"rt712-sdca-dmic",
-	"rt722-sdca",
-};
-
 int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_component *component;
-	struct snd_soc_dai *codec_dai;
 	char *mic_name;
 
-	codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics));
-	if (!codec_dai)
-		return -EINVAL;
-
-	component = codec_dai->component;
+	component = dai->component;
 
 	/*
 	 * rt715-sdca (aka rt714) is a special case that uses different name in card->components
diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
index 012195c5051917f23e6f35ccc44018ea3559f252..4254e30ee4c3dd7b5ef2d9462ceeaf400c52f993 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
+++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
@@ -74,10 +74,6 @@ static struct snd_soc_jack_pin rt_sdca_jack_pins[] = {
 	},
 };
 
-static const char * const jack_codecs[] = {
-	"rt711", "rt712", "rt713", "rt722"
-};
-
 /*
  * The sdca suffix is required for rt711 since there are two generations of the same chip.
  * RT713 is an SDCA device but the sdca suffix is required for backwards-compatibility with
@@ -91,17 +87,12 @@ int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *d
 {
 	struct snd_soc_card *card = rtd->card;
 	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai;
 	struct snd_soc_component *component;
 	struct snd_soc_jack *jack;
 	int ret;
 	int i;
 
-	codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs));
-	if (!codec_dai)
-		return -EINVAL;
-
-	component = codec_dai->component;
+	component = dai->component;
 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 					  "%s hs:%s",
 					  card->components, component->name_prefix);
diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c
index 4cb0d463bf404912e94c4f58dc1cf4bfc76bd66b..b2d02cc92a6a8dfb22d09ad23a3c1d7c1833a1a7 100644
--- a/sound/soc/intel/boards/sof_wm8804.c
+++ b/sound/soc/intel/boards/sof_wm8804.c
@@ -148,7 +148,7 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream,
 }
 
 /* machine stream operations */
-static struct snd_soc_ops sof_wm8804_ops = {
+static const struct snd_soc_ops sof_wm8804_ops = {
 	.hw_params = sof_wm8804_hw_params,
 };
 
diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
index 79d26e0f2c28da3e56807514395903eb6eece412..cc87c34e5a08eab8de3ead491b4a64fbf10404cb 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -15,6 +15,42 @@ static const struct snd_soc_acpi_endpoint single_endpoint = {
 	.group_id = 0,
 };
 
+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
+	{ /* Jack Playback Endpoint */
+		.num = 0,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	{ /* DMIC Capture Endpoint */
+		.num = 1,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	{ /* Jack Capture Endpoint */
+		.num = 2,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	{ /* Speaker Playback Endpoint */
+		.num = 3,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
+	{
+		.adr = 0x00003001FA424301ull,
+		.num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+		.endpoints = cs42l43_endpoints,
+		.name_prefix = "cs42l43"
+	}
+};
+
 static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
 	{
 		.adr = 0x000020025D071100ull,
@@ -33,6 +69,14 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
 	}
 };
 
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = {
+	{
+		.mask = BIT(0),
+		.num_adr = ARRAY_SIZE(cs42l43_0_adr),
+		.adr_d = cs42l43_0_adr,
+	},
+};
+
 static const struct snd_soc_acpi_link_adr arl_rvp[] = {
 	{
 		.mask = BIT(0),
@@ -58,6 +102,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines);
 
 /* this table is used when there is no I2S codec present */
 struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
+	{
+		.link_mask = BIT(0),
+		.links = arl_cs42l43_l0,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-arl-cs42l43-l0.tplg",
+	},
 	{
 		.link_mask = 0x1, /* link0 required */
 		.links = arl_rvp,
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index b0a49e28ab0926857e558a32d1d7e04728fc3ba0..bc8817633b81b010421337ad5e95f7b717ee8f74 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -30,6 +30,42 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
 	.group_id = 1,
 };
 
+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
+	{ /* Jack Playback Endpoint */
+		.num = 0,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	{ /* DMIC Capture Endpoint */
+		.num = 1,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	{ /* Jack Capture Endpoint */
+		.num = 2,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	{ /* Speaker Playback Endpoint */
+		.num = 3,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
+	{
+		.adr = 0x00003001FA424301ull,
+		.num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+		.endpoints = cs42l43_endpoints,
+		.name_prefix = "cs42l43"
+	}
+};
+
 static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
 	{
 		.adr = 0x000020025D071100ull,
@@ -156,6 +192,14 @@ static const struct snd_soc_acpi_adr_device rt714_3_adr[] = {
 	}
 };
 
+static const struct snd_soc_acpi_link_adr rpl_cs42l43_l0[] = {
+	{
+		.mask = BIT(0),
+		.num_adr = ARRAY_SIZE(cs42l43_0_adr),
+		.adr_d = cs42l43_0_adr,
+	},
+};
+
 static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
 	{
 		.mask = BIT(0),
@@ -446,6 +490,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines);
 
 /* this table is used when there is no I2S codec present */
 struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
+	{
+		.link_mask = BIT(0),
+		.links = rpl_cs42l43_l0,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-rpl-cs42l43-l0.tplg",
+	},
 	{
 		.link_mask = 0xF, /* 4 active links required */
 		.links = rpl_sdca_3_in_1,
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index e27f0fc3d897958a609846cc2f9abb095f2a90da..602ef432112218f16a1e12fed6aed957927debf8 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -3470,7 +3470,7 @@ static int skl_tplg_complete(struct snd_soc_component *component)
 	return 0;
 }
 
-static struct snd_soc_tplg_ops skl_tplg_ops  = {
+static const struct snd_soc_tplg_ops skl_tplg_ops = {
 	.widget_load = skl_tplg_widget_load,
 	.control_load = skl_tplg_control_load,
 	.bytes_ext_ops = skl_tlv_ops,
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
index 59abe0b3c59fb40ed20cc97a4cff344fd85ed49d..7e6090af720b9a2b569e20f5a25e702f0338e7d8 100644
--- a/sound/soc/meson/axg-fifo.c
+++ b/sound/soc/meson/axg-fifo.c
@@ -32,7 +32,7 @@ static const struct snd_pcm_hardware axg_fifo_hw = {
 		 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
 	.formats = AXG_FIFO_FORMATS,
 	.rate_min = 5512,
-	.rate_max = 384000,
+	.rate_max = 768000,
 	.channels_min = 1,
 	.channels_max = AXG_FIFO_CH_MAX,
 	.period_bytes_min = AXG_FIFO_BURST,
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
index e97d43ae7fd291da826634de659147a319f400c1..e70c8c34c7db86ad1eceb7e671a8d746bb3dbcdf 100644
--- a/sound/soc/meson/axg-frddr.c
+++ b/sound/soc/meson/axg-frddr.c
@@ -112,7 +112,7 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = {
 		.channels_max	= AXG_FIFO_CH_MAX,
 		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
 		.rate_min	= 5515,
-		.rate_max	= 384000,
+		.rate_max	= 768000,
 		.formats	= AXG_FIFO_FORMATS,
 	},
 	.ops		= &axg_frddr_ops,
@@ -189,7 +189,7 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
 		.channels_max	= AXG_FIFO_CH_MAX,
 		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
 		.rate_min	= 5515,
-		.rate_max	= 384000,
+		.rate_max	= 768000,
 		.formats	= AXG_FIFO_FORMATS,
 	},
 	.ops		= &g12a_frddr_ops,
diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h
index daaca10fec9e2bff82164ccccea75f1aefadaba1..1a17f546ce6e80ac6b1354f8e85e29f4ed6b61fd 100644
--- a/sound/soc/meson/axg-tdm.h
+++ b/sound/soc/meson/axg-tdm.h
@@ -16,7 +16,7 @@
 #define AXG_TDM_NUM_LANES	4
 #define AXG_TDM_CHANNEL_MAX	128
 #define AXG_TDM_RATES		(SNDRV_PCM_RATE_5512 |		\
-				 SNDRV_PCM_RATE_8000_384000)
+				 SNDRV_PCM_RATE_8000_768000)
 #define AXG_TDM_FORMATS		(SNDRV_PCM_FMTBIT_S8 |		\
 				 SNDRV_PCM_FMTBIT_S16_LE |	\
 				 SNDRV_PCM_FMTBIT_S20_LE |	\
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
index e03a6e21c1c649e6e9aa5a55fb3c3a2bb2e899e9..03512da4092b66a2c19da6e3efc794f12f71b321 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -131,7 +131,7 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = {
 		.channels_max	= AXG_FIFO_CH_MAX,
 		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
 		.rate_min	= 5515,
-		.rate_max	= 384000,
+		.rate_max	= 768000,
 		.formats	= AXG_FIFO_FORMATS,
 	},
 	.ops		= &axg_toddr_ops,
@@ -228,7 +228,7 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
 		.channels_max	= AXG_FIFO_CH_MAX,
 		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
 		.rate_min	= 5515,
-		.rate_max	= 384000,
+		.rate_max	= 768000,
 		.formats	= AXG_FIFO_FORMATS,
 	},
 	.ops		= &g12a_toddr_ops,
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 3d02aa3844f294a437cc86be0e1908dc07e31446..56b4a3654aec3becebe14833e3d043a6c686b7fe 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -8,9 +8,19 @@
 #include <linux/input-event-codes.h>
 #include "common.h"
 
+#define NAME_SIZE	32
+
 static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = {
 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_SPK("DP0 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP1 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP2 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP3 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP4 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP5 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP6 Jack", NULL),
+	SND_SOC_DAPM_SPK("DP7 Jack", NULL),
 };
 
 int qcom_snd_parse_of(struct snd_soc_card *card)
@@ -240,5 +250,30 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
 }
 EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup);
 
+int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd,
+			   struct snd_soc_jack *dp_jack, int dp_pcm_id)
+{
+	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+	struct snd_soc_card *card = rtd->card;
+	char jack_name[NAME_SIZE];
+	int rval, i;
+
+	snprintf(jack_name, sizeof(jack_name), "DP%d Jack", dp_pcm_id);
+	rval = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, dp_jack);
+	if (rval)
+		return rval;
+
+	for_each_rtd_codec_dais(rtd, i, codec_dai) {
+		rval = snd_soc_component_set_jack(codec_dai->component, dp_jack, NULL);
+		if (rval != 0 && rval != -ENOTSUPP) {
+			dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+			return rval;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_dp_jack_setup);
+
 MODULE_DESCRIPTION("ASoC Qualcomm helper functions");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index d7f80ee5ae26aed26c20f8d751d96cdbce224550..1b8d3f90bffaf4c418a4b37522dcd1c81bd2a140 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -9,5 +9,8 @@
 int qcom_snd_parse_of(struct snd_soc_card *card);
 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
 			    struct snd_soc_jack *jack, bool *jack_setup);
+int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd,
+			   struct snd_soc_jack *dp_jack, int id);
+
 
 #endif
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index b0f3e02cb043c6c46af732b5d4202af3ed2f51fa..5a47f661e0c6f79599aba9361bfed99f1bd93f90 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -1166,9 +1166,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 		}
 
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
+		if (!res)
+			return -EINVAL;
 		drvdata->rxtx_cdc_dma_lpm_buf = res->start;
 
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
+		if (!res)
+			return -EINVAL;
 		drvdata->va_cdc_dma_lpm_buf = res->start;
 	}
 
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 5291deac0a0b39cd511b6af5647a46ed9e9c08a9..4ebaaf736fb98a5a8a58d06416b3ace2504856e1 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -267,7 +267,7 @@ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token
 }
 EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt);
 
-static void audioreach_set_channel_mapping(u8 *ch_map, int num_channels)
+void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels)
 {
 	if (num_channels == 1) {
 		ch_map[0] =  PCM_CHANNEL_FL;
@@ -281,6 +281,7 @@ static void audioreach_set_channel_mapping(u8 *ch_map, int num_channels)
 		ch_map[3] =  PCM_CHANNEL_RS;
 	}
 }
+EXPORT_SYMBOL_GPL(audioreach_set_default_channel_mapping);
 
 static void apm_populate_container_config(struct apm_container_obj *cfg,
 					  struct audioreach_container *cont)
@@ -819,7 +820,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
 	uint32_t num_channels = cfg->num_channels;
 	int payload_size;
 	struct gpr_pkt *pkt;
-	int rc;
+	int rc, i;
 	void *p;
 
 	payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
@@ -842,18 +843,8 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
 	media_format->sample_rate = cfg->sample_rate;
 	media_format->bit_width = cfg->bit_width;
 	media_format->num_channels = cfg->num_channels;
-
-	if (num_channels == 1) {
-		media_format->channel_mapping[0] = PCM_CHANNEL_FL;
-	} else if (num_channels == 2) {
-		media_format->channel_mapping[0] = PCM_CHANNEL_FL;
-		media_format->channel_mapping[1] = PCM_CHANNEL_FR;
-	} else if (num_channels == 4) {
-		media_format->channel_mapping[0] = PCM_CHANNEL_FL;
-		media_format->channel_mapping[1] = PCM_CHANNEL_FR;
-		media_format->channel_mapping[2] = PCM_CHANNEL_LS;
-		media_format->channel_mapping[3] = PCM_CHANNEL_RS;
-	}
+	for (i = 0; i < num_channels; i++)
+		media_format->channel_mapping[i] = cfg->channel_map[i];
 
 	rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
 
@@ -883,9 +874,6 @@ static int audioreach_set_compr_media_format(struct media_format *media_fmt_hdr,
 		mp3_cfg->q_factor = mcfg->bit_width - 1;
 		mp3_cfg->endianness = PCM_LITTLE_ENDIAN;
 		mp3_cfg->num_channels = mcfg->num_channels;
-
-		audioreach_set_channel_mapping(mp3_cfg->channel_mapping,
-					       mcfg->num_channels);
 		break;
 	case SND_AUDIOCODEC_AAC:
 		media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
@@ -1104,9 +1092,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
 	media_cfg->num_channels = mcfg->num_channels;
 	media_cfg->q_factor = mcfg->bit_width - 1;
 	media_cfg->bits_per_sample = mcfg->bit_width;
-
-	audioreach_set_channel_mapping(media_cfg->channel_mapping,
-				       num_channels);
+	memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
 
 	rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
 
@@ -1163,9 +1149,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
 		cfg->q_factor = mcfg->bit_width - 1;
 		cfg->endianness = PCM_LITTLE_ENDIAN;
 		cfg->num_channels = mcfg->num_channels;
-
-		audioreach_set_channel_mapping(cfg->channel_mapping,
-					       num_channels);
+		memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
 	} else {
 		rc = audioreach_set_compr_media_format(header, p, mcfg);
 		if (rc) {
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 2c82917b71621a9875fbf06c51032462ff74d29c..61a69df4f50f6cc90b56697c272ade6f1411bbf2 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -755,7 +755,6 @@ struct audioreach_module_config {
 
 	u16	data_format;
 	u16	num_channels;
-	u16	active_channels_mask;
 	u16	dp_idx;
 	u32	channel_allocation;
 	u32	sd_line_mask;
@@ -767,6 +766,7 @@ struct audioreach_module_config {
 /* Packet Allocation routines */
 void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t
 				    token);
+void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels);
 void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode,
 			       uint32_t token, uint32_t src_port,
 			       uint32_t dest_port);
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index a9c4f896a7dfd64af3f3a51ebba72e6c5e960586..7d9628cda87534dd3cad8bcb1e0faa7b8e5dd770 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -172,8 +172,8 @@ static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
 }
 
 static int q6tdm_set_channel_map(struct snd_soc_dai *dai,
-				unsigned int tx_num, unsigned int *tx_slot,
-				unsigned int rx_num, unsigned int *rx_slot)
+				unsigned int tx_num, const unsigned int *tx_slot,
+				unsigned int rx_num, const unsigned int *rx_slot)
 {
 
 	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -250,8 +250,10 @@ static int q6tdm_hw_params(struct snd_pcm_substream *substream,
 }
 
 static int q6dma_set_channel_map(struct snd_soc_dai *dai,
-				 unsigned int tx_num, unsigned int *tx_ch_mask,
-				 unsigned int rx_num, unsigned int *rx_ch_mask)
+				 unsigned int tx_num,
+				 const unsigned int *tx_ch_mask,
+				 unsigned int rx_num,
+				 const unsigned int *rx_ch_mask)
 {
 
 	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -407,8 +409,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
 }
 
 static int q6slim_set_channel_map(struct snd_soc_dai *dai,
-				unsigned int tx_num, unsigned int *tx_slot,
-				unsigned int rx_num, unsigned int *rx_slot)
+				  unsigned int tx_num,
+				  const unsigned int *tx_slot,
+				  unsigned int rx_num,
+				  const unsigned int *rx_slot)
 {
 	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index c7df8343b2dc78b3cc197b3084359f310c7c3dfa..c9404b5934c7e65ade2bb6f0845d3d339d97fb35 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -239,6 +239,7 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
 	cfg.num_channels = runtime->channels;
 	cfg.bit_width = prtd->bits_per_sample;
 	cfg.fmt = SND_AUDIOCODEC_PCM;
+	audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels);
 
 	if (prtd->state) {
 		/* clear the previous setup if any  */
@@ -665,6 +666,8 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component,
 		cfg.num_channels = 2;
 		cfg.bit_width = prtd->bits_per_sample;
 		cfg.fmt = codec->id;
+		audioreach_set_default_channel_mapping(cfg.channel_map,
+						       cfg.num_channels);
 		memcpy(&cfg.codec, codec, sizeof(*codec));
 
 		ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
index 66b911b49e3f41507396cd1f4f2aca94938c828f..9c98a35ad09945173c15dd6dff34830f43fe9388 100644
--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
@@ -25,13 +25,15 @@ struct q6apm_lpass_dai_data {
 };
 
 static int q6dma_set_channel_map(struct snd_soc_dai *dai,
-				 unsigned int tx_num, unsigned int *tx_ch_mask,
-				 unsigned int rx_num, unsigned int *rx_ch_mask)
+				 unsigned int tx_num,
+				 const unsigned int *tx_ch_mask,
+				 unsigned int rx_num,
+				 const unsigned int *rx_ch_mask)
 {
 
 	struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	struct audioreach_module_config *cfg = &dai_data->module_config[dai->id];
-	int ch_mask;
+	int i;
 
 	switch (dai->id) {
 	case WSA_CODEC_DMA_TX_0:
@@ -56,7 +58,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai,
 				tx_num);
 			return -EINVAL;
 		}
-		ch_mask = *tx_ch_mask;
+		for (i = 0; i < tx_num; i++)
+			cfg->channel_map[i] = tx_ch_mask[i];
 
 		break;
 	case WSA_CODEC_DMA_RX_0:
@@ -79,7 +82,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai,
 				rx_num);
 			return -EINVAL;
 		}
-		ch_mask = *rx_ch_mask;
+		for (i = 0; i < rx_num; i++)
+			cfg->channel_map[i] = rx_ch_mask[i];
 
 		break;
 	default:
@@ -88,8 +92,6 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	cfg->active_channels_mask = ch_mask;
-
 	return 0;
 }
 
@@ -104,6 +106,7 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream,
 	cfg->bit_width = params_width(params);
 	cfg->sample_rate = params_rate(params);
 	cfg->num_channels = channels;
+	audioreach_set_default_channel_mapping(cfg->channel_map, channels);
 
 	switch (dai->id) {
 	case DISPLAY_PORT_RX_0:
@@ -128,10 +131,12 @@ static int q6dma_hw_params(struct snd_pcm_substream *substream,
 {
 	struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	struct audioreach_module_config *cfg = &dai_data->module_config[dai->id];
+	int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max;
 
 	cfg->bit_width = params_width(params);
 	cfg->sample_rate = params_rate(params);
-	cfg->num_channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max;
+	cfg->num_channels = channels;
+	audioreach_set_default_channel_mapping(cfg->channel_map, channels);
 
 	return 0;
 }
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index 70572c83e1017df794c9857ae3fb98363f935604..83319a928f291714bd24ad8b5036a75ef326610b 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2020, Linaro Limited
 
+#include <linux/cleanup.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
@@ -730,6 +731,29 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
 	return 0;
 }
 
+static int audioreach_widget_dp_module_load(struct audioreach_module *mod,
+					struct snd_soc_tplg_vendor_array *mod_array)
+{
+	struct snd_soc_tplg_vendor_value_elem *mod_elem;
+	int tkn_count = 0;
+
+	mod_elem = mod_array->value;
+
+	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
+		switch (le32_to_cpu(mod_elem->token)) {
+		case AR_TKN_U32_MODULE_FMT_DATA:
+			mod->data_format = le32_to_cpu(mod_elem->value);
+			break;
+		default:
+			break;
+		}
+		tkn_count++;
+		mod_elem++;
+	}
+
+	return 0;
+}
+
 static int audioreach_widget_load_buffer(struct snd_soc_component *component,
 					 int index, struct snd_soc_dapm_widget *w,
 					 struct snd_soc_tplg_dapm_widget *tplg_w)
@@ -760,6 +784,9 @@ static int audioreach_widget_load_buffer(struct snd_soc_component *component,
 	case MODULE_ID_I2S_SOURCE:
 		audioreach_widget_i2s_module_load(mod, mod_array);
 		break;
+	case MODULE_ID_DISPLAY_PORT_SINK:
+		audioreach_widget_dp_module_load(mod, mod_array);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1240,7 +1267,7 @@ static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
 		audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
 };
 
-static struct snd_soc_tplg_ops audioreach_tplg_ops  = {
+static const struct snd_soc_tplg_ops audioreach_tplg_ops = {
 	.io_ops = audioreach_io_ops,
 	.io_ops_count = ARRAY_SIZE(audioreach_io_ops),
 
@@ -1262,18 +1289,19 @@ int audioreach_tplg_init(struct snd_soc_component *component)
 	struct snd_soc_card *card = component->card;
 	struct device *dev = component->dev;
 	const struct firmware *fw;
-	char *tplg_fw_name;
 	int ret;
 
 	/* Inline with Qualcomm UCM configs and linux-firmware path */
-	tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name);
+	char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin",
+						     card->driver_name,
+						     card->name);
 	if (!tplg_fw_name)
 		return -ENOMEM;
 
 	ret = request_firmware(&fw, tplg_fw_name, dev);
 	if (ret < 0) {
 		dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
-		goto err;
+		return ret;
 	}
 
 	ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
@@ -1283,8 +1311,6 @@ int audioreach_tplg_init(struct snd_soc_component *component)
 	}
 
 	release_firmware(fw);
-err:
-	kfree(tplg_fw_name);
 
 	return ret;
 }
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
index 06fd47c4178ff313d7fb238b6902ca1f9333725c..922ecada1cd8d9192cea1d9edf18ef9f6cf3e84d 100644
--- a/sound/soc/qcom/sc8280xp.c
+++ b/sound/soc/qcom/sc8280xp.c
@@ -19,6 +19,7 @@ struct sc8280xp_snd_data {
 	struct snd_soc_card *card;
 	struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
 	struct snd_soc_jack jack;
+	struct snd_soc_jack dp_jack[8];
 	bool jack_setup;
 };
 
@@ -27,6 +28,8 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
 	struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
 	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_jack *dp_jack  = NULL;
+	int dp_pcm_id = 0;
 
 	switch (cpu_dai->id) {
 	case WSA_CODEC_DMA_RX_0:
@@ -41,10 +44,22 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
 		snd_soc_limit_volume(card, "SpkrLeft PA Volume", 17);
 		snd_soc_limit_volume(card, "SpkrRight PA Volume", 17);
 		break;
+	case DISPLAY_PORT_RX_0:
+		/* DISPLAY_PORT dai ids are not contiguous */
+		dp_pcm_id = 0;
+		dp_jack = &data->dp_jack[dp_pcm_id];
+		break;
+	case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7:
+		dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1;
+		dp_jack = &data->dp_jack[dp_pcm_id];
+		break;
 	default:
 		break;
 	}
 
+	if (dp_jack)
+		return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
+
 	return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
 }
 
diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c
index 0e0773a8580996f42603ea3e903ddab4a91d3e9f..898b5c26bf1ee6bfa6a7a296f90257c6b31851fb 100644
--- a/sound/soc/qcom/x1e80100.c
+++ b/sound/soc/qcom/x1e80100.c
@@ -12,6 +12,7 @@
 
 #include "common.h"
 #include "qdsp6/q6afe.h"
+#include "qdsp6/q6dsp-common.h"
 #include "sdw.h"
 
 struct x1e80100_snd_data {
@@ -19,12 +20,32 @@ struct x1e80100_snd_data {
 	struct snd_soc_card *card;
 	struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
 	struct snd_soc_jack jack;
+	struct snd_soc_jack dp_jack[8];
 	bool jack_setup;
 };
 
 static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_jack *dp_jack = NULL;
+	int dp_pcm_id = 0;
+
+	switch (cpu_dai->id) {
+	case DISPLAY_PORT_RX_0:
+		dp_pcm_id = 0;
+		dp_jack = &data->dp_jack[dp_pcm_id];
+		break;
+	case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7:
+		dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1;
+		dp_jack = &data->dp_jack[dp_pcm_id];
+		break;
+	default:
+		break;
+	}
+
+	if (dp_jack)
+		return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
 
 	return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
 }
@@ -80,6 +101,23 @@ static int x1e80100_snd_prepare(struct snd_pcm_substream *substream)
 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
 	struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
 	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+	const unsigned int rx_slot[4] = { PCM_CHANNEL_FL,
+					  PCM_CHANNEL_LB,
+					  PCM_CHANNEL_FR,
+					  PCM_CHANNEL_RB };
+	int ret;
+
+	switch (cpu_dai->id) {
+	case WSA_CODEC_DMA_RX_0:
+	case WSA_CODEC_DMA_RX_1:
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+						  ARRAY_SIZE(rx_slot), rx_slot);
+		if (ret)
+			return ret;
+		break;
+	default:
+		break;
+	}
 
 	return qcom_snd_sdw_prepare(substream, sruntime,
 				    &data->stream_prepared[cpu_dai->id]);
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index b0c3ef030e06215bd948bcd428cbbb27e828a8ff..b378f870b3ad2ecff7fa8f3a3c407d1a7ed92246 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -11,7 +11,6 @@
 #include <linux/mfd/syscon.h>
 #include <linux/delay.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/clk.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 1a24b78e9e02a20d7b969a604f0386da8b071928..eb9d5dee196ebc55e8b1e03de7d960745f0fd968 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/of_gpio.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
 #include <linux/mfd/syscon.h>
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 93c2b1b08d0a6fff030688b7aca71145f0b08bfc..4b1ea7b2c79617c3ffaa493ae9de0629c1943378 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -140,7 +140,7 @@ config SND_SOC_SAMSUNG_ARIES_WM8994
 
 config SND_SOC_SAMSUNG_MIDAS_WM1811
 	tristate "SoC I2S Audio support for Midas boards"
-	depends on SND_SOC_SAMSUNG
+	depends on SND_SOC_SAMSUNG && IIO
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8994
 	help
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index a548ac33dd94a4c14012b117ef09e5db0f0f732b..01716df0c842037b0fd0503bbbf00cf5b5e520ec 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -1,11 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include <linux/extcon.h>
+#include <linux/gpio/consumer.h>
 #include <linux/iio/consumer.h>
 #include <linux/input-event-codes.h>
 #include <linux/mfd/wm8994/registers.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/regulator/consumer.h>
 #include <sound/jack.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index 0841e2e6f8ce4c1aa3d3774c7d0abfae6a6370f8..bbfe5fef59af1af7cf7b79c19bd7478134775258 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -7,10 +7,11 @@
 
 #include <linux/clk.h>
 #include <linux/gpio/consumer.h>
+#include <linux/iio/consumer.h>
 #include <linux/mfd/wm8994/registers.h>
+#include <linux/input-event-codes.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/regulator/consumer.h>
 #include <sound/jack.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -27,10 +28,11 @@
 #define DEFAULT_FLL1_RATE 11289600U
 
 struct midas_priv {
-	struct regulator *reg_mic_bias;
-	struct regulator *reg_submic_bias;
 	struct gpio_desc *gpio_fm_sel;
 	struct gpio_desc *gpio_lineout_sel;
+	struct gpio_desc *gpio_headset_detect;
+	struct gpio_desc *gpio_headset_key;
+	struct iio_channel *adc_headset_detect;
 	unsigned int fll1_rate;
 
 	struct snd_soc_jack headset_jack;
@@ -47,6 +49,117 @@ static struct snd_soc_jack_pin headset_jack_pins[] = {
 	},
 };
 
+/*
+ * min_mv/max_mv values in this struct are set up based on DT values.
+ */
+static struct snd_soc_jack_zone headset_jack_zones[] = {
+	{ .jack_type = SND_JACK_HEADPHONE, },
+	{ .jack_type = SND_JACK_HEADSET, },
+	{ .jack_type = SND_JACK_HEADPHONE, },
+};
+
+/*
+ * This is used for manual detection in headset_key_check, we reuse the
+ * structure since it's convenient.
+ *
+ * min_mv/max_mv values in this struct are set up based on DT values.
+ */
+static struct snd_soc_jack_zone headset_key_zones[] = {
+	{ .jack_type = SND_JACK_BTN_0, },  /* Media */
+	{ .jack_type = SND_JACK_BTN_1, },  /* Volume Up */
+	{ .jack_type = SND_JACK_BTN_2, },  /* Volume Down */
+};
+
+static int headset_jack_check(void *data)
+{
+	struct snd_soc_component *codec = data;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+	struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card);
+	int adc, ret;
+	int jack_type = 0;
+
+	if (!gpiod_get_value_cansleep(priv->gpio_headset_detect))
+		return 0;
+
+	/* Enable headset mic bias regulator so that the ADC reading works */
+	ret = snd_soc_dapm_force_enable_pin(dapm, "headset-mic-bias");
+	if (ret < 0) {
+		pr_err("%s: Failed to enable headset mic bias regulator (%d), assuming headphones\n",
+		       __func__, ret);
+		return SND_JACK_HEADPHONE;
+	}
+	snd_soc_dapm_sync(dapm);
+
+	/* Sleep for a small amount of time to get the value to stabilize */
+	msleep(20);
+
+	ret = iio_read_channel_processed(priv->adc_headset_detect, &adc);
+	if (ret) {
+		pr_err("%s: Failed to read ADC (%d), assuming headphones\n",
+		       __func__, ret);
+		jack_type = SND_JACK_HEADPHONE;
+		goto out;
+	}
+	pr_debug("%s: ADC value is %d\n", __func__, adc);
+
+	jack_type = snd_soc_jack_get_type(&priv->headset_jack, adc);
+
+out:
+	ret = snd_soc_dapm_disable_pin(dapm, "headset-mic-bias");
+	if (ret < 0)
+		pr_err("%s: Failed to disable headset mic bias regulator (%d)\n",
+		       __func__, ret);
+	snd_soc_dapm_sync(dapm);
+
+	return jack_type;
+}
+
+static int headset_key_check(void *data)
+{
+	struct snd_soc_component *codec = data;
+	struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card);
+	int adc, i, ret;
+
+	if (!gpiod_get_value_cansleep(priv->gpio_headset_key))
+		return 0;
+
+	/* Filter out keypresses when 4 pole jack not detected */
+	if (!(priv->headset_jack.status & SND_JACK_MICROPHONE))
+		return 0;
+
+	ret = iio_read_channel_processed(priv->adc_headset_detect, &adc);
+	if (ret) {
+		pr_err("%s: Failed to read ADC (%d), can't detect key type\n",
+		       __func__, ret);
+		return 0;
+	}
+	pr_debug("%s: ADC value is %d\n", __func__, adc);
+
+	for (i = 0; i < ARRAY_SIZE(headset_key_zones); i++) {
+		if (adc >= headset_key_zones[i].min_mv &&
+		    adc <= headset_key_zones[i].max_mv) {
+			return headset_key_zones[i].jack_type;
+		}
+	}
+
+	return 0;
+}
+
+static struct snd_soc_jack_gpio headset_gpio[] = {
+	{
+		.name = "Headset Jack",
+		.report = SND_JACK_HEADSET,
+		.debounce_time = 150,
+		.jack_status_check = headset_jack_check,
+	},
+	{
+		.name = "Headset Key",
+		.report = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+		.debounce_time = 30,
+		.jack_status_check = headset_key_check,
+	},
+};
+
 static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
 {
 	struct snd_soc_card *card = rtd->card;
@@ -169,38 +282,6 @@ static int midas_ext_spkmode(struct snd_soc_dapm_widget *w,
 	return ret;
 }
 
-static int midas_mic_bias(struct snd_soc_dapm_widget *w,
-			  struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_card *card = w->dapm->card;
-	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		return regulator_enable(priv->reg_mic_bias);
-	case SND_SOC_DAPM_POST_PMD:
-		return regulator_disable(priv->reg_mic_bias);
-	}
-
-	return 0;
-}
-
-static int midas_submic_bias(struct snd_soc_dapm_widget *w,
-			     struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_card *card = w->dapm->card;
-	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		return regulator_enable(priv->reg_submic_bias);
-	case SND_SOC_DAPM_POST_PMD:
-		return regulator_disable(priv->reg_submic_bias);
-	}
-
-	return 0;
-}
-
 static int midas_fm_set(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
@@ -272,8 +353,19 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
 
 	SND_SOC_DAPM_HP("Headphone", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-	SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
-	SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("headset-mic-bias", 0, 0),
+	SND_SOC_DAPM_MIC("Main Mic", NULL),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("mic-bias", 0, 0),
+	SND_SOC_DAPM_MIC("Sub Mic", NULL),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("submic-bias", 0, 0),
+};
+
+/* Default routing; supplemented by audio-routing DT property */
+static const struct snd_soc_dapm_route midas_dapm_routes[] = {
+	/* Bind microphones with their respective regulator supplies */
+	{"Main Mic", NULL, "mic-bias"},
+	{"Sub Mic", NULL, "submic-bias"},
+	{"Headset Mic", NULL, "headset-mic-bias"},
 };
 
 static int midas_set_bias_level(struct snd_soc_card *card,
@@ -315,18 +407,67 @@ static int midas_late_probe(struct snd_soc_card *card)
 		return ret;
 	}
 
-	ret = snd_soc_card_jack_new_pins(card, "Headset",
-					 SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-					 SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-					 SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
-					 &priv->headset_jack,
-					 headset_jack_pins,
-					 ARRAY_SIZE(headset_jack_pins));
-	if (ret)
+	if (!priv->gpio_headset_detect) {
+		ret = snd_soc_card_jack_new_pins(card, "Headset",
+				 SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+				 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				 SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+				 SND_JACK_BTN_4 | SND_JACK_BTN_5,
+				 &priv->headset_jack,
+				 headset_jack_pins,
+				 ARRAY_SIZE(headset_jack_pins));
+		if (ret)
+			return ret;
+
+		wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
+				  NULL, NULL, NULL, NULL);
+	} else {
+		/* Some devices (n8000, t310) use a GPIO to detect the jack. */
+		ret = snd_soc_card_jack_new_pins(card, "Headset",
+				SND_JACK_HEADSET | SND_JACK_BTN_0 |
+				SND_JACK_BTN_1 | SND_JACK_BTN_2,
+				&priv->headset_jack,
+				headset_jack_pins,
+				ARRAY_SIZE(headset_jack_pins));
+		if (ret) {
+			dev_err(card->dev,
+				"Failed to set up headset pins: %d\n", ret);
+			return ret;
+		}
+
+		ret = snd_soc_jack_add_zones(&priv->headset_jack,
+				ARRAY_SIZE(headset_jack_zones),
+				headset_jack_zones);
+		if (ret) {
+			dev_err(card->dev,
+				"Failed to set up headset zones: %d\n", ret);
+			return ret;
+		}
+
+		headset_gpio[0].data = aif1_dai->component;
+		headset_gpio[0].desc = priv->gpio_headset_detect;
+
+		headset_gpio[1].data = aif1_dai->component;
+		headset_gpio[1].desc = priv->gpio_headset_key;
+
+		snd_jack_set_key(priv->headset_jack.jack,
+				 SND_JACK_BTN_0, KEY_MEDIA);
+		snd_jack_set_key(priv->headset_jack.jack,
+				 SND_JACK_BTN_1, KEY_VOLUMEUP);
+		snd_jack_set_key(priv->headset_jack.jack,
+				 SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+
+		ret = snd_soc_jack_add_gpios(&priv->headset_jack,
+				ARRAY_SIZE(headset_gpio),
+				headset_gpio);
+		if (ret)
+			dev_err(card->dev,
+				"Failed to set up headset jack GPIOs: %d\n",
+				ret);
+
 		return ret;
+	}
 
-	wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
-			  NULL, NULL, NULL, NULL);
 	return 0;
 }
 
@@ -421,6 +562,8 @@ static struct snd_soc_card midas_card = {
 	.num_controls = ARRAY_SIZE(midas_controls),
 	.dapm_widgets = midas_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets),
+	.dapm_routes = midas_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(midas_dapm_routes),
 
 	.set_bias_level = midas_set_bias_level,
 	.late_probe = midas_late_probe,
@@ -433,6 +576,9 @@ static int midas_probe(struct platform_device *pdev)
 	struct snd_soc_card *card = &midas_card;
 	struct device *dev = &pdev->dev;
 	static struct snd_soc_dai_link *dai_link;
+	enum iio_chan_type channel_type;
+	u32 fourpole_threshold[2];
+	u32 button_threshold[3];
 	struct midas_priv *priv;
 	int ret, i;
 
@@ -443,29 +589,99 @@ static int midas_probe(struct platform_device *pdev)
 	snd_soc_card_set_drvdata(card, priv);
 	card->dev = dev;
 
-	priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias");
-	if (IS_ERR(priv->reg_mic_bias)) {
-		dev_err(dev, "Failed to get mic bias regulator\n");
-		return PTR_ERR(priv->reg_mic_bias);
-	}
-
-	priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias");
-	if (IS_ERR(priv->reg_submic_bias)) {
-		dev_err(dev, "Failed to get submic bias regulator\n");
-		return PTR_ERR(priv->reg_submic_bias);
-	}
-
 	priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH);
-	if (IS_ERR(priv->gpio_fm_sel)) {
-		dev_err(dev, "Failed to get FM selection GPIO\n");
-		return PTR_ERR(priv->gpio_fm_sel);
-	}
+	if (IS_ERR(priv->gpio_fm_sel))
+		return dev_err_probe(dev, PTR_ERR(priv->gpio_fm_sel),
+				     "Failed to get FM selection GPIO\n");
 
 	priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel",
 						    GPIOD_OUT_HIGH);
-	if (IS_ERR(priv->gpio_lineout_sel)) {
-		dev_err(dev, "Failed to get line out selection GPIO\n");
-		return PTR_ERR(priv->gpio_lineout_sel);
+	if (IS_ERR(priv->gpio_lineout_sel))
+		return dev_err_probe(dev, PTR_ERR(priv->gpio_lineout_sel),
+				     "Failed to get line out selection GPIO\n");
+
+	priv->gpio_headset_detect = devm_gpiod_get_optional(dev,
+				"headset-detect", GPIOD_IN);
+	if (IS_ERR(priv->gpio_headset_detect))
+		return dev_err_probe(dev, PTR_ERR(priv->gpio_headset_detect),
+				     "Failed to get headset jack detect GPIO\n");
+
+	if (priv->gpio_headset_detect) {
+		priv->adc_headset_detect = devm_iio_channel_get(dev,
+							"headset-detect");
+		if (IS_ERR(priv->adc_headset_detect))
+			return dev_err_probe(dev,
+					     PTR_ERR(priv->adc_headset_detect),
+					     "Failed to get ADC channel\n");
+
+		ret = iio_get_channel_type(priv->adc_headset_detect,
+					   &channel_type);
+		if (ret) {
+			dev_err(dev, "Failed to get ADC channel type\n");
+			return ret;
+		}
+
+		if (channel_type != IIO_VOLTAGE) {
+			dev_err(dev, "ADC channel is not voltage\n");
+			return -EINVAL;
+		}
+
+		priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key",
+							GPIOD_IN);
+		if (IS_ERR(priv->gpio_headset_key))
+			return dev_err_probe(dev,
+					     PTR_ERR(priv->gpio_headset_key),
+					     "Failed to get headset key GPIO\n");
+
+		ret = of_property_read_u32_array(dev->of_node,
+				"samsung,headset-4pole-threshold-microvolt",
+				fourpole_threshold,
+				ARRAY_SIZE(fourpole_threshold));
+		if (ret) {
+			dev_err(dev, "Failed to get 4-pole jack detection threshold\n");
+			return ret;
+		}
+
+		if (fourpole_threshold[0] > fourpole_threshold[1]) {
+			dev_err(dev, "Invalid 4-pole jack detection threshold value\n");
+			return -EINVAL;
+		}
+
+		headset_jack_zones[0].max_mv = (fourpole_threshold[0]);
+		headset_jack_zones[1].min_mv = (fourpole_threshold[0] + 1);
+
+		headset_jack_zones[1].max_mv = (fourpole_threshold[1]);
+		headset_jack_zones[2].min_mv = (fourpole_threshold[1] + 1);
+
+		ret = of_property_read_u32_array(dev->of_node,
+				"samsung,headset-button-threshold-microvolt",
+				button_threshold,
+				ARRAY_SIZE(button_threshold));
+		if (ret) {
+			dev_err(dev, "Failed to get headset button detection threshold\n");
+			return ret;
+		}
+
+		if (button_threshold[0] > button_threshold[1] ||
+		    button_threshold[1] > button_threshold[2]) {
+			dev_err(dev, "Invalid headset button detection threshold value\n");
+			return -EINVAL;
+		}
+
+		for (i = 0; i < 3; i++) {
+			if (i != 0 && button_threshold[i] <= 0) {
+				dev_err(dev, "Invalid headset button detection threshold value\n");
+				return -EINVAL;
+			}
+
+			headset_key_zones[i].min_mv = button_threshold[i];
+
+			if (i == 2)
+				headset_key_zones[i].max_mv = UINT_MAX;
+			else
+				headset_key_zones[i].max_mv = \
+						(button_threshold[i+1] - 1);
+		}
 	}
 
 	ret = snd_soc_of_parse_card_name(card, "model");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 84601ba43b7d1cef69e874fbdaa7845413223b86..087e379aa3bc42f1babb7a96fabdece127a9fb5f 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1713,7 +1713,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
  *	SND_SOC_DAIFMT_CBC_CFC
  *	SND_SOC_DAIFMT_CBP_CFP
  */
-static u64 fsi_dai_formats =
+static const u64 fsi_dai_formats =
 	SND_SOC_POSSIBLE_DAIFMT_I2S	|
 	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
 	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 6bc7027ed4dbf64e158686234c6fea6f7a895e11..63b3c8bf0fdef5f57c36cf462069baa4400f360a 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1061,7 +1061,7 @@ static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
 	return rsnd_dai_call(prepare, io, priv);
 }
 
-static u64 rsnd_soc_dai_formats[] = {
+static const u64 rsnd_soc_dai_formats[] = {
 	/*
 	 * 1st Priority
 	 *
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 3ab6626ad68024d7cb8edea5bbd574c72b080015..724fe1f033b5505be197c1008ce7a310c0f27d54 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -297,7 +297,7 @@ static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
 	return 0;
 }
 
-const char *snd_soc_dai_name_get(struct snd_soc_dai *dai)
+const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai)
 {
 	/* see snd_soc_is_matching_dai() */
 	if (dai->driver->name)
@@ -3430,7 +3430,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_clock_provider_raw);
 
-int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream)
+int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream)
 {
 	/*
 	 * [Normal]
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index fefe394dce72d79b1730fa637a8f79f5a954dbfd..9e47053419c16eb121bd0eadf9583884322b484f 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -11,7 +11,7 @@
 #include <sound/soc-link.h>
 
 #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
-static inline int _soc_dai_ret(struct snd_soc_dai *dai,
+static inline int _soc_dai_ret(const struct snd_soc_dai *dai,
 			       const char *func, int ret)
 {
 	/* Positive, Zero values are not errors */
@@ -134,7 +134,7 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
 
-int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
+int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *dai;
 	int i, max = 0;
@@ -166,7 +166,7 @@ int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
  * modes.  This will mean that sometimes fewer formats
  * are reported here than are supported by set_fmt().
  */
-u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
+u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority)
 {
 	const struct snd_soc_dai_ops *ops = dai->driver->ops;
 	u64 fmt = 0;
@@ -304,8 +304,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
  * configure the relationship between channel number and TDM slot number.
  */
 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
-				unsigned int tx_num, unsigned int *tx_slot,
-				unsigned int rx_num, unsigned int *rx_slot)
+				unsigned int tx_num, const unsigned int *tx_slot,
+				unsigned int rx_num, const unsigned int *rx_slot)
 {
 	int ret = -ENOTSUPP;
 
@@ -327,7 +327,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
  * @rx_slot: pointer to an array which imply the RX slot number channel
  *           0~num-1 uses
  */
-int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai,
 				unsigned int *tx_num, unsigned int *tx_slot,
 				unsigned int *rx_num, unsigned int *rx_slot)
 {
@@ -471,9 +471,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
  *
  * Returns true if the DAI supports the indicated stream type.
  */
-bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
+bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir)
 {
-	struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
+	const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
 
 	/* If the codec specifies any channels at all, it supports the stream */
 	return stream->channels_min;
@@ -528,7 +528,7 @@ void snd_soc_dai_action(struct snd_soc_dai *dai,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_action);
 
-int snd_soc_dai_active(struct snd_soc_dai *dai)
+int snd_soc_dai_active(const struct snd_soc_dai *dai)
 {
 	int stream, active;
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 16dad4a454434d8279dce9d6e6ad1cfd4e506151..37dccd9c1ba01fb77bfa8518b68b18f0db417bd1 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/async.h>
+#include <linux/cleanup.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
@@ -323,9 +324,9 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
 	const struct snd_soc_dapm_widget *_widget,
 	const char *prefix)
 {
-	struct snd_soc_dapm_widget *w;
-
-	w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
+	struct snd_soc_dapm_widget *w __free(kfree) = kmemdup(_widget,
+							      sizeof(*_widget),
+							      GFP_KERNEL);
 	if (!w)
 		return NULL;
 
@@ -333,20 +334,18 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
 		w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, _widget->name);
 	else
 		w->name = kstrdup_const(_widget->name, GFP_KERNEL);
-	if (!w->name) {
-		kfree(w);
+	if (!w->name)
 		return NULL;
-	}
 
 	if (_widget->sname) {
 		w->sname = kstrdup_const(_widget->sname, GFP_KERNEL);
 		if (!w->sname) {
 			kfree_const(w->name);
-			kfree(w);
 			return NULL;
 		}
 	}
-	return w;
+
+	return_ptr(w);
 }
 
 struct dapm_kcontrol_data {
@@ -3857,7 +3856,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
  */
 int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 	const struct snd_soc_dapm_widget *widget,
-	int num)
+	unsigned int num)
 {
 	int i;
 	int ret = 0;
@@ -3883,11 +3882,10 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 	struct snd_soc_dapm_path *path;
 	struct snd_soc_dai *source, *sink;
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-	struct snd_pcm_hw_params *params = NULL;
 	const struct snd_soc_pcm_stream *config = NULL;
 	struct snd_pcm_runtime *runtime = NULL;
 	unsigned int fmt;
-	int ret = 0;
+	int ret;
 
 	/*
 	 * NOTE
@@ -3898,15 +3896,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 	 * stuff that increases stack usage.
 	 * So, we use kzalloc()/kfree() for params in this function.
 	 */
-	params = kzalloc(sizeof(*params), GFP_KERNEL);
+	struct snd_pcm_hw_params *params __free(kfree) = kzalloc(sizeof(*params),
+								 GFP_KERNEL);
 	if (!params)
 		return -ENOMEM;
 
 	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
-	if (!runtime) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!runtime)
+		return -ENOMEM;
 
 	substream->runtime = runtime;
 
@@ -3916,7 +3913,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 
 		ret = snd_soc_dai_startup(source, substream);
 		if (ret < 0)
-			goto out;
+			return ret;
 
 		snd_soc_dai_activate(source, substream->stream);
 	}
@@ -3927,7 +3924,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 
 		ret = snd_soc_dai_startup(sink, substream);
 		if (ret < 0)
-			goto out;
+			return ret;
 
 		snd_soc_dai_activate(sink, substream->stream);
 	}
@@ -3942,16 +3939,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 	config = rtd->dai_link->c2c_params + rtd->c2c_params_select;
 	if (!config) {
 		dev_err(w->dapm->dev, "ASoC: link config missing\n");
-		ret = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	/* Be a little careful as we don't want to overflow the mask array */
 	if (!config->formats) {
 		dev_warn(w->dapm->dev, "ASoC: Invalid format was specified\n");
 
-		ret = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	fmt = ffs(config->formats) - 1;
@@ -3972,7 +3967,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 
 		ret = snd_soc_dai_hw_params(source, substream, params);
 		if (ret < 0)
-			goto out;
+			return ret;
 
 		dapm_update_dai_unlocked(substream, params, source);
 	}
@@ -3983,7 +3978,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 
 		ret = snd_soc_dai_hw_params(sink, substream, params);
 		if (ret < 0)
-			goto out;
+			return ret;
 
 		dapm_update_dai_unlocked(substream, params, sink);
 	}
@@ -3993,11 +3988,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
 	runtime->channels = params_channels(params);
 	runtime->rate = params_rate(params);
 
-out:
-	/* see above NOTE */
-	kfree(params);
-
-	return ret;
+	return 0;
 }
 
 static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index b27e89ff6a1673f57db6e253a818d6fbe3d1ab91..19928f098d8dcbf9055727b2a81b6eade6fe52ef 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -11,6 +11,7 @@
 //         with code, comments and ideas from :-
 //         Richard Purdie <richard@openedhand.com>
 
+#include <linux/cleanup.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -727,14 +728,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
 	struct soc_bytes *params = (void *)kcontrol->private_value;
 	int ret, len;
 	unsigned int val, mask;
-	void *data;
 
 	if (!component->regmap || !params->num_regs)
 		return -EINVAL;
 
 	len = params->num_regs * component->val_bytes;
 
-	data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
+	void *data __free(kfree) = kmemdup(ucontrol->value.bytes.data, len,
+					   GFP_KERNEL | GFP_DMA);
 	if (!data)
 		return -ENOMEM;
 
@@ -746,7 +747,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
 	if (params->mask) {
 		ret = regmap_read(component->regmap, params->base, &val);
 		if (ret != 0)
-			goto out;
+			return ret;
 
 		val &= params->mask;
 
@@ -760,14 +761,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
 			ret = regmap_parse_val(component->regmap,
 							&mask, &mask);
 			if (ret != 0)
-				goto out;
+				return ret;
 
 			((u16 *)data)[0] &= mask;
 
 			ret = regmap_parse_val(component->regmap,
 							&val, &val);
 			if (ret != 0)
-				goto out;
+				return ret;
 
 			((u16 *)data)[0] |= val;
 			break;
@@ -776,30 +777,23 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
 			ret = regmap_parse_val(component->regmap,
 							&mask, &mask);
 			if (ret != 0)
-				goto out;
+				return ret;
 
 			((u32 *)data)[0] &= mask;
 
 			ret = regmap_parse_val(component->regmap,
 							&val, &val);
 			if (ret != 0)
-				goto out;
+				return ret;
 
 			((u32 *)data)[0] |= val;
 			break;
 		default:
-			ret = -EINVAL;
-			goto out;
+			return -EINVAL;
 		}
 	}
 
-	ret = regmap_raw_write(component->regmap, params->base,
-			       data, len);
-
-out:
-	kfree(data);
-
-	return ret;
+	return regmap_raw_write(component->regmap, params->base, data, len);
 }
 EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
 
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 711b2f49ed88de8df5db9a80dfdd82c112d5ced4..bad823718ae476fb57913106421e96e212d2a683 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -504,7 +504,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
 	unsigned int bits = 0, cpu_bits = 0;
 
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
-		struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
+		const struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
 
 		if (pcm_codec->sig_bits == 0) {
 			bits = 0;
@@ -514,7 +514,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
 	}
 
 	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-		struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
+		const struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
 
 		if (pcm_cpu->sig_bits == 0) {
 			cpu_bits = 0;
@@ -538,7 +538,7 @@ static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
 }
 
 static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
-				   struct snd_soc_pcm_stream *p)
+				   const struct snd_soc_pcm_stream *p)
 {
 	hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
 
@@ -551,20 +551,20 @@ static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
 }
 
 static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
-				   struct snd_soc_pcm_stream *p)
+				   const struct snd_soc_pcm_stream *p)
 {
 	hw->channels_min = max(hw->channels_min, p->channels_min);
 	hw->channels_max = min(hw->channels_max, p->channels_max);
 }
 
 static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
-				     struct snd_soc_pcm_stream *p)
+				     const struct snd_soc_pcm_stream *p)
 {
 	hw->formats &= p->formats;
 }
 
 static void soc_pcm_hw_update_subformat(struct snd_pcm_hardware *hw,
-					struct snd_soc_pcm_stream *p)
+					const struct snd_soc_pcm_stream *p)
 {
 	hw->subformats &= p->subformats;
 }
@@ -583,8 +583,8 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 {
 	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai;
-	struct snd_soc_pcm_stream *codec_stream;
-	struct snd_soc_pcm_stream *cpu_stream;
+	const struct snd_soc_pcm_stream *codec_stream;
+	const struct snd_soc_pcm_stream *cpu_stream;
 	unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
 	int i;
 
@@ -1712,7 +1712,7 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
 		hw->formats &= formats;
 
 	for_each_rtd_cpu_dais(fe, i, dai) {
-		struct snd_soc_pcm_stream *cpu_stream;
+		const struct snd_soc_pcm_stream *cpu_stream;
 
 		/*
 		 * Skip CPUs which don't support the current stream
@@ -1750,7 +1750,7 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
 
 	for_each_dpcm_be(fe, stream, dpcm) {
 		struct snd_soc_pcm_runtime *be = dpcm->be;
-		struct snd_soc_pcm_stream *codec_stream;
+		const struct snd_soc_pcm_stream *codec_stream;
 		int i;
 
 		for_each_rtd_codec_dais(be, i, dai) {
@@ -1787,7 +1787,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
 
 	for_each_dpcm_be(fe, stream, dpcm) {
 		struct snd_soc_pcm_runtime *be = dpcm->be;
-		struct snd_soc_pcm_stream *cpu_stream;
+		const struct snd_soc_pcm_stream *cpu_stream;
 		struct snd_soc_dai *dai;
 		int i;
 
@@ -1809,7 +1809,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
 		 * DAIs connected to a single CPU DAI, use CPU DAI's directly
 		 */
 		if (be->dai_link->num_codecs == 1) {
-			struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream(
+			const struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream(
 				snd_soc_rtd_to_codec(be, 0), stream);
 
 			soc_pcm_hw_update_chan(hw, codec_stream);
@@ -1835,7 +1835,7 @@ static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
 
 	for_each_dpcm_be(fe, stream, dpcm) {
 		struct snd_soc_pcm_runtime *be = dpcm->be;
-		struct snd_soc_pcm_stream *pcm;
+		const struct snd_soc_pcm_stream *pcm;
 		struct snd_soc_dai *dai;
 		int i;
 
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 6951ff7bc61e7c44e578418b6bc8c723a512ece3..af5d42b57be7eb5c7c228a601e3387d23081a147 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -73,7 +73,7 @@ struct soc_tplg {
 	int bytes_ext_ops_count;
 
 	/* optional fw loading callbacks to component drivers */
-	struct snd_soc_tplg_ops *ops;
+	const struct snd_soc_tplg_ops *ops;
 };
 
 /* check we dont overflow the data for this control chunk */
@@ -394,13 +394,9 @@ static void soc_tplg_remove_widget(struct snd_soc_component *comp,
 	if (dobj->unload)
 		dobj->unload(comp, dobj);
 
-	if (!w->kcontrols)
-		goto free_news;
-
-	for (i = 0; w->kcontrols && i < w->num_kcontrols; i++)
-		snd_ctl_remove(card, w->kcontrols[i]);
-
-free_news:
+	if (w->kcontrols)
+		for (i = 0; i < w->num_kcontrols; i++)
+			snd_ctl_remove(card, w->kcontrols[i]);
 
 	list_del(&dobj->list);
 
@@ -644,105 +640,33 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
 	return 0;
 }
 
-static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size)
-{
-	struct snd_soc_tplg_bytes_control *be;
-	struct soc_bytes_ext *sbe;
-	struct snd_kcontrol_new kc;
-	int ret = 0;
-
-	if (soc_tplg_check_elem_count(tplg,
-				      sizeof(struct snd_soc_tplg_bytes_control),
-				      1, size, "mixer bytes"))
-		return -EINVAL;
-
-	be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
-
-	/* validate kcontrol */
-	if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
-		SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
-		return -EINVAL;
-
-	sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
-	if (sbe == NULL)
-		return -ENOMEM;
-
-	tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
-		      le32_to_cpu(be->priv.size));
-
-	dev_dbg(tplg->dev,
-		"ASoC: adding bytes kcontrol %s with access 0x%x\n",
-		be->hdr.name, be->hdr.access);
-
-	memset(&kc, 0, sizeof(kc));
-	kc.name = be->hdr.name;
-	kc.private_value = (long)sbe;
-	kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	kc.access = le32_to_cpu(be->hdr.access);
-
-	sbe->max = le32_to_cpu(be->max);
-	sbe->dobj.type = SND_SOC_DOBJ_BYTES;
-	if (tplg->ops)
-		sbe->dobj.unload = tplg->ops->control_unload;
-	INIT_LIST_HEAD(&sbe->dobj.list);
-
-	/* map io handlers */
-	ret = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
-	if (ret) {
-		soc_control_err(tplg, &be->hdr, be->hdr.name);
-		goto err;
-	}
-
-	/* pass control to driver for optional further init */
-	ret = soc_tplg_control_load(tplg, &kc, &be->hdr);
-	if (ret < 0)
-		goto err;
-
-	/* register control here */
-	ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol);
-	if (ret < 0)
-		goto err;
-
-	list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
-
-err:
-	return ret;
-}
-
-static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
+static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
 {
 	struct snd_soc_tplg_mixer_control *mc;
 	struct soc_mixer_control *sm;
-	struct snd_kcontrol_new kc;
-	int ret = 0;
-
-	if (soc_tplg_check_elem_count(tplg,
-				      sizeof(struct snd_soc_tplg_mixer_control),
-				      1, size, "mixers"))
-		return -EINVAL;
+	int err;
 
 	mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
 
 	/* validate kcontrol */
-	if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
-		SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+	if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 		return -EINVAL;
 
 	sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
-	if (sm == NULL)
+	if (!sm)
 		return -ENOMEM;
-	tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
-		      le32_to_cpu(mc->priv.size));
 
-	dev_dbg(tplg->dev,
-		"ASoC: adding mixer kcontrol %s with access 0x%x\n",
+	tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + le32_to_cpu(mc->priv.size);
+
+	dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n",
 		mc->hdr.name, mc->hdr.access);
 
-	memset(&kc, 0, sizeof(kc));
-	kc.name = mc->hdr.name;
-	kc.private_value = (long)sm;
-	kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	kc.access = le32_to_cpu(mc->hdr.access);
+	kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
+	if (!kc->name)
+		return -ENOMEM;
+	kc->private_value = (long)sm;
+	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kc->access = le32_to_cpu(mc->hdr.access);
 
 	/* we only support FL/FR channel mapping atm */
 	sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL);
@@ -754,40 +678,23 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
 	sm->min = le32_to_cpu(mc->min);
 	sm->invert = le32_to_cpu(mc->invert);
 	sm->platform_max = le32_to_cpu(mc->platform_max);
-	sm->dobj.index = tplg->index;
-	sm->dobj.type = SND_SOC_DOBJ_MIXER;
-	if (tplg->ops)
-		sm->dobj.unload = tplg->ops->control_unload;
-	INIT_LIST_HEAD(&sm->dobj.list);
 
 	/* map io handlers */
-	ret = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
-	if (ret) {
+	err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg);
+	if (err) {
 		soc_control_err(tplg, &mc->hdr, mc->hdr.name);
-		goto err;
+		return err;
 	}
 
 	/* create any TLV data */
-	ret = soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
-	if (ret < 0) {
+	err = soc_tplg_create_tlv(tplg, kc, &mc->hdr);
+	if (err < 0) {
 		dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name);
-		goto err;
+		return err;
 	}
 
 	/* pass control to driver for optional further init */
-	ret = soc_tplg_control_load(tplg, &kc, &mc->hdr);
-	if (ret < 0)
-		goto err;
-
-	/* register control here */
-	ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol);
-	if (ret < 0)
-		goto err;
-
-	list_add(&sm->dobj.list, &tplg->comp->dobj_list);
-
-err:
-	return ret;
+	return soc_tplg_control_load(tplg, kc, &mc->hdr);
 }
 
 static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se,
@@ -851,107 +758,220 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *
 		se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]);
 	}
 
+	se->items = le32_to_cpu(ec->items);
+	se->values = (const unsigned int *)se->dobj.control.dvalues;
 	return 0;
 }
 
-static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size)
+static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
 {
 	struct snd_soc_tplg_enum_control *ec;
 	struct soc_enum *se;
-	struct snd_kcontrol_new kc;
-	int ret = 0;
-
-	if (soc_tplg_check_elem_count(tplg,
-				      sizeof(struct snd_soc_tplg_enum_control),
-				      1, size, "enums"))
-		return -EINVAL;
+	int err;
 
 	ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
 
 	/* validate kcontrol */
-	if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
-		SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+	if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 		return -EINVAL;
 
-	se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL);
-	if (se == NULL)
+	se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL);
+	if (!se)
 		return -ENOMEM;
 
-	tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
-		      le32_to_cpu(ec->priv.size));
+	tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + le32_to_cpu(ec->priv.size));
 
-	dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
-		ec->hdr.name, ec->items);
+	dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items);
 
-	memset(&kc, 0, sizeof(kc));
-	kc.name = ec->hdr.name;
-	kc.private_value = (long)se;
-	kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	kc.access = le32_to_cpu(ec->hdr.access);
+	kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
+	if (!kc->name)
+		return -ENOMEM;
+	kc->private_value = (long)se;
+	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kc->access = le32_to_cpu(ec->hdr.access);
 
+	/* we only support FL/FR channel mapping atm */
 	se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
-	se->shift_l = tplg_chan_get_shift(tplg, ec->channel,
-		SNDRV_CHMAP_FL);
-	se->shift_r = tplg_chan_get_shift(tplg, ec->channel,
-		SNDRV_CHMAP_FL);
+	se->shift_l = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL);
+	se->shift_r = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR);
 
 	se->mask = le32_to_cpu(ec->mask);
-	se->dobj.index = tplg->index;
-	se->dobj.type = SND_SOC_DOBJ_ENUM;
-	if (tplg->ops)
-		se->dobj.unload = tplg->ops->control_unload;
-	INIT_LIST_HEAD(&se->dobj.list);
 
 	switch (le32_to_cpu(ec->hdr.ops.info)) {
-	case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
 	case SND_SOC_TPLG_CTL_ENUM_VALUE:
-		ret = soc_tplg_denum_create_values(tplg, se, ec);
-		if (ret < 0) {
-			dev_err(tplg->dev,
-				"ASoC: could not create values for %s\n",
-				ec->hdr.name);
-			goto err;
+	case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+		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);
+			return err;
 		}
 		fallthrough;
 	case SND_SOC_TPLG_CTL_ENUM:
 	case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
 	case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
-		ret = soc_tplg_denum_create_texts(tplg, se, ec);
-		if (ret < 0) {
-			dev_err(tplg->dev,
-				"ASoC: could not create texts for %s\n",
-				ec->hdr.name);
-			goto err;
+		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);
+			return err;
 		}
 		break;
 	default:
-		ret = -EINVAL;
-		dev_err(tplg->dev,
-			"ASoC: invalid enum control type %d for %s\n",
+		dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
 			ec->hdr.ops.info, ec->hdr.name);
-		goto err;
+		return -EINVAL;
 	}
 
 	/* map io handlers */
-	ret = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg);
-	if (ret) {
+	err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
+	if (err) {
 		soc_control_err(tplg, &ec->hdr, ec->hdr.name);
-		goto err;
+		return err;
+	}
+
+	/* pass control to driver for optional further init */
+	return soc_tplg_control_load(tplg, kc, &ec->hdr);
+}
+
+static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
+{
+	struct snd_soc_tplg_bytes_control *be;
+	struct soc_bytes_ext *sbe;
+	int err;
+
+	be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
+
+	/* validate kcontrol */
+	if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+		return -EINVAL;
+
+	sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
+	if (!sbe)
+		return -ENOMEM;
+
+	tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + le32_to_cpu(be->priv.size));
+
+	dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n",
+		be->hdr.name, be->hdr.access);
+
+	kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
+	if (!kc->name)
+		return -ENOMEM;
+	kc->private_value = (long)sbe;
+	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kc->access = le32_to_cpu(be->hdr.access);
+
+	sbe->max = le32_to_cpu(be->max);
+
+	/* map standard io handlers and check for external handlers */
+	err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg);
+	if (err) {
+		soc_control_err(tplg, &be->hdr, be->hdr.name);
+		return err;
 	}
 
 	/* pass control to driver for optional further init */
-	ret = soc_tplg_control_load(tplg, &kc, &ec->hdr);
+	return soc_tplg_control_load(tplg, kc, &be->hdr);
+}
+
+static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size)
+{
+	struct snd_kcontrol_new kc = {0};
+	struct soc_bytes_ext *sbe;
+	int ret;
+
+	if (soc_tplg_check_elem_count(tplg,
+				      sizeof(struct snd_soc_tplg_bytes_control),
+				      1, size, "mixer bytes"))
+		return -EINVAL;
+
+	ret = soc_tplg_control_dbytes_create(tplg, &kc);
+	if (ret)
+		return ret;
+
+	/* register dynamic object */
+	sbe = (struct soc_bytes_ext *)&kc.private_value;
+
+	INIT_LIST_HEAD(&sbe->dobj.list);
+	sbe->dobj.type = SND_SOC_DOBJ_BYTES;
+	sbe->dobj.index = tplg->index;
+	if (tplg->ops)
+		sbe->dobj.unload = tplg->ops->control_unload;
+
+	/* create control directly */
+	ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol);
 	if (ret < 0)
-		goto err;
+		return ret;
+
+	list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
 
-	/* register control here */
+	return ret;
+}
+
+static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
+{
+	struct snd_kcontrol_new kc = {0};
+	struct soc_mixer_control *sm;
+	int ret;
+
+	if (soc_tplg_check_elem_count(tplg,
+				      sizeof(struct snd_soc_tplg_mixer_control),
+				      1, size, "mixers"))
+		return -EINVAL;
+
+	ret = soc_tplg_control_dmixer_create(tplg, &kc);
+	if (ret)
+		return ret;
+
+	/* register dynamic object */
+	sm = (struct soc_mixer_control *)&kc.private_value;
+
+	INIT_LIST_HEAD(&sm->dobj.list);
+	sm->dobj.type = SND_SOC_DOBJ_MIXER;
+	sm->dobj.index = tplg->index;
+	if (tplg->ops)
+		sm->dobj.unload = tplg->ops->control_unload;
+
+	/* create control directly */
+	ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol);
+	if (ret < 0)
+		return ret;
+
+	list_add(&sm->dobj.list, &tplg->comp->dobj_list);
+
+	return ret;
+}
+
+static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size)
+{
+	struct snd_kcontrol_new kc = {0};
+	struct soc_enum *se;
+	int ret;
+
+	if (soc_tplg_check_elem_count(tplg,
+				      sizeof(struct snd_soc_tplg_enum_control),
+				      1, size, "enums"))
+		return -EINVAL;
+
+	ret = soc_tplg_control_denum_create(tplg, &kc);
+	if (ret)
+		return ret;
+
+	/* register dynamic object */
+	se = (struct soc_enum *)kc.private_value;
+
+	INIT_LIST_HEAD(&se->dobj.list);
+	se->dobj.type = SND_SOC_DOBJ_ENUM;
+	se->dobj.index = tplg->index;
+	if (tplg->ops)
+		se->dobj.unload = tplg->ops->control_unload;
+
+	/* create control directly */
 	ret = soc_tplg_add_kcontrol(tplg, &kc, &se->dobj.control.kcontrol);
 	if (ret < 0)
-		goto err;
+		return ret;
 
 	list_add(&se->dobj.list, &tplg->comp->dobj_list);
 
-err:
 	return ret;
 }
 
@@ -1094,206 +1114,6 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
 	return ret;
 }
 
-static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
-{
-	struct soc_mixer_control *sm;
-	struct snd_soc_tplg_mixer_control *mc;
-	int err;
-
-	mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
-
-	/* validate kcontrol */
-	if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
-	    SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
-		return -EINVAL;
-
-	sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
-	if (!sm)
-		return -ENOMEM;
-
-	tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) +
-		le32_to_cpu(mc->priv.size);
-
-	dev_dbg(tplg->dev, " adding DAPM widget mixer control %s\n",
-		mc->hdr.name);
-
-	kc->private_value = (long)sm;
-	kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
-	if (!kc->name)
-		return -ENOMEM;
-	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	kc->access = le32_to_cpu(mc->hdr.access);
-
-	/* we only support FL/FR channel mapping atm */
-	sm->reg = tplg_chan_get_reg(tplg, mc->channel,
-				    SNDRV_CHMAP_FL);
-	sm->rreg = tplg_chan_get_reg(tplg, mc->channel,
-				     SNDRV_CHMAP_FR);
-	sm->shift = tplg_chan_get_shift(tplg, mc->channel,
-					SNDRV_CHMAP_FL);
-	sm->rshift = tplg_chan_get_shift(tplg, mc->channel,
-					 SNDRV_CHMAP_FR);
-
-	sm->max = le32_to_cpu(mc->max);
-	sm->min = le32_to_cpu(mc->min);
-	sm->invert = le32_to_cpu(mc->invert);
-	sm->platform_max = le32_to_cpu(mc->platform_max);
-	sm->dobj.index = tplg->index;
-	INIT_LIST_HEAD(&sm->dobj.list);
-
-	/* map io handlers */
-	err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg);
-	if (err) {
-		soc_control_err(tplg, &mc->hdr, mc->hdr.name);
-		return err;
-	}
-
-	/* create any TLV data */
-	err = soc_tplg_create_tlv(tplg, kc, &mc->hdr);
-	if (err < 0) {
-		dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
-			mc->hdr.name);
-		return err;
-	}
-
-	/* pass control to driver for optional further init */
-	err = soc_tplg_control_load(tplg, kc, &mc->hdr);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
-{
-	struct snd_soc_tplg_enum_control *ec;
-	struct soc_enum *se;
-	int err;
-
-	ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
-	/* validate kcontrol */
-	if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
-	    SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
-		return -EINVAL;
-
-	se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL);
-	if (!se)
-		return -ENOMEM;
-
-	tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
-		      le32_to_cpu(ec->priv.size));
-
-	dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
-		ec->hdr.name);
-
-	kc->private_value = (long)se;
-	kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
-	if (!kc->name)
-		return -ENOMEM;
-	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	kc->access = le32_to_cpu(ec->hdr.access);
-
-	/* we only support FL/FR channel mapping atm */
-	se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
-	se->shift_l = tplg_chan_get_shift(tplg, ec->channel,
-					  SNDRV_CHMAP_FL);
-	se->shift_r = tplg_chan_get_shift(tplg, ec->channel,
-					  SNDRV_CHMAP_FR);
-
-	se->items = le32_to_cpu(ec->items);
-	se->mask = le32_to_cpu(ec->mask);
-	se->dobj.index = tplg->index;
-
-	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(tplg, se, ec);
-		if (err < 0) {
-			dev_err(tplg->dev, "ASoC: could not create values for %s\n",
-				ec->hdr.name);
-			return err;
-		}
-		fallthrough;
-	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(tplg, se, ec);
-		if (err < 0) {
-			dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
-				ec->hdr.name);
-			return err;
-		}
-		break;
-	default:
-		dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
-			ec->hdr.ops.info, ec->hdr.name);
-		return -EINVAL;
-	}
-
-	/* map io handlers */
-	err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
-	if (err) {
-		soc_control_err(tplg, &ec->hdr, ec->hdr.name);
-		return err;
-	}
-
-	/* pass control to driver for optional further init */
-	err = soc_tplg_control_load(tplg, kc, &ec->hdr);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
-{
-	struct snd_soc_tplg_bytes_control *be;
-	struct soc_bytes_ext *sbe;
-	int err;
-
-	be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
-
-	/* validate kcontrol */
-	if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
-	    SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
-		return -EINVAL;
-
-	sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
-	if (!sbe)
-		return -ENOMEM;
-
-	tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
-		      le32_to_cpu(be->priv.size));
-
-	dev_dbg(tplg->dev,
-		"ASoC: adding bytes kcontrol %s with access 0x%x\n",
-		be->hdr.name, be->hdr.access);
-
-	kc->private_value = (long)sbe;
-	kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
-	if (!kc->name)
-		return -ENOMEM;
-	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	kc->access = le32_to_cpu(be->hdr.access);
-
-	sbe->max = le32_to_cpu(be->max);
-	INIT_LIST_HEAD(&sbe->dobj.list);
-
-	/* map standard io handlers and check for external handlers */
-	err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg);
-	if (err) {
-		soc_control_err(tplg, &be->hdr, be->hdr.name);
-		return err;
-	}
-
-	/* pass control to driver for optional further init */
-	err = soc_tplg_control_load(tplg, kc, &be->hdr);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
 static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
 	struct snd_soc_tplg_dapm_widget *w)
 {
@@ -1381,7 +1201,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
 			kc[i].index = mixer_count;
 			kcontrol_type[i] = SND_SOC_TPLG_TYPE_MIXER;
 			mixer_count++;
-			ret = soc_tplg_dapm_widget_dmixer_create(tplg, &kc[i]);
+			ret = soc_tplg_control_dmixer_create(tplg, &kc[i]);
 			if (ret < 0)
 				goto hdr_err;
 			break;
@@ -1394,7 +1214,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
 			kc[i].index = enum_count;
 			kcontrol_type[i] = SND_SOC_TPLG_TYPE_ENUM;
 			enum_count++;
-			ret = soc_tplg_dapm_widget_denum_create(tplg, &kc[i]);
+			ret = soc_tplg_control_denum_create(tplg, &kc[i]);
 			if (ret < 0)
 				goto hdr_err;
 			break;
@@ -1403,7 +1223,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
 			kc[i].index = bytes_count;
 			kcontrol_type[i] = SND_SOC_TPLG_TYPE_BYTES;
 			bytes_count++;
-			ret = soc_tplg_dapm_widget_dbytes_create(tplg, &kc[i]);
+			ret = soc_tplg_control_dbytes_create(tplg, &kc[i]);
 			if (ret < 0)
 				goto hdr_err;
 			break;
@@ -2331,7 +2151,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)
+	const struct snd_soc_tplg_ops *ops, const struct firmware *fw)
 {
 	struct soc_tplg tplg;
 	int ret;
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index d05e712c95189bcdd4595e9ff5334aa882560467..303823dc45d7ace3434064619055367445ef1064 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -21,7 +21,7 @@ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
 }
 EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
 
-int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
+int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params)
 {
 	int sample_size;
 
@@ -40,7 +40,7 @@ int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots)
 }
 EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
 
-int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
+int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *params)
 {
 	int ret;
 
@@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
  * Return: bclk frequency in Hz, else a negative error code if params format
  *	   is invalid.
  */
-int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params,
+int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params,
 			       int tdm_width, int tdm_slots, int slot_multiple)
 {
 	if (!tdm_slots)
@@ -144,7 +144,6 @@ static const struct snd_soc_component_driver dummy_codec = {
 	.endianness		= 1,
 };
 
-#define STUB_RATES	SNDRV_PCM_RATE_8000_384000
 #define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
 			SNDRV_PCM_FMTBIT_U8 | \
 			SNDRV_PCM_FMTBIT_S16_LE | \
@@ -163,7 +162,7 @@ static const struct snd_soc_component_driver dummy_codec = {
  *	SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
  *	SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
  */
-static u64 dummy_dai_formats =
+static const u64 dummy_dai_formats =
 	SND_SOC_POSSIBLE_DAIFMT_I2S	|
 	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
 	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
@@ -198,20 +197,24 @@ static struct snd_soc_dai_driver dummy_dai = {
 		.stream_name	= "Playback",
 		.channels_min	= 1,
 		.channels_max	= 384,
-		.rates		= STUB_RATES,
+		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min	= 5512,
+		.rate_max	= 768000,
 		.formats	= STUB_FORMATS,
 	},
 	.capture = {
 		.stream_name	= "Capture",
 		.channels_min	= 1,
 		.channels_max	= 384,
-		.rates = STUB_RATES,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min	= 5512,
+		.rate_max	= 768000,
 		.formats = STUB_FORMATS,
 	 },
 	.ops = &dummy_dai_ops,
 };
 
-int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
+int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai)
 {
 	if (dai->driver == &dummy_dai)
 		return 1;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index dead1c19558bb02af35f23eae1f73c4426a093e4..daf364f773ddcdda948bfb9abf27bd6f5868082d 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -783,8 +783,8 @@ int hda_dsp_probe_early(struct snd_sof_dev *sdev)
 				pci->class);
 			return -ENODEV;
 		}
-		dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
-			 pci->class);
+		dev_info_once(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
+			      pci->class);
 	}
 
 	chip = get_chip_info(sdev->pdata);
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index ebe1a7d1668946018e7a3277993c95291dc7b1ee..01db2e720b44ed614a55ce6644d7d45b54175fef 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -183,7 +183,7 @@ static const struct sof_dev_desc adl_desc = {
 	.ops_free = hda_ops_free,
 };
 
-static const struct sof_dev_desc adl_n_desc = {
+static const struct sof_dev_desc adln_desc = {
 	.machines               = snd_soc_acpi_intel_adl_machines,
 	.alt_machines           = snd_soc_acpi_intel_adl_sdw_machines,
 	.use_acpi_target_states = true,
@@ -298,7 +298,7 @@ static const struct pci_device_id sof_pci_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) },
 	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) },
 	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) },
-	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) },
+	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adln_desc) },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 32c7d1f3b528dd63634f3ba1ab7288585a07732a..be61e377e59e03470e035bcd11500eb0745407d8 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -2500,7 +2500,7 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
 	return 0;
 }
 
-static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
+static int sof_ipc3_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type)
 {
 	struct sof_dai_private_data *private = dai->private;
 
@@ -2509,15 +2509,17 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
 
 	switch (private->dai_config->type) {
 	case SOF_DAI_INTEL_SSP:
-		switch (clk_type) {
-		case SOF_DAI_CLK_INTEL_SSP_MCLK:
+		switch (param_type) {
+		case SOF_DAI_PARAM_INTEL_SSP_MCLK:
 			return private->dai_config->ssp.mclk_rate;
-		case SOF_DAI_CLK_INTEL_SSP_BCLK:
+		case SOF_DAI_PARAM_INTEL_SSP_BCLK:
 			return private->dai_config->ssp.bclk_rate;
+		case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS:
+			return private->dai_config->ssp.tdm_slots;
 		default:
+			dev_err(sdev->dev, "invalid SSP param %d\n", param_type);
 			break;
 		}
-		dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type);
 		break;
 	default:
 		/* not yet implemented for platforms other than the above */
@@ -2692,7 +2694,7 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
 	.widget_free = sof_ipc3_widget_free,
 	.widget_setup = sof_ipc3_widget_setup,
 	.dai_config = sof_ipc3_dai_config,
-	.dai_get_clk = sof_ipc3_dai_get_clk,
+	.dai_get_param = sof_ipc3_dai_get_param,
 	.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
 	.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
 	.parse_manifest = sof_ipc3_parse_manifest,
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 00987039c9720ff0034d4baf536b8cb6c27a0f13..90f6856ee80cd2a2c16b52d0472689b944560a72 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -2869,7 +2869,7 @@ static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
 					   struct snd_sof_widget *src_widget,
 					   struct snd_sof_widget *sink_widget,
-					   int sink_id)
+					   struct snd_sof_route *sroute)
 {
 	struct sof_ipc4_copier_config_set_sink_format format;
 	const struct sof_ipc_ops *iops = sdev->ipc->ops;
@@ -2878,9 +2878,6 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
 	struct sof_ipc4_fw_module *fw_module;
 	struct sof_ipc4_msg msg = {{ 0 }};
 
-	dev_dbg(sdev->dev, "%s set copier sink %d format\n",
-		src_widget->widget->name, sink_id);
-
 	if (WIDGET_IS_DAI(src_widget->id)) {
 		struct snd_sof_dai *dai = src_widget->private;
 
@@ -2891,13 +2888,15 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
 
 	fw_module = src_widget->module_info;
 
-	format.sink_id = sink_id;
+	format.sink_id = sroute->src_queue_id;
 	memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
 
-	pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id);
+	pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sroute->dst_queue_id);
 	if (!pin_fmt) {
-		dev_err(sdev->dev, "Unable to get pin %d format for %s",
-			sink_id, sink_widget->widget->name);
+		dev_err(sdev->dev,
+			"Failed to get input audio format of %s:%d for output of %s:%d\n",
+			sink_widget->widget->name, sroute->dst_queue_id,
+			src_widget->widget->name, sroute->src_queue_id);
 		return -EINVAL;
 	}
 
@@ -2955,7 +2954,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
 	sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
 						     SOF_PIN_TYPE_OUTPUT);
 	if (sroute->src_queue_id < 0) {
-		dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
+		dev_err(sdev->dev,
+			"failed to get src_queue_id ID from source widget %s\n",
 			src_widget->widget->name);
 		return sroute->src_queue_id;
 	}
@@ -2963,7 +2963,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
 	sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
 						     SOF_PIN_TYPE_INPUT);
 	if (sroute->dst_queue_id < 0) {
-		dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
+		dev_err(sdev->dev,
+			"failed to get dst_queue_id ID from sink widget %s\n",
 			sink_widget->widget->name);
 		sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
 				      SOF_PIN_TYPE_OUTPUT);
@@ -2972,10 +2973,11 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
 
 	/* Pin 0 format is already set during copier module init */
 	if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
-		ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget,
-						      sroute->src_queue_id);
+		ret = sof_ipc4_set_copier_sink_format(sdev, src_widget,
+						      sink_widget, sroute);
 		if (ret < 0) {
-			dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n",
+			dev_err(sdev->dev,
+				"failed to set sink format for source %s:%d\n",
 				src_widget->widget->name, sroute->src_queue_id);
 			goto out;
 		}
@@ -3195,7 +3197,7 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
 	return 0;
 }
 
-static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
+static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type)
 {
 	struct sof_ipc4_copier *ipc4_copier = dai->private;
 	struct snd_soc_tplg_hw_config *hw_config;
@@ -3234,13 +3236,15 @@ static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
 
 	switch (ipc4_copier->dai_type) {
 	case SOF_DAI_INTEL_SSP:
-		switch (clk_type) {
-		case SOF_DAI_CLK_INTEL_SSP_MCLK:
+		switch (param_type) {
+		case SOF_DAI_PARAM_INTEL_SSP_MCLK:
 			return le32_to_cpu(hw_config->mclk_rate);
-		case SOF_DAI_CLK_INTEL_SSP_BCLK:
+		case SOF_DAI_PARAM_INTEL_SSP_BCLK:
 			return le32_to_cpu(hw_config->bclk_rate);
+		case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS:
+			return le32_to_cpu(hw_config->tdm_slots);
 		default:
-			dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
+			dev_err(sdev->dev, "invalid SSP param %d\n", param_type);
 			break;
 		}
 		break;
@@ -3303,14 +3307,17 @@ static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link
 	return 0;
 }
 
-static enum sof_tokens common_copier_token_list[] = {
+/* Tokens needed for different copier variants (aif, dai and buffer) */
+static enum sof_tokens copier_token_list[] = {
 	SOF_COMP_TOKENS,
+	SOF_COPIER_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
 	SOF_IN_AUDIO_FORMAT_TOKENS,
 	SOF_OUT_AUDIO_FORMAT_TOKENS,
-	SOF_COPIER_DEEP_BUFFER_TOKENS,
-	SOF_COPIER_TOKENS,
 	SOF_COMP_EXT_TOKENS,
+
+	SOF_COPIER_DEEP_BUFFER_TOKENS,	/* for AIF copier */
+	SOF_DAI_TOKENS,			/* for DAI copier */
 };
 
 static enum sof_tokens pipeline_token_list[] = {
@@ -3318,16 +3325,6 @@ static enum sof_tokens pipeline_token_list[] = {
 	SOF_PIPELINE_TOKENS,
 };
 
-static enum sof_tokens dai_token_list[] = {
-	SOF_COMP_TOKENS,
-	SOF_AUDIO_FMT_NUM_TOKENS,
-	SOF_IN_AUDIO_FORMAT_TOKENS,
-	SOF_OUT_AUDIO_FORMAT_TOKENS,
-	SOF_COPIER_TOKENS,
-	SOF_DAI_TOKENS,
-	SOF_COMP_EXT_TOKENS,
-};
-
 static enum sof_tokens pga_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_GAIN_TOKENS,
@@ -3364,23 +3361,23 @@ static enum sof_tokens process_token_list[] = {
 
 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
-				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
+				  copier_token_list, ARRAY_SIZE(copier_token_list),
 				  NULL, sof_ipc4_prepare_copier_module,
 				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
-				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
+				  copier_token_list, ARRAY_SIZE(copier_token_list),
 				  NULL, sof_ipc4_prepare_copier_module,
 				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
-				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+				 copier_token_list, ARRAY_SIZE(copier_token_list), NULL,
 				 sof_ipc4_prepare_copier_module,
 				 sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
-				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+				  copier_token_list, ARRAY_SIZE(copier_token_list), NULL,
 				  sof_ipc4_prepare_copier_module,
 				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
-				 common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
+				 copier_token_list, ARRAY_SIZE(copier_token_list),
 				 NULL, sof_ipc4_prepare_copier_module,
 				 sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
@@ -3417,7 +3414,7 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.route_free = sof_ipc4_route_free,
 	.dai_config = sof_ipc4_dai_config,
 	.parse_manifest = sof_ipc4_parse_manifest,
-	.dai_get_clk = sof_ipc4_dai_get_clk,
+	.dai_get_param = sof_ipc4_dai_get_param,
 	.tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
 	.link_setup = sof_ipc4_link_setup,
 };
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index bea1b9d9ca2886db2b1f513ab10327b77f10b764..74522400207e12a70ab046b49952ceb8178265f0 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -82,7 +82,7 @@ static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc)
 	}
 }
 
-static struct mtk_adsp_ipc_ops dsp_ops = {
+static const struct mtk_adsp_ipc_ops dsp_ops = {
 	.handle_reply		= mt8186_dsp_handle_reply,
 	.handle_request		= mt8186_dsp_handle_request,
 };
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index 31dc98d1b1d8bddde8f91047125ea034b912f691..24ae1d4959be59a9d683310248f420eab5b55ef2 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -82,7 +82,7 @@ static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc)
 	}
 }
 
-static struct mtk_adsp_ipc_ops dsp_ops = {
+static const struct mtk_adsp_ipc_ops dsp_ops = {
 	.handle_reply		= mt8195_dsp_handle_reply,
 	.handle_request		= mt8195_dsp_handle_request,
 };
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index ef9318947d74f5b06575d81e0d961be5eade441c..9a52781bf8d8b97330a19999b9f874fd25eda80f 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -978,7 +978,7 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
 	return NULL;
 }
 
-static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
+static int sof_dai_get_param(struct snd_soc_pcm_runtime *rtd, int param_type)
 {
 	struct snd_soc_component *component =
 		snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
@@ -991,8 +991,8 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
 	if (!dai)
 		return 0;
 
-	if (tplg_ops && tplg_ops->dai_get_clk)
-		return tplg_ops->dai_get_clk(sdev, dai, clk_type);
+	if (tplg_ops && tplg_ops->dai_get_param)
+		return tplg_ops->dai_get_param(sdev, dai, param_type);
 
 	return 0;
 }
@@ -1003,7 +1003,7 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
  */
 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd)
 {
-	return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK);
+	return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_MCLK);
 }
 EXPORT_SYMBOL(sof_dai_get_mclk);
 
@@ -1013,6 +1013,16 @@ EXPORT_SYMBOL(sof_dai_get_mclk);
  */
 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
 {
-	return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK);
+	return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_BCLK);
 }
 EXPORT_SYMBOL(sof_dai_get_bclk);
+
+/*
+ * Helper to get SSP TDM slot number from a pcm_runtime.
+ * Return 0 if not exist.
+ */
+int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd)
+{
+	return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS);
+}
+EXPORT_SYMBOL(sof_dai_get_tdm_slots);
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index ec2a3bb644d2b62fc9530e99b49deceef7e5928a..49be02234fc386a032df0fc57d0319cbab03e4b5 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -44,8 +44,9 @@
 #define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id))
 #define WIDGET_IS_COPIER(id) (WIDGET_IS_AIF_OR_DAI(id) || (id) == snd_soc_dapm_buffer)
 
-#define SOF_DAI_CLK_INTEL_SSP_MCLK	0
-#define SOF_DAI_CLK_INTEL_SSP_BCLK	1
+#define SOF_DAI_PARAM_INTEL_SSP_MCLK		0
+#define SOF_DAI_PARAM_INTEL_SSP_BCLK		1
+#define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS	2
 
 enum sof_widget_op {
 	SOF_WIDGET_PREPARE,
@@ -208,7 +209,7 @@ struct sof_ipc_tplg_widget_ops {
  * @widget_setup: Function pointer for setting up setup in the DSP
  * @widget_free: Function pointer for freeing widget in the DSP
  * @dai_config: Function pointer for sending DAI config IPC to the DSP
- * @dai_get_clk: Function pointer for getting the DAI clock setting
+ * @dai_get_param: Function pointer for getting the DAI parameter
  * @set_up_all_pipelines: Function pointer for setting up all topology pipelines
  * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines
  * @parse_manifest: Function pointer for ipc4 specific parsing of topology manifest
@@ -229,7 +230,7 @@ struct sof_ipc_tplg_ops {
 	int (*widget_free)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
 	int (*dai_config)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
 			  unsigned int flags, struct snd_sof_dai_config_data *data);
-	int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type);
+	int (*dai_get_param)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type);
 	int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
 	int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
 	int (*parse_manifest)(struct snd_soc_component *scomp, int index,
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index da182314aa8745a06084acfb09ab1a5c91fedde6..b5438213199163d305aba29cc7b94e3c9ade5a43 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -2278,7 +2278,7 @@ static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = {
 	{SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_bytes_ext_volatile_get},
 };
 
-static struct snd_soc_tplg_ops sof_tplg_ops = {
+static const struct snd_soc_tplg_ops sof_tplg_ops = {
 	/* external kcontrol init - used for any driver specific init */
 	.control_load	= sof_control_load,
 	.control_unload	= sof_control_unload,
@@ -2433,7 +2433,7 @@ static int sof_dspless_link_load(struct snd_soc_component *scomp, int index,
 	return 0;
 }
 
-static struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
+static const struct snd_soc_tplg_ops sof_dspless_tplg_ops = {
 	/* external widget init - used for any driver specific init */
 	.widget_ready	= sof_dspless_widget_ready,
 	.widget_unload	= sof_dspless_widget_unload,
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index ba7fdd7405acda6d6a290ca514992e30290acdc9..fe4fde844d86106909f1963ca6d1c9a39f89af75 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -8,11 +8,13 @@
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm_params.h>
+#include <sound/simple_card_utils.h>
 #include <sound/soc.h>
 #include "tegra210_i2s.h"
 #include "tegra_cif.h"
@@ -603,6 +605,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
 	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 	unsigned int sample_size, channels, srate, val, reg, path;
 	struct tegra_cif_conf cif_conf;
+	snd_pcm_format_t sample_format;
 
 	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
 
@@ -615,28 +618,51 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
 
 	cif_conf.audio_ch = channels;
 	cif_conf.client_ch = channels;
+	if (i2s->client_channels)
+		cif_conf.client_ch = i2s->client_channels;
 
+	/* AHUB CIF Audio bits configs */
 	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported params audio bit format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	sample_format = params_format(params);
+	if (i2s->client_sample_format >= 0)
+		sample_format = (snd_pcm_format_t)i2s->client_sample_format;
+
+	/*
+	 * Format of the I2S for sending/receiving the audio
+	 * to/from external device.
+	 */
+	switch (sample_format) {
 	case SNDRV_PCM_FORMAT_S8:
 		val = I2S_BITS_8;
 		sample_size = 8;
-		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
 		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
 		break;
 	case SNDRV_PCM_FORMAT_S16_LE:
 		val = I2S_BITS_16;
 		sample_size = 16;
-		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
 		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 		val = I2S_BITS_32;
 		sample_size = 32;
-		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
 		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
 		break;
 	default:
-		dev_err(dev, "unsupported format!\n");
+		dev_err(dev, "unsupported client bit format!\n");
 		return -EOPNOTSUPP;
 	}
 
@@ -872,6 +898,40 @@ static const struct regmap_config tegra210_i2s_regmap_config = {
 	.cache_type		= REGCACHE_FLAT,
 };
 
+/*
+ * The AHUB HW modules are interconnected with CIF which are capable of
+ * supporting Channel and Sample bit format conversion. This needs different
+ * CIF Audio and client configuration. As one of the config comes from
+ * params_channels() or params_format(), the extra configuration is passed from
+ * CIF Port of DT I2S node which can help to perform this conversion.
+ *
+ *    4ch          audio = 4ch      client = 2ch       2ch
+ *   -----> ADMAIF -----------> CIF -------------> I2S ---->
+ */
+static void tegra210_parse_client_convert(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	struct device_node *ports, *ep;
+	struct simple_util_data data = {};
+	int cif_port = 0;
+
+	ports = of_get_child_by_name(dev->of_node, "ports");
+	if (ports) {
+		ep = of_graph_get_endpoint_by_regs(ports, cif_port, -1);
+		if (ep) {
+			simple_util_parse_convert(ep, NULL, &data);
+			of_node_put(ep);
+		}
+		of_node_put(ports);
+	}
+
+	if (data.convert_channels)
+		i2s->client_channels = data.convert_channels;
+
+	if (data.convert_sample_format)
+		i2s->client_sample_format = simple_util_get_sample_fmt(&data);
+}
+
 static int tegra210_i2s_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -887,6 +947,7 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
 	i2s->tx_mask = DEFAULT_I2S_SLOT_MASK;
 	i2s->rx_mask = DEFAULT_I2S_SLOT_MASK;
 	i2s->loopback = false;
+	i2s->client_sample_format = -EINVAL;
 
 	dev_set_drvdata(dev, i2s);
 
@@ -916,6 +977,8 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
 		return PTR_ERR(i2s->regmap);
 	}
 
+	tegra210_parse_client_convert(dev);
+
 	regcache_cache_only(i2s->regmap, true);
 
 	err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt,
diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h
index 030d70c45e18ba35757a13e32690183bd57cd387..fe478f3d843529a518df06c13a276ca5009e2801 100644
--- a/sound/soc/tegra/tegra210_i2s.h
+++ b/sound/soc/tegra/tegra210_i2s.h
@@ -112,6 +112,8 @@ struct tegra210_i2s {
 	struct clk *clk_i2s;
 	struct clk *clk_sync_input;
 	struct regmap *regmap;
+	int client_sample_format;
+	unsigned int client_channels;
 	unsigned int stereo_to_mono[I2S_PATHS];
 	unsigned int mono_to_stereo[I2S_PATHS];
 	unsigned int dai_fmt;
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 5648d744aa79ff4a92e0bfe5b50fe60d704305ca..8f6929ced2c8a659726b3a2937319471d5ea3d9b 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -726,12 +726,8 @@ static int snd_at73c213_mixer(struct snd_at73c213 *chip)
 	return 0;
 
 cleanup:
-	for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) {
-		struct snd_kcontrol *kctl;
-		kctl = snd_ctl_find_numid(card, idx);
-		if (kctl)
-			snd_ctl_remove(card, kctl);
-	}
+	for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++)
+		snd_ctl_remove(card, snd_ctl_find_numid(card, idx));
 	return errval;
 }
 
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 3b45d0ee769389aafb3e752cec5b96223c52077b..1bb6a455a1b461f3c241b387c855e33d7e66cf2b 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -82,13 +82,13 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
 	fp->fmt_bits = sample_width;
 
 	if ((pcm_formats == 0) &&
-	    (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
+	    (format == 0 || format == BIT(UAC_FORMAT_TYPE_I_UNDEFINED))) {
 		/* some devices don't define this correctly... */
 		usb_audio_info(chip, "%u:%d : format type 0 is detected, processed as PCM\n",
 			fp->iface, fp->altsetting);
-		format = 1 << UAC_FORMAT_TYPE_I_PCM;
+		format = BIT(UAC_FORMAT_TYPE_I_PCM);
 	}
-	if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
+	if (format & BIT(UAC_FORMAT_TYPE_I_PCM)) {
 		if (((chip->usb_id == USB_ID(0x0582, 0x0016)) ||
 		     /* Edirol SD-90 */
 		     (chip->usb_id == USB_ID(0x0582, 0x000c))) &&
@@ -128,7 +128,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
 			break;
 		}
 	}
-	if (format & (1 << UAC_FORMAT_TYPE_I_PCM8)) {
+	if (format & BIT(UAC_FORMAT_TYPE_I_PCM8)) {
 		/* Dallas DS4201 workaround: it advertises U8 format, but really
 		   supports S8. */
 		if (chip->usb_id == USB_ID(0x04fa, 0x4201))
@@ -136,15 +136,12 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
 		else
 			pcm_formats |= SNDRV_PCM_FMTBIT_U8;
 	}
-	if (format & (1 << UAC_FORMAT_TYPE_I_IEEE_FLOAT)) {
+	if (format & BIT(UAC_FORMAT_TYPE_I_IEEE_FLOAT))
 		pcm_formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
-	}
-	if (format & (1 << UAC_FORMAT_TYPE_I_ALAW)) {
+	if (format & BIT(UAC_FORMAT_TYPE_I_ALAW))
 		pcm_formats |= SNDRV_PCM_FMTBIT_A_LAW;
-	}
-	if (format & (1 << UAC_FORMAT_TYPE_I_MULAW)) {
+	if (format & BIT(UAC_FORMAT_TYPE_I_MULAW))
 		pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW;
-	}
 	if (format & ~0x3f) {
 		usb_audio_info(chip,
 			 "%u:%d : unsupported format bits %#llx\n",
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 409fc11646948e40ec6b03be6840c150c04db8b7..c00009b545c002d7fead12091e75f3e15c259665 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -433,7 +433,7 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
 {
 	int err;
 
-	if (cval->cached & (1 << channel)) {
+	if (cval->cached & BIT(channel)) {
 		*value = cval->cache_val[index];
 		return 0;
 	}
@@ -445,7 +445,7 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
 				      cval->control, channel, err);
 		return err;
 	}
-	cval->cached |= 1 << channel;
+	cval->cached |= BIT(channel);
 	cval->cache_val[index] = *value;
 	return 0;
 }
@@ -522,7 +522,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
 	int err;
 	unsigned int read_only = (channel == 0) ?
 		cval->master_readonly :
-		cval->ch_readonly & (1 << (channel - 1));
+		cval->ch_readonly & BIT(channel - 1);
 
 	if (read_only) {
 		usb_audio_dbg(cval->head.mixer->chip,
@@ -536,7 +536,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
 					  value);
 	if (err < 0)
 		return err;
-	cval->cached |= 1 << channel;
+	cval->cached |= BIT(channel);
 	cval->cache_val[index] = value;
 	return 0;
 }
@@ -1253,7 +1253,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
 		int minchn = 0;
 		if (cval->cmask) {
 			for (i = 0; i < MAX_CHANNELS; i++)
-				if (cval->cmask & (1 << i)) {
+				if (cval->cmask & BIT(i)) {
 					minchn = i + 1;
 					break;
 				}
@@ -1358,7 +1358,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
 	} else {
 		idx = 0;
 		for (i = 0; i < MAX_CHANNELS; i++) {
-			if (cval->cmask & (1 << i)) {
+			if (cval->cmask & BIT(i)) {
 				init_cur_mix_raw(cval, i + 1, idx);
 				idx++;
 			}
@@ -1416,7 +1416,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
 	if (cval->cmask) {
 		cnt = 0;
 		for (c = 0; c < MAX_CHANNELS; c++) {
-			if (!(cval->cmask & (1 << c)))
+			if (!(cval->cmask & BIT(c)))
 				continue;
 			err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val);
 			if (err < 0)
@@ -1448,7 +1448,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
 	if (cval->cmask) {
 		cnt = 0;
 		for (c = 0; c < MAX_CHANNELS; c++) {
-			if (!(cval->cmask & (1 << c)))
+			if (!(cval->cmask & BIT(c)))
 				continue;
 			err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval);
 			if (err < 0)
@@ -1700,7 +1700,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
 	} else {
 		int i, c = 0;
 		for (i = 0; i < 16; i++)
-			if (ctl_mask & (1 << i))
+			if (ctl_mask & BIT(i))
 				c++;
 		cval->channels = c;
 		cval->ch_readonly = readonly_mask;
@@ -2014,6 +2014,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
 		bmaControls = ftr->bmaControls;
 	}
 
+	if (channels > 32) {
+		usb_audio_info(state->chip,
+			       "usbmixer: too many channels (%d) in unit %d\n",
+			       channels, unitid);
+		return -EINVAL;
+	}
+
 	/* parse the source unit */
 	err = parse_audio_unit(state, hdr->bSourceID);
 	if (err < 0)
@@ -2053,8 +2060,8 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
 
 				mask = snd_usb_combine_bytes(bmaControls +
 							     csize * (j+1), csize);
-				if (mask & (1 << i))
-					ch_bits |= (1 << j);
+				if (mask & BIT(i))
+					ch_bits |= BIT(j);
 			}
 			/* audio class v1 controls are never read-only */
 
@@ -2065,7 +2072,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
 			if (ch_bits & 1)
 				build_feature_ctl(state, _ftr, ch_bits, control,
 						  &iterm, unitid, 0);
-			if (master_bits & (1 << i))
+			if (master_bits & BIT(i))
 				build_feature_ctl(state, _ftr, 0, control,
 						  &iterm, unitid, 0);
 		}
@@ -2081,9 +2088,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
 				mask = snd_usb_combine_bytes(bmaControls +
 							     csize * (j+1), csize);
 				if (uac_v2v3_control_is_readable(mask, control)) {
-					ch_bits |= (1 << j);
+					ch_bits |= BIT(j);
 					if (!uac_v2v3_control_is_writeable(mask, control))
-						ch_read_only |= (1 << j);
+						ch_read_only |= BIT(j);
 				}
 			}
 
@@ -2174,7 +2181,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
 		__u8 *c = uac_mixer_unit_bmControls(desc, state->mixer->protocol);
 
 		if (check_matrix_bitmap(c, in_ch, i, num_outs)) {
-			cval->cmask |= (1 << i);
+			cval->cmask |= BIT(i);
 			cval->channels++;
 		}
 	}
@@ -2497,7 +2504,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
 
 		if (state->mixer->protocol == UAC_VERSION_1) {
 			if (!(controls[valinfo->control / 8] &
-					(1 << ((valinfo->control % 8) - 1))))
+			      BIT((valinfo->control % 8) - 1)))
 				continue;
 		} else { /* UAC_VERSION_2/3 */
 			if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8],
@@ -3441,7 +3448,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
 		case UAC2_CS_CUR:
 			/* invalidate cache, so the value is read from the device */
 			if (channel)
-				info->cached &= ~(1 << channel);
+				info->cached &= ~BIT(channel);
 			else /* master channel */
 				info->cached = 0;
 
@@ -3677,9 +3684,9 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
 	if (cval->cmask) {
 		idx = 0;
 		for (c = 0; c < MAX_CHANNELS; c++) {
-			if (!(cval->cmask & (1 << c)))
+			if (!(cval->cmask & BIT(c)))
 				continue;
-			if (cval->cached & (1 << (c + 1))) {
+			if (cval->cached & BIT(c + 1)) {
 				err = snd_usb_set_cur_mix_value(cval, c + 1, idx,
 							cval->cache_val[idx]);
 				if (err < 0)
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 212b5e6443d88fefd31d25cb4a3c31f7556c71e8..2bc344cf54a83188a63249df9e89b823d38f649b 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1139,7 +1139,7 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 	for (out = 0; out < 8; out++) {
 		control = out + 1;
 		for (in = 0; in < 8; in++) {
-			cmask = 1 << in;
+			cmask = BIT(in);
 			snprintf(name, sizeof(name),
 				"AIn%d - Out%d Capture Volume",
 				in  + 1, out + 1);
@@ -1150,7 +1150,7 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 				return err;
 		}
 		for (in = 8; in < 16; in++) {
-			cmask = 1 << in;
+			cmask = BIT(in);
 			snprintf(name, sizeof(name),
 				"DIn%d - Out%d Playback Volume",
 				in - 7, out + 1);
@@ -1215,7 +1215,7 @@ static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
 	const unsigned int control = 7;
 
 	for (ch = 0; ch < 4; ++ch) {
-		cmask = 1 << ch;
+		cmask = BIT(ch);
 		snprintf(name, sizeof(name),
 			"Effect Return %d Volume", ch + 1);
 		err = snd_create_std_mono_ctl(mixer, id, control,
@@ -1239,7 +1239,7 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
 	const unsigned int control = 9;
 
 	for (ch = 0; ch < 8; ++ch) {
-		cmask = 1 << ch;
+		cmask = BIT(ch);
 		snprintf(name, sizeof(name),
 			"Effect Send AIn%d Volume", ch + 1);
 		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
@@ -1249,7 +1249,7 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
 			return err;
 	}
 	for (ch = 8; ch < 16; ++ch) {
-		cmask = 1 << ch;
+		cmask = BIT(ch);
 		snprintf(name, sizeof(name),
 			"Effect Send DIn%d Volume", ch - 7);
 		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
@@ -1352,7 +1352,7 @@ static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer)
 					chan - num_outs + 1, out + 1);
 			}
 
-			cmask = (out == 0) ? 0 : 1 << (out - 1);
+			cmask = (out == 0) ? 0 : BIT(out - 1);
 			offset = chan * num_outs;
 			err = snd_create_std_mono_ctl_offset(mixer, id, control,
 						cmask, val_type, offset, name,
@@ -1438,7 +1438,7 @@ static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer)
 				chan - num_outs + 1);
 		}
 
-		cmask = (chan == 0) ? 0 : 1 << (chan - 1);
+		cmask = (chan == 0) ? 0 : BIT(chan - 1);
 		err = snd_create_std_mono_ctl(mixer, id, control,
 						cmask, val_type, name,
 						&snd_usb_mixer_vol_tlv);
@@ -1480,7 +1480,7 @@ static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer
 			chan + 1);
 
 		cmask = (chan == 0) ? 0 :
-			1 << (chan + (chan % 2) * num_outs - 1);
+			BIT(chan + (chan % 2) * num_outs - 1);
 		err = snd_create_std_mono_ctl_offset(mixer, id, control,
 						cmask, val_type, offset, name,
 						&snd_usb_mixer_vol_tlv);
@@ -2568,12 +2568,12 @@ static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg,
 			usb_idx = 3;
 			usb_val = value ? 3 : 0;
 		} else {
-			usb_idx = 1 << index;
+			usb_idx = BIT(index);
 			usb_val = value ? usb_idx : 0;
 		}
 	} else {
 		usb_req = SND_BBFPRO_USBREQ_CTL_REG2;
-		usb_idx = 1 << index;
+		usb_idx = BIT(index);
 		usb_val = value ? usb_idx : 0;
 	}
 
diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c
index 31b5dc0f34d246aaae615b48ef14aa6f97da49df..b229eb6f70571df1c1af9d455b3b12ffa07cc0f2 100644
--- a/sound/xen/xen_snd_front_alsa.c
+++ b/sound/xen/xen_snd_front_alsa.c
@@ -69,11 +69,6 @@ struct alsa_sndif_sample_format {
 	snd_pcm_format_t alsa;
 };
 
-struct alsa_sndif_hw_param {
-	u8 sndif;
-	snd_pcm_hw_param_t alsa;
-};
-
 static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS[] = {
 	{
 		.sndif = XENSND_PCM_FORMAT_U8,
diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c
index 1c04e5f638a0b00fa5397ae72d36bb84540ed8fc..2a4b2662035efc7b92bf5baacbe5774919846b32 100644
--- a/tools/testing/selftests/alsa/mixer-test.c
+++ b/tools/testing/selftests/alsa/mixer-test.c
@@ -33,6 +33,8 @@
 struct card_data {
 	snd_ctl_t *handle;
 	int card;
+	snd_ctl_card_info_t *info;
+	const char *card_name;
 	struct pollfd pollfd;
 	int num_ctls;
 	snd_ctl_elem_list_t *ctls;
@@ -91,8 +93,26 @@ static void find_controls(void)
 		err = snd_card_get_longname(card, &card_longname);
 		if (err != 0)
 			card_longname = "Unknown";
-		ksft_print_msg("Card %d - %s (%s)\n", card,
-			       card_name, card_longname);
+
+		err = snd_ctl_card_info_malloc(&card_data->info);
+		if (err != 0)
+			ksft_exit_fail_msg("Failed to allocate card info: %d\n",
+				err);
+
+		err = snd_ctl_card_info(card_data->handle, card_data->info);
+		if (err == 0) {
+			card_data->card_name = snd_ctl_card_info_get_id(card_data->info);
+			if (!card_data->card_name)
+				ksft_print_msg("Failed to get card ID\n");
+		} else {
+			ksft_print_msg("Failed to get card info: %d\n", err);
+		}
+
+		if (!card_data->card_name)
+			card_data->card_name = "Unknown";
+
+		ksft_print_msg("Card %d/%s - %s (%s)\n", card,
+			       card_data->card_name, card_name, card_longname);
 
 		/* Count controls */
 		snd_ctl_elem_list_malloc(&card_data->ctls);
@@ -389,16 +409,16 @@ static void test_ctl_get_value(struct ctl_data *ctl)
 	/* If the control is turned off let's be polite */
 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
 		ksft_print_msg("%s is inactive\n", ctl->name);
-		ksft_test_result_skip("get_value.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("get_value.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	/* Can't test reading on an unreadable control */
 	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
 		ksft_print_msg("%s is not readable\n", ctl->name);
-		ksft_test_result_skip("get_value.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("get_value.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
@@ -413,8 +433,8 @@ static void test_ctl_get_value(struct ctl_data *ctl)
 		err = -EINVAL;
 
 out:
-	ksft_test_result(err >= 0, "get_value.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(err >= 0, "get_value.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 static bool strend(const char *haystack, const char *needle)
@@ -431,7 +451,7 @@ static void test_ctl_name(struct ctl_data *ctl)
 {
 	bool name_ok = true;
 
-	ksft_print_msg("%d.%d %s\n", ctl->card->card, ctl->elem,
+	ksft_print_msg("%s.%d %s\n", ctl->card->card_name, ctl->elem,
 		       ctl->name);
 
 	/* Only boolean controls should end in Switch */
@@ -453,8 +473,8 @@ static void test_ctl_name(struct ctl_data *ctl)
 		}
 	}
 
-	ksft_test_result(name_ok, "name.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(name_ok, "name.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 static void show_values(struct ctl_data *ctl, snd_ctl_elem_value_t *orig_val,
@@ -625,6 +645,21 @@ static int write_and_verify(struct ctl_data *ctl,
 		return err;
 	}
 
+	/*
+	 * We can't verify any specific value for volatile controls
+	 * but we should still check that whatever we read is a valid
+	 * vale for the control.
+	 */
+	if (snd_ctl_elem_info_is_volatile(ctl->info)) {
+		if (!ctl_value_valid(ctl, read_val)) {
+			ksft_print_msg("Volatile control %s has invalid value\n",
+				       ctl->name);
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
 	/*
 	 * Check for an event if the value changed, or confirm that
 	 * there was none if it didn't.  We rely on the kernel
@@ -632,22 +667,20 @@ static int write_and_verify(struct ctl_data *ctl,
 	 * write, this is currently true, should that ever change this
 	 * will most likely break and need updating.
 	 */
-	if (!snd_ctl_elem_info_is_volatile(ctl->info)) {
-		err = wait_for_event(ctl, 0);
-		if (snd_ctl_elem_value_compare(initial_val, read_val)) {
-			if (err < 1) {
-				ksft_print_msg("No event generated for %s\n",
-					       ctl->name);
-				show_values(ctl, initial_val, read_val);
-				ctl->event_missing++;
-			}
-		} else {
-			if (err != 0) {
-				ksft_print_msg("Spurious event generated for %s\n",
-					       ctl->name);
-				show_values(ctl, initial_val, read_val);
-				ctl->event_spurious++;
-			}
+	err = wait_for_event(ctl, 0);
+	if (snd_ctl_elem_value_compare(initial_val, read_val)) {
+		if (err < 1) {
+			ksft_print_msg("No event generated for %s\n",
+				       ctl->name);
+			show_values(ctl, initial_val, read_val);
+			ctl->event_missing++;
+		}
+	} else {
+		if (err != 0) {
+			ksft_print_msg("Spurious event generated for %s\n",
+				       ctl->name);
+			show_values(ctl, initial_val, read_val);
+			ctl->event_spurious++;
 		}
 	}
 
@@ -682,30 +715,30 @@ static void test_ctl_write_default(struct ctl_data *ctl)
 	/* If the control is turned off let's be polite */
 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
 		ksft_print_msg("%s is inactive\n", ctl->name);
-		ksft_test_result_skip("write_default.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_default.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
 		ksft_print_msg("%s is not writeable\n", ctl->name);
-		ksft_test_result_skip("write_default.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_default.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	/* No idea what the default was for unreadable controls */
 	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
 		ksft_print_msg("%s couldn't read default\n", ctl->name);
-		ksft_test_result_skip("write_default.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_default.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	err = write_and_verify(ctl, ctl->def_val, NULL);
 
-	ksft_test_result(err >= 0, "write_default.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(err >= 0, "write_default.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 static bool test_ctl_write_valid_boolean(struct ctl_data *ctl)
@@ -815,15 +848,15 @@ static void test_ctl_write_valid(struct ctl_data *ctl)
 	/* If the control is turned off let's be polite */
 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
 		ksft_print_msg("%s is inactive\n", ctl->name);
-		ksft_test_result_skip("write_valid.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_valid.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
 		ksft_print_msg("%s is not writeable\n", ctl->name);
-		ksft_test_result_skip("write_valid.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_valid.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
@@ -846,16 +879,16 @@ static void test_ctl_write_valid(struct ctl_data *ctl)
 
 	default:
 		/* No tests for this yet */
-		ksft_test_result_skip("write_valid.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_valid.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	/* Restore the default value to minimise disruption */
 	write_and_verify(ctl, ctl->def_val, NULL);
 
-	ksft_test_result(pass, "write_valid.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(pass, "write_valid.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 static bool test_ctl_write_invalid_value(struct ctl_data *ctl,
@@ -1027,15 +1060,15 @@ static void test_ctl_write_invalid(struct ctl_data *ctl)
 	/* If the control is turned off let's be polite */
 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
 		ksft_print_msg("%s is inactive\n", ctl->name);
-		ksft_test_result_skip("write_invalid.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_invalid.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
 		ksft_print_msg("%s is not writeable\n", ctl->name);
-		ksft_test_result_skip("write_invalid.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_invalid.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
@@ -1058,28 +1091,28 @@ static void test_ctl_write_invalid(struct ctl_data *ctl)
 
 	default:
 		/* No tests for this yet */
-		ksft_test_result_skip("write_invalid.%d.%d\n",
-				      ctl->card->card, ctl->elem);
+		ksft_test_result_skip("write_invalid.%s.%d\n",
+				      ctl->card->card_name, ctl->elem);
 		return;
 	}
 
 	/* Restore the default value to minimise disruption */
 	write_and_verify(ctl, ctl->def_val, NULL);
 
-	ksft_test_result(pass, "write_invalid.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(pass, "write_invalid.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 static void test_ctl_event_missing(struct ctl_data *ctl)
 {
-	ksft_test_result(!ctl->event_missing, "event_missing.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(!ctl->event_missing, "event_missing.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 static void test_ctl_event_spurious(struct ctl_data *ctl)
 {
-	ksft_test_result(!ctl->event_spurious, "event_spurious.%d.%d\n",
-			 ctl->card->card, ctl->elem);
+	ksft_test_result(!ctl->event_spurious, "event_spurious.%s.%d\n",
+			 ctl->card->card_name, ctl->elem);
 }
 
 int main(void)
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c
index de664dedb5418e4f69fe8661ce0e7a5f1fc5669d..dbd7c222ce938eb6dd0e19ce205ddbf8c7e1ae0a 100644
--- a/tools/testing/selftests/alsa/pcm-test.c
+++ b/tools/testing/selftests/alsa/pcm-test.c
@@ -24,6 +24,8 @@ typedef struct timespec timestamp_t;
 
 struct card_data {
 	int card;
+	snd_ctl_card_info_t *info;
+	const char *name;
 	pthread_t thread;
 	struct card_data *next;
 };
@@ -35,6 +37,7 @@ struct pcm_data {
 	int card;
 	int device;
 	int subdevice;
+	const char *card_name;
 	snd_pcm_stream_t stream;
 	snd_config_t *pcm_config;
 	struct pcm_data *next;
@@ -167,6 +170,10 @@ static void find_pcms(void)
 	config = get_alsalib_config();
 
 	while (card >= 0) {
+		card_data = calloc(1, sizeof(*card_data));
+		if (!card_data)
+			ksft_exit_fail_msg("Out of memory\n");
+
 		sprintf(name, "hw:%d", card);
 
 		err = snd_ctl_open_lconf(&handle, name, 0, config);
@@ -182,14 +189,29 @@ static void find_pcms(void)
 		err = snd_card_get_longname(card, &card_longname);
 		if (err != 0)
 			card_longname = "Unknown";
-		ksft_print_msg("Card %d - %s (%s)\n", card,
-			       card_name, card_longname);
+
+		err = snd_ctl_card_info_malloc(&card_data->info);
+		if (err != 0)
+			ksft_exit_fail_msg("Failed to allocate card info: %d\n",
+				err);
+
+		err = snd_ctl_card_info(handle, card_data->info);
+		if (err == 0) {
+			card_data->name = snd_ctl_card_info_get_id(card_data->info);
+			if (!card_data->name)
+				ksft_print_msg("Failed to get card ID\n");
+		} else {
+			ksft_print_msg("Failed to get card info: %d\n", err);
+		}
+
+		if (!card_data->name)
+			card_data->name = "Unknown";
+
+		ksft_print_msg("Card %d/%s - %s (%s)\n", card,
+			       card_data->name, card_name, card_longname);
 
 		card_config = conf_by_card(card);
 
-		card_data = calloc(1, sizeof(*card_data));
-		if (!card_data)
-			ksft_exit_fail_msg("Out of memory\n");
 		card_data->card = card;
 		card_data->next = card_list;
 		card_list = card_data;
@@ -218,6 +240,10 @@ static void find_pcms(void)
 				if (err < 0)
 					ksft_exit_fail_msg("snd_ctl_pcm_info: %d:%d:%d\n",
 							   dev, 0, stream);
+
+				ksft_print_msg("%s.0 - %s\n", card_data->name,
+					       snd_pcm_info_get_id(pcm_info));
+
 				count = snd_pcm_info_get_subdevices_count(pcm_info);
 				for (subdev = 0; subdev < count; subdev++) {
 					sprintf(key, "pcm.%d.%d.%s", dev, subdev, snd_pcm_stream_name(stream));
@@ -232,6 +258,7 @@ static void find_pcms(void)
 					pcm_data->card = card;
 					pcm_data->device = dev;
 					pcm_data->subdevice = subdev;
+					pcm_data->card_name = card_data->name;
 					pcm_data->stream = stream;
 					pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL);
 					pcm_data->next = pcm_list;
@@ -294,9 +321,9 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class,
 
 	desc = conf_get_string(pcm_cfg, "description", NULL, NULL);
 	if (desc)
-		ksft_print_msg("%s.%s.%d.%d.%d.%s - %s\n",
+		ksft_print_msg("%s.%s.%s.%d.%d.%s - %s\n",
 			       test_class_name, test_name,
-			       data->card, data->device, data->subdevice,
+			       data->card_name, data->device, data->subdevice,
 			       snd_pcm_stream_name(data->stream),
 			       desc);
 
@@ -352,9 +379,9 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class,
 			old_format = format;
 			format = snd_pcm_format_value(alt_formats[i]);
 			if (format != SND_PCM_FORMAT_UNKNOWN) {
-				ksft_print_msg("%s.%d.%d.%d.%s.%s format %s -> %s\n",
+				ksft_print_msg("%s.%s.%d.%d.%s.%s format %s -> %s\n",
 						 test_name,
-						 data->card, data->device, data->subdevice,
+						 data->card_name, data->device, data->subdevice,
 						 snd_pcm_stream_name(data->stream),
 						 snd_pcm_access_name(access),
 						 snd_pcm_format_name(old_format),
@@ -383,7 +410,7 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class,
 		goto __close;
 	}
 	if (rrate != rate) {
-		snprintf(msg, sizeof(msg), "rate mismatch %ld != %d", rate, rrate);
+		snprintf(msg, sizeof(msg), "rate mismatch %ld != %u", rate, rrate);
 		goto __close;
 	}
 	rperiod_size = period_size;
@@ -430,9 +457,9 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class,
 		goto __close;
 	}
 
-	ksft_print_msg("%s.%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n",
+	ksft_print_msg("%s.%s.%s.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n",
 		         test_class_name, test_name,
-			 data->card, data->device, data->subdevice,
+			 data->card_name, data->device, data->subdevice,
 			 snd_pcm_stream_name(data->stream),
 			 snd_pcm_access_name(access),
 			 snd_pcm_format_name(format),
@@ -491,9 +518,10 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class,
 		 * Anything specified as specific to this system
 		 * should always be supported.
 		 */
-		ksft_test_result(!skip, "%s.%s.%d.%d.%d.%s.params\n",
+		ksft_test_result(!skip, "%s.%s.%s.%d.%d.%s.params\n",
 				 test_class_name, test_name,
-				 data->card, data->device, data->subdevice,
+				 data->card_name, data->device,
+				 data->subdevice,
 				 snd_pcm_stream_name(data->stream));
 		break;
 	default:
@@ -501,14 +529,16 @@ static void test_pcm_time(struct pcm_data *data, enum test_class class,
 	}
 
 	if (!skip)
-		ksft_test_result(pass, "%s.%s.%d.%d.%d.%s\n",
+		ksft_test_result(pass, "%s.%s.%s.%d.%d.%s\n",
 				 test_class_name, test_name,
-				 data->card, data->device, data->subdevice,
+				 data->card_name, data->device,
+				 data->subdevice,
 				 snd_pcm_stream_name(data->stream));
 	else
-		ksft_test_result_skip("%s.%s.%d.%d.%d.%s\n",
+		ksft_test_result_skip("%s.%s.%s.%d.%d.%s\n",
 				 test_class_name, test_name,
-				 data->card, data->device, data->subdevice,
+				 data->card_name, data->device,
+				 data->subdevice,
 				 snd_pcm_stream_name(data->stream));
 
 	if (msg[0])
@@ -609,8 +639,8 @@ int main(void)
 					      conf->filename, conf->config_id);
 
 	for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) {
-		ksft_test_result(false, "test.missing.%d.%d.%d.%s\n",
-				 pcm->card, pcm->device, pcm->subdevice,
+		ksft_test_result(false, "test.missing.%s.%d.%d.%s\n",
+				 pcm->card_name, pcm->device, pcm->subdevice,
 				 snd_pcm_stream_name(pcm->stream));
 	}