diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
index 2005014161bea08da137f8de67f191362ad78825..766e9109b2f77dc16f04a78ddaae10a795be2e4c 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
+++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml
@@ -71,9 +71,6 @@ properties:
             description: CPU to Codec rate channels.
             $ref: /schemas/types.yaml#/definitions/uint32
 
-        required:
-          - remote-endpoint
-
   ports:
     description: multi OF-Graph subnode
     type: object
diff --git a/Documentation/devicetree/bindings/sound/ingenic,codec.yaml b/Documentation/devicetree/bindings/sound/ingenic,codec.yaml
index eb4be86464bb4dfc14651bc528ff26bb15153e76..97d5f3819b276cc3eba86068773875a6f984fda1 100644
--- a/Documentation/devicetree/bindings/sound/ingenic,codec.yaml
+++ b/Documentation/devicetree/bindings/sound/ingenic,codec.yaml
@@ -15,9 +15,14 @@ properties:
 
   compatible:
     oneOf:
-      - const: ingenic,jz4770-codec
-      - const: ingenic,jz4725b-codec
-      - const: ingenic,jz4740-codec
+      - enum:
+          - ingenic,jz4770-codec
+          - ingenic,jz4760-codec
+          - ingenic,jz4725b-codec
+          - ingenic,jz4740-codec
+      - items:
+          - const: ingenic,jz4760b-codec
+          - const: ingenic,jz4760-codec
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
index d346e61ab708550f7ca136b8d9689fb4116e04db..6f71294909a5fb4136dd9a408cdd88aaea926a2d 100644
--- a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml
@@ -18,6 +18,7 @@ properties:
     enum:
       - intel,keembay-i2s
       - intel,keembay-tdm
+      - intel,keembay-hdmi-i2s
 
   "#sound-dai-cells":
     const: 0
@@ -45,6 +46,16 @@ properties:
       - const: osc
       - const: apb_clk
 
+  dmas:
+    items:
+      - description: DMA TX channel
+      - description: DMA RX channel
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+
 required:
   - compatible
   - "#sound-dai-cells"
@@ -70,4 +81,6 @@ examples:
          interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
          clock-names = "osc", "apb_clk";
          clocks = <&scmi_clk KEEM_BAY_PSS_AUX_I2S3>, <&scmi_clk KEEM_BAY_PSS_I2S3>;
+         dmas = <&axi_dma0 29 &axi_dma0 33>;
+         dma-names = "tx", "rx";
      };
diff --git a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
index 54650823b29a41de10061ad664ac2080eefdab66..5a5b765b859a54c1b2bd2d21733ba00d9b35fd70 100644
--- a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
@@ -23,6 +23,10 @@ properties:
     $ref: "/schemas/types.yaml#/definitions/phandle"
     description: The phandle of MT8192 ASoC platform.
 
+  mediatek,hdmi-codec:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of HDMI codec.
+
 additionalProperties: false
 
 required:
@@ -35,6 +39,7 @@ examples:
     sound: mt8192-sound {
         compatible = "mediatek,mt8192_mt6359_rt1015_rt5682";
         mediatek,platform = <&afe>;
+        mediatek,hdmi-codec = <&anx_bridge_dp>;
         pinctrl-names = "aud_clk_mosi_off",
                         "aud_clk_mosi_on";
         pinctrl-0 = <&aud_clk_mosi_off>;
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..249970952202b3256c41335e3f234608e6704fa4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml
@@ -0,0 +1,190 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-graph-card.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio Graph based Tegra sound card driver
+
+description: |
+  This is based on generic audio graph card driver along with additional
+  customizations for Tegra platforms. It uses the same bindings with
+  additional standard clock DT bindings required for Tegra.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+  - $ref: audio-graph.yaml#
+
+properties:
+  compatible:
+    enum:
+      - nvidia,tegra210-audio-graph-card
+      - nvidia,tegra186-audio-graph-card
+
+  clocks:
+    minItems: 2
+
+  clock-names:
+    minItems: 2
+    items:
+      - const: pll_a
+      - const: plla_out0
+
+  assigned-clocks:
+    minItems: 1
+    maxItems: 3
+
+  assigned-clock-parents:
+    minItems: 1
+    maxItems: 3
+
+  assigned-clock-rates:
+    minItems: 1
+    maxItems: 3
+
+  iommus:
+    maxItems: 1
+
+required:
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    tegra_sound {
+        compatible = "nvidia,tegra210-audio-graph-card";
+
+        clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+                 <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        clock-names = "pll_a", "plla_out0";
+
+        assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+                          <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+                          <&tegra_car TEGRA210_CLK_EXTERN1>;
+        assigned-clock-parents = <0>, <0>, <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <368640000>, <49152000>, <12288000>;
+
+        dais = /* FE */
+               <&admaif1_port>,
+               /* Router */
+               <&xbar_i2s1_port>,
+               /* I/O DAP Ports */
+               <&i2s1_port>;
+
+        label = "jetson-tx1-ape";
+    };
+
+    // The ports are defined for AHUB and its child devices.
+    ahub@702d0800 {
+        compatible = "nvidia,tegra210-ahub";
+        reg = <0x702d0800 0x800>;
+        clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        clock-names = "ahub";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x702d0000 0x702d0000 0x0000e400>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0x0>;
+                xbar_admaif1_ep: endpoint {
+                    remote-endpoint = <&admaif1_ep>;
+                };
+            };
+
+            // ...
+
+            xbar_i2s1_port: port@a {
+                reg = <0xa>;
+                xbar_i2s1_ep: endpoint {
+                    remote-endpoint = <&i2s1_cif_ep>;
+                };
+            };
+        };
+
+        admaif@702d0000 {
+            compatible = "nvidia,tegra210-admaif";
+            reg = <0x702d0000 0x800>;
+            dmas = <&adma 1>,  <&adma 1>,
+                   <&adma 2>,  <&adma 2>,
+                   <&adma 3>,  <&adma 3>,
+                   <&adma 4>,  <&adma 4>,
+                   <&adma 5>,  <&adma 5>,
+                   <&adma 6>,  <&adma 6>,
+                   <&adma 7>,  <&adma 7>,
+                   <&adma 8>,  <&adma 8>,
+                   <&adma 9>,  <&adma 9>,
+                   <&adma 10>, <&adma 10>;
+            dma-names = "rx1",  "tx1",
+                        "rx2",  "tx2",
+                        "rx3",  "tx3",
+                        "rx4",  "tx4",
+                        "rx5",  "tx5",
+                        "rx6",  "tx6",
+                        "rx7",  "tx7",
+                        "rx8",  "tx8",
+                        "rx9",  "tx9",
+                        "rx10", "tx10";
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                admaif1_port: port@0 {
+                    reg = <0x0>;
+                    admaif1_ep: endpoint {
+                        remote-endpoint = <&xbar_admaif1_ep>;
+                    };
+                };
+
+                // More ADMAIF ports to follow
+            };
+        };
+
+        i2s@702d1000 {
+            compatible = "nvidia,tegra210-i2s";
+            clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            clock-names = "i2s";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <1536000>;
+            reg = <0x702d1000 0x100>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0x0>;
+
+                    i2s1_cif_ep: endpoint {
+                        remote-endpoint = <&xbar_i2s1_ep>;
+                    };
+                };
+
+                i2s1_port: port@1 {
+                    reg = <0x1>;
+
+                    i2s1_dap: endpoint {
+                        dai-format = "i2s";
+                    };
+                };
+            };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
index ed2fb32fcdd4453ca78deef086123d491d221a3d..b8645d9c38ac878b60fa83db1b8426e6c9fd6ae7 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
@@ -17,6 +17,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^dspk@[0-9a-f]*$"
@@ -55,6 +58,19 @@ properties:
       The name can be "DSPK1" or "DSPKx", where x depends on the maximum
       available instances on a Tegra SoC.
 
+  ports:
+    type: object
+    properties:
+      port@0:
+        description: |
+          DSPK ACIF (Audio Client Interface) port connected to the
+          corresponding AHUB (Audio Hub) ACIF port.
+
+      port@1:
+        description: |
+          DSPK DAP (Digital Audio Port) interface which can be connected
+          to external audio codec for playback.
+
 required:
   - compatible
   - reg
@@ -64,7 +80,7 @@ required:
   - assigned-clock-parents
   - sound-name-prefix
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
index c028b259e822ec2d0ba9ad8faab09e5149184d34..7cee7722df413fa9adffa6c5bdf3723e142225d1 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
@@ -17,6 +17,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^admaif@[0-9a-f]*$"
@@ -37,6 +40,14 @@ properties:
 
   dma-names: true
 
+  ports:
+    description: |
+      Contains list of ACIF (Audio CIF) port nodes for ADMAIF channels.
+      The number of port nodes depends on the number of ADMAIF channels
+      that SoC may have. These are interfaced with respective ACIF ports
+      in AHUB (Audio Hub). Each port is capable of data transfers in
+      both directions.
+
 if:
   properties:
     compatible:
@@ -81,7 +92,7 @@ required:
   - dmas
   - dma-names
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
index d77219727768e4f23901cacd1f118904484d9e20..31f3e51974bb4f5ea47771f250036a23f9ed0b9e 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -17,6 +17,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^ahub@[0-9a-f]*$"
@@ -56,6 +59,13 @@ properties:
 
   ranges: true
 
+  ports:
+    description: |
+      Contains list of ACIF (Audio CIF) port nodes for AHUB (Audio Hub).
+      These are connected to ACIF interfaces of AHUB clients. Thus the
+      number of port nodes depend on the number of clients that AHUB may
+      have depending on the SoC revision.
+
 required:
   - compatible
   - reg
@@ -67,8 +77,7 @@ required:
   - "#size-cells"
   - ranges
 
-additionalProperties:
-  type: object
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
index 2a3207b550e7a276436af3a3c72b1b4b77d73ef4..89f4f471be24f58b48e148d5124ae354501eccba 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
@@ -16,6 +16,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^dmic@[0-9a-f]*$"
@@ -56,6 +59,19 @@ properties:
       The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
       on the maximum available instances on a Tegra SoC.
 
+  ports:
+    type: object
+    properties:
+      port@0:
+        description: |
+          DMIC ACIF (Audio Client Interface) port connected to the
+          corresponding AHUB (Audio Hub) ACIF port.
+
+      port@1:
+        description: |
+          DMIC DAP (Digital Audio Port) interface which can be connected
+          to external audio codec for capture.
+
 required:
   - compatible
   - reg
@@ -64,7 +80,7 @@ required:
   - assigned-clocks
   - assigned-clock-parents
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
index dfc1bf7b77222a081398aeb5f9a8cd0fb1a9f691..556460332ffb888a3915eaff12536818fa8ad561 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
@@ -16,6 +16,9 @@ maintainers:
   - Jon Hunter <jonathanh@nvidia.com>
   - Sameer Pujar <spujar@nvidia.com>
 
+allOf:
+  - $ref: audio-graph-port.yaml#
+
 properties:
   $nodename:
     pattern: "^i2s@[0-9a-f]*$"
@@ -74,6 +77,19 @@ properties:
       The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
       on the maximum available instances on a Tegra SoC.
 
+  ports:
+    type: object
+    properties:
+      port@0:
+        description: |
+          I2S ACIF (Audio Client Interface) port connected to the
+          corresponding AHUB (Audio Hub) ACIF port.
+
+      port@1:
+        description: |
+          I2S DAP (Digital Audio Port) interface which can be connected
+          to external audio codec for playback or capture.
+
 required:
   - compatible
   - reg
@@ -82,7 +98,7 @@ required:
   - assigned-clocks
   - assigned-clock-parents
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..443d556caa694153778f6cfa133990ec563fc6bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.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/qcom,lpass-rx-macro.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPASS(Low Power Audio Subsystem) RX Macro audio codec DT bindings
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-rx-macro
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  '#clock-cells':
+    const: 0
+
+  clocks:
+    maxItems: 5
+
+  clock-names:
+    items:
+      - const: mclk
+      - const: npl
+      - const: macro
+      - const: dcodec
+      - const: fsgen
+
+  clock-output-names:
+    items:
+      - const: mclk
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    codec@3200000 {
+      compatible = "qcom,sm8250-lpass-rx-macro";
+      reg = <0x3200000 0x1000>;
+      #sound-dai-cells = <1>;
+      #clock-cells = <0>;
+      clocks = <&audiocc 0>,
+               <&audiocc 1>,
+               <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&vamacro>;
+      clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+      clock-output-names = "mclk";
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6b5ca02ccce411f6d9702a65df8b4d494d02681f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.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/qcom,lpass-tx-macro.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LPASS(Low Power Audio Subsystem) TX Macro audio codec DT bindings
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-tx-macro
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  '#clock-cells':
+    const: 0
+
+  clocks:
+    maxItems: 5
+
+  clock-names:
+    items:
+      - const: mclk
+      - const: npl
+      - const: macro
+      - const: dcodec
+      - const: fsgen
+
+  clock-output-names:
+    items:
+      - const: mclk
+
+  qcom,dmic-sample-rate:
+    description: dmic sample rate
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    codec@3220000 {
+      compatible = "qcom,sm8250-lpass-tx-macro";
+      reg = <0x3220000 0x1000>;
+      #sound-dai-cells = <1>;
+      #clock-cells = <0>;
+      clocks = <&aoncc 0>,
+               <&aoncc 1>,
+               <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&vamacro>;
+      clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+      clock-output-names = "mclk";
+      qcom,dmic-sample-rate = <600000>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
index 0fd37aa84947aa89e667b35175b3cfc869a13211..2e1046513603ed012b3400fda94056c237595872 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
@@ -404,7 +404,7 @@ examples:
         /* DAI base */
         rcar_sound,dai {
             dai0 {
-                playback = <&ssi5 &src5>;
+                playback = <&ssi5>, <&src5>;
                 capture  = <&ssi6>;
             };
             dai1 {
@@ -430,8 +430,8 @@ examples:
                 bitclock-master = <&rsnd_endpoint0>;
                 frame-master = <&rsnd_endpoint0>;
 
-                playback = <&ssi0 &src0 &dvc0>;
-                capture  = <&ssi1 &src1 &dvc1>;
+                playback = <&ssi0>, <&src0>, <&dvc0>;
+                capture  = <&ssi1>, <&src1>, <&dvc1>;
             };
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
index 56788f50b6cf4690fa9508a7b06a0c719a77d975..c473df5c878c67ae8c240446aa2c9a2225f134fc 100644
--- a/Documentation/devicetree/bindings/sound/rt5659.txt
+++ b/Documentation/devicetree/bindings/sound/rt5659.txt
@@ -37,10 +37,21 @@ Optional properties:
 - 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 name-prefix.txt
+
+- 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
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
deleted file mode 100644
index 062f5ec36f9b69fb3a8061642e041e5cd410d486..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-SiRF internal audio CODEC
-
-Required properties:
-
-  - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec"
-
-  - reg : the register address of the device.
-
-  - clocks: the clock of SiRF internal audio codec
-
-Example:
-
-audiocodec: audiocodec@b0040000 {
-	compatible = "sirf,atlas6-audio-codec";
-	reg = <0xb0040000 0x10000>;
-	clocks = <&clks 27>;
-};
diff --git a/Documentation/devicetree/bindings/sound/sirf-usp.txt b/Documentation/devicetree/bindings/sound/sirf-usp.txt
deleted file mode 100644
index 02f85b32d3598333dafb94971c2ecf88ae4c8f20..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/sirf-usp.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* SiRF SoC USP module
-
-Required properties:
-- compatible: "sirf,prima2-usp-pcm"
-- reg: Base address and size entries:
-- dmas: List of DMA controller phandle and DMA request line ordered pairs.
-- dma-names: Identifier string for each DMA request line in the dmas property.
-  These strings correspond 1:1 with the ordered pairs in dmas.
-
-  One of the DMA channels will be responsible for transmission (should be
-  named "tx") and one for reception (should be named "rx").
-
-- clocks: USP controller clock source
-- pinctrl-names: Must contain a "default" entry.
-- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
-
-Example:
-usp0: usp@b0080000 {
-	compatible = "sirf,prima2-usp-pcm";
-	reg = <0xb0080000 0x10000>;
-	clocks = <&clks 28>;
-	dmas = <&dmac1 1>, <&dmac1 2>;
-	dma-names = "rx", "tx";
-	pinctrl-names = "default";
-	pinctrl-0 = <&usp0_only_utfs_pins_a>;
-};
-
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
index f32410890589f6bec7473ebffbbcf4e1cb89fde5..6feb5a09c184e35be3b74b5c58b098be9b70e80a 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
@@ -54,6 +54,10 @@ properties:
   resets:
     maxItems: 1
 
+  "#clock-cells":
+    description: Configure the I2S device as MCLK clock provider.
+    const: 0
+
 required:
   - compatible
   - "#sound-dai-cells"
diff --git a/Documentation/devicetree/bindings/sound/wm8962.txt b/Documentation/devicetree/bindings/sound/wm8962.txt
index dcfa9a3369fde640da518de0f61466a1a54235c4..c36c649ddfd04f370d14ba32bf2ba2cb1096d8c3 100644
--- a/Documentation/devicetree/bindings/sound/wm8962.txt
+++ b/Documentation/devicetree/bindings/sound/wm8962.txt
@@ -9,6 +9,9 @@ Required properties:
   - reg : the I2C address of the device.
 
 Optional properties:
+
+  - clocks : The clock source of the mclk
+
   - spk-mono: This is a boolean property. If present, the SPK_MONO bit
     of R51 (Class D Control 2) gets set, indicating that the speaker is
     in mono mode.
@@ -27,6 +30,7 @@ Example:
 wm8962: codec@1a {
 	compatible = "wlf,wm8962";
 	reg = <0x1a>;
+	clocks = <&clks IMX6QDL_CLK_CKO>;
 
 	gpio-cfg = <
 		0x0000 /* 0:Default */
diff --git a/Documentation/devicetree/bindings/sound/zte,tdm.txt b/Documentation/devicetree/bindings/sound/zte,tdm.txt
deleted file mode 100644
index 2a07ca655264c377a2d8a658b10f594d6206b34a..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/zte,tdm.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-ZTE TDM DAI driver
-
-Required properties:
-
-- compatible : should be one of the following.
-       * zte,zx296718-tdm
-- reg : physical base address of the controller and length of memory mapped
-    region.
-- clocks : Pairs of phandle and specifier referencing the controller's clocks.
-- clock-names: "wclk" for the wclk.
-               "pclk" for the pclk.
--#clock-cells: should be 1.
-- zte,tdm-dma-sysctrl : Reference to the sysctrl controller controlling
-    the dma. includes:
-	phandle of sysctrl.
-	register offset in sysctrl for control dma.
-	mask of the register that be written to sysctrl.
-
-Example:
-
-	tdm: tdm@1487000 {
-		compatible = "zte,zx296718-tdm";
-		reg = <0x01487000 0x1000>;
-		clocks = <&audiocrm AUDIO_TDM_WCLK>, <&audiocrm AUDIO_TDM_PCLK>;
-		clock-names = "wclk", "pclk";
-		#clock-cells = <1>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&tdm_global_pin>;
-		zte,tdm-dma-sysctrl = <&sysctrl 0x10c 4>;
-	};
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt
deleted file mode 100644
index 41bb1040eb71615558c415fe57a2dbf081715d6f..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-ZTE ZX AUD96P22 Audio Codec
-
-Required properties:
- - compatible: Must be "zte,zx-aud96p22"
- - #sound-dai-cells: Should be 0
- - reg: I2C bus slave address of AUD96P22
-
-Example:
-
-	i2c0: i2c@1486000 {
-		compatible = "zte,zx296718-i2c";
-		reg = <0x01486000 0x1000>;
-		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
-		clock-frequency = <1600000>;
-
-		aud96p22: codec@22 {
-			compatible = "zte,zx-aud96p22";
-			#sound-dai-cells = <0>;
-			reg = <0x22>;
-		};
-	};
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt b/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
deleted file mode 100644
index 3927251464f0619da76a6c43f2f24e978cf97d06..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-ZTE ZX296702 I2S controller
-
-Required properties:
- - compatible : Must be one of:
-	"zte,zx296718-i2s", "zte,zx296702-i2s"
-	"zte,zx296702-i2s"
- - reg : Must contain I2S core's registers location and length
- - clocks : Pairs of phandle and specifier referencing the controller's clocks.
- - clock-names: "wclk" for the wclk, "pclk" for the pclk to the I2S interface.
- - dmas: Pairs of phandle and specifier for the DMA channel that is used by
-   the core. The core expects two dma channels for transmit.
- - dma-names : Must be "tx" and "rx"
-
-For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
-please check:
-	* resource-names.txt
-	* clock/clock-bindings.txt
-	* dma/dma.txt
-
-Example:
-	i2s0: i2s@b005000 {
-		#sound-dai-cells = <0>;
-		compatible = "zte,zx296718-i2s", "zte,zx296702-i2s";
-		reg = <0x0b005000 0x1000>;
-		clocks = <&audiocrm AUDIO_I2S0_WCLK>, <&audiocrm AUDIO_I2S0_PCLK>;
-		clock-names = "wclk", "pclk";
-		interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-		dmas = <&dma 5>, <&dma 6>;
-		dma-names = "tx", "rx";
-	};
-
-	sound {
-		compatible = "simple-audio-card";
-		simple-audio-card,name = "zx296702_snd";
-		simple-audio-card,format = "left_j";
-		simple-audio-card,bitclock-master = <&sndcodec>;
-		simple-audio-card,frame-master = <&sndcodec>;
-		sndcpu: simple-audio-card,cpu {
-			sound-dai = <&i2s0>;
-		};
-
-		sndcodec: simple-audio-card,codec {
-			sound-dai = <&acodec>;
-		};
-	};
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt b/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
deleted file mode 100644
index 09231d7586b2e184dab34353a06d3458499bb69e..0000000000000000000000000000000000000000
--- a/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-ZTE ZX296702 SPDIF controller
-
-Required properties:
- - compatible : Must be "zte,zx296702-spdif"
- - reg : Must contain SPDIF core's registers location and length
- - clocks : Pairs of phandle and specifier referencing the controller's clocks.
- - clock-names: "tx" for the clock to the SPDIF interface.
- - dmas: Pairs of phandle and specifier for the DMA channel that is used by
-   the core. The core expects one dma channel for transmit.
- - dma-names : Must be "tx"
-
-For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
-please check:
-	* resource-names.txt
-	* clock/clock-bindings.txt
-	* dma/dma.txt
-
-Example:
-	spdif0: spdif0@b004000 {
-		compatible = "zte,zx296702-spdif";
-		reg = <0x0b004000 0x1000>;
-		clocks = <&lsp0clk ZX296702_SPDIF0_DIV>;
-		clock-names = "tx";
-		interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-		dmas = <&dma 4>;
-		dma-names = "tx";
-	};
diff --git a/Documentation/sound/designs/index.rst b/Documentation/sound/designs/index.rst
index f0749943ccb21511d7e6bf1df152a84bbb50ab6a..1eb08e7bae5224b9b0d36a612dc35c8c74b5ea4d 100644
--- a/Documentation/sound/designs/index.rst
+++ b/Documentation/sound/designs/index.rst
@@ -14,3 +14,4 @@ Designs and Implementations
    powersave
    oss-emulation
    seq-oss
+   jack-injection
diff --git a/Documentation/sound/designs/jack-injection.rst b/Documentation/sound/designs/jack-injection.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f9790521523ef262e5a3bce8f70d442b5ff6cb75
--- /dev/null
+++ b/Documentation/sound/designs/jack-injection.rst
@@ -0,0 +1,166 @@
+============================
+ALSA Jack Software Injection
+============================
+
+Simple Introduction On Jack Injection
+=====================================
+
+Here jack injection means users could inject plugin or plugout events
+to the audio jacks through debugfs interface, it is helpful to
+validate ALSA userspace changes. For example, we change the audio
+profile switching code in the pulseaudio, and we want to verify if the
+change works as expected and if the change introduce the regression,
+in this case, we could inject plugin or plugout events to an audio
+jack or to some audio jacks, we don't need to physically access the
+machine and plug/unplug physical devices to the audio jack.
+
+In this design, an audio jack doesn't equal to a physical audio jack.
+Sometimes a physical audio jack contains multi functions, and the
+ALSA driver creates multi ``jack_kctl`` for a ``snd_jack``, here the
+``snd_jack`` represents a physical audio jack and the ``jack_kctl``
+represents a function, for example a physical jack has two functions:
+headphone and mic_in, the ALSA ASoC driver will build 2 ``jack_kctl``
+for this jack. The jack injection is implemented based on the
+``jack_kctl`` instead of ``snd_jack``.
+
+To inject events to audio jacks, we need to enable the jack injection
+via ``sw_inject_enable`` first, once it is enabled, this jack will not
+change the state by hardware events anymore, we could inject plugin or
+plugout events via ``jackin_inject`` and check the jack state via
+``status``, after we finish our test, we need to disable the jack
+injection via ``sw_inject_enable`` too, once it is disabled, the jack
+state will be restored according to the last reported hardware events
+and will change by future hardware events.
+
+The Layout of Jack Injection Interface
+======================================
+
+If users enable the SND_JACK_INJECTION_DEBUG in the kernel, the audio
+jack injection interface will be created as below:
+::
+
+   $debugfs_mount_dir/sound
+   |-- card0
+   |-- |-- HDMI_DP_pcm_10_Jack
+   |-- |-- |-- jackin_inject
+   |-- |-- |-- kctl_id
+   |-- |-- |-- mask_bits
+   |-- |-- |-- status
+   |-- |-- |-- sw_inject_enable
+   |-- |-- |-- type
+   ...
+   |-- |-- HDMI_DP_pcm_9_Jack
+   |--     |-- jackin_inject
+   |--     |-- kctl_id
+   |--     |-- mask_bits
+   |--     |-- status
+   |--     |-- sw_inject_enable
+   |--     |-- type
+   |-- card1
+       |-- HDMI_DP_pcm_5_Jack
+       |-- |-- jackin_inject
+       |-- |-- kctl_id
+       |-- |-- mask_bits
+       |-- |-- status
+       |-- |-- sw_inject_enable
+       |-- |-- type
+       ...
+       |-- Headphone_Jack
+       |-- |-- jackin_inject
+       |-- |-- kctl_id
+       |-- |-- mask_bits
+       |-- |-- status
+       |-- |-- sw_inject_enable
+       |-- |-- type
+       |-- Headset_Mic_Jack
+           |-- jackin_inject
+           |-- kctl_id
+           |-- mask_bits
+           |-- status
+           |-- sw_inject_enable
+           |-- type
+
+The Explanation Of The Nodes
+======================================
+
+kctl_id
+  read-only, get jack_kctl->kctl's id
+  ::
+
+     sound/card1/Headphone_Jack# cat kctl_id
+     Headphone Jack
+
+mask_bits
+  read-only, get jack_kctl's supported events mask_bits
+  ::
+
+     sound/card1/Headphone_Jack# cat mask_bits
+     0x0001 HEADPHONE(0x0001)
+
+status
+  read-only, get jack_kctl's current status
+
+- headphone unplugged:
+
+  ::
+
+     sound/card1/Headphone_Jack# cat status
+     Unplugged
+
+- headphone plugged:
+
+  ::
+
+     sound/card1/Headphone_Jack# cat status
+     Plugged
+
+type
+  read-only, get snd_jack's supported events from type (all supported events on the physical audio jack)
+  ::
+
+     sound/card1/Headphone_Jack# cat type
+     0x7803 HEADPHONE(0x0001) MICROPHONE(0x0002) BTN_3(0x0800) BTN_2(0x1000) BTN_1(0x2000) BTN_0(0x4000)
+
+sw_inject_enable
+  read-write, enable or disable injection
+
+- injection disabled:
+
+  ::
+
+     sound/card1/Headphone_Jack# cat sw_inject_enable
+     Jack: Headphone Jack		Inject Enabled: 0
+
+- injection enabled:
+
+  ::
+
+     sound/card1/Headphone_Jack# cat sw_inject_enable
+     Jack: Headphone Jack		Inject Enabled: 1
+
+- to enable jack injection:
+
+  ::
+
+     sound/card1/Headphone_Jack# echo 1 > sw_inject_enable
+
+- to disable jack injection:
+
+  ::
+
+     sound/card1/Headphone_Jack# echo 0 > sw_inject_enable
+
+jackin_inject
+  write-only, inject plugin or plugout
+
+- to inject plugin:
+
+  ::
+
+     sound/card1/Headphone_Jack# echo 1 > jackin_inject
+
+- to inject plugout:
+
+  ::
+
+     sound/card1/Headphone_Jack# echo 0 > jackin_inject
diff --git a/drivers/base/isa.c b/drivers/base/isa.c
index 2772f5d1948a01f116a7c1dc9985f426dba0add2..aa4737667026b0399c812985ec359d3f157d61af 100644
--- a/drivers/base/isa.c
+++ b/drivers/base/isa.c
@@ -51,7 +51,7 @@ static int isa_bus_remove(struct device *dev)
 	struct isa_driver *isa_driver = dev->platform_data;
 
 	if (isa_driver && isa_driver->remove)
-		return isa_driver->remove(dev, to_isa_dev(dev)->id);
+		isa_driver->remove(dev, to_isa_dev(dev)->id);
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 140426db28df19bac1a3eb4b1782798049dcb065..b72a3c3ef2abb8c22448129045f889f2c9013854 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -282,7 +282,7 @@ static int elektor_probe(struct device *dev, unsigned int id)
 	return -ENODEV;
 }
 
-static int elektor_remove(struct device *dev, unsigned int id)
+static void elektor_remove(struct device *dev, unsigned int id)
 {
 	i2c_del_adapter(&pcf_isa_ops);
 
@@ -298,8 +298,6 @@ static int elektor_remove(struct device *dev, unsigned int id)
 		iounmap(base_iomem);
 		release_mem_region(base, 2);
 	}
-
-	return 0;
 }
 
 static struct isa_driver i2c_elektor_driver = {
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index f27bc1e553852145d021ac1546c318525dd7787f..85e8cf58e8bfcb469d0b43c65a61d722129c5d98 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -161,7 +161,7 @@ static int pca_isa_probe(struct device *dev, unsigned int id)
 	return -ENODEV;
 }
 
-static int pca_isa_remove(struct device *dev, unsigned int id)
+static void pca_isa_remove(struct device *dev, unsigned int id)
 {
 	i2c_del_adapter(&pca_isa_ops);
 
@@ -170,8 +170,6 @@ static int pca_isa_remove(struct device *dev, unsigned int id)
 		free_irq(irq, &pca_isa_ops);
 	}
 	release_region(base, IO_SIZE);
-
-	return 0;
 }
 
 static struct isa_driver pca_isa_driver = {
diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c
index 2f261a34f9c299f9556c1a6556f3bf9a918d89fc..056ba76087e8d90a83c66be4ed2563603191a42a 100644
--- a/drivers/input/touchscreen/htcpen.c
+++ b/drivers/input/touchscreen/htcpen.c
@@ -171,7 +171,7 @@ static int htcpen_isa_probe(struct device *dev, unsigned int id)
 	return err;
 }
 
-static int htcpen_isa_remove(struct device *dev, unsigned int id)
+static void htcpen_isa_remove(struct device *dev, unsigned int id)
 {
 	struct input_dev *htcpen_dev = dev_get_drvdata(dev);
 
@@ -182,8 +182,6 @@ static int htcpen_isa_remove(struct device *dev, unsigned int id)
 	release_region(HTCPEN_PORT_INDEX, 2);
 	release_region(HTCPEN_PORT_INIT, 1);
 	release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index ad2ac16ff12dd138f1213baca636dd25eb7e58be..c591c0851fa28bd58087486b855a66900b3fbfe2 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -273,8 +273,8 @@ static int radio_isa_common_probe(struct radio_isa_card *isa,
 	return res;
 }
 
-static int radio_isa_common_remove(struct radio_isa_card *isa,
-				   unsigned region_size)
+static void radio_isa_common_remove(struct radio_isa_card *isa,
+				    unsigned region_size)
 {
 	const struct radio_isa_ops *ops = isa->drv->ops;
 
@@ -285,7 +285,6 @@ static int radio_isa_common_remove(struct radio_isa_card *isa,
 	release_region(isa->io, region_size);
 	v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
 	kfree(isa);
-	return 0;
 }
 
 int radio_isa_probe(struct device *pdev, unsigned int dev)
@@ -338,11 +337,11 @@ int radio_isa_probe(struct device *pdev, unsigned int dev)
 }
 EXPORT_SYMBOL_GPL(radio_isa_probe);
 
-int radio_isa_remove(struct device *pdev, unsigned int dev)
+void radio_isa_remove(struct device *pdev, unsigned int dev)
 {
 	struct radio_isa_card *isa = dev_get_drvdata(pdev);
 
-	return radio_isa_common_remove(isa, isa->drv->region_size);
+	radio_isa_common_remove(isa, isa->drv->region_size);
 }
 EXPORT_SYMBOL_GPL(radio_isa_remove);
 
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
index 2f0736edfda848bf6ae7d4497b688fefc9813e1f..c9159958203e9590c8b6edcf7784a2b4ddd2bbde 100644
--- a/drivers/media/radio/radio-isa.h
+++ b/drivers/media/radio/radio-isa.h
@@ -91,7 +91,7 @@ struct radio_isa_driver {
 
 int radio_isa_match(struct device *pdev, unsigned int dev);
 int radio_isa_probe(struct device *pdev, unsigned int dev);
-int radio_isa_remove(struct device *pdev, unsigned int dev);
+void radio_isa_remove(struct device *pdev, unsigned int dev);
 #ifdef CONFIG_PNP
 int radio_isa_pnp_probe(struct pnp_dev *dev,
 			const struct pnp_device_id *dev_id);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 0388894cfe41e52a5733325e4b2ff9e37cb91d5a..d0dde55b7930c60242e1771e9d066cb956be8060 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -293,11 +293,9 @@ static void fmr2_remove(struct fmr2 *fmr2)
 	kfree(fmr2);
 }
 
-static int fmr2_isa_remove(struct device *pdev, unsigned int ndev)
+static void fmr2_isa_remove(struct device *pdev, unsigned int ndev)
 {
 	fmr2_remove(dev_get_drvdata(pdev));
-
-	return 0;
 }
 
 static void fmr2_pnp_remove(struct pnp_dev *pdev)
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 000cb82023e358904e9036241260e7a582eb9a28..75f1bc671d59e630c34c8d6ff68c1a4538157d93 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -797,17 +797,6 @@ const struct dev_pm_ops arizona_pm_ops = {
 EXPORT_SYMBOL_GPL(arizona_pm_ops);
 
 #ifdef CONFIG_OF
-unsigned long arizona_of_get_type(struct device *dev)
-{
-	const struct of_device_id *id = of_match_device(arizona_of_match, dev);
-
-	if (id)
-		return (unsigned long)id->data;
-	else
-		return 0;
-}
-EXPORT_SYMBOL_GPL(arizona_of_get_type);
-
 static int arizona_of_get_core_pdata(struct arizona *arizona)
 {
 	struct arizona_pdata *pdata = &arizona->pdata;
diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c
index 4b58e3ad6eb6ff73bcd105fb38ffc7871ad90203..5e83b730c4ced6340d4327d7e6b56ea6d88e4726 100644
--- a/drivers/mfd/arizona-i2c.c
+++ b/drivers/mfd/arizona-i2c.c
@@ -23,14 +23,16 @@
 static int arizona_i2c_probe(struct i2c_client *i2c,
 			     const struct i2c_device_id *id)
 {
+	const void *match_data;
 	struct arizona *arizona;
 	const struct regmap_config *regmap_config = NULL;
-	unsigned long type;
+	unsigned long type = 0;
 	int ret;
 
-	if (i2c->dev.of_node)
-		type = arizona_of_get_type(&i2c->dev);
-	else
+	match_data = device_get_match_data(&i2c->dev);
+	if (match_data)
+		type = (unsigned long)match_data;
+	else if (id)
 		type = id->driver_data;
 
 	switch (type) {
@@ -115,6 +117,7 @@ static struct i2c_driver arizona_i2c_driver = {
 
 module_i2c_driver(arizona_i2c_driver);
 
+MODULE_SOFTDEP("pre: arizona_ldo1");
 MODULE_DESCRIPTION("Arizona I2C bus interface");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index 2633e147b76c2da975225a98577be8e85cb97d92..24a2c75d691a4e3c186ba2c840bdecfc3e1d0dd7 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -7,7 +7,10 @@
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  */
 
+#include <linux/acpi.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
@@ -15,22 +18,141 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/of.h>
+#include <uapi/linux/input-event-codes.h>
 
 #include <linux/mfd/arizona/core.h>
 
 #include "arizona.h"
 
+#ifdef CONFIG_ACPI
+const struct acpi_gpio_params reset_gpios = { 1, 0, false };
+const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
+
+static const struct acpi_gpio_mapping arizona_acpi_gpios[] = {
+	{ "reset-gpios", &reset_gpios, 1, },
+	{ "wlf,ldoena-gpios", &ldoena_gpios, 1 },
+	{ }
+};
+
+/*
+ * The ACPI resources for the device only describe external GPIO-s. They do
+ * not provide mappings for the GPIO-s coming from the Arizona codec itself.
+ */
+static const struct gpiod_lookup arizona_soc_gpios[] = {
+	{ "arizona", 2, "wlf,spkvdd-ena", 0, GPIO_ACTIVE_HIGH },
+	{ "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW },
+};
+
+/*
+ * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
+ * Function A Play/Pause:           0 ohm
+ * Function D Voice assistant:    135 ohm
+ * Function B Volume Up           240 ohm
+ * Function C Volume Down         470 ohm
+ * Minimum Mic DC resistance     1000 ohm
+ * Minimum Ear speaker impedance   16 ohm
+ * Note the first max value below must be less then the min. speaker impedance,
+ * to allow CTIA/OMTP detection to work. The other max values are the closest
+ * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
+ */
+static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
+	{ .max =  11, .key = KEY_PLAYPAUSE },
+	{ .max = 186, .key = KEY_VOICECOMMAND },
+	{ .max = 348, .key = KEY_VOLUMEUP },
+	{ .max = 752, .key = KEY_VOLUMEDOWN },
+};
+
+static void arizona_spi_acpi_remove_lookup(void *lookup)
+{
+	gpiod_remove_lookup_table(lookup);
+}
+
+static int arizona_spi_acpi_probe(struct arizona *arizona)
+{
+	struct gpiod_lookup_table *lookup;
+	acpi_status status;
+	int ret;
+
+	/* Add mappings for the 2 ACPI declared GPIOs used for reset and ldo-ena */
+	devm_acpi_dev_add_driver_gpios(arizona->dev, arizona_acpi_gpios);
+
+	/* Add lookups for the SoCs own GPIOs used for micdet-polarity and spkVDD-enable */
+	lookup = devm_kzalloc(arizona->dev,
+			      struct_size(lookup, table, ARRAY_SIZE(arizona_soc_gpios) + 1),
+			      GFP_KERNEL);
+	if (!lookup)
+		return -ENOMEM;
+
+	lookup->dev_id = dev_name(arizona->dev);
+	memcpy(lookup->table, arizona_soc_gpios, sizeof(arizona_soc_gpios));
+
+	gpiod_add_lookup_table(lookup);
+	ret = devm_add_action_or_reset(arizona->dev, arizona_spi_acpi_remove_lookup, lookup);
+	if (ret)
+		return ret;
+
+	/* Enable 32KHz clock from SoC to codec for jack-detect */
+	status = acpi_evaluate_object(ACPI_HANDLE(arizona->dev), "CLKE", NULL, NULL);
+	if (ACPI_FAILURE(status))
+		dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status);
+
+	/*
+	 * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING
+	 * The IRQ line will stay low when a new IRQ event happens between reading
+	 * the IRQ status flags and acknowledging them. When the IRQ line stays
+	 * low like this the IRQ will never trigger again when its type is set
+	 * to IRQF_TRIGGER_FALLING. Correct the IRQ trigger-type to fix this.
+	 *
+	 * Note theoretically it is possible that some boards are not capable
+	 * of handling active low level interrupts. In that case setting the
+	 * flag to IRQF_TRIGGER_FALLING would not be a bug (and we would need
+	 * to work around this) but so far all known usages of IRQF_TRIGGER_FALLING
+	 * are a bug in the board's DSDT.
+	 */
+	arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
+
+	/* Wait 200 ms after jack insertion */
+	arizona->pdata.micd_detect_debounce = 200;
+
+	/* Use standard AOSP values for headset-button mappings */
+	arizona->pdata.micd_ranges = arizona_micd_aosp_ranges;
+	arizona->pdata.num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges);
+
+	return 0;
+}
+
+static const struct acpi_device_id arizona_acpi_match[] = {
+	{
+		.id = "WM510204",
+		.driver_data = WM5102,
+	},
+	{
+		.id = "WM510205",
+		.driver_data = WM5102,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, arizona_acpi_match);
+#else
+static int arizona_spi_acpi_probe(struct arizona *arizona)
+{
+	return -ENODEV;
+}
+#endif
+
 static int arizona_spi_probe(struct spi_device *spi)
 {
 	const struct spi_device_id *id = spi_get_device_id(spi);
+	const void *match_data;
 	struct arizona *arizona;
 	const struct regmap_config *regmap_config = NULL;
-	unsigned long type;
+	unsigned long type = 0;
 	int ret;
 
-	if (spi->dev.of_node)
-		type = arizona_of_get_type(&spi->dev);
-	else
+	match_data = device_get_match_data(&spi->dev);
+	if (match_data)
+		type = (unsigned long)match_data;
+	else if (id)
 		type = id->driver_data;
 
 	switch (type) {
@@ -75,6 +197,12 @@ static int arizona_spi_probe(struct spi_device *spi)
 	arizona->dev = &spi->dev;
 	arizona->irq = spi->irq;
 
+	if (has_acpi_companion(&spi->dev)) {
+		ret = arizona_spi_acpi_probe(arizona);
+		if (ret)
+			return ret;
+	}
+
 	return arizona_dev_init(arizona);
 }
 
@@ -102,6 +230,7 @@ static struct spi_driver arizona_spi_driver = {
 		.name	= "arizona",
 		.pm	= &arizona_pm_ops,
 		.of_match_table	= of_match_ptr(arizona_of_match),
+		.acpi_match_table = ACPI_PTR(arizona_acpi_match),
 	},
 	.probe		= arizona_spi_probe,
 	.remove		= arizona_spi_remove,
@@ -110,6 +239,7 @@ static struct spi_driver arizona_spi_driver = {
 
 module_spi_driver(arizona_spi_driver);
 
+MODULE_SOFTDEP("pre: arizona_ldo1");
 MODULE_DESCRIPTION("Arizona SPI bus interface");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h
index 995efc6d7f32ad80342d5875a34552fd0c6b3ce8..801cbbcd71cb528e4f3b818f77f414d62a46d50c 100644
--- a/drivers/mfd/arizona.h
+++ b/drivers/mfd/arizona.h
@@ -50,13 +50,4 @@ int arizona_dev_exit(struct arizona *arizona);
 int arizona_irq_init(struct arizona *arizona);
 int arizona_irq_exit(struct arizona *arizona);
 
-#ifdef CONFIG_OF
-unsigned long arizona_of_get_type(struct device *dev);
-#else
-static inline unsigned long arizona_of_get_type(struct device *dev)
-{
-	return 0;
-}
-#endif
-
 #endif
diff --git a/drivers/net/can/sja1000/tscan1.c b/drivers/net/can/sja1000/tscan1.c
index 6ea802c661246e836070e0cbc5051f76a855b3d7..3dbba8d61afb1080682b6300e3b58bedfdba4de9 100644
--- a/drivers/net/can/sja1000/tscan1.c
+++ b/drivers/net/can/sja1000/tscan1.c
@@ -159,7 +159,7 @@ static int tscan1_probe(struct device *dev, unsigned id)
 	return -ENXIO;
 }
 
-static int tscan1_remove(struct device *dev, unsigned id /*unused*/)
+static void tscan1_remove(struct device *dev, unsigned id /*unused*/)
 {
 	struct net_device *netdev;
 	struct sja1000_priv *priv;
@@ -179,8 +179,6 @@ static int tscan1_remove(struct device *dev, unsigned id /*unused*/)
 	release_region(pld_base, TSCAN1_PLD_SIZE);
 
 	free_sja1000dev(netdev);
-
-	return 0;
 }
 
 static struct isa_driver tscan1_isa_driver = {
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
index 667f38c9e4c63051131966e1349cf5774b37d594..53e1f7e0795984172523a52a0c73923876f5022a 100644
--- a/drivers/net/ethernet/3com/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -335,12 +335,11 @@ static int el3_isa_match(struct device *pdev, unsigned int ndev)
 	return 1;
 }
 
-static int el3_isa_remove(struct device *pdev,
+static void el3_isa_remove(struct device *pdev,
 				    unsigned int ndev)
 {
 	el3_device_remove(pdev);
 	dev_set_drvdata(pdev, NULL);
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 79830e77afa9770512eccccad330841d3efe1889..b1e97f75b0ba983797b51bb2fec7e4b5ad493ed1 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -11459,12 +11459,11 @@ static int advansys_isa_probe(struct device *dev, unsigned int id)
 	return err;
 }
 
-static int advansys_isa_remove(struct device *dev, unsigned int id)
+static void advansys_isa_remove(struct device *dev, unsigned int id)
 {
 	int ioport = _asc_def_iop_base[id];
 	advansys_release(dev_get_drvdata(dev));
 	release_region(ioport, ASC_IOADR_GAP);
-	return 0;
 }
 
 static struct isa_driver advansys_isa_driver = {
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index dc5667afeb271677184af001a88aabfe593b8cb5..e0d8cca1c70b994e84ab9f77aa893a2469b41395 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -1025,12 +1025,11 @@ static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
 	return 1;
 }
 
-static int aha1542_isa_remove(struct device *pdev,
+static void aha1542_isa_remove(struct device *pdev,
 				    unsigned int ndev)
 {
 	aha1542_release(dev_get_drvdata(pdev));
 	dev_set_drvdata(pdev, NULL);
-	return 0;
 }
 
 static struct isa_driver aha1542_isa_driver = {
diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c
index e0cdcd2003d05f5ef3c5bd43bf7a017035604945..2b4280a43a53e2d9233c8a1bf1f78f8c05deafbf 100644
--- a/drivers/scsi/fdomain_isa.c
+++ b/drivers/scsi/fdomain_isa.c
@@ -175,7 +175,7 @@ static int fdomain_isa_param_match(struct device *dev, unsigned int ndev)
 	return 1;
 }
 
-static int fdomain_isa_remove(struct device *dev, unsigned int ndev)
+static void fdomain_isa_remove(struct device *dev, unsigned int ndev)
 {
 	struct Scsi_Host *sh = dev_get_drvdata(dev);
 	int base = sh->io_port;
@@ -183,7 +183,6 @@ static int fdomain_isa_remove(struct device *dev, unsigned int ndev)
 	fdomain_destroy(sh);
 	release_region(base, FDOMAIN_REGION_SIZE);
 	dev_set_drvdata(dev, NULL);
-	return 0;
 }
 
 static struct isa_driver fdomain_isa_driver = {
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 2df2f38a9b1228fd984ed6a34639fea1e1265d31..7ba3c9312731dab438cfd83c89b9bae124778154 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -720,12 +720,11 @@ static int generic_NCR5380_isa_match(struct device *pdev, unsigned int ndev)
 	return 1;
 }
 
-static int generic_NCR5380_isa_remove(struct device *pdev,
-                                      unsigned int ndev)
+static void generic_NCR5380_isa_remove(struct device *pdev,
+				       unsigned int ndev)
 {
 	generic_NCR5380_release_resources(dev_get_drvdata(pdev));
 	dev_set_drvdata(pdev, NULL);
-	return 0;
 }
 
 static struct isa_driver generic_NCR5380_isa_driver = {
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c
index e86fa7f8351d8fc44cce2e30a81e2cafebbe0738..a793b03a785db1f6fded8fb8670d57f21b24a4c8 100644
--- a/drivers/watchdog/pcwd.c
+++ b/drivers/watchdog/pcwd.c
@@ -951,14 +951,11 @@ static int pcwd_isa_probe(struct device *dev, unsigned int id)
 	return ret;
 }
 
-static int pcwd_isa_remove(struct device *dev, unsigned int id)
+static void pcwd_isa_remove(struct device *dev, unsigned int id)
 {
 	if (debug >= DEBUG)
 		pr_debug("pcwd_isa_remove id=%d\n", id);
 
-	if (!pcwd_private.io_addr)
-		return 1;
-
 	/*  Disable the board  */
 	if (!nowayout)
 		pcwd_stop();
@@ -971,8 +968,6 @@ static int pcwd_isa_remove(struct device *dev, unsigned int id)
 			(pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
 	pcwd_private.io_addr = 0x0000;
 	cards_found--;
-
-	return 0;
 }
 
 static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
diff --git a/include/linux/isa.h b/include/linux/isa.h
index 41336da0f4e72069a3f6dede709af04c687df5a6..e30963190968fd0313d8affaff64ecc02d0d9a70 100644
--- a/include/linux/isa.h
+++ b/include/linux/isa.h
@@ -13,7 +13,7 @@
 struct isa_driver {
 	int (*match)(struct device *, unsigned int);
 	int (*probe)(struct device *, unsigned int);
-	int (*remove)(struct device *, unsigned int);
+	void (*remove)(struct device *, unsigned int);
 	void (*shutdown)(struct device *, unsigned int);
 	int (*suspend)(struct device *, unsigned int, pm_message_t);
 	int (*resume)(struct device *, unsigned int);
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index 50e1caad81be72168329bfa059e289856cd226cd..ca6f4fcad51f485b4d5913cfb809f3556aa40cda 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -4610,6 +4610,7 @@ enum ec_codec_i2s_rx_subcmd {
 	EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x2,
 	EC_CODEC_I2S_RX_SET_DAIFMT = 0x3,
 	EC_CODEC_I2S_RX_SET_BCLK = 0x4,
+	EC_CODEC_I2S_RX_RESET = 0x5,
 	EC_CODEC_I2S_RX_SUBCMD_COUNT,
 };
 
diff --git a/include/sound/core.h b/include/sound/core.h
index 0462c577d7a3f832d38442c637cd16ab1488866e..2e24f194ef70f15704e6dc5c354dba821f676686 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -122,6 +122,9 @@ struct snd_card {
 
 	size_t total_pcm_alloc_bytes;	/* total amount of allocated buffers */
 	struct mutex memory_mutex;	/* protection for the above */
+#ifdef CONFIG_SND_DEBUG
+	struct dentry *debugfs_root;    /* debugfs root for card */
+#endif
 
 #ifdef CONFIG_PM
 	unsigned int power_state;	/* power state */
@@ -180,6 +183,9 @@ static inline struct device *snd_card_get_device_link(struct snd_card *card)
 extern int snd_major;
 extern int snd_ecards_limit;
 extern struct class *sound_class;
+#ifdef CONFIG_SND_DEBUG
+extern struct dentry *sound_debugfs_root;
+#endif
 
 void snd_request_card(int card);
 
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index 8c5e38180fb0412a127024d71df21029694e27ff..96666efddb396b7c44d8be2be0fff12fdba829c2 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -66,6 +66,9 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
  * @chan_name: Custom channel name to use when requesting DMA channel.
  * @fifo_size: FIFO size of the DAI controller in bytes
  * @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now
+ * @peripheral_config: peripheral configuration for programming peripheral
+ * for dmaengine transfer
+ * @peripheral_size: peripheral configuration buffer size
  */
 struct snd_dmaengine_dai_dma_data {
 	dma_addr_t addr;
@@ -76,6 +79,8 @@ struct snd_dmaengine_dai_dma_data {
 	const char *chan_name;
 	unsigned int fifo_size;
 	unsigned int flags;
+	void *peripheral_config;
+	size_t peripheral_size;
 };
 
 void snd_dmaengine_pcm_set_config_from_dai_data(
diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h
index bbb5a137855c1789aec69d1ceab4bc669d20036d..013784467bec39fb606ddd6117983488d14c576c 100644
--- a/include/sound/graph_card.h
+++ b/include/sound/graph_card.h
@@ -9,8 +9,10 @@
 
 #include <sound/simple_card_utils.h>
 
-int graph_card_probe(struct snd_soc_card *card);
+int audio_graph_card_probe(struct snd_soc_card *card);
 
-int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
+int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
+
+int audio_graph_remove(struct platform_device *pdev);
 
 #endif /* __GRAPH_CARD_H */
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 6eed61e6cf8accecfb12569455d8658f46532780..22af68b014262618e90f30507a42bdd629032619 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -241,6 +241,8 @@ struct hdac_bus_ops {
 	/* get a response from the last command */
 	int (*get_response)(struct hdac_bus *bus, unsigned int addr,
 			    unsigned int *res);
+	/* notify of codec link power-up/down */
+	void (*link_power)(struct hdac_device *hdev, bool enable);
 };
 
 /*
@@ -378,15 +380,8 @@ void snd_hdac_bus_exit(struct hdac_bus *bus);
 int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
 				    unsigned int cmd, unsigned int *res);
 
-static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
-{
-	set_bit(codec->addr, &codec->bus->codec_powered);
-}
-
-static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
-{
-	clear_bit(codec->addr, &codec->bus->codec_powered);
-}
+void snd_hdac_codec_link_up(struct hdac_device *codec);
+void snd_hdac_codec_link_down(struct hdac_device *codec);
 
 int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
 int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
@@ -400,6 +395,7 @@ void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus);
 void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus);
 void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus);
 int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset);
+void snd_hdac_bus_link_power(struct hdac_device *hdev, bool enable);
 
 void snd_hdac_bus_update_rirb(struct hdac_bus *bus);
 int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index 7abf74c1c47406c1dcc46c2f3e38e497b782a8c2..a125e3814b582c66e88f2e3878b58fa07668c1ba 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -131,6 +131,8 @@ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
 int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
 int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);
 
+void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable);
+
 /* update register macro */
 #define snd_hdac_updatel(addr, reg, mask, val)		\
 	writel(((readl(addr + reg) & ~(mask)) | (val)), \
diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h
index b55970859a13c1fc5cb39ed33181b693ab16558f..4b3a1d374b9042d3172b94e51f4bdc54b750ec74 100644
--- a/include/sound/hdmi-codec.h
+++ b/include/sound/hdmi-codec.h
@@ -34,6 +34,11 @@ struct hdmi_codec_daifmt {
 	unsigned int frame_clk_inv:1;
 	unsigned int bit_clk_master:1;
 	unsigned int frame_clk_master:1;
+	/* bit_fmt could be standard PCM format or
+	 * IEC958 encoded format. ALSA IEC958 plugin will pass
+	 * IEC958_SUBFRAME format to the underneath driver.
+	 */
+	snd_pcm_format_t bit_fmt;
 };
 
 /*
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 9eb2b5ec1ec4104199c5716e2875a90af5205d31..1181f536557ebeff2cbef19c731f9c6ff89f40fc 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -67,6 +67,7 @@ struct snd_jack {
 	char name[100];
 	unsigned int key[6];   /* Keep in sync with definitions above */
 #endif /* CONFIG_SND_JACK_INPUT_DEV */
+	int hw_status_cache;
 	void *private_data;
 	void (*private_free)(struct snd_jack *);
 };
diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h
index 39a77c7cea364dfc0bc43084823d2d1b8ee5666b..710c95be55098968239702b9941d235d0af1ca62 100644
--- a/include/sound/rt5645.h
+++ b/include/sound/rt5645.h
@@ -22,6 +22,8 @@ struct rt5645_platform_data {
 	bool level_trigger_irq;
 	/* Invert JD1_1 status polarity */
 	bool inv_jd1_1;
+	/* Invert HP detect status polarity */
+	bool inv_hp_pol;
 
 	/* Value to asign to snd_soc_card.long_name */
 	const char *long_name;
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 0bce41fefd3068f0e17ebf2516ae0a648d31ca1a..5b47768222b7f975038583553db8c517f341263a 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -353,6 +353,12 @@ int snd_soc_component_test_bits(struct snd_soc_component *component,
 				unsigned int reg, unsigned int mask,
 				unsigned int value);
 
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
+					  unsigned int reg, unsigned int mask);
+int snd_soc_component_write_field(struct snd_soc_component *component,
+				  unsigned int reg, unsigned int mask,
+				  unsigned int val);
+
 /* component wide operations */
 int snd_soc_component_set_sysclk(struct snd_soc_component *component,
 				 int clk_id, int source,
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 34d0dbf73ca9c728e694e1deac4e02ca425bb5cc..1358a0ceb4d01c4bf32ebcf26f3806ec00d4cadc 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -353,9 +353,9 @@ struct snd_soc_dai_driver {
 	/* DAI capabilities */
 	struct snd_soc_pcm_stream capture;
 	struct snd_soc_pcm_stream playback;
-	unsigned int symmetric_rates:1;
+	unsigned int symmetric_rate:1;
 	unsigned int symmetric_channels:1;
-	unsigned int symmetric_samplebits:1;
+	unsigned int symmetric_sample_bits:1;
 
 	/* probe ordering - for components with runtime dependencies */
 	int probe_order;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 3fa6c40a63b7eaa121a2c738b9ec4ef000ddff70..bd38015d6c6d825d3ee04240af6cce136f596c29 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -685,9 +685,9 @@ struct snd_soc_dai_link {
 	unsigned int ignore_suspend:1;
 
 	/* Symmetry requirements */
-	unsigned int symmetric_rates:1;
+	unsigned int symmetric_rate:1;
 	unsigned int symmetric_channels:1;
-	unsigned int symmetric_samplebits:1;
+	unsigned int symmetric_sample_bits:1;
 
 	/* Do not create a PCM for this DAI link (Backend link) */
 	unsigned int no_pcm:1;
diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h
index 7abc4f0bd3ade1155b65809fcbc1df24197dfb25..2a7e055584f9f38d2510d287bf22136cbe33caac 100644
--- a/include/sound/sof/ext_manifest.h
+++ b/include/sound/sof/ext_manifest.h
@@ -58,9 +58,9 @@ struct sof_ext_man_header {
 /* Extended manifest elements types */
 enum sof_ext_man_elem_type {
 	SOF_EXT_MAN_ELEM_FW_VERSION		= 0,
-	SOF_EXT_MAN_ELEM_WINDOW			= SOF_IPC_EXT_WINDOW,
-	SOF_EXT_MAN_ELEM_CC_VERSION		= SOF_IPC_EXT_CC_INFO,
-	SOF_EXT_MAN_ELEM_DBG_ABI		= SOF_IPC_EXT_USER_ABI_INFO,
+	SOF_EXT_MAN_ELEM_WINDOW			= 1,
+	SOF_EXT_MAN_ELEM_CC_VERSION		= 2,
+	SOF_EXT_MAN_ELEM_DBG_ABI		= 4,
 	SOF_EXT_MAN_ELEM_CONFIG_DATA		= 5, /**< ABI3.17 */
 	SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA   = 6,
 };
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
index 7985dd8198b6c4ae066d38041aeb3d45c6947ab8..d9077e91382bfae2cc500f3d2a36243ac31b06ca 100644
--- a/sound/ac97/bus.c
+++ b/sound/ac97/bus.c
@@ -273,7 +273,7 @@ static struct attribute *ac97_controller_device_attrs[] = {
 	NULL
 };
 
-static struct attribute_group ac97_adapter_attr_group = {
+static const struct attribute_group ac97_adapter_attr_group = {
 	.name	= "ac97_operations",
 	.attrs	= ac97_controller_device_attrs,
 };
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 12028b3e2eee4e87f50e42e7f6eedecf50335a2a..1abee841cc451f89d0936b46678c3bcda87e5860 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -1013,7 +1013,7 @@ static int onyx_i2c_probe(struct i2c_client *client,
 		goto fail;
 	}
 
-	strlcpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN);
+	strscpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN);
 	onyx->codec.owner = THIS_MODULE;
 	onyx->codec.init = onyx_init_codec;
 	onyx->codec.exit = onyx_exit_codec;
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index d3e37577b52990e6fbc5b186db59dcc75be1d8e5..ac246dd3ab49d64de8ea323421bbade44f4cd75a 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -894,7 +894,7 @@ static int tas_i2c_probe(struct i2c_client *client,
 	/* seems that half is a saner default */
 	tas->drc_range = TAS3004_DRC_MAX / 2;
 
-	strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN);
+	strscpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN);
 	tas->codec.owner = THIS_MODULE;
 	tas->codec.init = tas_init_codec;
 	tas->codec.exit = tas_exit_codec;
diff --git a/sound/aoa/codecs/toonie.c b/sound/aoa/codecs/toonie.c
index c2d014486c33a0ecb99a0b5146f1ed1ea602d5c1..0da5af12949280c485c2dff2016bb2076b956d8d 100644
--- a/sound/aoa/codecs/toonie.c
+++ b/sound/aoa/codecs/toonie.c
@@ -126,7 +126,7 @@ static int __init toonie_init(void)
 	if (!toonie)
 		return -ENOMEM;
 
-	strlcpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name));
+	strscpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name));
 	toonie->codec.owner = THIS_MODULE;
 	toonie->codec.init = toonie_init_codec;
 	toonie->codec.exit = toonie_exit_codec;
diff --git a/sound/aoa/core/alsa.c b/sound/aoa/core/alsa.c
index b61081342266e82ecf6cdb64e995c5e52a0235f0..7fce8581ddbd12b1522b0d0a9a572f4fc840b267 100644
--- a/sound/aoa/core/alsa.c
+++ b/sound/aoa/core/alsa.c
@@ -28,10 +28,10 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
 		return err;
 	aoa_card = alsa_card->private_data;
 	aoa_card->alsa_card = alsa_card;
-	strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
-	strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
-	strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
-	strlcpy(alsa_card->mixername, name, sizeof(alsa_card->mixername));
+	strscpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
+	strscpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
+	strscpy(alsa_card->longname, name, sizeof(alsa_card->longname));
+	strscpy(alsa_card->mixername, name, sizeof(alsa_card->mixername));
 	err = snd_card_register(aoa_card->alsa_card);
 	if (err < 0) {
 		printk(KERN_ERR "snd-aoa: couldn't register alsa card\n");
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index d2e85b83f7ed06e0e87d119ffbc42b2b3264a0a0..ec4ef18555bc90b6aade3050ea97a9438e37a425 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -948,7 +948,7 @@ static void layout_attached_codec(struct aoa_codec *codec)
 				ldev->gpio.methods->set_lineout(codec->gpio, 1);
 			ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
 			if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
-				strlcpy(ctl->id.name,
+				strscpy(ctl->id.name,
 					"Headphone Switch", sizeof(ctl->id.name));
 			ldev->lineout_ctrl = ctl;
 			aoa_snd_ctl_add(ctl);
@@ -962,14 +962,14 @@ static void layout_attached_codec(struct aoa_codec *codec)
 				ctl = snd_ctl_new1(&lineout_detect_choice,
 						   ldev);
 				if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
-					strlcpy(ctl->id.name,
+					strscpy(ctl->id.name,
 						"Headphone Detect Autoswitch",
 						sizeof(ctl->id.name));
 				aoa_snd_ctl_add(ctl);
 				ctl = snd_ctl_new1(&lineout_detected,
 						   ldev);
 				if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
-					strlcpy(ctl->id.name,
+					strscpy(ctl->id.name,
 						"Headphone Detected",
 						sizeof(ctl->id.name));
 				ldev->lineout_detected_ctrl = ctl;
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
index a2d55e15afbb8a6754fab387bae16cc7be064beb..dead3105689b747454b982dbfcdfe6efe9e220be 100644
--- a/sound/aoa/soundbus/sysfs.c
+++ b/sound/aoa/soundbus/sysfs.c
@@ -13,7 +13,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
 	int length;
 
 	if (*sdev->modalias) {
-		strlcpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1);
+		strscpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1);
 		strcat(buf, "\n");
 		length = strlen(buf);
 	} else {
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index a0996c47e58fee5b72da40163162ab895770758a..f02a91bdaa97217ab4d967a8ba779794d6c5e9fd 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -890,8 +890,8 @@ static struct aaci *aaci_init_card(struct amba_device *dev)
 
 	card->private_free = aaci_free_card;
 
-	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
-	strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
+	strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+	strscpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
 	snprintf(card->longname, sizeof(card->longname),
 		 "%s PL%03x rev%u at 0x%08llx, irq %d",
 		 card->shortname, amba_part(dev), amba_rev(dev),
@@ -921,7 +921,7 @@ static int aaci_init_pcm(struct aaci *aaci)
 		pcm->private_data = aaci;
 		pcm->info_flags = 0;
 
-		strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+		strscpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
 
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index ea8e233150c8d6ef0b84ecd8b08af83b053b7e77..6322e639259476bf672ecaf51ae821aa51c200d1 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -235,7 +235,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
 	if (ret < 0)
 		goto err;
 
-	strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
+	strscpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
 
 	ret = pxa2xx_ac97_pcm_new(card);
 	if (ret)
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index d4554f376160a95224b7e49a47742a73a8d2c472..a4050f87f230220991c043d178a37f2416532c52 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -187,6 +187,15 @@ config SND_CTL_VALIDATION
 	  from the driver are in the proper ranges or the check of the invalid
 	  access at out-of-array areas.
 
+config SND_JACK_INJECTION_DEBUG
+	bool "Sound jack injection interface via debugfs"
+	depends on SND_JACK && SND_DEBUG && DEBUG_FS
+	help
+	  This option can be used to enable or disable sound jack
+	  software injection.
+	  Say Y if you are debugging via jack injection interface.
+	  If unsure select "N".
+
 config SND_VMASTER
 	bool
 
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index debc30fcf5b384b415805104f3e66085d1521072..21ce4c056a9269d6db07b100de77d274ac64a964 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -1132,7 +1132,7 @@ static void snd_compress_proc_done(struct snd_compr *compr)
 
 static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)
 {
-	strlcpy(compr->id, id, sizeof(compr->id));
+	strscpy(compr->id, id, sizeof(compr->id));
 }
 #else
 static inline int snd_compress_proc_init(struct snd_compr *compr)
diff --git a/sound/core/control.c b/sound/core/control.c
index 3b44378b9dec9edb1595dae8282b835a946e6ae7..5165741a8400f96b502cfa36713b69669dcac96f 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -261,7 +261,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
 	kctl->id.device = ncontrol->device;
 	kctl->id.subdevice = ncontrol->subdevice;
 	if (ncontrol->name) {
-		strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name));
+		strscpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name));
 		if (strcmp(ncontrol->name, kctl->id.name) != 0)
 			pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
 				ncontrol->name, kctl->id.name);
@@ -701,12 +701,12 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
 		return -ENOMEM;
 	down_read(&snd_ioctl_rwsem);
 	info->card = card->number;
-	strlcpy(info->id, card->id, sizeof(info->id));
-	strlcpy(info->driver, card->driver, sizeof(info->driver));
-	strlcpy(info->name, card->shortname, sizeof(info->name));
-	strlcpy(info->longname, card->longname, sizeof(info->longname));
-	strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
-	strlcpy(info->components, card->components, sizeof(info->components));
+	strscpy(info->id, card->id, sizeof(info->id));
+	strscpy(info->driver, card->driver, sizeof(info->driver));
+	strscpy(info->name, card->shortname, sizeof(info->name));
+	strscpy(info->longname, card->longname, sizeof(info->longname));
+	strscpy(info->mixername, card->mixername, sizeof(info->mixername));
+	strscpy(info->components, card->components, sizeof(info->components));
 	up_read(&snd_ioctl_rwsem);
 	if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
 		kfree(info);
@@ -836,7 +836,7 @@ static void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
 {
 	size_t offset = value_sizes[info->type] * info->count;
 
-	offset = (offset + sizeof(u32) - 1) / sizeof(u32);
+	offset = DIV_ROUND_UP(offset, sizeof(u32));
 	memset32((u32 *)control->value.bytes.data + offset, pattern,
 		 sizeof(control->value) / sizeof(u32) - offset);
 }
@@ -928,7 +928,7 @@ static int sanity_check_elem_value(struct snd_card *card,
 
 	/* check whether the remaining area kept untouched */
 	offset = value_sizes[info->type] * info->count;
-	offset = (offset + sizeof(u32) - 1) / sizeof(u32);
+	offset = DIV_ROUND_UP(offset, sizeof(u32));
 	p = (u32 *)control->value.bytes.data + offset;
 	for (; offset < sizeof(control->value) / sizeof(u32); offset++, p++) {
 		if (*p != pattern) {
@@ -2137,7 +2137,7 @@ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
 	WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name),
 	     "ALSA: too long item name '%s'\n",
 	     names[info->value.enumerated.item]);
-	strlcpy(info->value.enumerated.name,
+	strscpy(info->value.enumerated.name,
 		names[info->value.enumerated.item],
 		sizeof(info->value.enumerated.name));
 	return 0;
diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c
index 9be4e282f2e02034e39c35ceaf31ae1f0827361d..709b1a9c2caa3d486062ec63892cedef3f2a806e 100644
--- a/sound/core/ctljack.c
+++ b/sound/core/ctljack.c
@@ -35,7 +35,7 @@ static int get_available_index(struct snd_card *card, const char *name)
 
 	sid.index = 0;
 	sid.iface = SNDRV_CTL_ELEM_IFACE_CARD;
-	strlcpy(sid.name, name, sizeof(sid.name));
+	strscpy(sid.name, name, sizeof(sid.name));
 
 	while (snd_ctl_find_id(card, &sid)) {
 		sid.index++;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 0c029892880a802cea9a65d66d292f7076f51b06..264b8ea64bc24893c65df66f46b5a4ee24120040 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -177,8 +177,8 @@ static int snd_hwdep_info(struct snd_hwdep *hw,
 	
 	memset(&info, 0, sizeof(info));
 	info.card = hw->card->number;
-	strlcpy(info.id, hw->id, sizeof(info.id));	
-	strlcpy(info.name, hw->name, sizeof(info.name));
+	strscpy(info.id, hw->id, sizeof(info.id));
+	strscpy(info.name, hw->name, sizeof(info.name));
 	info.iface = hw->iface;
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
@@ -379,7 +379,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
 	hwdep->card = card;
 	hwdep->device = device;
 	if (id)
-		strlcpy(hwdep->id, id, sizeof(hwdep->id));
+		strscpy(hwdep->id, id, sizeof(hwdep->id));
 
 	snd_device_initialize(&hwdep->dev, card);
 	hwdep->dev.release = release_hwdep_device;
diff --git a/sound/core/init.c b/sound/core/init.c
index 75aec71c48a86705e6d1751bab2cb7aced987487..45f4b01de23fb41b9ee1f0a09d4efc438a0df448 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -13,7 +13,9 @@
 #include <linux/time.h>
 #include <linux/ctype.h>
 #include <linux/pm.h>
+#include <linux/debugfs.h>
 #include <linux/completion.h>
+#include <linux/interrupt.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -161,6 +163,9 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
 {
 	struct snd_card *card;
 	int err;
+#ifdef CONFIG_SND_DEBUG
+	char name[8];
+#endif
 
 	if (snd_BUG_ON(!card_ret))
 		return -EINVAL;
@@ -174,7 +179,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
 	if (extra_size > 0)
 		card->private_data = (char *)card + sizeof(struct snd_card);
 	if (xid)
-		strlcpy(card->id, xid, sizeof(card->id));
+		strscpy(card->id, xid, sizeof(card->id));
 	err = 0;
 	mutex_lock(&snd_card_mutex);
 	if (idx < 0) /* first check the matching module-name slot */
@@ -244,6 +249,12 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
 		dev_err(parent, "unable to create card info\n");
 		goto __error_ctl;
 	}
+
+#ifdef CONFIG_SND_DEBUG
+	sprintf(name, "card%d", idx);
+	card->debugfs_root = debugfs_create_dir(name, sound_debugfs_root);
+#endif
+
 	*card_ret = card;
 	return 0;
 
@@ -416,6 +427,9 @@ int snd_card_disconnect(struct snd_card *card)
 	/* notify all devices that we are disconnected */
 	snd_device_disconnect_all(card);
 
+	if (card->sync_irq > 0)
+		synchronize_irq(card->sync_irq);
+
 	snd_info_card_disconnect(card);
 	if (card->registered) {
 		device_del(&card->card_dev);
@@ -477,6 +491,10 @@ static int snd_card_do_free(struct snd_card *card)
 		dev_warn(card->dev, "unable to free card info\n");
 		/* Not fatal error */
 	}
+#ifdef CONFIG_SND_DEBUG
+	debugfs_remove(card->debugfs_root);
+	card->debugfs_root = NULL;
+#endif
 	if (card->release_completion)
 		complete(card->release_completion);
 	kfree(card);
@@ -526,6 +544,7 @@ int snd_card_free(struct snd_card *card)
 		return ret;
 	/* wait, until all devices are ready for the free operation */
 	wait_for_completion(&released);
+
 	return 0;
 }
 EXPORT_SYMBOL(snd_card_free);
@@ -623,7 +642,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
 	/* last resort... */
 	dev_err(card->dev, "unable to set card id (%s)\n", id);
 	if (card->proc_root->name)
-		strlcpy(card->id, card->proc_root->name, sizeof(card->id));
+		strscpy(card->id, card->proc_root->name, sizeof(card->id));
 }
 
 /**
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 503c8af79d550d5c59e4dc523afe926232e370b5..32350c6aba849d41af1586a0583f6b1f87b51d35 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -8,6 +8,9 @@
 #include <linux/input.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
 #include <sound/jack.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -16,6 +19,11 @@ struct snd_jack_kctl {
 	struct snd_kcontrol *kctl;
 	struct list_head list;  /* list of controls belong to the same jack */
 	unsigned int mask_bits; /* only masked status bits are reported via kctl */
+	struct snd_jack *jack;  /* pointer to struct snd_jack */
+	bool sw_inject_enable;  /* allow to inject plug event via debugfs */
+#ifdef CONFIG_SND_JACK_INJECTION_DEBUG
+	struct dentry *jack_debugfs_root; /* jack_kctl debugfs root */
+#endif
 };
 
 #ifdef CONFIG_SND_JACK_INPUT_DEV
@@ -109,12 +117,291 @@ static int snd_jack_dev_register(struct snd_device *device)
 }
 #endif /* CONFIG_SND_JACK_INPUT_DEV */
 
+#ifdef CONFIG_SND_JACK_INJECTION_DEBUG
+static void snd_jack_inject_report(struct snd_jack_kctl *jack_kctl, int status)
+{
+	struct snd_jack *jack;
+#ifdef CONFIG_SND_JACK_INPUT_DEV
+	int i;
+#endif
+	if (!jack_kctl)
+		return;
+
+	jack = jack_kctl->jack;
+
+	if (jack_kctl->sw_inject_enable)
+		snd_kctl_jack_report(jack->card, jack_kctl->kctl,
+				     status & jack_kctl->mask_bits);
+
+#ifdef CONFIG_SND_JACK_INPUT_DEV
+	if (!jack->input_dev)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
+		int testbit = ((SND_JACK_BTN_0 >> i) & jack_kctl->mask_bits);
+
+		if (jack->type & testbit)
+			input_report_key(jack->input_dev, jack->key[i],
+					 status & testbit);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
+		int testbit = ((1 << i) & jack_kctl->mask_bits);
+
+		if (jack->type & testbit)
+			input_report_switch(jack->input_dev,
+					    jack_switch_types[i],
+					    status & testbit);
+	}
+
+	input_sync(jack->input_dev);
+#endif /* CONFIG_SND_JACK_INPUT_DEV */
+}
+
+static ssize_t sw_inject_enable_read(struct file *file,
+				     char __user *to, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	int len, ret;
+	char buf[128];
+
+	len = scnprintf(buf, sizeof(buf), "%s: %s\t\t%s: %i\n", "Jack", jack_kctl->kctl->id.name,
+			"Inject Enabled", jack_kctl->sw_inject_enable);
+	ret = simple_read_from_buffer(to, count, ppos, buf, len);
+
+	return ret;
+}
+
+static ssize_t sw_inject_enable_write(struct file *file,
+				      const char __user *from, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	int ret, err;
+	unsigned long enable;
+	char buf[8] = { 0 };
+
+	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count);
+	err = kstrtoul(buf, 0, &enable);
+	if (err)
+		return err;
+
+	if (jack_kctl->sw_inject_enable == (!!enable))
+		return ret;
+
+	jack_kctl->sw_inject_enable = !!enable;
+
+	if (!jack_kctl->sw_inject_enable)
+		snd_jack_report(jack_kctl->jack, jack_kctl->jack->hw_status_cache);
+
+	return ret;
+}
+
+static ssize_t jackin_inject_write(struct file *file,
+				   const char __user *from, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	int ret, err;
+	unsigned long enable;
+	char buf[8] = { 0 };
+
+	if (!jack_kctl->sw_inject_enable)
+		return -EINVAL;
+
+	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count);
+	err = kstrtoul(buf, 0, &enable);
+	if (err)
+		return err;
+
+	snd_jack_inject_report(jack_kctl, !!enable ? jack_kctl->mask_bits : 0);
+
+	return ret;
+}
+
+static ssize_t jack_kctl_id_read(struct file *file,
+				 char __user *to, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	char buf[64];
+	int len, ret;
+
+	len = scnprintf(buf, sizeof(buf), "%s\n", jack_kctl->kctl->id.name);
+	ret = simple_read_from_buffer(to, count, ppos, buf, len);
+
+	return ret;
+}
+
+/* the bit definition is aligned with snd_jack_types in jack.h */
+static const char * const jack_events_name[] = {
+	"HEADPHONE(0x0001)", "MICROPHONE(0x0002)", "LINEOUT(0x0004)",
+	"MECHANICAL(0x0008)", "VIDEOOUT(0x0010)", "LINEIN(0x0020)",
+	"", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)", "BTN_3(0x0800)",
+	"BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)", "",
+};
+
+/* the recommended buffer size is 256 */
+static int parse_mask_bits(unsigned int mask_bits, char *buf, size_t buf_size)
+{
+	int i;
+
+	scnprintf(buf, buf_size, "0x%04x", mask_bits);
+
+	for (i = 0; i < ARRAY_SIZE(jack_events_name); i++)
+		if (mask_bits & (1 << i)) {
+			strlcat(buf, " ", buf_size);
+			strlcat(buf, jack_events_name[i], buf_size);
+		}
+	strlcat(buf, "\n", buf_size);
+
+	return strlen(buf);
+}
+
+static ssize_t jack_kctl_mask_bits_read(struct file *file,
+					char __user *to, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	char buf[256];
+	int len, ret;
+
+	len = parse_mask_bits(jack_kctl->mask_bits, buf, sizeof(buf));
+	ret = simple_read_from_buffer(to, count, ppos, buf, len);
+
+	return ret;
+}
+
+static ssize_t jack_kctl_status_read(struct file *file,
+				     char __user *to, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	char buf[16];
+	int len, ret;
+
+	len = scnprintf(buf, sizeof(buf), "%s\n", jack_kctl->kctl->private_value ?
+			"Plugged" : "Unplugged");
+	ret = simple_read_from_buffer(to, count, ppos, buf, len);
+
+	return ret;
+}
+
+#ifdef CONFIG_SND_JACK_INPUT_DEV
+static ssize_t jack_type_read(struct file *file,
+			      char __user *to, size_t count, loff_t *ppos)
+{
+	struct snd_jack_kctl *jack_kctl = file->private_data;
+	char buf[256];
+	int len, ret;
+
+	len = parse_mask_bits(jack_kctl->jack->type, buf, sizeof(buf));
+	ret = simple_read_from_buffer(to, count, ppos, buf, len);
+
+	return ret;
+}
+
+static const struct file_operations jack_type_fops = {
+	.open = simple_open,
+	.read = jack_type_read,
+	.llseek = default_llseek,
+};
+#endif
+
+static const struct file_operations sw_inject_enable_fops = {
+	.open = simple_open,
+	.read = sw_inject_enable_read,
+	.write = sw_inject_enable_write,
+	.llseek = default_llseek,
+};
+
+static const struct file_operations jackin_inject_fops = {
+	.open = simple_open,
+	.write = jackin_inject_write,
+	.llseek = default_llseek,
+};
+
+static const struct file_operations jack_kctl_id_fops = {
+	.open = simple_open,
+	.read = jack_kctl_id_read,
+	.llseek = default_llseek,
+};
+
+static const struct file_operations jack_kctl_mask_bits_fops = {
+	.open = simple_open,
+	.read = jack_kctl_mask_bits_read,
+	.llseek = default_llseek,
+};
+
+static const struct file_operations jack_kctl_status_fops = {
+	.open = simple_open,
+	.read = jack_kctl_status_read,
+	.llseek = default_llseek,
+};
+
+static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
+					    struct snd_jack_kctl *jack_kctl)
+{
+	char *tname;
+	int i;
+
+	/* Don't create injection interface for Phantom jacks */
+	if (strstr(jack_kctl->kctl->id.name, "Phantom"))
+		return 0;
+
+	tname = kstrdup(jack_kctl->kctl->id.name, GFP_KERNEL);
+	if (!tname)
+		return -ENOMEM;
+
+	/* replace the chars which are not suitable for folder's name with _ */
+	for (i = 0; tname[i]; i++)
+		if (!isalnum(tname[i]))
+			tname[i] = '_';
+
+	jack_kctl->jack_debugfs_root = debugfs_create_dir(tname, jack->card->debugfs_root);
+	kfree(tname);
+
+	debugfs_create_file("sw_inject_enable", 0644, jack_kctl->jack_debugfs_root, jack_kctl,
+			    &sw_inject_enable_fops);
+
+	debugfs_create_file("jackin_inject", 0200, jack_kctl->jack_debugfs_root, jack_kctl,
+			    &jackin_inject_fops);
+
+	debugfs_create_file("kctl_id", 0444, jack_kctl->jack_debugfs_root, jack_kctl,
+			    &jack_kctl_id_fops);
+
+	debugfs_create_file("mask_bits", 0444, jack_kctl->jack_debugfs_root, jack_kctl,
+			    &jack_kctl_mask_bits_fops);
+
+	debugfs_create_file("status", 0444, jack_kctl->jack_debugfs_root, jack_kctl,
+			    &jack_kctl_status_fops);
+
+#ifdef CONFIG_SND_JACK_INPUT_DEV
+	debugfs_create_file("type", 0444, jack_kctl->jack_debugfs_root, jack_kctl,
+			    &jack_type_fops);
+#endif
+	return 0;
+}
+
+static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl)
+{
+	debugfs_remove(jack_kctl->jack_debugfs_root);
+	jack_kctl->jack_debugfs_root = NULL;
+}
+#else /* CONFIG_SND_JACK_INJECTION_DEBUG */
+static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
+					    struct snd_jack_kctl *jack_kctl)
+{
+	return 0;
+}
+
+static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl)
+{
+}
+#endif /* CONFIG_SND_JACK_INJECTION_DEBUG */
+
 static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
 {
 	struct snd_jack_kctl *jack_kctl;
 
 	jack_kctl = kctl->private_data;
 	if (jack_kctl) {
+		snd_jack_debugfs_clear_inject_node(jack_kctl);
 		list_del(&jack_kctl->list);
 		kfree(jack_kctl);
 	}
@@ -122,7 +409,9 @@ static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
 
 static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl)
 {
+	jack_kctl->jack = jack;
 	list_add_tail(&jack_kctl->list, &jack->kctl_list);
+	snd_jack_debugfs_add_inject_node(jack, jack_kctl);
 }
 
 static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask)
@@ -340,6 +629,7 @@ EXPORT_SYMBOL(snd_jack_set_key);
 void snd_jack_report(struct snd_jack *jack, int status)
 {
 	struct snd_jack_kctl *jack_kctl;
+	unsigned int mask_bits = 0;
 #ifdef CONFIG_SND_JACK_INPUT_DEV
 	int i;
 #endif
@@ -347,16 +637,21 @@ void snd_jack_report(struct snd_jack *jack, int status)
 	if (!jack)
 		return;
 
+	jack->hw_status_cache = status;
+
 	list_for_each_entry(jack_kctl, &jack->kctl_list, list)
-		snd_kctl_jack_report(jack->card, jack_kctl->kctl,
-					    status & jack_kctl->mask_bits);
+		if (jack_kctl->sw_inject_enable)
+			mask_bits |= jack_kctl->mask_bits;
+		else
+			snd_kctl_jack_report(jack->card, jack_kctl->kctl,
+					     status & jack_kctl->mask_bits);
 
 #ifdef CONFIG_SND_JACK_INPUT_DEV
 	if (!jack->input_dev)
 		return;
 
 	for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
-		int testbit = SND_JACK_BTN_0 >> i;
+		int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits);
 
 		if (jack->type & testbit)
 			input_report_key(jack->input_dev, jack->key[i],
@@ -364,7 +659,8 @@ void snd_jack_report(struct snd_jack *jack, int status)
 	}
 
 	for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
-		int testbit = 1 << i;
+		int testbit = ((1 << i) & ~mask_bits);
+
 		if (jack->type & testbit)
 			input_report_switch(jack->input_dev,
 					    jack_switch_types[i],
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index f702c96a7478ff1ef3be32e62d4a16ba6fdb4b49..bec928327478bd44a80257a64e7da0c71e33e667 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -87,8 +87,8 @@ static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
 	struct mixer_info info;
 	
 	memset(&info, 0, sizeof(info));
-	strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
-	strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
+	strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
+	strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
 	info.modify_counter = card->mixer_oss_change_count;
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
@@ -103,8 +103,8 @@ static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
 	_old_mixer_info info;
 	
 	memset(&info, 0, sizeof(info));
-	strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
-	strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
+	strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
+	strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
@@ -418,7 +418,7 @@ static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long n
 	
 	if (orange == 0)
 		return 0;
-	return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
+	return DIV_ROUND_CLOSEST(nrange * (val - omin), orange) + nmin;
 }
 
 /* convert from alsa native to oss values (0-100) */
@@ -499,7 +499,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
 	
 	memset(&id, 0, sizeof(id));
 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strlcpy(id.name, name, sizeof(id.name));
+	strscpy(id.name, name, sizeof(id.name));
 	id.index = index;
 	return snd_ctl_find_id(card, &id);
 }
@@ -1355,7 +1355,7 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
 		mixer->oss_dev_alloc = 1;
 		mixer->card = card;
 		if (*card->mixername)
-			strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
+			strscpy(mixer->name, card->mixername, sizeof(mixer->name));
 		else
 			snprintf(mixer->name, sizeof(mixer->name),
 				 "mixer%i", card->number);
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index d381f4c967c902a8acace2cdca1af23a764f35f2..98269119347fed5010fe4e6a6a061855e83e33af 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -193,7 +193,7 @@ static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_
 	if (plugin->src_format.rate < plugin->dst_format.rate) {
 		res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
 	} else {
-		res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);		
+		res = DIV_ROUND_CLOSEST(frames << SHIFT, data->pitch);
 	}
 	if (data->old_src_frames > 0) {
 		snd_pcm_sframes_t frames1 = frames, res1 = data->old_dst_frames;
@@ -224,7 +224,7 @@ static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_
 		return 0;
 	data = (struct rate_priv *)plugin->extra_data;
 	if (plugin->src_format.rate < plugin->dst_format.rate) {
-		res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
+		res = DIV_ROUND_CLOSEST(frames << SHIFT, data->pitch);
 	} else {
 		res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
 	}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index be5714f1bb58c6e71af6a818eef9d48819d9f9d9..b163164a83ec1d97c9b3a349dbecb8cb12cf97e1 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -729,7 +729,7 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
 	init_waitqueue_head(&pcm->open_wait);
 	INIT_LIST_HEAD(&pcm->list);
 	if (id)
-		strlcpy(pcm->id, id, sizeof(pcm->id));
+		strscpy(pcm->id, id, sizeof(pcm->id));
 
 	err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 				 playback_count);
@@ -1095,22 +1095,23 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
 	mutex_lock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	list_del_init(&pcm->list);
-	for (cidx = 0; cidx < 2; cidx++) {
-		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
-			snd_pcm_stream_lock_irq(substream);
-			if (substream->runtime) {
-				if (snd_pcm_running(substream))
-					snd_pcm_stop(substream,
-						     SNDRV_PCM_STATE_DISCONNECTED);
-				/* to be sure, set the state unconditionally */
-				substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
-				wake_up(&substream->runtime->sleep);
-				wake_up(&substream->runtime->tsleep);
-			}
-			snd_pcm_stream_unlock_irq(substream);
+
+	for_each_pcm_substream(pcm, cidx, substream) {
+		snd_pcm_stream_lock_irq(substream);
+		if (substream->runtime) {
+			if (snd_pcm_running(substream))
+				snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+			/* to be sure, set the state unconditionally */
+			substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
+			wake_up(&substream->runtime->sleep);
+			wake_up(&substream->runtime->tsleep);
 		}
+		snd_pcm_stream_unlock_irq(substream);
 	}
 
+	for_each_pcm_substream(pcm, cidx, substream)
+		snd_pcm_sync_stop(substream, false);
+
 	pcm_call_notify(pcm, n_disconnect);
 	for (cidx = 0; cidx < 2; cidx++) {
 		snd_unregister_device(&pcm->streams[cidx].dev);
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 4d0e8fe535a1e8087b677c2571d38ae17a08e11b..1fc2fa07757445948afc98c7e9a3fee891f0acba 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -125,6 +125,8 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
 	}
 
 	slave_config->slave_id = dma_data->slave_id;
+	slave_config->peripheral_config = dma_data->peripheral_config;
+	slave_config->peripheral_size = dma_data->peripheral_size;
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
 
diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h
index 17a1a5d870980bb34945b5a807434cb6b3a84ac2..e3b3558aeab687cf6222dd10b3aeb8067301f98d 100644
--- a/sound/core/pcm_local.h
+++ b/sound/core/pcm_local.h
@@ -63,6 +63,7 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
 
 void __snd_pcm_xrun(struct snd_pcm_substream *substream);
 void snd_pcm_group_init(struct snd_pcm_group *group);
+void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq);
 
 #ifdef CONFIG_SND_DMA_SGBUF
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
@@ -71,4 +72,10 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
 
 #define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
 
+/* loop over all PCM substreams */
+#define for_each_pcm_substream(pcm, str, subs) \
+	for ((str) = 0; (str) < 2; (str)++) \
+		for ((subs) = (pcm)->streams[str].substream; (subs); \
+		     (subs) = (subs)->next)
+
 #endif	/* __SOUND_CORE_PCM_LOCAL_H */
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index ee6e9c5eec45d4096d617f7e9238d633aa7231e9..289dd1fd8fe74066ca523cc908c8d17740d29a51 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -111,9 +111,8 @@ void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
 	struct snd_pcm_substream *substream;
 	int stream;
 
-	for (stream = 0; stream < 2; stream++)
-		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
-			snd_pcm_lib_preallocate_free(substream);
+	for_each_pcm_substream(pcm, stream, substream)
+		snd_pcm_lib_preallocate_free(substream);
 }
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
 
@@ -246,11 +245,8 @@ static void preallocate_pages_for_all(struct snd_pcm *pcm, int type,
 	struct snd_pcm_substream *substream;
 	int stream;
 
-	for (stream = 0; stream < 2; stream++)
-		for (substream = pcm->streams[stream].substream; substream;
-		     substream = substream->next)
-			preallocate_pages(substream, type, data, size, max,
-					  managed);
+	for_each_pcm_substream(pcm, stream, substream)
+		preallocate_pages(substream, type, data, size, max, managed);
 }
 
 /**
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c4aac703dc224c0c58995239275fe2c515be445c..17a85f4815d506fcc21ab74c226d04e408385a49 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -209,13 +209,13 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
 	info->device = pcm->device;
 	info->stream = substream->stream;
 	info->subdevice = substream->number;
-	strlcpy(info->id, pcm->id, sizeof(info->id));
-	strlcpy(info->name, pcm->name, sizeof(info->name));
+	strscpy(info->id, pcm->id, sizeof(info->id));
+	strscpy(info->name, pcm->name, sizeof(info->name));
 	info->dev_class = pcm->dev_class;
 	info->dev_subclass = pcm->dev_subclass;
 	info->subdevices_count = pstr->substream_count;
 	info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
-	strlcpy(info->subname, substream->name, sizeof(info->subname));
+	strscpy(info->subname, substream->name, sizeof(info->subname));
 
 	return 0;
 }
@@ -583,13 +583,13 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
 #endif
 }
 
-static void snd_pcm_sync_stop(struct snd_pcm_substream *substream)
+void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq)
 {
-	if (substream->runtime->stop_operating) {
+	if (substream->runtime && substream->runtime->stop_operating) {
 		substream->runtime->stop_operating = false;
-		if (substream->ops->sync_stop)
+		if (substream->ops && substream->ops->sync_stop)
 			substream->ops->sync_stop(substream);
-		else if (substream->pcm->card->sync_irq > 0)
+		else if (sync_irq && substream->pcm->card->sync_irq > 0)
 			synchronize_irq(substream->pcm->card->sync_irq);
 	}
 }
@@ -686,7 +686,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 		if (atomic_read(&substream->mmap_count))
 			return -EBADFD;
 
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 
 	params->rmask = ~0U;
 	err = snd_pcm_hw_refine(substream, params);
@@ -809,7 +809,7 @@ static int do_hw_free(struct snd_pcm_substream *substream)
 {
 	int result = 0;
 
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 	if (substream->ops->hw_free)
 		result = substream->ops->hw_free(substream);
 	if (substream->managed_buffer_alloc)
@@ -1421,8 +1421,10 @@ static int snd_pcm_do_stop(struct snd_pcm_substream *substream,
 			   snd_pcm_state_t state)
 {
 	if (substream->runtime->trigger_master == substream &&
-	    snd_pcm_running(substream))
+	    snd_pcm_running(substream)) {
 		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+		substream->runtime->stop_operating = true;
+	}
 	return 0; /* unconditonally stop all substreams */
 }
 
@@ -1435,7 +1437,6 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream,
 		runtime->status->state = state;
 		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP);
 	}
-	runtime->stop_operating = true;
 	wake_up(&runtime->sleep);
 	wake_up(&runtime->tsleep);
 }
@@ -1615,6 +1616,7 @@ static int snd_pcm_do_suspend(struct snd_pcm_substream *substream,
 	if (! snd_pcm_running(substream))
 		return 0;
 	substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
+	runtime->stop_operating = true;
 	return 0; /* suspend unconditionally */
 }
 
@@ -1672,25 +1674,26 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
 	if (! pcm)
 		return 0;
 
-	for (stream = 0; stream < 2; stream++) {
-		for (substream = pcm->streams[stream].substream;
-		     substream; substream = substream->next) {
-			/* FIXME: the open/close code should lock this as well */
-			if (substream->runtime == NULL)
-				continue;
+	for_each_pcm_substream(pcm, stream, substream) {
+		/* FIXME: the open/close code should lock this as well */
+		if (!substream->runtime)
+			continue;
 
-			/*
-			 * Skip BE dai link PCM's that are internal and may
-			 * not have their substream ops set.
-			 */
-			if (!substream->ops)
-				continue;
+		/*
+		 * Skip BE dai link PCM's that are internal and may
+		 * not have their substream ops set.
+		 */
+		if (!substream->ops)
+			continue;
 
-			err = snd_pcm_suspend(substream);
-			if (err < 0 && err != -EBUSY)
-				return err;
-		}
+		err = snd_pcm_suspend(substream);
+		if (err < 0 && err != -EBUSY)
+			return err;
 	}
+
+	for_each_pcm_substream(pcm, stream, substream)
+		snd_pcm_sync_stop(substream, false);
+
 	return 0;
 }
 EXPORT_SYMBOL(snd_pcm_suspend_all);
@@ -1736,7 +1739,6 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream,
 	snd_pcm_trigger_tstamp(substream);
 	runtime->status->state = runtime->status->suspended_state;
 	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
-	snd_pcm_sync_stop(substream);
 }
 
 static const struct action_ops snd_pcm_action_resume = {
@@ -1866,7 +1868,7 @@ static int snd_pcm_do_prepare(struct snd_pcm_substream *substream,
 			      snd_pcm_state_t state)
 {
 	int err;
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 	err = substream->ops->prepare(substream);
 	if (err < 0)
 		return err;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 257ad5206240fd0cff47545f505a38a2dca8c81b..aca00af93afeebe8253483cd20004ee9c3702aa6 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1686,7 +1686,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
 	INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);
 
 	if (id != NULL)
-		strlcpy(rmidi->id, id, sizeof(rmidi->id));
+		strscpy(rmidi->id, id, sizeof(rmidi->id));
 
 	snd_device_initialize(&rmidi->dev, card);
 	rmidi->dev.release = release_rawmidi_device;
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 2ddfe22266517ced0b06f3e14cce137d16ef1fe6..3f82c196de46972d30d9e77fb78ca2801b331413 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -173,7 +173,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
 	snd_use_lock_init(&mdev->use_lock);
 
 	/* copy and truncate the name of synth device */
-	strlcpy(mdev->name, pinfo->name, sizeof(mdev->name));
+	strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
 
 	/* create MIDI coder */
 	if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
@@ -647,7 +647,7 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info
 	inf->device = dev;
 	inf->dev_type = 0; /* FIXME: ?? */
 	inf->capabilities = 0; /* FIXME: ?? */
-	strlcpy(inf->name, mdev->name, sizeof(inf->name));
+	strscpy(inf->name, mdev->name, sizeof(inf->name));
 	snd_use_lock_free(&mdev->use_lock);
 	return 0;
 }
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index 1b8409ec2c97f69460441bc3fcdd6b700ca820d4..722f5059b30019d6b9a64b5bf93dcfb83c4a05bb 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -107,7 +107,7 @@ snd_seq_oss_synth_probe(struct device *_dev)
 	snd_use_lock_init(&rec->use_lock);
 
 	/* copy and truncate the name of synth device */
-	strlcpy(rec->name, dev->name, sizeof(rec->name));
+	strscpy(rec->name, dev->name, sizeof(rec->name));
 
 	/* registration */
 	spin_lock_irqsave(&register_lock, flags);
@@ -617,7 +617,7 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
 		inf->synth_subtype = 0;
 		inf->nr_voices = 16;
 		inf->device = dev;
-		strlcpy(inf->name, minf.name, sizeof(inf->name));
+		strscpy(inf->name, minf.name, sizeof(inf->name));
 	} else {
 		if ((rec = get_synthdev(dp, dev)) == NULL)
 			return -ENXIO;
@@ -625,7 +625,7 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
 		inf->synth_subtype = rec->synth_subtype;
 		inf->nr_voices = rec->nr_voices;
 		inf->device = dev;
-		strlcpy(inf->name, rec->name, sizeof(inf->name));
+		strscpy(inf->name, rec->name, sizeof(inf->name));
 		snd_use_lock_free(&rec->use_lock);
 	}
 	return 0;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index f9f2fea58b32cf3d81e9b7695a10bcd8c52e3e51..b6a24fb5e76bc9a933de34dc6e5f41851b32cce1 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1584,7 +1584,7 @@ static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client,
 	info->queue = q->queue;
 	info->owner = q->owner;
 	info->locked = q->locked;
-	strlcpy(info->name, q->name, sizeof(info->name));
+	strscpy(info->name, q->name, sizeof(info->name));
 	queuefree(q);
 
 	return 0;
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 65db1a7c77b7696995f806624f48f095fb0a4f10..e245bb6ba5339f04d8598e336ac1ea33c408b02d 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -290,7 +290,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
 	extlen = 0;
 	if (snd_seq_ev_is_variable(event)) {
 		extlen = event->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
-		ncells = (extlen + sizeof(struct snd_seq_event) - 1) / sizeof(struct snd_seq_event);
+		ncells = DIV_ROUND_UP(extlen, sizeof(struct snd_seq_event));
 	}
 	if (ncells >= pool->total_elements)
 		return -ENOMEM;
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 83be6b982a87c8d4930df060e2588d1abf07eacd..b9c2ce2b8d5a369068250fd05fb4ff3e43576cae 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -327,7 +327,7 @@ int snd_seq_set_port_info(struct snd_seq_client_port * port,
 
 	/* set port name */
 	if (info->name[0])
-		strlcpy(port->name, info->name, sizeof(port->name));
+		strscpy(port->name, info->name, sizeof(port->name));
 	
 	/* set capabilities */
 	port->capability = info->capability;
@@ -356,7 +356,7 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
 		return -EINVAL;
 
 	/* get port name */
-	strlcpy(info->name, port->name, sizeof(info->name));
+	strscpy(info->name, port->name, sizeof(info->name));
 	
 	/* get capabilities */
 	info->capability = port->capability;
@@ -654,7 +654,7 @@ int snd_seq_event_port_attach(int client,
 	/* Set up the port */
 	memset(&portinfo, 0, sizeof(portinfo));
 	portinfo.addr.client = client;
-	strlcpy(portinfo.name, portname ? portname : "Unnamed port",
+	strscpy(portinfo.name, portname ? portname : "Unnamed port",
 		sizeof(portinfo.name));
 
 	portinfo.capability = cap;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index b75f78f2c4b8e222e46297589c5bf6ca8055d9d4..af89e51dd44a66b2ec57e7b98b6aa1bc06a25f1e 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -9,6 +9,7 @@
 #include <linux/time.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
@@ -39,6 +40,11 @@ MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
 int snd_ecards_limit;
 EXPORT_SYMBOL(snd_ecards_limit);
 
+#ifdef CONFIG_SND_DEBUG
+struct dentry *sound_debugfs_root;
+EXPORT_SYMBOL_GPL(sound_debugfs_root);
+#endif
+
 static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
 static DEFINE_MUTEX(sound_mutex);
 
@@ -337,6 +343,8 @@ static const char *snd_device_type_name(int type)
 		return "sequencer";
 	case SNDRV_DEVICE_TYPE_TIMER:
 		return "timer";
+	case SNDRV_DEVICE_TYPE_COMPRESS:
+		return "compress";
 	default:
 		return "?";
 	}
@@ -395,6 +403,10 @@ static int __init alsa_sound_init(void)
 		unregister_chrdev(major, "alsa");
 		return -ENOMEM;
 	}
+
+#ifdef CONFIG_SND_DEBUG
+	sound_debugfs_root = debugfs_create_dir("sound", NULL);
+#endif
 #ifndef MODULE
 	pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
 #endif
@@ -403,6 +415,9 @@ static int __init alsa_sound_init(void)
 
 static void __exit alsa_sound_exit(void)
 {
+#ifdef CONFIG_SND_DEBUG
+	debugfs_remove(sound_debugfs_root);
+#endif
 	snd_info_done();
 	unregister_chrdev(major, "alsa");
 }
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 765ea66665a8c5e4b19f3763ef73f48a1ce35ba4..6898b1ac0d7f4572e36958834d6c602f4c937c70 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -959,7 +959,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
 	timer->tmr_device = tid->device;
 	timer->tmr_subdevice = tid->subdevice;
 	if (id)
-		strlcpy(timer->id, id, sizeof(timer->id));
+		strscpy(timer->id, id, sizeof(timer->id));
 	timer->sticks = 1;
 	INIT_LIST_HEAD(&timer->device_list);
 	INIT_LIST_HEAD(&timer->open_list_head);
@@ -1659,8 +1659,8 @@ static int snd_timer_user_ginfo(struct file *file,
 		ginfo->card = t->card ? t->card->number : -1;
 		if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
 			ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
-		strlcpy(ginfo->id, t->id, sizeof(ginfo->id));
-		strlcpy(ginfo->name, t->name, sizeof(ginfo->name));
+		strscpy(ginfo->id, t->id, sizeof(ginfo->id));
+		strscpy(ginfo->name, t->name, sizeof(ginfo->name));
 		ginfo->resolution = t->hw.resolution;
 		if (t->hw.resolution_min > 0) {
 			ginfo->resolution_min = t->hw.resolution_min;
@@ -1814,8 +1814,8 @@ static int snd_timer_user_info(struct file *file,
 	info->card = t->card ? t->card->number : -1;
 	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
 		info->flags |= SNDRV_TIMER_FLG_SLAVE;
-	strlcpy(info->id, t->id, sizeof(info->id));
-	strlcpy(info->name, t->name, sizeof(info->name));
+	strscpy(info->id, t->id, sizeof(info->id));
+	strscpy(info->name, t->name, sizeof(info->name));
 	info->resolution = t->hw.resolution;
 	if (copy_to_user(_info, info, sizeof(*_info)))
 		err = -EFAULT;
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 0103d16f6f9f9e6370663cea87770892ac749f1d..ee973b7b804499a52936100bdfcbe4235aeb4a28 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -61,8 +61,8 @@ static int snd_timer_user_info_compat(struct file *file,
 	info.card = t->card ? t->card->number : -1;
 	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
 		info.flags |= SNDRV_TIMER_FLG_SLAVE;
-	strlcpy(info.id, t->id, sizeof(info.id));
-	strlcpy(info.name, t->name, sizeof(info.name));
+	strscpy(info.id, t->id, sizeof(info.id));
+	strscpy(info.name, t->name, sizeof(info.name));
 	info.resolution = t->hw.resolution;
 	if (copy_to_user(_info, &info, sizeof(*_info)))
 		return -EFAULT;
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 702f91b9c60f76e7f07272d15214699eaac3609d..8a24e5ae7cef4e7b5f60b4f331d7c8750bea8799 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -219,7 +219,7 @@ static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm)
 		dpcm->period_update_pending = 1;
 	}
 	tick = dpcm->period_size_frac - dpcm->irq_pos;
-	tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
+	tick = DIV_ROUND_UP(tick, dpcm->pcm_bps);
 	mod_timer(&dpcm->timer, jiffies + tick);
 
 	return 0;
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index b5486de08b97be39cca056659cbbf9bcfe3b37d8..316c9afadefee1740a1437d8a2dadf1934d453b5 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -236,7 +236,7 @@ struct dummy_systimer_pcm {
 static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
 {
 	mod_timer(&dpcm->timer, jiffies +
-		(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
+		DIV_ROUND_UP(dpcm->frac_period_rest, dpcm->rate));
 }
 
 static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 7bf0d5f3fedd0cffc2702df0775c92c7dbbb9b9d..c82c7c1c0714346cf2d962d70ad853387a50e9cc 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -97,7 +97,7 @@ void snd_opl3_init_seq_oss(struct snd_opl3 *opl3, char *name)
 		return;
 
 	opl3->oss_seq_dev = dev;
-	strlcpy(dev->name, name, sizeof(dev->name));
+	strscpy(dev->name, name, sizeof(dev->name));
 	arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
 	arg->type = SYNTH_TYPE_FM;
 	if (opl3->hardware < OPL3_HW_OPL3) {
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 08c10ac9d6c87a75374ac97e787ded3be15c4617..97d30a833ac81eea6ad3b1b236302c2a754a8dd0 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -290,7 +290,7 @@ int snd_opl3_load_patch(struct snd_opl3 *opl3,
 	}
 
 	if (name)
-		strlcpy(patch->name, name, sizeof(patch->name));
+		strscpy(patch->name, name, sizeof(patch->name));
 
 	return 0;
 }
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 3d2e3bcafca83e3a9e385bb7eab4168a38280186..daffda99b4f7998d5c3971da3034267a39190624 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -1154,8 +1154,7 @@ static int vx_init_audio_io(struct vx_core *chip)
 	chip->ibl.size = 0;
 	vx_set_ibl(chip, &chip->ibl); /* query the info */
 	if (preferred > 0) {
-		chip->ibl.size = ((preferred + chip->ibl.granularity - 1) /
-				  chip->ibl.granularity) * chip->ibl.granularity;
+		chip->ibl.size = roundup(preferred, chip->ibl.granularity);
 		if (chip->ibl.size > chip->ibl.max_size)
 			chip->ibl.size = chip->ibl.max_size;
 	} else
diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c
index c362eb38ab906ce6a71bcdbc5f2485ccd8a5b19d..6f9331655d4313f4f7d08f544d7fe5eed7193286 100644
--- a/sound/firewire/bebob/bebob_hwdep.c
+++ b/sound/firewire/bebob/bebob_hwdep.c
@@ -37,11 +37,9 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
 
 	memset(&event, 0, sizeof(event));
 	count = min_t(long, count, sizeof(event.lock_status));
-	if (bebob->dev_lock_changed) {
-		event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
-		event.lock_status.status = (bebob->dev_lock_count > 0);
-		bebob->dev_lock_changed = false;
-	}
+	event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+	event.lock_status.status = (bebob->dev_lock_count > 0);
+	bebob->dev_lock_changed = false;
 
 	spin_unlock_irq(&bebob->lock);
 
@@ -80,7 +78,7 @@ hwdep_get_info(struct snd_bebob *bebob, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile
index 7a62dafd0f788e59f2e88ec25f1c7e9a25e5b833..9bf7b960a7206ffa0765631902fbf549d087c09a 100644
--- a/sound/firewire/dice/Makefile
+++ b/sound/firewire/dice/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
 		 dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
-		 dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o
+		 dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o \
+		 dice-harman.o
 obj-$(CONFIG_SND_DICE) += snd-dice.o
diff --git a/sound/firewire/dice/dice-harman.c b/sound/firewire/dice/dice-harman.c
new file mode 100644
index 0000000000000000000000000000000000000000..a8ca00c397e84dfb4459322cbd46735ddd25656a
--- /dev/null
+++ b/sound/firewire/dice/dice-harman.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+// dice-harman.c - a part of driver for DICE based devices
+//
+// Copyright (c) 2021 Takashi Sakamoto
+//
+// Licensed under the terms of the GNU General Public License, version 2.
+
+#include "dice.h"
+
+int snd_dice_detect_harman_formats(struct snd_dice *dice)
+{
+	int i;
+
+	// Lexicon I-ONYX FW810s supports sampling transfer frequency up to
+	// 96.0 kHz, 12 PCM channels and 1 MIDI channel in its first tx stream
+	// , 10 PCM channels and 1 MIDI channel in its first rx stream for all
+	// of the frequencies.
+	for (i = 0; i < 2; ++i) {
+		dice->tx_pcm_chs[0][i] = 12;
+		dice->tx_midi_ports[0] = 1;
+		dice->rx_pcm_chs[0][i] = 10;
+		dice->rx_midi_ports[0] = 1;
+	}
+
+	return 0;
+}
diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c
index f69f7996762f6a7b4b05912e352410c0a4d8e8e5..ffc0b97782d6319f7c840c89134566bff870898f 100644
--- a/sound/firewire/dice/dice-hwdep.c
+++ b/sound/firewire/dice/dice-hwdep.c
@@ -79,7 +79,7 @@ static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 06c94f009dfb29f1552b9b32dd88ceac22d7ac65..107a81691f0e819fad9bb79c858c844c58723cc9 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -20,10 +20,12 @@ MODULE_LICENSE("GPL v2");
 #define OUI_MYTEK		0x001ee8
 #define OUI_SSL			0x0050c2	// Actually ID reserved by IEEE.
 #define OUI_PRESONUS		0x000a92
+#define OUI_HARMAN		0x000fd7
 
 #define DICE_CATEGORY_ID	0x04
 #define WEISS_CATEGORY_ID	0x00
 #define LOUD_CATEGORY_ID	0x10
+#define HARMAN_CATEGORY_ID	0x20
 
 #define MODEL_ALESIS_IO_BOTH	0x000001
 
@@ -56,6 +58,8 @@ static int check_dice_category(struct fw_unit *unit)
 		category = WEISS_CATEGORY_ID;
 	else if (vendor == OUI_LOUD)
 		category = LOUD_CATEGORY_ID;
+	else if (vendor == OUI_HARMAN)
+		category = HARMAN_CATEGORY_ID;
 	else
 		category = DICE_CATEGORY_ID;
 	if (device->config_rom[3] != ((vendor << 8) | category) ||
@@ -388,6 +392,14 @@ static const struct ieee1394_device_id dice_id_table[] = {
 		.model_id	= 0x000008,
 		.driver_data	= (kernel_ulong_t)snd_dice_detect_presonus_formats,
 	},
+	// Lexicon I-ONYX FW810S.
+	{
+		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
+				  IEEE1394_MATCH_MODEL_ID,
+		.vendor_id	= OUI_HARMAN,
+		.model_id	= 0x000001,
+		.driver_data	= (kernel_ulong_t)snd_dice_detect_harman_formats,
+	},
 	{
 		.match_flags = IEEE1394_MATCH_VERSION,
 		.version     = DICE_INTERFACE,
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index 7fbffcab94c22ee54cd8bb20c5abe6c77152745b..adc6f7c8446091f0b2ef5370ff0765dee879ae68 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -233,5 +233,6 @@ int snd_dice_detect_alesis_mastercontrol_formats(struct snd_dice *dice);
 int snd_dice_detect_extension_formats(struct snd_dice *dice);
 int snd_dice_detect_mytek_formats(struct snd_dice *dice);
 int snd_dice_detect_presonus_formats(struct snd_dice *dice);
+int snd_dice_detect_harman_formats(struct snd_dice *dice);
 
 #endif
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
index 41c5857c612e5c0ab436e9e33c8c9019d45f5c71..aadf7d72485684763ea888de4ef3774532246eef 100644
--- a/sound/firewire/digi00x/digi00x-hwdep.c
+++ b/sound/firewire/digi00x/digi00x-hwdep.c
@@ -87,7 +87,7 @@ static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/fireface/ff-hwdep.c b/sound/firewire/fireface/ff-hwdep.c
index e73e8d2865a516f2b5f0de523996ff8f3f7d4916..ea64a2a41eea0dbb10fffb0c6c20ac00701143ea 100644
--- a/sound/firewire/fireface/ff-hwdep.c
+++ b/sound/firewire/fireface/ff-hwdep.c
@@ -35,13 +35,11 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
 	}
 
 	memset(&event, 0, sizeof(event));
-	if (ff->dev_lock_changed) {
-		event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
-		event.lock_status.status = (ff->dev_lock_count > 0);
-		ff->dev_lock_changed = false;
+	event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+	event.lock_status.status = (ff->dev_lock_count > 0);
+	ff->dev_lock_changed = false;
 
-		count = min_t(long, count, sizeof(event.lock_status));
-	}
+	count = min_t(long, count, sizeof(event.lock_status));
 
 	spin_unlock_irq(&ff->lock);
 
@@ -79,7 +77,7 @@ static int hwdep_get_info(struct snd_ff *ff, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c
index 8d3b23778eb260982ff3f209a11d2c580cf3fc31..7ddb7b97f02db7409e70acb984aca330e536ed74 100644
--- a/sound/firewire/fireface/ff-protocol-latter.c
+++ b/sound/firewire/fireface/ff-protocol-latter.c
@@ -15,6 +15,61 @@
 #define LATTER_FETCH_MODE	0xffff00000010ULL
 #define LATTER_SYNC_STATUS	0x0000801c0000ULL
 
+// The content of sync status register differs between models.
+//
+// Fireface UCX:
+//  0xf0000000: (unidentified)
+//  0x0f000000: effective rate of sampling clock
+//  0x00f00000: detected rate of word clock on BNC interface
+//  0x000f0000: detected rate of ADAT or S/PDIF on optical interface
+//  0x0000f000: detected rate of S/PDIF on coaxial interface
+//  0x00000e00: effective source of sampling clock
+//    0x00000e00: Internal
+//    0x00000800: (unidentified)
+//    0x00000600: Word clock on BNC interface
+//    0x00000400: ADAT on optical interface
+//    0x00000200: S/PDIF on coaxial or optical interface
+//  0x00000100: Optical interface is used for ADAT signal
+//  0x00000080: (unidentified)
+//  0x00000040: Synchronized to word clock on BNC interface
+//  0x00000020: Synchronized to ADAT or S/PDIF on optical interface
+//  0x00000010: Synchronized to S/PDIF on coaxial interface
+//  0x00000008: (unidentified)
+//  0x00000004: Lock word clock on BNC interface
+//  0x00000002: Lock ADAT or S/PDIF on optical interface
+//  0x00000001: Lock S/PDIF on coaxial interface
+//
+// Fireface 802 (and perhaps UFX):
+//   0xf0000000: effective rate of sampling clock
+//   0x0f000000: detected rate of ADAT-B on 2nd optical interface
+//   0x00f00000: detected rate of ADAT-A on 1st optical interface
+//   0x000f0000: detected rate of AES/EBU on XLR or coaxial interface
+//   0x0000f000: detected rate of word clock on BNC interface
+//   0x00000e00: effective source of sampling clock
+//     0x00000e00: internal
+//     0x00000800: ADAT-B
+//     0x00000600: ADAT-A
+//     0x00000400: AES/EBU
+//     0x00000200: Word clock
+//   0x00000080: Synchronized to ADAT-B on 2nd optical interface
+//   0x00000040: Synchronized to ADAT-A on 1st optical interface
+//   0x00000020: Synchronized to AES/EBU on XLR or 2nd optical interface
+//   0x00000010: Synchronized to word clock on BNC interface
+//   0x00000008: Lock ADAT-B on 2nd optical interface
+//   0x00000004: Lock ADAT-A on 1st optical interface
+//   0x00000002: Lock AES/EBU on XLR or 2nd optical interface
+//   0x00000001: Lock word clock on BNC interface
+//
+// The pattern for rate bits:
+//   0x00: 32.0 kHz
+//   0x01: 44.1 kHz
+//   0x02: 48.0 kHz
+//   0x04: 64.0 kHz
+//   0x05: 88.2 kHz
+//   0x06: 96.0 kHz
+//   0x08: 128.0 kHz
+//   0x09: 176.4 kHz
+//   0x0a: 192.0 kHz
 static int parse_clock_bits(u32 data, unsigned int *rate,
 			    enum snd_ff_clock_src *src,
 			    enum snd_ff_unit_version unit_version)
@@ -23,35 +78,48 @@ static int parse_clock_bits(u32 data, unsigned int *rate,
 		unsigned int rate;
 		u32 flag;
 	} *rate_entry, rate_entries[] = {
-		{ 32000,	0x00000000, },
-		{ 44100,	0x01000000, },
-		{ 48000,	0x02000000, },
-		{ 64000,	0x04000000, },
-		{ 88200,	0x05000000, },
-		{ 96000,	0x06000000, },
-		{ 128000,	0x08000000, },
-		{ 176400,	0x09000000, },
-		{ 192000,	0x0a000000, },
+		{ 32000,	0x00, },
+		{ 44100,	0x01, },
+		{ 48000,	0x02, },
+		{ 64000,	0x04, },
+		{ 88200,	0x05, },
+		{ 96000,	0x06, },
+		{ 128000,	0x08, },
+		{ 176400,	0x09, },
+		{ 192000,	0x0a, },
 	};
 	static const struct {
 		enum snd_ff_clock_src src;
 		u32 flag;
-	} *clk_entry, clk_entries[] = {
+	} *clk_entry, *clk_entries, ucx_clk_entries[] = {
 		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000200, },
 		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000400, },
 		{ SND_FF_CLOCK_SRC_WORD,	0x00000600, },
 		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },
+	}, ufx_ff802_clk_entries[] = {
+		{ SND_FF_CLOCK_SRC_WORD,	0x00000200, },
+		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000400, },
+		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000600, },
+		{ SND_FF_CLOCK_SRC_ADAT2,	0x00000800, },
+		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },
 	};
+	u32 rate_bits;
+	unsigned int clk_entry_count;
 	int i;
 
-	if (unit_version != SND_FF_UNIT_VERSION_UCX) {
-		// e.g. 0x00fe0f20 but expected 0x00eff002.
-		data = ((data & 0xf0f0f0f0) >> 4) | ((data & 0x0f0f0f0f) << 4);
+	if (unit_version == SND_FF_UNIT_VERSION_UCX) {
+		rate_bits = (data & 0x0f000000) >> 24;
+		clk_entries = ucx_clk_entries;
+		clk_entry_count = ARRAY_SIZE(ucx_clk_entries);
+	} else {
+		rate_bits = (data & 0xf0000000) >> 28;
+		clk_entries = ufx_ff802_clk_entries;
+		clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
 		rate_entry = rate_entries + i;
-		if ((data & 0x0f000000) == rate_entry->flag) {
+		if (rate_bits == rate_entry->flag) {
 			*rate = rate_entry->rate;
 			break;
 		}
@@ -59,14 +127,14 @@ static int parse_clock_bits(u32 data, unsigned int *rate,
 	if (i == ARRAY_SIZE(rate_entries))
 		return -EIO;
 
-	for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
+	for (i = 0; i < clk_entry_count; ++i) {
 		clk_entry = clk_entries + i;
 		if ((data & 0x000e00) == clk_entry->flag) {
 			*src = clk_entry->src;
 			break;
 		}
 	}
-	if (i == ARRAY_SIZE(clk_entries))
+	if (i == clk_entry_count)
 		return -EIO;
 
 	return 0;
@@ -249,16 +317,22 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer
 		char *const label;
 		u32 locked_mask;
 		u32 synced_mask;
-	} *clk_entry, clk_entries[] = {
+	} *clk_entry, *clk_entries, ucx_clk_entries[] = {
 		{ "S/PDIF",	0x00000001, 0x00000010, },
 		{ "ADAT",	0x00000002, 0x00000020, },
 		{ "WDClk",	0x00000004, 0x00000040, },
+	}, ufx_ff802_clk_entries[] = {
+		{ "WDClk",	0x00000001, 0x00000010, },
+		{ "AES/EBU",	0x00000002, 0x00000020, },
+		{ "ADAT-A",	0x00000004, 0x00000040, },
+		{ "ADAT-B",	0x00000008, 0x00000080, },
 	};
 	__le32 reg;
 	u32 data;
 	unsigned int rate;
 	enum snd_ff_clock_src src;
 	const char *label;
+	unsigned int clk_entry_count;
 	int i;
 	int err;
 
@@ -270,7 +344,15 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer
 
 	snd_iprintf(buffer, "External source detection:\n");
 
-	for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
+	if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {
+		clk_entries = ucx_clk_entries;
+		clk_entry_count = ARRAY_SIZE(ucx_clk_entries);
+	} else {
+		clk_entries = ufx_ff802_clk_entries;
+		clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);
+	}
+
+	for (i = 0; i < clk_entry_count; ++i) {
 		clk_entry = clk_entries + i;
 		snd_iprintf(buffer, "%s: ", clk_entry->label);
 		if (data & clk_entry->locked_mask) {
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c
index e93eb4616c5f40afd1ada95794f3bc090e08bce2..626c0c34b0b668f9c0bc6b8b8ea635e8f57f86f1 100644
--- a/sound/firewire/fireworks/fireworks_hwdep.c
+++ b/sound/firewire/fireworks/fireworks_hwdep.c
@@ -212,7 +212,7 @@ hwdep_get_info(struct snd_efw *efw, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c
index 0764a477052a2407378d95be0647af7e453d87dc..b5ced5d27758b63860835ba7d0aced1deed0fd93 100644
--- a/sound/firewire/motu/motu-hwdep.c
+++ b/sound/firewire/motu/motu-hwdep.c
@@ -86,7 +86,7 @@ static int hwdep_get_info(struct snd_motu *motu, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c
index eba33d0500605db255adc5fd63e6b0862d1bb80a..a0fe9961855497202ff2d3455547d1be6a1531f0 100644
--- a/sound/firewire/oxfw/oxfw-hwdep.c
+++ b/sound/firewire/oxfw/oxfw-hwdep.c
@@ -35,13 +35,11 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
 	}
 
 	memset(&event, 0, sizeof(event));
-	if (oxfw->dev_lock_changed) {
-		event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
-		event.lock_status.status = (oxfw->dev_lock_count > 0);
-		oxfw->dev_lock_changed = false;
+	event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+	event.lock_status.status = (oxfw->dev_lock_count > 0);
+	oxfw->dev_lock_changed = false;
 
-		count = min_t(long, count, sizeof(event.lock_status));
-	}
+	count = min_t(long, count, sizeof(event.lock_status));
 
 	spin_unlock_irq(&oxfw->lock);
 
@@ -79,7 +77,7 @@ static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 6f38335fe10bfd56673166c9ebc3d52cf4dfa25c..74eed9505665c7fb67c9bf6b1f4f3157257ea97a 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -154,7 +154,7 @@ static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg)
 	info.card = dev->card->index;
 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
-	strlcpy(info.device_name, dev_name(&dev->device),
+	strscpy(info.device_name, dev_name(&dev->device),
 		sizeof(info.device_name));
 
 	if (copy_to_user(arg, &info, sizeof(info)))
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index 3bc9224d5e4fee31b7d133bc84e2bfdb966beb50..9ed5cfa3c18c3e585e229f808a5ad927f464dd1c 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -46,3 +46,17 @@ config SND_INTEL_DSP_CONFIG
 	select SND_INTEL_NHLT if ACPI
 	# this config should be selected only for Intel DSP platforms.
 	# A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_BYT_PREFER_SOF
+	bool "Prefer SOF driver over SST on BY/CHT platforms"
+	depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL
+	default n
+	help
+	  The kernel has 2 drivers for the Low Power Engine audio-block on
+	  Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF
+	  driver. If both drivers are enabled then the kernel will default
+	  to using the old SST driver, unless told otherwise through the
+	  snd_intel_dspcfg.dsp_driver module-parameter.
+
+	  Set this option to Y to make the kernel default to the new SOF
+	  driver instead.
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index b0c0ef824d7d914f5748f01bed8616fb876f146f..a9bd39b93697036b9663525a7deeb59433ff26da 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -332,3 +332,40 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
+
+static void hdac_ext_codec_link_up(struct hdac_device *codec)
+{
+	const char *devname = dev_name(&codec->dev);
+	struct hdac_ext_link *hlink =
+		snd_hdac_ext_bus_get_link(codec->bus, devname);
+
+	if (hlink)
+		snd_hdac_ext_bus_link_get(codec->bus, hlink);
+}
+
+static void hdac_ext_codec_link_down(struct hdac_device *codec)
+{
+	const char *devname = dev_name(&codec->dev);
+	struct hdac_ext_link *hlink =
+		snd_hdac_ext_bus_get_link(codec->bus, devname);
+
+	if (hlink)
+		snd_hdac_ext_bus_link_put(codec->bus, hlink);
+}
+
+void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable)
+{
+	struct hdac_bus *bus = codec->bus;
+	bool oldstate = test_bit(codec->addr, &bus->codec_powered);
+
+	if (enable == oldstate)
+		return;
+
+	snd_hdac_bus_link_power(codec, enable);
+
+	if (enable)
+		hdac_ext_codec_link_up(codec);
+	else
+		hdac_ext_codec_link_down(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power);
diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c
index 9766f6af87430db6068b812c7308f2767d8ad30b..71db8592b33dbf666849f2922aaf68435055088d 100644
--- a/sound/hda/hdac_bus.c
+++ b/sound/hda/hdac_bus.c
@@ -17,6 +17,7 @@ static void snd_hdac_bus_process_unsol_events(struct work_struct *work);
 static const struct hdac_bus_ops default_ops = {
 	.command = snd_hdac_bus_send_cmd,
 	.get_response = snd_hdac_bus_get_response,
+	.link_power = snd_hdac_bus_link_power,
 };
 
 /**
@@ -264,3 +265,25 @@ void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
 }
 EXPORT_SYMBOL_GPL(snd_hdac_aligned_write);
 #endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
+
+void snd_hdac_codec_link_up(struct hdac_device *codec)
+{
+	struct hdac_bus *bus = codec->bus;
+
+	if (bus->ops->link_power)
+		bus->ops->link_power(codec, true);
+	else
+		snd_hdac_bus_link_power(codec, true);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_link_up);
+
+void snd_hdac_codec_link_down(struct hdac_device *codec)
+{
+	struct hdac_bus *bus = codec->bus;
+
+	if (bus->ops->link_power)
+		bus->ops->link_power(codec, false);
+	else
+		snd_hdac_bus_link_power(codec, false);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_link_down);
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index b98449fd92f3b184d0d4312eef1e84f652528318..062da7a7a5861f994da1236a62b6138b158eb514 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -648,3 +648,17 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus)
 		snd_dma_free_pages(&bus->posbuf);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
+
+/**
+ * snd_hdac_bus_link_power - power up/down codec link
+ * @codec: HD-audio device
+ * @enable: whether to power-up the link
+ */
+void snd_hdac_bus_link_power(struct hdac_device *codec, bool enable)
+{
+	if (enable)
+		set_bit(codec->addr, &codec->bus->codec_powered);
+	else
+		clear_bit(codec->addr, &codec->bus->codec_powered);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_link_power);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index abe7a1b16fe1eacbc5a312232a2818eebf848ef5..a6ed3dc35f7eae67c7f3d8bb3de3f72082c307db 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -435,12 +435,11 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
 	pos_adj = bus->bdl_pos_adj;
 	if (!azx_dev->no_period_wakeup && pos_adj > 0) {
 		pos_align = pos_adj;
-		pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
+		pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000);
 		if (!pos_adj)
 			pos_adj = pos_align;
 		else
-			pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
-				pos_align;
+			pos_adj = roundup(pos_adj, pos_align);
 		pos_adj = frames_to_bytes(runtime, pos_adj);
 		if (pos_adj >= period_bytes) {
 			dev_warn(bus->dev, "Too big adjustment %d\n",
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c
index e56e8332590310f8de65efd3701553544d0e1b0b..0d7771fca9f06642059e84ce688ad8498d2a854d 100644
--- a/sound/hda/hdac_sysfs.c
+++ b/sound/hda/hdac_sysfs.c
@@ -66,7 +66,7 @@ static struct attribute *hdac_dev_attrs[] = {
 	NULL
 };
 
-static struct attribute_group hdac_dev_attr_group = {
+static const struct attribute_group hdac_dev_attr_group = {
 	.attrs	= hdac_dev_attrs,
 };
 
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index c4568617251723c41090a7a188d3d7013007c747..d1eb9d34993aa07a2b6284f304df78a21c033218 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -321,6 +321,18 @@ static const struct config_entry config_table[] = {
 	},
 #endif
 
+/* Alder Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+	{
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+		.device = 0x7ad0,
+	},
+	{
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+		.device = 0x51c8,
+	},
+#endif
+
 };
 
 static const struct config_entry *snd_intel_dsp_find_config
@@ -452,35 +464,30 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
 }
 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
 
+/* Should we default to SOF or SST for BYT/CHT ? */
+#if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
+    !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
+#define FLAG_SST_OR_SOF_BYT	FLAG_SOF
+#else
+#define FLAG_SST_OR_SOF_BYT	FLAG_SST
+#endif
+
 /*
  * configuration table
  * - the order of similar ACPI ID entries is important!
  * - the first successful match will win
  */
 static const struct config_entry acpi_config_table[] = {
+#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
+    IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* BayTrail */
-#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
-	{
-		.flags = FLAG_SST,
-		.acpi_hid = "80860F28",
-	},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 	{
-		.flags = FLAG_SOF,
+		.flags = FLAG_SST_OR_SOF_BYT,
 		.acpi_hid = "80860F28",
 	},
-#endif
 /* CherryTrail */
-#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
 	{
-		.flags = FLAG_SST,
-		.acpi_hid = "808622A8",
-	},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-	{
-		.flags = FLAG_SOF,
+		.flags = FLAG_SST_OR_SOF_BYT,
 		.acpi_hid = "808622A8",
 	},
 #endif
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index a684faa771ef55f03191e53054a15cc989918575..847e3b6ca601898a4f4e335d51c20828c699f609 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -84,7 +84,7 @@ int snd_i2c_bus_create(struct snd_card *card, const char *name,
 		list_add_tail(&bus->buses, &master->buses);
 		bus->master = master;
 	}
-	strlcpy(bus->name, name, sizeof(bus->name));
+	strscpy(bus->name, name, sizeof(bus->name));
 	err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops);
 	if (err < 0) {
 		snd_i2c_bus_free(bus);
@@ -108,7 +108,7 @@ int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name,
 	if (device == NULL)
 		return -ENOMEM;
 	device->addr = addr;
-	strlcpy(device->name, name, sizeof(device->name));
+	strscpy(device->name, name, sizeof(device->name));
 	list_add_tail(&device->list, &bus->devices);
 	device->bus = bus;
 	*rdevice = device;
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 593c6e959afec1bfd474276e8b192d22d63253c2..6f221eed44e2110118c485141769153bfb45d1e4 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -95,8 +95,8 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
 	if (error < 0)
 		goto out;
 
-	strlcpy(card->driver, "AD1848", sizeof(card->driver));
-	strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
+	strscpy(card->driver, "AD1848", sizeof(card->driver));
+	strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
 
 	if (!thinkpad[n])
 		snprintf(card->longname, sizeof(card->longname),
@@ -118,10 +118,9 @@ out:	snd_card_free(card);
 	return error;
 }
 
-static int snd_ad1848_remove(struct device *dev, unsigned int n)
+static void snd_ad1848_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
index 5105524b6f3866495f53cbdfef5c6b822f8c2aa9..e6cd7c4da38e06c3af32e01bddd2125b666014a2 100644
--- a/sound/isa/adlib.c
+++ b/sound/isa/adlib.c
@@ -97,10 +97,9 @@ out:	snd_card_free(card);
 	return error;
 }
 
-static int snd_adlib_remove(struct device *dev, unsigned int n)
+static void snd_adlib_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 static struct isa_driver snd_adlib_driver = {
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
index faca5dd95bfea465b1a64c777b303abdde142589..3b9fbb02864bd8a6baa6a95a97aa9464c78e2532 100644
--- a/sound/isa/cmi8328.c
+++ b/sound/isa/cmi8328.c
@@ -403,7 +403,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
 	return err;
 }
 
-static int snd_cmi8328_remove(struct device *pdev, unsigned int dev)
+static void snd_cmi8328_remove(struct device *pdev, unsigned int dev)
 {
 	struct snd_card *card = dev_get_drvdata(pdev);
 	struct snd_cmi8328 *cmi = card->private_data;
@@ -420,7 +420,6 @@ static int snd_cmi8328_remove(struct device *pdev, unsigned int dev)
 	snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
 	snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
 	snd_card_free(card);
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 4669eb0cc8ce2c01124906eec8d29d85040b947b..19e258527d690764b3819f0bb2f7e8721c9e6c25 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -631,11 +631,10 @@ static int snd_cmi8330_isa_probe(struct device *pdev,
 	return 0;
 }
 
-static int snd_cmi8330_isa_remove(struct device *devptr,
+static void snd_cmi8330_isa_remove(struct device *devptr,
 				  unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index 2135963eba78ee8a33d08a03a8398b7ec944734d..c56cbc072918adcb7ab568795b868643e42348b2 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -95,8 +95,8 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
 	if (error < 0)
 		goto out;
 
-	strlcpy(card->driver, "CS4231", sizeof(card->driver));
-	strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
+	strscpy(card->driver, "CS4231", sizeof(card->driver));
+	strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
 
 	if (dma2[n] < 0)
 		snprintf(card->longname, sizeof(card->longname),
@@ -135,10 +135,9 @@ out:	snd_card_free(card);
 	return error;
 }
 
-static int snd_cs4231_remove(struct device *dev, unsigned int n)
+static void snd_cs4231_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index fa3c39cff5f854a88b602feb832fa174624f3a84..63fb0cb754d07f51b410207c330a584d4c76aefa 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -405,8 +405,8 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
 		if (err < 0)
 			return err;
 	}
-	strlcpy(card->driver, chip->pcm->name, sizeof(card->driver));
-	strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
+	strscpy(card->driver, chip->pcm->name, sizeof(card->driver));
+	strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
 	if (dma2[dev] < 0)
 		snprintf(card->longname, sizeof(card->longname),
 			 "%s at 0x%lx, irq %i, dma %i",
@@ -487,11 +487,10 @@ static int snd_cs423x_isa_probe(struct device *pdev,
 	return 0;
 }
 
-static int snd_cs423x_isa_remove(struct device *pdev,
+static void snd_cs423x_isa_remove(struct device *pdev,
 				 unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(pdev));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 64610571a5e163f3d677baa54e6d33d880169f16..4a1f61f1a3310765d4007713db0f24c19607973f 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -133,8 +133,8 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
 	if (error < 0)
 		return error;
 
-	strlcpy(card->driver, "ES1688", sizeof(card->driver));
-	strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
+	strscpy(card->driver, "ES1688", sizeof(card->driver));
+	strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
 	snprintf(card->longname, sizeof(card->longname),
 		"%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
 		 chip->irq, chip->dma8);
@@ -192,10 +192,9 @@ static int snd_es1688_isa_probe(struct device *dev, unsigned int n)
 	return error;
 }
 
-static int snd_es1688_isa_remove(struct device *dev, unsigned int n)
+static void snd_es1688_isa_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 static struct isa_driver snd_es1688_driver = {
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 5f8d7e8a54775f768f58075aa3b3633935d361ba..9beef807917753587418252b624325b297edc51c 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -2210,11 +2210,10 @@ static int snd_es18xx_isa_probe(struct device *pdev, unsigned int dev)
 	}
 }
 
-static int snd_es18xx_isa_remove(struct device *devptr,
-				 unsigned int dev)
+static void snd_es18xx_isa_remove(struct device *devptr,
+				  unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
index 65f9f46c9f583a480c4cbd162365f4752b192c5d..d33d69f29924a8c5443c8aaa59b6d5b485f2fc56 100644
--- a/sound/isa/galaxy/galaxy.c
+++ b/sound/isa/galaxy/galaxy.c
@@ -608,10 +608,9 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
 	return err;
 }
 
-static int snd_galaxy_remove(struct device *dev, unsigned int n)
+static void snd_galaxy_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 static struct isa_driver snd_galaxy_driver = {
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 7419b193975476ba087f09e43346f846a933bccf..015f88a113524fb815a5f951ffd0259d782a2af7 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -195,10 +195,9 @@ out:	snd_card_free(card);
 	return error;
 }
 
-static int snd_gusclassic_remove(struct device *dev, unsigned int n)
+static void snd_gusclassic_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 static struct isa_driver snd_gusclassic_driver = {
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index ed2f9d64efae26ab5c6903f1de32dbb31671a548..c9f31b4fb88737ea789b24ca8d2878f0a4c6c600 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -324,10 +324,9 @@ out:	snd_card_free(card);
 	return error;
 }
 
-static int snd_gusextreme_remove(struct device *dev, unsigned int n)
+static void snd_gusextreme_remove(struct device *dev, unsigned int n)
 {
 	snd_card_free(dev_get_drvdata(dev));
-	return 0;
 }
 
 static struct isa_driver snd_gusextreme_driver = {
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index 05cd9be4dd8af9d61b39c5e9c7339fc812f1041f..dc09fbd6f88da5d10c8ca2a71fff754edfdbd43c 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -338,10 +338,9 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
 	return err;
 }
 
-static int snd_gusmax_remove(struct device *devptr, unsigned int dev)
+static void snd_gusmax_remove(struct device *devptr, unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #define DEV_NAME "gusmax"
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 3e9ad930deae2981926fc075b8627230724a1a08..e4d412e72b75afaf56882eb668785d8f54b6722d 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -825,10 +825,9 @@ static int snd_interwave_isa_probe(struct device *pdev,
 	}
 }
 
-static int snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
+static void snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 static struct isa_driver snd_interwave_driver = {
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 24b34ecf5e5ba3949bf67b54c208a84416199e19..69647b41300d606eb2ad3b010a0ab033a9a4d4c1 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -1049,10 +1049,9 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
 #endif
 }
 
-static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
+static void snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
 {
 	snd_msnd_unload(dev_get_drvdata(pdev));
-	return 0;
 }
 
 static struct isa_driver snd_msnd_driver = {
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 85a181acd38841e4c11d70de5a2e99768ef05e30..7649a8a4128d10c081d49a538b839f04211980fd 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -878,11 +878,10 @@ static int snd_opl3sa2_isa_probe(struct device *pdev,
 	return 0;
 }
 
-static int snd_opl3sa2_isa_remove(struct device *devptr,
+static void snd_opl3sa2_isa_remove(struct device *devptr,
 				  unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 44ed1b65f6ce80b26e11ad8602618570a3e967c8..20933342f5eb3f088327f49452f8fad2c89f0e09 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -1480,11 +1480,10 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
 	return 0;
 }
 
-static int snd_miro_isa_remove(struct device *devptr,
+static void snd_miro_isa_remove(struct device *devptr,
 			       unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #define DEV_NAME "miro"
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 881d3b5711d273c8f92563131fb460f920668e16..758f5b579138ac3ad13c4e2ce81cc0782de413e3 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -1024,11 +1024,10 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
 	return 0;
 }
 
-static int snd_opti9xx_isa_remove(struct device *devptr,
-				  unsigned int dev)
+static void snd_opti9xx_isa_remove(struct device *devptr,
+				   unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
index ee379bbf70a4b75262ffa7331d16fc1ded68cfc2..0e2e0ab3b9e4c6559f07e35c85ebb9be67956943 100644
--- a/sound/isa/sb/jazz16.c
+++ b/sound/isa/sb/jazz16.c
@@ -339,12 +339,11 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
 	return err;
 }
 
-static int snd_jazz16_remove(struct device *devptr, unsigned int dev)
+static void snd_jazz16_remove(struct device *devptr, unsigned int dev)
 {
 	struct snd_card *card = dev_get_drvdata(devptr);
 
 	snd_card_free(card);
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 479197c13803edb72e5e83101600f2aebd10c52a..db284b7b88a7342343da831a48544d90f7952580 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -547,10 +547,9 @@ static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
 	}
 }
 
-static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev)
+static void snd_sb16_isa_remove(struct device *pdev, unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(pdev));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 270af863e198bdede162f75e8a7b00f8c7204811..8635a2b6b36b26447207a78011cf87662325362b 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -388,7 +388,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
 				return err;
 
 			/* fill in codec header */
-			strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name));
+			strscpy(p->codec_name, info.codec_name, sizeof(p->codec_name));
 			p->func_nr = func_nr;
 			p->mode = le16_to_cpu(funcdesc_h.flags_play_rec);
 			switch (le16_to_cpu(funcdesc_h.VOC_type)) {
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 438109f167d61bd28f40eb71400f01facae06877..8e3e67b9a3414f36c83af62356d3bec99abd0599 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -192,10 +192,9 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
 	return err;
 }
 
-static int snd_sb8_remove(struct device *pdev, unsigned int dev)
+static void snd_sb8_remove(struct device *pdev, unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(pdev));
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 3f703b4a304d369e342481ef2a844785a8f962b6..5de5506e7e609b7fcff45cbc4068749b6598d484 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -482,7 +482,7 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
 	ctl = snd_ctl_new1(&newctls[type], chip);
 	if (! ctl)
 		return -ENOMEM;
-	strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
+	strscpy(ctl->id.name, name, sizeof(ctl->id.name));
 	ctl->id.index = index;
 	ctl->private_value = value;
 	if ((err = snd_ctl_add(chip->card, ctl)) < 0)
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 3d0bea44f454ac8e4f58ab89ef31ba2a50f61a09..def13757971712e5c6c62250e3346e9cc7acb44e 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -672,7 +672,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
 	return err;
 }
 
-static int snd_sc6000_remove(struct device *devptr, unsigned int dev)
+static void snd_sc6000_remove(struct device *devptr, unsigned int dev)
 {
 	struct snd_card *card = dev_get_drvdata(devptr);
 	char __iomem **vport = card->private_data;
@@ -684,7 +684,6 @@ static int snd_sc6000_remove(struct device *devptr, unsigned int dev)
 	release_region(mss_port[dev], 4);
 
 	snd_card_free(card);
-	return 0;
 }
 
 static struct isa_driver snd_sc6000_driver = {
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 2e5a5c5279e8d1ebc9be1f9585d0aa8d76770c25..e70ef9aee545b83d23133827bde2d83109df3770 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1183,10 +1183,9 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
 	return ret;
 }
 
-static int snd_sscape_remove(struct device *devptr, unsigned int dev)
+static void snd_sscape_remove(struct device *devptr, unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #define DEV_NAME "sscape"
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 9e0f6b226775ef82c96afcf21d51d422c651007d..b750a4fd40de7cc4d754d114efbdfe8b325f1831 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -565,11 +565,10 @@ static int snd_wavefront_isa_probe(struct device *pdev,
 	return 0;
 }
 
-static int snd_wavefront_isa_remove(struct device *devptr,
+static void snd_wavefront_isa_remove(struct device *devptr,
 				    unsigned int dev)
 {
 	snd_card_free(dev_get_drvdata(devptr));
-	return 0;
 }
 
 #define DEV_NAME "wavefront"
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 38f25e97538fa8468a1bdecbae8147abb1168b4e..49679aa8631d428e0555eb4172aba1f963f3fd8b 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -355,8 +355,8 @@ static int mixer_ioctl(struct file *file, u_int cmd, u_long arg)
 		{
 		    mixer_info info;
 		    memset(&info, 0, sizeof(info));
-		    strlcpy(info.id, dmasound.mach.name2, sizeof(info.id));
-		    strlcpy(info.name, dmasound.mach.name2, sizeof(info.name));
+		    strscpy(info.id, dmasound.mach.name2, sizeof(info.id));
+		    strscpy(info.name, dmasound.mach.name2, sizeof(info.name));
 		    info.modify_counter = mixer.modify_counter;
 		    if (copy_to_user((void __user *)arg, &info, sizeof(info)))
 			    return -EFAULT;
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 5d42c42491bf190582a908fc408e63b66597df44..5d835d2af0549068f927fe702b6253d31aed2154 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -857,8 +857,7 @@ snd_ad1889_create(struct snd_card *card,
 		return err;
 
 	/* check PCI availability (32bit DMA) */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(32)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
 		dev_err(card->dev, "error setting 32-bit DMA mask.\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 4462375d2d826cb66192d62a5a0d489d4c3eddab..51f24796f03faebfce4a1224039f041878d4076f 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2057,8 +2057,7 @@ static int snd_ali_create(struct snd_card *card,
 	if (err < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 31 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(31)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(31)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31))) {
 		dev_err(card->dev,
 			"architecture does not support 31bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 8d2471ea090bf98cb4dfcbae8f618358de735bac..1dc8c4ed0592bd5c69322829e205ce4399360101 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -625,8 +625,7 @@ static int snd_als300_create(struct snd_card *card,
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(28)) < 0 ||
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(28)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) {
 		dev_err(card->dev, "error setting 28bit DMA mask\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index ba6390e9a694f06d6d11d7cf90f1330a55c5c3ac..2edc7455285a47263f85845182fc3ab5bbd27a5a 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -837,8 +837,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
 		return err;
 	}
 	/* check, if we can restrict PCI DMA transfers to 24 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(24)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(24)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) {
 		dev_err(&pci->dev, "architecture does not support 24bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/asihpi/hpidebug.c b/sound/pci/asihpi/hpidebug.c
index f37856ab05f8660f8820bcc380554cf45a5bb5a0..9570d9a44fe8db11b443f50854669e45f655068f 100644
--- a/sound/pci/asihpi/hpidebug.c
+++ b/sound/pci/asihpi/hpidebug.c
@@ -52,7 +52,7 @@ void hpi_debug_data(u16 *pdata, u32 len)
 	int lines;
 	int cols = 8;
 
-	lines = (len + cols - 1) / cols;
+	lines = DIV_ROUND_UP(len, cols);
 	if (lines > 8)
 		lines = 8;
 
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index be276fb3f5afe4e0e2831d058c0dcbf44ae4c26c..5dd98e6ff34b9369c6ae232bd3091c5c93287c14 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -151,8 +151,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
 	// check PCI availability (DMA).
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(32)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
 		dev_err(card->dev, "error to set DMA mask\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index f1865afedc59bb9a2880ff67b6859c7f36a2dc2b..43396849a01c27b5e03eaa96d7520e40bae7e2b0 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -236,8 +236,7 @@ static int snd_aw2_create(struct snd_card *card,
 	pci_set_master(pci);
 
 	/* check PCI availability (32bit DMA) */
-	if ((dma_set_mask(&pci->dev, DMA_BIT_MASK(32)) < 0) ||
-	    (dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)) < 0)) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
 		dev_err(card->dev, "Impossible to set 32bit mask DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 77c7030ebbfa9e224b1f25e3fcef3df25d871d86..2ac594dcf21c8d88b8f959e57d2e2a0c694b4817 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2379,8 +2379,7 @@ snd_azf3328_create(struct snd_card *card,
 	chip->irq = -1;
 
 	/* check if we can restrict PCI DMA transfers to 24 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(24)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(24)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) {
 		dev_err(card->dev,
 			"architecture does not support 24bit PCI busmaster DMA\n"
 		);
@@ -2448,7 +2447,7 @@ snd_azf3328_create(struct snd_card *card,
 
 		/* shutdown codecs to reduce power / noise */
 			/* have ...ctrl_codec_activity() act properly */
-		codec->running = 1;
+		codec->running = true;
 		snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
 
 		spin_lock_irq(codec->lock);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 54cb223caa2f6be8ae5e41223d30309ebe69a087..cf9f8d80a0b61daf1900101a220b707e59b71c7c 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -327,7 +327,8 @@ static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id)
 		current_block = chip->current_line * 16 / chip->lines;
 		irq_block = status >> INT_RISCS_SHIFT;
 		if (current_block != irq_block)
-			chip->current_line = (irq_block * chip->lines + 15) / 16;
+			chip->current_line = DIV_ROUND_UP(irq_block * chip->lines,
+							  16);
 
 		snd_pcm_period_elapsed(chip->substream);
 	}
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index c189f70c82cb9a1a9f98aef77ba4e861184e9195..ee20f9a1aae98d0188b355c7cebd5bf2e5132729 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1605,8 +1605,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
 	err = pci_enable_device(pci);
 	if (err < 0)
 		return err;
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(32)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
 		dev_err(card->dev, "error to set 32bit mask DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 4490dd7469d996a9f398e571bd35fd0eb9b9afb9..37f516e6a5c244e8f4d60fefe77a0ca98f63b27f 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -813,7 +813,7 @@ static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned
 	correctionPerGOF = tmp1 / GOF_PER_SEC;
 	tmp1 -= correctionPerGOF * GOF_PER_SEC;
 	correctionPerSec = tmp1;
-	initialDelay = ((48000 * 24) + rate - 1) / rate;
+	initialDelay = DIV_ROUND_UP(48000 * 24, rate);
 
 	/*
 	 *  Fill in the VariDecimate control block.
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 11ce3c4589faf52445287a19c742e3578412b165..359bc6af867085da309a4f436c8eb7b4e92ff5dd 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -269,8 +269,7 @@ static int snd_cs5535audio_create(struct snd_card *card,
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(32)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
 		dev_warn(card->dev, "unable to get 32bit dma\n");
 		err = -ENXIO;
 		goto pcifail;
diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c
index 4e295303b041d50c95a2dc3e88b8c0aeb4043536..110d3209441b7b24f9bb7d9e51ff08625be45dc6 100644
--- a/sound/pci/cs5535audio/cs5535audio_olpc.c
+++ b/sound/pci/cs5535audio/cs5535audio_olpc.c
@@ -158,13 +158,13 @@ int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
 	/* drop the original AD1888 HPF control */
 	memset(&elem, 0, sizeof(elem));
 	elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strlcpy(elem.name, "High Pass Filter Enable", sizeof(elem.name));
+	strscpy(elem.name, "High Pass Filter Enable", sizeof(elem.name));
 	snd_ctl_remove_id(card, &elem);
 
 	/* drop the original V_REFOUT control */
 	memset(&elem, 0, sizeof(elem));
 	elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strlcpy(elem.name, "V_REFOUT Enable", sizeof(elem.name));
+	strscpy(elem.name, "V_REFOUT Enable", sizeof(elem.name));
 	snd_ctl_remove_id(card, &elem);
 
 	/* add the OLPC-specific controls */
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 108ab449c968d86b0402b89d715a18a268f689a1..0cea4982ed7dcc5aa9b49ed79a364bf789b2e1c4 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1901,12 +1901,8 @@ static int hw_card_start(struct hw *hw)
 		return err;
 
 	/* Set DMA transfer mask */
-	if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
-	} else {
-		dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
-	}
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits)))
+		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
 
 	if (!hw->io_base) {
 		err = pci_request_regions(pci, "XFi");
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index fc1bc18caee989ca3cf1ef15d7d915f187a427f3..a855fb8c58bd6a23bd9fafe6987cdbe38f5073ac 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -2026,12 +2026,8 @@ static int hw_card_start(struct hw *hw)
 		return err;
 
 	/* Set DMA transfer mask */
-	if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
-	} else {
-		dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
-	}
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits)))
+		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
 
 	if (!hw->io_base) {
 		err = pci_request_regions(pci, "XFi");
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index 3f48ad0e27e7f6e6c6d2f96d36dbe33b9b2e8f4f..81dfc6a76b1878daec9243499e0e6ab069b4cd39 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -433,7 +433,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
 	pcm->private_data = atc;
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
-	strlcpy(pcm->name, device_name, sizeof(pcm->name));
+	strscpy(pcm->name, device_name, sizeof(pcm->name));
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
 
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
index 61e51e35ba168547d000e99b19769ee170a4d5fa..6d0a01b189e123d842a4ef2ef3939fe5f536ba51 100644
--- a/sound/pci/ctxfi/ctresource.c
+++ b/sound/pci/ctxfi/ctresource.c
@@ -209,7 +209,7 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
 
 	mgr->type = NUM_RSCTYP;
 
-	mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
+	mgr->rscs = kzalloc(DIV_ROUND_UP(amount, 8), GFP_KERNEL);
 	if (!mgr->rscs)
 		return -ENOMEM;
 
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 29b7720d7961abf327426a3fec8c3251e73ed934..353934c88cbd8340be10f87b1717047f3c9804c8 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -168,9 +168,9 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
 	}
 #endif
  
-	strlcpy(card->driver, emu->card_capabilities->driver,
+	strscpy(card->driver, emu->card_capabilities->driver,
 		sizeof(card->driver));
-	strlcpy(card->shortname, emu->card_capabilities->name,
+	strscpy(card->shortname, emu->card_capabilities->name,
 		sizeof(card->shortname));
 	snprintf(card->longname, sizeof(card->longname),
 		 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index bd70e112ffd7aff31c925d067bf96c6a86b1383e..24a2fd706d69438fe7501af5ce81cd5f72635f21 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1869,7 +1869,7 @@ int snd_emu10k1_create(struct snd_card *card,
 			emu->serial);
 
 	if (!*card->id && c->id)
-		strlcpy(card->id, c->id, sizeof(card->id));
+		strscpy(card->id, c->id, sizeof(card->id));
 
 	is_audigy = emu->audigy = c->emu10k2_chip;
 
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 4e76ed0e91d5da0a531fb9e6f78dee82d62c24a5..80ef62a4a7c0735df104e4f8c79d86100adde625 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -940,7 +940,7 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
 			memset(gctl, 0, sizeof(*gctl));
 			id = &ctl->kcontrol->id;
 			gctl->id.iface = (__force int)id->iface;
-			strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
+			strscpy(gctl->id.name, id->name, sizeof(gctl->id.name));
 			gctl->id.index = id->index;
 			gctl->id.device = id->device;
 			gctl->id.subdevice = id->subdevice;
@@ -976,7 +976,7 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
 	err = snd_emu10k1_verify_controls(emu, icode, in_kernel);
 	if (err < 0)
 		goto __error;
-	strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
+	strscpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
 	/* stop FX processor - this may be dangerous, but it's better to miss
 	   some samples than generate wrong ones - [jk] */
 	if (emu->audigy)
@@ -1015,7 +1015,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
 	int err;
 
 	mutex_lock(&emu->fx8010.lock);
-	strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
+	strscpy(icode->name, emu->fx8010.name, sizeof(icode->name));
 	/* ok, do the main job */
 	err = snd_emu10k1_gpr_peek(emu, icode);
 	if (err >= 0)
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 94b8d5b082259692c4ea54cd844b6358ecd4523c..288e0fd2e47d1ed8eceaa962453fb5792559ea60 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -375,7 +375,7 @@ int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
 					struct snd_dma_buffer *dmab)
 {
 	if (emu->iommu_workaround) {
-		size_t npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+		size_t npages = DIV_ROUND_UP(size, PAGE_SIZE);
 		size_t size_real = npages * PAGE_SIZE;
 
 		/*
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index d9acef0826a96774d1b9ec159da1077cbd3af3de..93c4fd31331152dc7c0d60c6f326f69188010f34 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -752,7 +752,7 @@ static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate)
 	unsigned int freq, r;
 
 	mutex_lock(&ensoniq->src_mutex);
-	freq = ((rate << 15) + 1500) / 3000;
+	freq = DIV_ROUND_CLOSEST(rate << 15, 3000);
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P2 | ES_1371_DIS_R1)) |
 		ES_1371_DIS_P1;
@@ -773,7 +773,7 @@ static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate)
 	unsigned int freq, r;
 
 	mutex_lock(&ensoniq->src_mutex);
-	freq = ((rate << 15) + 1500) / 3000;
+	freq = DIV_ROUND_CLOSEST(rate << 15, 3000);
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P1 | ES_1371_DIS_R1)) |
 		ES_1371_DIS_P2;
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 09704a78d799eb0a541d5d4bf89f230948b0e29a..3b5d68ce9dd55b877467baf253e4856b1b10b945 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1560,8 +1560,7 @@ static int snd_es1938_create(struct snd_card *card,
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
         /* check, if we can restrict PCI DMA transfers to 24 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(24)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(24)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) {
 		dev_err(card->dev,
 			"architecture does not support 24bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 34332d008b27d0a68be11ff0fa6e004ef34e4d33..747fa69bb1c90c4454af94fe9cf0780ca42e0eda 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2668,8 +2668,7 @@ static int snd_es1968_create(struct snd_card *card,
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(28)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(28)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) {
 		dev_err(card->dev,
 			"architecture does not support 28bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
@@ -2768,7 +2767,7 @@ static int snd_es1968_create(struct snd_card *card,
 		if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
 			dev_info(card->dev, "detected TEA575x radio type %s\n",
 				   get_tea575x_gpio(chip)->name);
-			strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
+			strscpy(chip->tea.card, get_tea575x_gpio(chip)->name,
 				sizeof(chip->tea.card));
 			break;
 		}
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 0a95032fd297fa7710b3332f1eeba7026c6e2c42..c6ad6235a66993c7d4a401af09eeefe766bb5e51 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1300,7 +1300,7 @@ static int snd_fm801_create(struct snd_card *card,
 		chip->tea575x_tuner |= tuner_only;
 	}
 	if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
-		strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
+		strscpy(chip->tea.card, get_tea575x_gpio(chip)->name,
 			sizeof(chip->tea.card));
 	}
 #endif
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 4dc01647753c8fd4090949d048585293042ac428..1a001ecf7f63fbabf3fb36c6b0fc7a5cda627bf4 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -764,7 +764,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
 	}
 	if (!name)
 		return 0;
-	strlcpy(label, name, maxlen);
+	strscpy(label, name, maxlen);
 	return 1;
 }
 EXPORT_SYMBOL_GPL(snd_hda_get_pin_label);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index eec1775dfffe9fc57278f75669337e5d703c28c5..9b755062d84152a2e55438d67d80471fbee89fd7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -3999,7 +3999,7 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
 			 sizeof(imux->items[imux->num_items].label),
 			 "%s %d", label, label_idx);
 	else
-		strlcpy(imux->items[imux->num_items].label, label,
+		strscpy(imux->items[imux->num_items].label, label,
 			sizeof(imux->items[imux->num_items].label));
 	imux->items[imux->num_items].index = index;
 	imux->num_items++;
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 80016b7b6849e987c9de3f53152fa809d64d3c09..9087981cd1f709f8b9a785d8fce079e28f46920a 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -735,7 +735,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
 			  &pcm);
 	if (err < 0)
 		return err;
-	strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
+	strscpy(pcm->name, cpcm->name, sizeof(pcm->name));
 	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
 	if (apcm == NULL) {
 		snd_device_free(chip->card, pcm);
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 136477ed46ae2673db07fcd200b61871063dab07..9e97443795f837323aef902fa3f16970eb3d9413 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -260,7 +260,7 @@ int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e,
 		codec_info(codec, "HDMI: out of range MNL %d\n", mnl);
 		goto out_fail;
 	} else
-		strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1);
+		strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1);
 
 	for (i = 0; i < e->sad_count; i++) {
 		if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 8060cc86dfea39d1378db9a73f874df5d8084b95..5e40944e734275ea11011fcb4506ad72c0b4c194 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -5721,7 +5721,7 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
 
 	if (*str)
 		return;
-	strlcpy(str, chip_name, len);
+	strscpy(str, chip_name, len);
 
 	/* drop non-alnum chars after a space */
 	for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 068847e263e84946a515d5dce291702c1f27f9d7..5b492c3f816c1841a505fbea44af20178ab0d744 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1967,12 +1967,8 @@ static int azx_first_init(struct azx *chip)
 	/* allow 64bit DMA address if supported by H/W */
 	if (!(gcap & AZX_GCAP_64OK))
 		dma_bits = 32;
-	if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
-	} else {
-		dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
-	}
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits)))
+		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
 
 	/* read number of streams from GCAP register instead of using
 	 * hardcoded value
@@ -2037,7 +2033,7 @@ static int azx_first_init(struct azx *chip)
 		return -EBUSY;
 
 	strcpy(card->driver, "HDA-Intel");
-	strlcpy(card->shortname, driver_short_names[chip->driver_type],
+	strscpy(card->shortname, driver_short_names[chip->driver_type],
 		sizeof(card->shortname));
 	snprintf(card->longname, sizeof(card->longname),
 		 "%s at 0x%lx irq %i",
@@ -2221,8 +2217,6 @@ static const struct snd_pci_quirk power_save_denylist[] = {
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
 	SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
-	SND_PCI_QUIRK(0x1558, 0x6504, "Clevo W65_67SB", 0),
-	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
 	SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
 	/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
@@ -2304,7 +2298,7 @@ static int azx_probe_continue(struct azx *chip)
 
 		/* HSW/BDW controllers need this power */
 		if (CONTROLLER_IN_GPU(pci))
-			hda->need_i915_power = 1;
+			hda->need_i915_power = true;
 	}
 
 	/* Request display power well for the HDA controller or codec. For
@@ -2481,6 +2475,8 @@ static const struct pci_device_id azx_ids[] = {
 	/* CometLake-H */
 	{ PCI_DEVICE(0x8086, 0x06C8),
 	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+	{ PCI_DEVICE(0x8086, 0xf1c8),
+	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
 	/* CometLake-S */
 	{ PCI_DEVICE(0x8086, 0xa3f0),
 	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 588059428d8f56f43045b90e9ff9412749131a87..b8b568046592a74ba457646aeaaf847820a659f8 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -530,7 +530,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
 		       !is_jack_detectable(codec, nid);
 
 	if (base_name)
-		strlcpy(name, base_name, sizeof(name));
+		strscpy(name, base_name, sizeof(name));
 	else
 		snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL);
 	if (phantom_jack)
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 361cf2041911ad754970b9ee0f3a48cfedbd97e9..6f2b743b9d75c777c202c583151f13e1b1d23b27 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -17,6 +17,7 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/string.h>
@@ -70,9 +71,9 @@
 struct hda_tegra {
 	struct azx chip;
 	struct device *dev;
-	struct clk *hda_clk;
-	struct clk *hda2codec_2x_clk;
-	struct clk *hda2hdmi_clk;
+	struct reset_control *reset;
+	struct clk_bulk_data clocks[3];
+	unsigned int nclocks;
 	void __iomem *regs;
 	struct work_struct probe_work;
 };
@@ -113,36 +114,6 @@ static void hda_tegra_init(struct hda_tegra *hda)
 	writel(v, hda->regs + HDA_IPFS_INTR_MASK);
 }
 
-static int hda_tegra_enable_clocks(struct hda_tegra *data)
-{
-	int rc;
-
-	rc = clk_prepare_enable(data->hda_clk);
-	if (rc)
-		return rc;
-	rc = clk_prepare_enable(data->hda2codec_2x_clk);
-	if (rc)
-		goto disable_hda;
-	rc = clk_prepare_enable(data->hda2hdmi_clk);
-	if (rc)
-		goto disable_codec_2x;
-
-	return 0;
-
-disable_codec_2x:
-	clk_disable_unprepare(data->hda2codec_2x_clk);
-disable_hda:
-	clk_disable_unprepare(data->hda_clk);
-	return rc;
-}
-
-static void hda_tegra_disable_clocks(struct hda_tegra *data)
-{
-	clk_disable_unprepare(data->hda2hdmi_clk);
-	clk_disable_unprepare(data->hda2codec_2x_clk);
-	clk_disable_unprepare(data->hda_clk);
-}
-
 /*
  * power management
  */
@@ -186,7 +157,7 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
 		azx_stop_chip(chip);
 		azx_enter_link_reset(chip);
 	}
-	hda_tegra_disable_clocks(hda);
+	clk_bulk_disable_unprepare(hda->nclocks, hda->clocks);
 
 	return 0;
 }
@@ -198,15 +169,27 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
 	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
 	int rc;
 
-	rc = hda_tegra_enable_clocks(hda);
+	if (!chip->running) {
+		rc = reset_control_assert(hda->reset);
+		if (rc)
+			return rc;
+	}
+
+	rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks);
 	if (rc != 0)
 		return rc;
-	if (chip && chip->running) {
+	if (chip->running) {
 		hda_tegra_init(hda);
 		azx_init_chip(chip, 1);
 		/* disable controller wake up event*/
 		azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
 			   ~STATESTS_INT_MASK);
+	} else {
+		usleep_range(10, 100);
+
+		rc = reset_control_deassert(hda->reset);
+		if (rc)
+			return rc;
 	}
 
 	return 0;
@@ -268,29 +251,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
 	return 0;
 }
 
-static int hda_tegra_init_clk(struct hda_tegra *hda)
-{
-	struct device *dev = hda->dev;
-
-	hda->hda_clk = devm_clk_get(dev, "hda");
-	if (IS_ERR(hda->hda_clk)) {
-		dev_err(dev, "failed to get hda clock\n");
-		return PTR_ERR(hda->hda_clk);
-	}
-	hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x");
-	if (IS_ERR(hda->hda2codec_2x_clk)) {
-		dev_err(dev, "failed to get hda2codec_2x clock\n");
-		return PTR_ERR(hda->hda2codec_2x_clk);
-	}
-	hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi");
-	if (IS_ERR(hda->hda2hdmi_clk)) {
-		dev_err(dev, "failed to get hda2hdmi clock\n");
-		return PTR_ERR(hda->hda2hdmi_clk);
-	}
-
-	return 0;
-}
-
 static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
 {
 	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
@@ -495,7 +455,17 @@ static int hda_tegra_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = hda_tegra_init_clk(hda);
+	hda->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
+	if (IS_ERR(hda->reset)) {
+		err = PTR_ERR(hda->reset);
+		goto out_free;
+	}
+
+	hda->clocks[hda->nclocks++].id = "hda";
+	hda->clocks[hda->nclocks++].id = "hda2hdmi";
+	hda->clocks[hda->nclocks++].id = "hda2codec_2x";
+
+	err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks);
 	if (err < 0)
 		goto out_free;
 
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index d49cc4409d59c091d643f9082116c1aa583eb252..f2aa226d1373d1c680ae99662f8047729dc0d71b 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -567,7 +567,7 @@ static void cxt_fixup_mute_led_eapd(struct hda_codec *codec,
 
 	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 		spec->mute_led_eapd = 0x1b;
-		spec->dynamic_eapd = 1;
+		spec->dynamic_eapd = true;
 		snd_hda_gen_add_mute_led_cdev(codec, cx_auto_vmaster_mute_led);
 	}
 }
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 97adff0cbcab4bfcec1934a264941ca4d584710a..e405be7929e31c3f7775a4f272e130484abc4c32 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -2130,7 +2130,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
 			goto unlock;
 		}
 		per_cvt = get_cvt(spec, cvt_idx);
-		snd_BUG_ON(!per_cvt->assigned);
 		per_cvt->assigned = 0;
 		hinfo->nid = 0;
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 290645516313c6a034d9b6f4ebf9d6065261eb3e..1927605f0f7edcf512c9a09d9a6ce5cb2a261961 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1905,6 +1905,7 @@ enum {
 	ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
 	ALC889_FIXUP_VAIO_TT,
 	ALC888_FIXUP_EEE1601,
+	ALC886_FIXUP_EAPD,
 	ALC882_FIXUP_EAPD,
 	ALC883_FIXUP_EAPD,
 	ALC883_FIXUP_ACER_EAPD,
@@ -2238,6 +2239,15 @@ static const struct hda_fixup alc882_fixups[] = {
 			{ }
 		}
 	},
+	[ALC886_FIXUP_EAPD] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
+			{ }
+		}
+	},
 	[ALC882_FIXUP_EAPD] = {
 		.type = HDA_FIXUP_VERBS,
 		.v.verbs = (const struct hda_verb[]) {
@@ -2510,6 +2520,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
 
 	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
 	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
 	SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_CLEVO_P950),
@@ -4280,6 +4291,28 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
 	}
 }
 
+/* HP Spectre x360 14 model needs a unique workaround for enabling the amp;
+ * it needs to toggle the GPIO0 once on and off at each time (bko#210633)
+ */
+static void alc245_fixup_hp_x360_amp(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		spec->gpio_mask |= 0x01;
+		spec->gpio_dir |= 0x01;
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		/* need to toggle GPIO to enable the amp */
+		alc_update_gpio_data(codec, 0x01, true);
+		msleep(100);
+		alc_update_gpio_data(codec, 0x01, false);
+		break;
+	}
+}
+
 static void alc_update_coef_led(struct hda_codec *codec,
 				struct alc_coef_led *led,
 				bool polarity, bool on)
@@ -6266,6 +6299,7 @@ enum {
 	ALC280_FIXUP_HP_DOCK_PINS,
 	ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED,
 	ALC280_FIXUP_HP_9480M,
+	ALC245_FIXUP_HP_X360_AMP,
 	ALC288_FIXUP_DELL_HEADSET_MODE,
 	ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
 	ALC288_FIXUP_DELL_XPS_13,
@@ -6971,6 +7005,10 @@ static const struct hda_fixup alc269_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc280_fixup_hp_9480m,
 	},
+	[ALC245_FIXUP_HP_X360_AMP] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc245_fixup_hp_x360_amp,
+	},
 	[ALC288_FIXUP_DELL_HEADSET_MODE] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc_fixup_headset_mode_dell_alc288,
@@ -7985,6 +8023,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
 	SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
 	SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
+	SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
 	SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
 	SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
 	SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -8357,6 +8396,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 	{.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"},
 	{.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"},
 	{.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"},
+	{.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"},
 	{}
 };
 #define ALC225_STANDARD_PINS \
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 73e1e5400506a82b5faf29fd2b29c9e8eb1b90b1..f814dbbec2a4316736e96676e00cf1b04a25d307 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2486,8 +2486,7 @@ static int snd_ice1712_create(struct snd_card *card,
 	if (err < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(28)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(28)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) {
 		dev_err(card->dev,
 			"architecture does not support 28bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index e57a55cebc5a3181fec289cb63d4b6c81d5afadb..f0f8324b08b686cf1e7f2074a5bd03c591ad9705 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -413,7 +413,7 @@ static struct snd_kcontrol *ctl_find(struct snd_card *card,
 {
 	struct snd_ctl_elem_id sid = {0};
 
-	strlcpy(sid.name, name, sizeof(sid.name));
+	strscpy(sid.name, name, sizeof(sid.name));
 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	return snd_ctl_find_id(card, &sid);
 }
diff --git a/sound/pci/ice1712/psc724.c b/sound/pci/ice1712/psc724.c
index 7aa3f92040d04886b56da3bc53782216eac90daa..82cf365cda10038b52aa6caf01f7ebf772e12992 100644
--- a/sound/pci/ice1712/psc724.c
+++ b/sound/pci/ice1712/psc724.c
@@ -189,12 +189,12 @@ static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected)
 	/* notify about master speaker mute change */
 	memset(&elem_id, 0, sizeof(elem_id));
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strlcpy(elem_id.name, "Master Speakers Playback Switch",
+	strscpy(elem_id.name, "Master Speakers Playback Switch",
 						sizeof(elem_id.name));
 	kctl = snd_ctl_find_id(ice->card, &elem_id);
 	snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
 	/* and headphone mute change */
-	strlcpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name,
+	strscpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name,
 						sizeof(elem_id.name));
 	kctl = snd_ctl_find_id(ice->card, &elem_id);
 	snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
index 0e3e04aa9faf615189a2b76af5f90c163e209c78..0dfa093f7dcaa1a60527732aeb6ab81b76f03b54 100644
--- a/sound/pci/ice1712/quartet.c
+++ b/sound/pci/ice1712/quartet.c
@@ -771,7 +771,7 @@ static struct snd_kcontrol *ctl_find(struct snd_card *card,
 {
 	struct snd_ctl_elem_id sid = {0};
 
-	strlcpy(sid.name, name, sizeof(sid.name));
+	strscpy(sid.name, name, sizeof(sid.name));
 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	return snd_ctl_find_id(card, &sid);
 }
diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c
index d96008df880d62f97aea4a96e47c0ba6ac402bf4..6eda86119dff60b382c881bdc9457aff4b66829b 100644
--- a/sound/pci/ice1712/wm8776.c
+++ b/sound/pci/ice1712/wm8776.c
@@ -38,7 +38,7 @@ static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm,
 	unsigned int index_offset;
 
 	memset(&elem_id, 0, sizeof(elem_id));
-	strlcpy(elem_id.name, ctl_name, sizeof(elem_id.name));
+	strscpy(elem_id.name, ctl_name, sizeof(elem_id.name));
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	kctl = snd_ctl_find_id(card, &elem_id);
 	if (!kctl)
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 1b7df0c4e57cb2e160a9b81b2dec0ea0c52a08ba..19872cecc9d2eb0d3d88e9ea4b4c33dd41635470 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1129,13 +1129,14 @@ static int snd_intel8x0m_create(struct snd_card *card,
 		chip->bmaddr = pci_iomap(pci, 3, 0);
 	else
 		chip->bmaddr = pci_iomap(pci, 1, 0);
+
+port_inited:
 	if (!chip->bmaddr) {
 		dev_err(card->dev, "Controller space ioremap problem\n");
 		snd_intel8x0m_free(chip);
 		return -EIO;
 	}
 
- port_inited:
 	/* initialize offsets */
 	chip->bdbars_count = 2;
 	tbl = intel_regs;
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index cdd8db79bcfadd5107a4fc007edf3c016e721523..491c90f83fbc0b2c58fd1bd24abad9bd7d46c8f0 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -669,7 +669,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
 	}
 
 	strcpy(card->driver, "Lola");
-	strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname));
+	strscpy(card->shortname, "Digigram Lola", sizeof(card->shortname));
 	snprintf(card->longname, sizeof(card->longname),
 		 "%s at 0x%lx irq %i",
 		 card->shortname, chip->bar[0].addr, chip->irq);
diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c
index fdb85f256ed5ea9537af477ec6b26c8ffe5defc3..cafd30e30913f1d03008129d8d6823322647b804 100644
--- a/sound/pci/lola/lola_clock.c
+++ b/sound/pci/lola/lola_clock.c
@@ -135,7 +135,7 @@ int lola_init_clock_widget(struct lola *chip, int nid)
 	}
 
 	nitems = chip->clock.items;
-	nb_verbs = (nitems + 3) / 4;
+	nb_verbs = DIV_ROUND_UP(nitems, 4);
 	idx = 0;
 	idx_list = 0;
 	for (i = 0; i < nb_verbs; i++) {
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index f647c7ed00c40ddc55e9f62a1a9ed7e5ce79f4f5..684faaf40f314fad94ead544c9c7246ee143ff5b 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -601,7 +601,7 @@ int lola_create_pcm(struct lola *chip)
 			  &pcm);
 	if (err < 0)
 		return err;
-	strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
+	strscpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
 	pcm->private_data = chip;
 	for (i = 0; i < 2; i++) {
 		if (chip->pcm[i].num_streams)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 40232a278b1a61d23ad9a0331879850879c7162e..d2c2cd6006f04711b7a782c133508c058610e3fc 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1245,7 +1245,7 @@ static void snd_m3_pcm_setup2(struct snd_m3 *chip, struct m3_dma *s,
 			  snd_pcm_format_width(runtime->format) == 16 ? 0 : 1);
 
 	/* set up dac/adc rate */
-	freq = ((runtime->rate << 15) + 24000 ) / 48000;
+	freq = DIV_ROUND_CLOSEST(runtime->rate << 15, 48000);
 	if (freq) 
 		freq--;
 
@@ -2532,8 +2532,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 		return -EIO;
 
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(28)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(28)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) {
 		dev_err(card->dev,
 			"architecture does not support 28bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index cea53a878c36006a4e63e81bd072d1f532874791..6d9029333a12421fab33912c8cce19d077863d7a 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -469,6 +469,7 @@ struct hdsp {
 	unsigned char	      qs_out_channels;
 	unsigned char         ds_out_channels;
 	unsigned char         ss_out_channels;
+	u32                   io_loopback;          /* output loopback channel states*/
 
 	struct snd_dma_buffer capture_dma_buf;
 	struct snd_dma_buffer playback_dma_buf;
@@ -3253,6 +3254,60 @@ static const struct snd_kcontrol_new snd_hdsp_96xx_aeb =
 			HDSP_AnalogExtensionBoard);
 static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
 
+
+static bool hdsp_loopback_get(struct hdsp *const hdsp, const u8 channel)
+{
+	return hdsp->io_loopback & (1 << channel);
+}
+
+static int hdsp_loopback_set(struct hdsp *const hdsp, const u8 channel, const bool enable)
+{
+	if (hdsp_loopback_get(hdsp, channel) == enable)
+		return 0;
+
+	hdsp->io_loopback ^= (1 << channel);
+
+	hdsp_write(hdsp, HDSP_inputEnable + (4 * (hdsp->max_channels + channel)), enable);
+
+	return 1;
+}
+
+static int snd_hdsp_loopback_get(struct snd_kcontrol *const kcontrol,
+				 struct snd_ctl_elem_value *const ucontrol)
+{
+	struct hdsp *const hdsp = snd_kcontrol_chip(kcontrol);
+	const u8 channel = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
+
+	if (channel >= hdsp->max_channels)
+		return -ENOENT;
+
+	ucontrol->value.integer.value[0] = hdsp_loopback_get(hdsp, channel);
+
+	return 0;
+}
+
+static int snd_hdsp_loopback_put(struct snd_kcontrol *const kcontrol,
+				 struct snd_ctl_elem_value *const ucontrol)
+{
+	struct hdsp *const hdsp = snd_kcontrol_chip(kcontrol);
+	const u8 channel = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
+	const bool enable = ucontrol->value.integer.value[0] & 1;
+
+	if (channel >= hdsp->max_channels)
+		return -ENOENT;
+
+	return hdsp_loopback_set(hdsp, channel, enable);
+}
+
+static struct snd_kcontrol_new snd_hdsp_loopback_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
+	.name = "Output Loopback",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_ctl_boolean_mono_info,
+	.get = snd_hdsp_loopback_get,
+	.put = snd_hdsp_loopback_put
+};
+
 static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 {
 	unsigned int idx;
@@ -3297,6 +3352,17 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 		}
 	}
 
+	/* Output loopback controls for H9632 cards */
+	if (hdsp->io_type == H9632) {
+		snd_hdsp_loopback_control.count = hdsp->max_channels;
+		kctl = snd_ctl_new1(&snd_hdsp_loopback_control, hdsp);
+		if (kctl == NULL)
+			return -ENOMEM;
+		err = snd_ctl_add(card, kctl);
+		if (err < 0)
+			return err;
+	}
+
 	/* AEB control for H96xx card */
 	if (hdsp->io_type == H9632 || hdsp->io_type == H9652) {
 		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0)
@@ -4956,7 +5022,7 @@ static int snd_hdsp_enable_io (struct hdsp *hdsp)
 
 static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
 {
-	int status, aebi_channels, aebo_channels;
+	int status, aebi_channels, aebo_channels, i;
 
 	switch (hdsp->io_type) {
 	case Digiface:
@@ -4983,6 +5049,12 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
 		hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels;
 		hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels;
 		hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels;
+		/* Disable loopback of output channels, as the set function
+		 * only sets on a change we fake all bits (channels) as enabled.
+		 */
+		hdsp->io_loopback = 0xffffffff;
+		for (i = 0; i < hdsp->max_channels; ++i)
+			hdsp_loopback_set(hdsp, i, false);
 		break;
 
 	case Multiface:
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 04e878a0f773b822909bb8b166b78e391460aaf4..b66711574b1a6991995dbc542ff934bc4e580ef0 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6329,7 +6329,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
 		memset(&hdspm_version, 0, sizeof(hdspm_version));
 
 		hdspm_version.card_type = hdspm->io_type;
-		strlcpy(hdspm_version.cardname, hdspm->card_name,
+		strscpy(hdspm_version.cardname, hdspm->card_name,
 				sizeof(hdspm_version.cardname));
 		hdspm_version.serial = hdspm->serial;
 		hdspm_version.firmware_rev = hdspm->firmware_rev;
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 7bf6059d50fbc92c367fa6ac0adf12c3e618e226..8ffa2f53c0b588a7986695d0eed08c156e67a135 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -363,7 +363,7 @@ static u32 sis_rate_to_delta(unsigned int rate)
 	else if (rate == 48000)
 		delta = 0x1000;
 	else
-		delta = (((rate << 12) + 24000) / 48000) & 0x0000ffff;
+		delta = DIV_ROUND_CLOSEST(rate << 12, 48000) & 0x0000ffff;
 	return delta;
 }
 
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index ecdd54d7a4e1a9e86be507044473919e5c40e85a..26fd1d08c179fb86a5d9b34799db28dc3436b136 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -570,7 +570,7 @@ static void snd_sonicvibes_set_dac_rate(struct sonicvibes * sonic, unsigned int
 	unsigned int div;
 	unsigned long flags;
 
-	div = (rate * 65536 + SV_FULLRATE / 2) / SV_FULLRATE;
+	div = DIV_ROUND_CLOSEST(rate * 65536, SV_FULLRATE);
 	if (div > 65535)
 		div = 65535;
 	spin_lock_irqsave(&sonic->reg_lock, flags);
@@ -1230,8 +1230,7 @@ static int snd_sonicvibes_create(struct snd_card *card,
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 24 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(24)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(24)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) {
 		dev_err(card->dev,
 			"architecture does not support 24bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 6e50376163a220db166ddbe5e100f8535a840ba8..20145143f6a67c5513454cd0cf5aaa82924d374e 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -678,7 +678,7 @@ static unsigned int snd_trident_convert_rate(unsigned int rate)
 	else if (rate == 48000)
 		delta = 0x1000;
 	else
-		delta = (((rate << 12) + 24000) / 48000) & 0x0000ffff;
+		delta = DIV_ROUND_CLOSEST(rate << 12, 48000) & 0x0000ffff;
 	return delta;
 }
 
@@ -1034,7 +1034,7 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream)
 	ESO_bytes++;
 
 	// Set channel sample rate, 4.12 format
-	val = (((unsigned int) 48000L << 12) + (runtime->rate/2)) / runtime->rate;
+	val = DIV_ROUND_CLOSEST(48000U << 12, runtime->rate);
 	outw(val, TRID_REG(trident, T4D_SBDELTA_DELTA_R));
 
 	// Set channel interrupt blk length
@@ -3497,8 +3497,7 @@ int snd_trident_create(struct snd_card *card,
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 30 bits */
-	if (dma_set_mask(&pci->dev, DMA_BIT_MASK(30)) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(30)) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(30))) {
 		dev_err(card->dev,
 			"architecture does not support 30bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 9554a0c506afbc60239453e8cfd5ea719e6ac695..a6c1905039de838b9a79c05c4965eaa4bfa8de3d 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -49,7 +49,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
 		return -EINVAL; /* ignored */
 
 	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "keywest", I2C_NAME_SIZE);
+	strscpy(info.type, "keywest", I2C_NAME_SIZE);
 	info.addr = keywest_ctx->addr;
 	client = i2c_new_client_device(adapter, &info);
 	if (IS_ERR(client))
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 71a6fe87d1a1931723a711ccb511514ce3635c9a..640494f76cbd1d5b839337864ded6de23d16ed1d 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -37,6 +37,23 @@ config SND_SOC_COMPRESS
 config SND_SOC_TOPOLOGY
 	bool
 
+config SND_SOC_TOPOLOGY_KUNIT_TESTS
+	tristate "KUnit tests for SoC topology"
+	depends on KUNIT
+	depends on SND_SOC_TOPOLOGY
+	default KUNIT_ALL_TESTS
+	help
+	  If you want to perform tests on ALSA SoC topology support say Y here.
+
+	  This builds a module which can be later manually loaded to run KUNIT
+	  test cases against soc-topology.c API. This should be primarily used
+	  by developers to test their changes to ASoC.
+
+	  Do note that it creates fake playback devices which do not interact
+	  well with userspace. When running tests one may want to disable
+	  userspace applications such as pulseaudio, to prevent unnecessary
+	  problems.
+
 config SND_SOC_ACPI
 	tristate
 
@@ -62,7 +79,6 @@ source "sound/soc/qcom/Kconfig"
 source "sound/soc/rockchip/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/sh/Kconfig"
-source "sound/soc/sirf/Kconfig"
 source "sound/soc/sof/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/sprd/Kconfig"
@@ -71,12 +87,10 @@ source "sound/soc/stm/Kconfig"
 source "sound/soc/sunxi/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/ti/Kconfig"
-source "sound/soc/txx9/Kconfig"
 source "sound/soc/uniphier/Kconfig"
 source "sound/soc/ux500/Kconfig"
 source "sound/soc/xilinx/Kconfig"
 source "sound/soc/xtensa/Kconfig"
-source "sound/soc/zte/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index ddbac3a2169f293386e84ba16c0584a4c0779720..f56ad996eae88bc5fda09250e130d4e84d2c3568 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -7,6 +7,11 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
 snd-soc-core-objs += soc-topology.o
 endif
 
+ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS),)
+# snd-soc-test-objs := soc-topology-test.o
+obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS) := soc-topology-test.o
+endif
+
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 endif
@@ -45,7 +50,6 @@ obj-$(CONFIG_SND_SOC)	+= qcom/
 obj-$(CONFIG_SND_SOC)	+= rockchip/
 obj-$(CONFIG_SND_SOC)	+= samsung/
 obj-$(CONFIG_SND_SOC)	+= sh/
-obj-$(CONFIG_SND_SOC)	+= sirf/
 obj-$(CONFIG_SND_SOC)	+= sof/
 obj-$(CONFIG_SND_SOC)	+= spear/
 obj-$(CONFIG_SND_SOC)	+= sprd/
@@ -54,9 +58,7 @@ obj-$(CONFIG_SND_SOC)	+= stm/
 obj-$(CONFIG_SND_SOC)	+= sunxi/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= ti/
-obj-$(CONFIG_SND_SOC)	+= txx9/
 obj-$(CONFIG_SND_SOC)	+= uniphier/
 obj-$(CONFIG_SND_SOC)	+= ux500/
 obj-$(CONFIG_SND_SOC)	+= xilinx/
 obj-$(CONFIG_SND_SOC)	+= xtensa/
-obj-$(CONFIG_SND_SOC)	+= zte/
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c
index 8c4dc82be0dfb3c1139eb2a8ac8b3b374046eb45..aa082131fb903be483812c1dbde4b8921837982d 100644
--- a/sound/soc/adi/axi-i2s.c
+++ b/sound/soc/adi/axi-i2s.c
@@ -156,7 +156,7 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
 static struct snd_soc_dai_driver axi_i2s_dai = {
 	.probe = axi_i2s_dai_probe,
 	.ops = &axi_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver axi_i2s_component = {
diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c
index 1a4e8ca0f99c24f674a1f45d9eb3c8b40093c288..cea320ad0e1c2624817a5513da5349fb6a215181 100644
--- a/sound/soc/amd/acp3x-rt5682-max9836.c
+++ b/sound/soc/amd/acp3x-rt5682-max9836.c
@@ -140,9 +140,7 @@ static int acp3x_1015_hw_params(struct snd_pcm_substream *substream,
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
 		if (strcmp(codec_dai->name, "rt1015-aif"))
 			continue;
-		ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-		if (ret < 0)
-			return ret;
+
 		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
 						64 * srate, 256 * srate);
 		if (ret < 0)
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 232300dda5482bd10a79aff837df41c2de038d29..7c6187e41f2b9dd043fe3ede86603072e0798b97 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -541,7 +541,7 @@ static struct snd_soc_dai_driver atmel_i2s_dai = {
 		.formats = ATMEL_I2S_FORMATS,
 	},
 	.ops = &atmel_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver atmel_i2s_component = {
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 704f700013d3e3e20f83b52c8d5449d4d6c741df..3e7ea2021b46b2faeeac1ab490873a5073fddd4b 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -34,86 +34,21 @@
 #include "atmel-pcm.h"
 
 
-static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
-	int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = ATMEL_SSC_DMABUF_SIZE;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_coherent(pcm->card->dev, size,
-			&buf->addr, GFP_KERNEL);
-	pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
-			(void *)buf->area, (void *)(long)buf->addr, size);
-
-	if (!buf->area)
-		return -ENOMEM;
-
-	buf->bytes = size;
-	return 0;
-}
-
-static int atmel_pcm_mmap(struct snd_soc_component *component,
-			  struct snd_pcm_substream *substream,
-			  struct vm_area_struct *vma)
-{
-	return remap_pfn_range(vma, vma->vm_start,
-		       substream->dma_buffer.addr >> PAGE_SHIFT,
-		       vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
-
 static int atmel_pcm_new(struct snd_soc_component *component,
 			 struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
 	int ret;
 
 	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
 	if (ret)
 		return ret;
 
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
-		ret = atmel_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto out;
-	}
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+				       card->dev, ATMEL_SSC_DMABUF_SIZE,
+				       ATMEL_SSC_DMABUF_SIZE);
 
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
-		ret = atmel_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto out;
-	}
- out:
-	return ret;
-}
-
-static void atmel_pcm_free(struct snd_soc_component *component,
-			   struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-		dma_free_coherent(pcm->card->dev, buf->bytes,
-				  buf->area, buf->addr);
-		buf->area = NULL;
-	}
+	return 0;
 }
 
 /*--------------------------------------------------------------------------*\
@@ -210,9 +145,6 @@ static int atmel_pcm_hw_params(struct snd_soc_component *component,
 	/* this may get called several times by oss emulation
 	 * with different params */
 
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
-
 	prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
 	prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
 
@@ -384,9 +316,7 @@ static const struct snd_soc_component_driver atmel_soc_platform = {
 	.prepare	= atmel_pcm_prepare,
 	.trigger	= atmel_pcm_trigger,
 	.pointer	= atmel_pcm_pointer,
-	.mmap		= atmel_pcm_mmap,
 	.pcm_construct	= atmel_pcm_new,
-	.pcm_destruct	= atmel_pcm_free,
 };
 
 int atmel_pcm_pdc_platform_register(struct device *dev)
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 04acc18f2d72ceeb5f644112d6d06836009eedcc..6d5ae18f8b3823c6709cb6682721ab4fe2fcdba8 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -859,8 +859,8 @@ static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
 		.formats = MCHP_I2SMCC_FORMATS,
 	},
 	.ops = &mchp_i2s_mcc_dai_ops,
-	.symmetric_rates = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_rate = 1,
+	.symmetric_sample_bits = 1,
 	.symmetric_channels = 1,
 };
 
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 7fd08fafa49039dee9c06e4645f7762da1d1c847..65bd39f5032dfe5fb55f28903915cc64e96d6b5a 100644
--- a/sound/soc/au1x/i2sc.c
+++ b/sound/soc/au1x/i2sc.c
@@ -210,7 +210,7 @@ static const struct snd_soc_dai_ops au1xi2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver au1xi2s_dai_driver = {
-	.symmetric_rates	= 1,
+	.symmetric_rate		= 1,
 	.playback = {
 		.rates		= AU1XI2SC_RATES,
 		.formats	= AU1XI2SC_FMTS,
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index c2f7631e8705165e795a599d8b94fba2e5b5be9f..3d668f449bc1cf4cffcbd441d37bd749efb99204 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -783,8 +783,8 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = {
 				| SNDRV_PCM_FMTBIT_S32_LE
 		},
 	.ops = &bcm2835_i2s_dai_ops,
-	.symmetric_rates = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_rate = 1,
+	.symmetric_sample_bits = 1,
 };
 
 static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
diff --git a/sound/soc/bcm/bcm63xx-i2s-whistler.c b/sound/soc/bcm/bcm63xx-i2s-whistler.c
index 246a57ac66799898c3a2d1966114021571657845..527caf430715bc8c0a0b080d448eb26fcfa64c3f 100644
--- a/sound/soc/bcm/bcm63xx-i2s-whistler.c
+++ b/sound/soc/bcm/bcm63xx-i2s-whistler.c
@@ -212,7 +212,7 @@ static struct snd_soc_dai_driver bcm63xx_i2s_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.ops = &bcm63xx_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	.symmetric_channels = 1,
 };
 
diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index 7ad07239f99c4909bc5c117173560ea7d882727e..56b71b9656249c5ed210c0def5229d428b0a1c7f 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -636,36 +636,6 @@ static int cygnus_pcm_close(struct snd_soc_component *component,
 	return 0;
 }
 
-static int cygnus_pcm_hw_params(struct snd_soc_component *component,
-				struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct cygnus_aio_port *aio;
-
-	aio = cygnus_dai_get_dma_data(substream);
-	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s  port %d\n", __func__, aio->portnum);
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
-
-	return 0;
-}
-
-static int cygnus_pcm_hw_free(struct snd_soc_component *component,
-			      struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-	struct cygnus_aio_port *aio;
-
-	aio = cygnus_dai_get_dma_data(substream);
-	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s  port %d\n", __func__, aio->portnum);
-
-	snd_pcm_set_runtime_buffer(substream, NULL);
-	return 0;
-}
-
 static int cygnus_pcm_prepare(struct snd_soc_component *component,
 			      struct snd_pcm_substream *substream)
 {
@@ -730,87 +700,19 @@ static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_soc_component *component,
 	return bytes_to_frames(substream->runtime, res);
 }
 
-static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size;
-
-	size = cygnus_pcm_hw.buffer_bytes_max;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_coherent(pcm->card->dev, size,
-			&buf->addr, GFP_KERNEL);
-
-	dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s: size 0x%zx @ %pK\n",
-				__func__, size, buf->area);
-
-	if (!buf->area) {
-		dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "%s: dma_alloc failed\n", __func__);
-		return -ENOMEM;
-	}
-	buf->bytes = size;
-
-	return 0;
-}
-
-static void cygnus_dma_free_dma_buffers(struct snd_soc_component *component,
-					struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-
-	substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-	if (substream) {
-		buf = &substream->dma_buffer;
-		if (buf->area) {
-			dma_free_coherent(pcm->card->dev, buf->bytes,
-				buf->area, buf->addr);
-			buf->area = NULL;
-		}
-	}
-
-	substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-	if (substream) {
-		buf = &substream->dma_buffer;
-		if (buf->area) {
-			dma_free_coherent(pcm->card->dev, buf->bytes,
-				buf->area, buf->addr);
-			buf->area = NULL;
-		}
-	}
-}
-
 static int cygnus_dma_new(struct snd_soc_component *component,
 			  struct snd_soc_pcm_runtime *rtd)
 {
+	size_t size = cygnus_pcm_hw.buffer_bytes_max;
 	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
-	int ret;
 
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &cygnus_dma_dmamask;
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = cygnus_pcm_preallocate_dma_buffer(pcm,
-				SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			return ret;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = cygnus_pcm_preallocate_dma_buffer(pcm,
-				SNDRV_PCM_STREAM_CAPTURE);
-		if (ret) {
-			cygnus_dma_free_dma_buffers(component, pcm);
-			return ret;
-		}
-	}
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+				       card->dev, size, size);
 
 	return 0;
 }
@@ -818,13 +720,10 @@ static int cygnus_dma_new(struct snd_soc_component *component,
 static struct snd_soc_component_driver cygnus_soc_platform = {
 	.open		= cygnus_pcm_open,
 	.close		= cygnus_pcm_close,
-	.hw_params	= cygnus_pcm_hw_params,
-	.hw_free	= cygnus_pcm_hw_free,
 	.prepare	= cygnus_pcm_prepare,
 	.trigger	= cygnus_pcm_trigger,
 	.pointer	= cygnus_pcm_pointer,
 	.pcm_construct	= cygnus_dma_new,
-	.pcm_destruct	= cygnus_dma_free_dma_buffers,
 };
 
 int cygnus_soc_platform_register(struct device *dev,
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 371708b17c09efa6ebc1044963bc629f3c0365c5..0d26550d0df8d26cbb9d0de1403b11bc96c13323 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -404,7 +404,7 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
 #define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_driver ep93xx_i2s_dai = {
-	.symmetric_rates= 1,
+	.symmetric_rate	= 1,
 	.probe		= ep93xx_i2s_dai_probe,
 	.playback	= {
 		.channels_min	= 2,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9bf6bfdaf11e4e6fc8f30403700855a9f38f46bd..e4cf14e66a51b15adf36de0f74ef3d801fe50469 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_ISABELLE
 	imply SND_SOC_JZ4740_CODEC
 	imply SND_SOC_JZ4725B_CODEC
+	imply SND_SOC_JZ4760_CODEC
 	imply SND_SOC_JZ4770_CODEC
 	imply SND_SOC_LM4857
 	imply SND_SOC_LM49453
@@ -227,6 +228,8 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_UDA1380
 	imply SND_SOC_WCD9335
 	imply SND_SOC_WCD934X
+	imply SND_SOC_LPASS_RX_MACRO
+	imply SND_SOC_LPASS_TX_MACRO
 	imply SND_SOC_WL1273
 	imply SND_SOC_WM0010
 	imply SND_SOC_WM1250_EV1
@@ -712,7 +715,7 @@ config SND_SOC_CX2072X
 	  Enable support for Conexant CX20721 and CX20723 codec chips.
 
 config SND_SOC_JZ4740_CODEC
-	depends on MIPS || COMPILE_TEST
+	depends on MACH_INGENIC || COMPILE_TEST
 	depends on OF
 	select REGMAP_MMIO
 	tristate "Ingenic JZ4740 internal CODEC"
@@ -724,7 +727,7 @@ config SND_SOC_JZ4740_CODEC
 	  will be called snd-soc-jz4740-codec.
 
 config SND_SOC_JZ4725B_CODEC
-	depends on MIPS || COMPILE_TEST
+	depends on MACH_INGENIC || COMPILE_TEST
 	depends on OF
 	select REGMAP
 	tristate "Ingenic JZ4725B internal CODEC"
@@ -735,8 +738,20 @@ config SND_SOC_JZ4725B_CODEC
 	  This driver can also be built as a module. If so, the module
 	  will be called snd-soc-jz4725b-codec.
 
+config SND_SOC_JZ4760_CODEC
+        depends on MACH_INGENIC || COMPILE_TEST
+        depends on OF
+        select REGMAP
+        tristate "Ingenic JZ4760 internal CODEC"
+        help
+          Enable support for the internal CODEC found in the JZ4760 SoC
+          from Ingenic.
+
+          This driver can also be built as a module. If so, the module
+          will be called snd-soc-jz4760-codec.
+
 config SND_SOC_JZ4770_CODEC
-	depends on MIPS || COMPILE_TEST
+	depends on MACH_INGENIC || COMPILE_TEST
 	depends on OF
 	select REGMAP
 	tristate "Ingenic JZ4770 internal CODEC"
@@ -1162,7 +1177,7 @@ config SND_SOC_RT5651
 	depends on I2C
 
 config SND_SOC_RT5659
-	tristate
+	tristate "Realtek RT5658/RT5659 Codec"
 	depends on I2C
 
 config SND_SOC_RT5660
@@ -1820,4 +1835,12 @@ config SND_SOC_LPASS_VA_MACRO
 	depends on COMMON_CLK
 	tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)"
 
+config SND_SOC_LPASS_RX_MACRO
+	depends on COMMON_CLK
+	tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)"
+
+config SND_SOC_LPASS_TX_MACRO
+	depends on COMMON_CLK
+	tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)"
+
 endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d277f0366e0961805b2f6e3c5399242c0b31971b..81357dc62ea0918aea1b7027f3ce177282857c5e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -101,11 +101,14 @@ snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-jz4725b-codec-objs := jz4725b.o
+snd-soc-jz4760-codec-objs := jz4760.o
 snd-soc-jz4770-codec-objs := jz4770.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
 snd-soc-lm49453-objs := lm49453.o
 snd-soc-lochnagar-sc-objs := lochnagar-sc.o
+snd-soc-lpass-rx-macro-objs := lpass-rx-macro.o
+snd-soc-lpass-tx-macro-objs := lpass-tx-macro.o
 snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o
 snd-soc-lpass-va-macro-objs := lpass-va-macro.o
 snd-soc-madera-objs := madera.o
@@ -201,7 +204,6 @@ snd-soc-sigmadsp-objs := sigmadsp.o
 snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
 snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
 snd-soc-si476x-objs := si476x.o
-snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
 snd-soc-spdif-tx-objs := spdif_transmitter.o
 snd-soc-spdif-rx-objs := spdif_receiver.o
 snd-soc-ssm2305-objs := ssm2305.o
@@ -302,7 +304,6 @@ snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-wsa881x-objs := wsa881x.o
 snd-soc-zl38060-objs := zl38060.o
-snd-soc-zx-aud96p22-objs := zx_aud96p22.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
@@ -418,6 +419,7 @@ obj-$(CONFIG_SND_SOC_INNO_RK3036)	+= snd-soc-inno-rk3036.o
 obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_JZ4725B_CODEC)	+= snd-soc-jz4725b-codec.o
+obj-$(CONFIG_SND_SOC_JZ4760_CODEC)      += snd-soc-jz4760-codec.o
 obj-$(CONFIG_SND_SOC_JZ4770_CODEC)	+= snd-soc-jz4770-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
@@ -516,7 +518,6 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP)	+= snd-soc-sigmadsp-regmap.o
 obj-$(CONFIG_SND_SOC_SI476X)	+= snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif-rx.o snd-soc-spdif-tx.o
-obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
 obj-$(CONFIG_SND_SOC_SSM2305)	+= snd-soc-ssm2305.o
 obj-$(CONFIG_SND_SOC_SSM2518)	+= snd-soc-ssm2518.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
@@ -618,7 +619,6 @@ obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_WSA881X)	+= snd-soc-wsa881x.o
 obj-$(CONFIG_SND_SOC_ZL38060)	+= snd-soc-zl38060.o
-obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
@@ -627,6 +627,8 @@ obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER)	+= snd-soc-simple-amplifier.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
 obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO)	+= snd-soc-lpass-wsa-macro.o
 obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO)	+= snd-soc-lpass-va-macro.o
+obj-$(CONFIG_SND_SOC_LPASS_RX_MACRO)	+= snd-soc-lpass-rx-macro.o
+obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO)	+= snd-soc-lpass-tx-macro.o
 
 # Mux
 obj-$(CONFIG_SND_SOC_SIMPLE_MUX)	+= snd-soc-simple-mux.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 31a8c4162d209cdc10d2c520c9eb1b5311835f4a..c95f007cede1aaabaf1256ad7649772fe5c81612 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2384,7 +2384,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
 			.formats = AB8500_SUPPORTED_FMT,
 		},
 		.ops = &ab8500_codec_ops,
-		.symmetric_rates = 1
+		.symmetric_rate = 1
 	},
 	{
 		.name = "ab8500-codec-dai.1",
@@ -2397,7 +2397,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
 			.formats = AB8500_SUPPORTED_FMT,
 		},
 		.ops = &ab8500_codec_ops,
-		.symmetric_rates = 1
+		.symmetric_rate = 1
 	}
 };
 
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
index 5ccbf1b6bcf5a33605e008922eb6e9aa7d1ff9d7..6811a8b3866dd96781e31d5c3c6ad9c3ba8ff2dd 100644
--- a/sound/soc/codecs/adau1372.c
+++ b/sound/soc/codecs/adau1372.c
@@ -890,7 +890,7 @@ static struct snd_soc_dai_driver adau1372_dai_driver = {
 		.sig_bits = 24,
 	},
 	.ops = &adau1372_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int adau1372_setup_pll(struct adau1372 *adau1372, unsigned int rate)
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index e71fde001b4667232260ffd0c8de7027553dfd31..9887aa6f0be5c0f9a09bb01f8c46e5302297c2fd 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1205,7 +1205,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
 			.formats = ADAU1373_FORMATS,
 		},
 		.ops = &adau1373_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.id = 1,
@@ -1225,7 +1225,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
 			.formats = ADAU1373_FORMATS,
 		},
 		.ops = &adau1373_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.id = 2,
@@ -1245,7 +1245,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
 			.formats = ADAU1373_FORMATS,
 		},
 		.ops = &adau1373_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 68130eaa64a404509f0aca81c854fcf0cb389b8e..5ce74697564af1017691063a6a1fcc743d30a60b 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -653,7 +653,7 @@ static struct snd_soc_dai_driver adau1701_dai = {
 		.formats = ADAU1701_FORMATS,
 	},
 	.ops = &adau1701_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 #ifdef CONFIG_OF
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 30e072c80ac179f2b08263a20b2ac93c9995495a..546ee817803878f41d24cdc1130b58b67c8a46b7 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -1095,8 +1095,7 @@ void adau17x1_remove(struct device *dev)
 {
 	struct adau *adau = dev_get_drvdata(dev);
 
-	if (adau->mclk)
-		clk_disable_unprepare(adau->mclk);
+	clk_disable_unprepare(adau->mclk);
 }
 EXPORT_SYMBOL_GPL(adau17x1_remove);
 
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index 2fa83a1a84cf126f7b37b8da00fd46d4fd45548b..8e60e2b56ad6d2afe6ad3eac8e8db4797ca2e34a 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -56,7 +56,7 @@ static struct snd_soc_dai_driver ak4554_dai = {
 		.rates = SNDRV_PCM_RATE_8000_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver soc_component_dev_ak4554 = {
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 8d663e8d64c49814763e97bf2dfceb3726e0ff63..fe208cfdd3ba5198352002efd65ba18bfffd6f84 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -575,7 +575,7 @@ static struct snd_soc_dai_driver ak4613_dai = {
 		.formats	= AK4613_PCM_FMTBIT,
 	},
 	.ops = &ak4613_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int ak4613_suspend(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 77004cd7caa3ec8db578f6af47f14336e0a30343..04aef0e72aa586c0cee53a9b4b11ee83d99954fa 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -499,7 +499,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 		.formats = AK4641_FORMATS,
 	},
 	.ops = &ak4641_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 },
 {
 	.name = "ak4641-voice",
@@ -519,7 +519,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 		.formats = AK4641_FORMATS,
 	},
 	.ops = &ak4641_pcm_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 },
 };
 
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 3532370255140e03f2f91289b871ff59e98762ee..c49c58eeb47631c39acb8690b6fca18f8b733205 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -516,7 +516,7 @@ static struct snd_soc_dai_driver ak4642_dai = {
 		.rates = SNDRV_PCM_RATE_8000_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE },
 	.ops = &ak4642_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int ak4642_suspend(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index bde5ded677542ecb62552457ec479df9bd64b0fa..79813882a955227670f2e973f22a8d55aef09771 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1032,7 +1032,7 @@ static struct snd_soc_dai_driver alc5632_dai = {
 		.formats = ALC5632_FORMATS,},
 
 	.ops = &alc5632_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 #ifdef CONFIG_PM
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index f046987ee4cdb3f44febe980ba3c1c6517c73c13..05bbacd0d174df98e1e9c3cf6ca7b7c795e36fd5 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -16,6 +16,14 @@
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
+/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
+#define CPCAP_BIT_AUDIO_LOW_PWR           6
+#define CPCAP_BIT_AUD_LOWPWR_SPEED        5
+#define CPCAP_BIT_VAUDIOPRISTBY           4
+#define CPCAP_BIT_VAUDIO_MODE1            2
+#define CPCAP_BIT_VAUDIO_MODE0            1
+#define CPCAP_BIT_V_AUDIO_EN              0
+
 /* Register 513 CPCAP_REG_CC     --- CODEC */
 #define CPCAP_BIT_CDC_CLK2                15
 #define CPCAP_BIT_CDC_CLK1                14
@@ -221,6 +229,7 @@ struct cpcap_reg_info {
 };
 
 static const struct cpcap_reg_info cpcap_default_regs[] = {
+	{ CPCAP_REG_VAUDIOC, 0x003F, 0x0000 },
 	{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
 	{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
 	{ CPCAP_REG_CDI, 0xBFFF, 0x0000 },
@@ -1264,12 +1273,12 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
 
 	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
 		mask = 0x0000;
-		mask |= CPCAP_BIT_MIC1_RX_TIMESLOT0;
-		mask |= CPCAP_BIT_MIC1_RX_TIMESLOT1;
-		mask |= CPCAP_BIT_MIC1_RX_TIMESLOT2;
-		mask |= CPCAP_BIT_MIC2_TIMESLOT0;
-		mask |= CPCAP_BIT_MIC2_TIMESLOT1;
-		mask |= CPCAP_BIT_MIC2_TIMESLOT2;
+		mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
+		mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT1);
+		mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT2);
+		mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT0);
+		mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT1);
+		mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT2);
 		val = 0x0000;
 		if (channels >= 2)
 			val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
@@ -1371,8 +1380,121 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int cpcap_voice_set_mute(struct snd_soc_dai *dai,
-				int mute, int direction)
+
+/*
+ * Configure codec for voice call if requested.
+ *
+ * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt()
+ * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the
+ * cpcap related hardware as CPU is not involved in the voice call.
+ */
+static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai,
+			    bool voice_call)
+{
+	int mask, err;
+
+	/* Modem to codec VAUDIO_MODE1 */
+	mask = BIT(CPCAP_BIT_VAUDIO_MODE1);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
+				 mask, voice_call ? mask : 0);
+	if (err)
+		return err;
+
+	/* Clear MIC1_MUX for call */
+	mask = BIT(CPCAP_BIT_MIC1_MUX);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+				 mask, voice_call ? 0 : mask);
+	if (err)
+		return err;
+
+	/* Set MIC2_MUX for call */
+	mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) |
+		BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+				 mask, voice_call ? mask : 0);
+	if (err)
+		return err;
+
+	/* Enable LDSP for call */
+	mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
+				 mask, voice_call ? mask : 0);
+	if (err)
+		return err;
+
+	/* Enable CPCAP_BIT_PGA_CDC_EN for call */
+	mask = BIT(CPCAP_BIT_PGA_CDC_EN);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+				 mask, voice_call ? mask : 0);
+	if (err)
+		return err;
+
+	/* Unmute voice for call */
+	if (dai) {
+		err = snd_soc_dai_digital_mute(dai, !voice_call,
+					       SNDRV_PCM_STREAM_PLAYBACK);
+		if (err)
+			return err;
+	}
+
+	/* Set modem to codec mic CDC and HPF for call */
+	mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) |
+	       BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) |
+	       BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
+				 mask, voice_call ? mask : 0);
+	if (err)
+		return err;
+
+	/* Enable modem to codec CDC for call*/
+	mask = BIT(CPCAP_BIT_CDC_CLK_EN);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+				 mask, voice_call ? mask : 0);
+
+	return err;
+}
+
+static int cpcap_voice_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 cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	int err, ts_mask, mask;
+	bool voice_call;
+
+	/*
+	 * Primitive test for voice call, probably needs more checks
+	 * later on for 16-bit calls detected, Bluetooth headset etc.
+	 */
+	if (tx_mask == 0 && rx_mask == 1 && slot_width == 8)
+		voice_call = true;
+	else
+		voice_call = false;
+
+	ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0;
+	ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0;
+
+	mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0;
+	mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0;
+
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+				 ts_mask, mask);
+	if (err)
+		return err;
+
+	err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000);
+	if (err)
+		return err;
+
+	err = cpcap_voice_call(cpcap, dai, voice_call);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction)
 {
 	struct snd_soc_component *component = dai->component;
 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
@@ -1393,6 +1515,7 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
 	.hw_params	= cpcap_voice_hw_params,
 	.set_sysclk	= cpcap_voice_set_dai_sysclk,
 	.set_fmt	= cpcap_voice_set_dai_fmt,
+	.set_tdm_slot	= cpcap_voice_set_tdm_slot,
 	.mute_stream	= cpcap_voice_set_mute,
 	.no_capture_mute = 1,
 };
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index f33a2a9654e76becb7d059b800d7c536c31749d7..c4772f82485a350fb52fe4934e6b7a6b927b61dd 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -1011,6 +1011,18 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev)
 	}
 	priv->ec_capabilities = r.capabilities;
 
+	/* Reset EC codec i2s rx. */
+	p.cmd = EC_CODEC_I2S_RX_RESET;
+	ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
+				   (uint8_t *)&p, sizeof(p), NULL, 0);
+	if (ret == -ENOPROTOOPT) {
+		dev_info(dev,
+			 "Missing reset command. Please update EC firmware.\n");
+	} else if (ret) {
+		dev_err(dev, "failed to EC_CODEC_I2S_RESET: %d\n", ret);
+		return ret;
+	}
+
 	platform_set_drvdata(pdev, priv);
 
 	ret = devm_snd_soc_register_component(dev, &i2s_rx_component_driver,
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 3a644a35c464390fbfbe71ce48d6aa455cba65d4..f4067230ac425a5388771343bb50cc527759436a 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -194,7 +194,7 @@ static struct snd_soc_dai_driver cs35l32_dai[] = {
 			.formats = CS35L32_FORMATS,
 		},
 		.ops = &cs35l32_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	}
 };
 
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 6042194d95d3ec9dee14ecbc032bb945b4b8766b..7ad7b733af9b6731c4778660b27af8278302af5a 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -691,7 +691,7 @@ static struct snd_soc_dai_driver cs35l33_dai = {
 			.formats = CS35L33_FORMATS,
 		},
 		.ops = &cs35l33_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 };
 
 static int cs35l33_set_hg_data(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index b792c006e530dc7d9e8eae88d4ee725f3f22e8d0..110ee2d063581c0879c9792565bf3d1c974c6ad7 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -666,7 +666,7 @@ static struct snd_soc_dai_driver cs35l34_dai = {
 			.formats = CS35L34_FORMATS,
 		},
 		.ops = &cs35l34_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 };
 
 static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34,
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index e330427a4314f7644ac2b83d0332ebcb03c39fb7..55d529aa00112df36574f4338d33a70a39cefc9c 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -692,7 +692,7 @@ static struct snd_soc_dai_driver cs35l35_dai[] = {
 			.formats = CS35L35_FORMATS,
 		},
 		.ops = &cs35l35_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "cs35l35-pdm",
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index e9b5f76f27a864682354ad3b7b4bcf77e9d8dedc..4451ca9f49166f2d6dcb5171a1f033eeecff0ee9 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -995,7 +995,7 @@ static struct snd_soc_dai_driver cs35l36_dai[] = {
 			.formats = CS35L36_TX_FORMATS,
 		},
 		.ops = &cs35l36_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c
index 2ea83233c3f16ad36220354000e05c56feaf11ab..20126cc675b13a34cc20dfa1fb5193870808b356 100644
--- a/sound/soc/codecs/cs4234.c
+++ b/sound/soc/codecs/cs4234.c
@@ -585,7 +585,7 @@ static struct snd_soc_dai_driver cs4234_dai[] = {
 			.formats = CS4234_FORMATS,
 		},
 		.ops = &cs4234_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index d43762ae8f3da7cbf84735d01920a57bf144dc4e..7663f89ac6a2420587b7976f528be6e71b904191 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -481,7 +481,7 @@ static struct snd_soc_dai_driver cs4271_dai = {
 		.formats	= CS4271_PCM_FORMATS,
 	},
 	.ops = &cs4271_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int cs4271_reset(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index bb9599cc832bcb5f33e75dabd49dea6f4e83ad2e..c44a5cdb796ecf8e0350ff5f488af0028408440b 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1250,6 +1250,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
 		dev_err(&i2c_client->dev,
 			"CS42L56 Device ID (%X). Expected %X\n",
 			devid, CS42L56_DEVID);
+		ret = -EINVAL;
 		goto err_enable;
 	}
 	alpha_rev = reg & CS42L56_AREV_MASK;
@@ -1307,7 +1308,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
 	ret =  devm_snd_soc_register_component(&i2c_client->dev,
 			&soc_component_dev_cs42l56, &cs42l56_dai, 1);
 	if (ret < 0)
-		return ret;
+		goto err_enable;
 
 	return 0;
 
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 988ca7e19821ea6dc6c72fc1c205875082e4a702..c3f974ec78e58b31d9c88f9c394ccc5c02027ef0 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1181,7 +1181,7 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
 			.formats = CS42L73_FORMATS,
 		},
 		.ops = &cs42l73_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	 },
 	{
 		.name = "cs42l73-asp",
@@ -1201,7 +1201,7 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
 			.formats = CS42L73_FORMATS,
 		},
 		.ops = &cs42l73_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	 },
 	{
 		.name = "cs42l73-vsp",
@@ -1221,7 +1221,7 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
 			.formats = CS42L73_FORMATS,
 		},
 		.ops = &cs42l73_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	 }
 };
 
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index 7fb34422a2a4b087d5a785597ee225f3cf4b684e..80bc7c10ed757fc693c4a9f57d64bbaf8ae3e495 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -1581,7 +1581,7 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
 			.formats = CS43130_PCM_FORMATS,
 		},
 		.ops = &cs43130_pcm_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "cs43130-asp-dop",
@@ -1594,7 +1594,7 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
 			.formats = CS43130_DOP_FORMATS,
 		},
 		.ops = &cs43130_dop_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "cs43130-xsp-dop",
@@ -1607,7 +1607,7 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
 			.formats = CS43130_DOP_FORMATS,
 		},
 		.ops = &cs43130_dop_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "cs43130-xsp-dsd",
diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c
index f566604de78cfe2d9ef1c4a91a08c9077d2aee72..7d3e54d8eef36f46f15b3b3d92c1469b70377416 100644
--- a/sound/soc/codecs/cs4341.c
+++ b/sound/soc/codecs/cs4341.c
@@ -189,7 +189,7 @@ static struct snd_soc_dai_driver cs4341_dai = {
 				  SNDRV_PCM_FMTBIT_S24_LE,
 	},
 	.ops			= &cs4341_dai_ops,
-	.symmetric_rates	= 1,
+	.symmetric_rate		= 1,
 };
 
 static const struct snd_soc_component_driver soc_component_cs4341 = {
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index fd55263197798a462c7683167e204d7b8d68cecd..786c69a8ec4a2dc757e0efa78af123b6d6bbcb82 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -250,7 +250,7 @@ static struct snd_soc_dai_driver cs4349_dai = {
 		.formats	= CS4349_PCM_FORMATS,
 	},
 	.ops = &cs4349_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver soc_component_dev_cs4349 = {
diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c
index 254f9d96e766de4f592811f3673289778d522d63..1ee83160b83fb7c6c8db02d96ff4d11620439215 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -1160,8 +1160,8 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l15-aif2",
@@ -1182,8 +1182,8 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l15-aif3",
@@ -1204,8 +1204,8 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l15-cpu-trace",
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index f6d173d0120e346069d21d593bb7a222f69173c3..eaabbb56a173415bec5cc3191d168163722787f5 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -977,8 +977,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
 			 .formats = CS47L24_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l24-aif2",
@@ -999,8 +999,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
 			 .formats = CS47L24_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l24-aif3",
@@ -1021,8 +1021,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
 			 .formats = CS47L24_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l24-cpu-voicectrl",
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index e967609da8a302e8fe732b9ee52d0cfec1f35f4a..3f04a2a7452178ff22e9ba0b9cfd54e4a78e6240 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -1368,8 +1368,8 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l35-aif2",
@@ -1390,8 +1390,8 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l35-aif3",
@@ -1412,8 +1412,8 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l35-slim1",
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index 47b16466b6c17a370f4eac9296b94cd37358d92e..748a180870bc83858a88da9b12d2e960a9eed80f 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -2269,8 +2269,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l85-aif2",
@@ -2291,8 +2291,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l85-aif3",
@@ -2313,8 +2313,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l85-aif4",
@@ -2335,8 +2335,8 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l85-slim1",
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index 8838dd557321a66f28e2e5b7f42010ce2d0a1ae0..d2911c014b863ee02cf242e81ddbafb0283501fe 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -2188,8 +2188,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l90-aif2",
@@ -2210,8 +2210,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l90-aif3",
@@ -2232,8 +2232,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l90-aif4",
@@ -2254,8 +2254,8 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l90-slim1",
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index 52dc29942ec271f25c2b8d695e8ec0b45cacb7e2..1a0280416d92a79f78cefae279b6d011b777a17c 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -1704,8 +1704,8 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l92-aif2",
@@ -1726,8 +1726,8 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l92-aif3",
@@ -1748,8 +1748,8 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
 			.formats = MADERA_FORMATS,
 		 },
 		.ops = &madera_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "cs47l92-slim1",
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index ed22361b35c1491198cb26d2315fcdf8ec63b38c..3d67cbf9eaaa2b58e78860cfbbec37020900089d 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -869,7 +869,7 @@ static struct snd_soc_dai_driver cs53l30_dai = {
 		.formats = CS53L30_FORMATS,
 	},
 	.ops = &cs53l30_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int cs53l30_component_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 2f10991a8bdb510f4177181b0ff701bdff4bae9c..8ab22815c2c9789efeec60847508aad6ff1ea9c7 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -1572,7 +1572,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
 			.formats = CX2072X_FORMATS,
 		},
 		.ops = &cx2072x_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{ /* plabayck only, return echo reference to Conexant DSP chip */
 		.name = "cx2072x-dsp",
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 3d05c37f676ebe7999d86c753ea797ef5e007e22..8af344b2fdbf6a9cb9ca91d4e24e680adcfb9e15 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1059,7 +1059,7 @@ static struct snd_soc_dai_driver da7210_dai = {
 		.formats = DA7210_FORMATS,
 	},
 	.ops = &da7210_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int da7210_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 72402467adcc629a8b1da53211c00c45e6ec68ae..3ab89387b4e6578b454792d20a0123dc0aba0901 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1551,7 +1551,7 @@ static struct snd_soc_dai_driver da7213_dai = {
 		.formats = DA7213_FORMATS,
 	},
 	.ops = &da7213_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int da7213_set_auto_pll(struct snd_soc_component *component, bool enable)
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 2bfafbe9e3dce0ea33d09a72e5f093f0c8c2d008..ea426d986d4ca610cb9d9dd63bf58cec0f441833 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -2194,9 +2194,9 @@ static struct snd_soc_dai_driver da7218_dai = {
 		.formats = DA7218_FORMATS,
 	},
 	.ops = &da7218_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	.symmetric_channels = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_sample_bits = 1,
 };
 
 
@@ -2278,14 +2278,12 @@ static irqreturn_t da7218_irq_thread(int irq, void *data)
  * DT
  */
 
-#ifdef CONFIG_OF
 static const struct of_device_id da7218_of_match[] = {
 	{ .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
 	{ .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, da7218_of_match);
-#endif
 
 static inline int da7218_of_get_id(struct device *dev)
 {
@@ -3311,7 +3309,7 @@ MODULE_DEVICE_TABLE(i2c, da7218_i2c_id);
 static struct i2c_driver da7218_i2c_driver = {
 	.driver = {
 		.name = "da7218",
-		.of_match_table = of_match_ptr(da7218_of_match),
+		.of_match_table = da7218_of_match,
 	},
 	.probe		= da7218_i2c_probe,
 	.id_table	= da7218_i2c_id,
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index e9b45daec0ca557c674a448407b0557ecc4f813a..13009d08b09ac5ed3271ffdc66b60d7d57cd1b41 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1692,9 +1692,9 @@ static struct snd_soc_dai_driver da7219_dai = {
 		.formats = DA7219_FORMATS,
 	},
 	.ops = &da7219_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	.symmetric_channels = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_sample_bits = 1,
 };
 
 
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index aed92f615b0239e0544b40a8aa03d04e9650c3df..a9676b261129e39e4b3e71b4d55e201364360e7f 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1347,7 +1347,7 @@ static struct snd_soc_dai_driver da9055_dai = {
 		.formats = DA9055_FORMATS,
 	},
 	.ops = &da9055_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int da9055_set_bias_level(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index f9ec5cf8259919f14e1f46dc6119b8d7a2241914..d632055370e09208cf6af576f9541e89d1a12b2e 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -543,7 +543,7 @@ static struct snd_soc_dai_driver es8316_dai = {
 		.formats = ES8316_FORMATS,
 	},
 	.ops = &es8316_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static void es8316_enable_micbias_for_mic_gnd_short_detect(
@@ -681,6 +681,9 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
 {
 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 
+	if (!es8316->jack)
+		return; /* Already disabled (or never enabled) */
+
 	disable_irq(es8316->irq);
 
 	mutex_lock(&es8316->lock);
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 7e26231a596a415f9b78d5b7121fb5ec45fcd9b4..9632afc2d4d64189db9368a6f1af1d7492622d82 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -715,7 +715,7 @@ static struct snd_soc_dai_driver es8328_dai = {
 		.formats = ES8328_FORMATS,
 	},
 	.ops = &es8328_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int es8328_suspend(struct snd_soc_component *component)
@@ -809,8 +809,7 @@ static void es8328_remove(struct snd_soc_component *component)
 
 	es8328 = snd_soc_component_get_drvdata(component);
 
-	if (es8328->clk)
-		clk_disable_unprepare(es8328->clk);
+	clk_disable_unprepare(es8328->clk);
 
 	regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
 			       es8328->supplies);
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 0f3ac22f2cf8ee124281e1b5247be38604f0d30a..422539f933debf038e17061cee823a9c564b9a5c 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -489,6 +489,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
 	hp.sample_rate = params_rate(params);
 	hp.channels = params_channels(params);
 
+	cf->bit_fmt = params_format(params);
 	return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data,
 				       cf, &hp);
 }
@@ -617,7 +618,8 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
 			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\
 			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
-			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
+			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
+			 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
 static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
 			      struct snd_soc_dai *dai)
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index 4dbce24c5f76ffc967e5a3601b52c896aa9884cd..e05c4f27486e7f82eaf8ed5dd57808592282bcd0 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -325,7 +325,7 @@ static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
 			.formats = RK3036_CODEC_FMTS,
 		},
 		.ops = &rk3036_codec_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 5e58bfee2b491e1f8f13bd9ac37bf9903089984b..081485f784e9bc588fcfcb41ed9697919f9621a2 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -214,7 +214,7 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
 	},
 	.ops = &jz4740_codec_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static void jz4740_codec_wakeup(struct regmap *regmap)
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
new file mode 100644
index 0000000000000000000000000000000000000000..e8f28ccc145a2cf49a61259e63493bd68cd12072
--- /dev/null
+++ b/sound/soc/codecs/jz4760.c
@@ -0,0 +1,889 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Ingenic JZ4760 CODEC driver
+//
+// Copyright (C) 2021, Christophe Branchereau <cbranchereau@gmail.com>
+// Copyright (C) 2021, Paul Cercueil <paul@crapouillou.net>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/time64.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#define ICDC_RGADW_OFFSET		0x00
+#define ICDC_RGDATA_OFFSET		0x04
+
+/* ICDC internal register access control register(RGADW) */
+#define ICDC_RGADW_RGWR			BIT(16)
+#define	ICDC_RGADW_RGADDR_MASK		GENMASK(14, 8)
+#define	ICDC_RGADW_RGDIN_MASK		GENMASK(7, 0)
+
+/* ICDC internal register data output register (RGDATA)*/
+#define ICDC_RGDATA_IRQ			BIT(8)
+#define ICDC_RGDATA_RGDOUT_MASK		GENMASK(7, 0)
+
+/* Internal register space, accessed through regmap */
+enum {
+	JZ4760_CODEC_REG_SR,
+	JZ4760_CODEC_REG_AICR,
+	JZ4760_CODEC_REG_CR1,
+	JZ4760_CODEC_REG_CR2,
+	JZ4760_CODEC_REG_CR3,
+	JZ4760_CODEC_REG_CR4,
+	JZ4760_CODEC_REG_CCR1,
+	JZ4760_CODEC_REG_CCR2,
+	JZ4760_CODEC_REG_PMR1,
+	JZ4760_CODEC_REG_PMR2,
+	JZ4760_CODEC_REG_ICR,
+	JZ4760_CODEC_REG_IFR,
+	JZ4760_CODEC_REG_GCR1,
+	JZ4760_CODEC_REG_GCR2,
+	JZ4760_CODEC_REG_GCR3,
+	JZ4760_CODEC_REG_GCR4,
+	JZ4760_CODEC_REG_GCR5,
+	JZ4760_CODEC_REG_GCR6,
+	JZ4760_CODEC_REG_GCR7,
+	JZ4760_CODEC_REG_GCR8,
+	JZ4760_CODEC_REG_GCR9,
+	JZ4760_CODEC_REG_AGC1,
+	JZ4760_CODEC_REG_AGC2,
+	JZ4760_CODEC_REG_AGC3,
+	JZ4760_CODEC_REG_AGC4,
+	JZ4760_CODEC_REG_AGC5,
+	JZ4760_CODEC_REG_MIX1,
+	JZ4760_CODEC_REG_MIX2,
+};
+
+#define REG_AICR_DAC_ADWL_MASK		GENMASK(7, 6)
+#define REG_AICR_DAC_SERIAL		BIT(3)
+#define REG_AICR_DAC_I2S		BIT(1)
+
+#define REG_AICR_ADC_ADWL_MASK		GENMASK(5, 4)
+
+#define REG_AICR_ADC_SERIAL		BIT(2)
+#define REG_AICR_ADC_I2S		BIT(0)
+
+#define REG_CR1_HP_LOAD			BIT(7)
+#define REG_CR1_HP_MUTE			BIT(5)
+#define REG_CR1_LO_MUTE_OFFSET		4
+#define REG_CR1_BTL_MUTE_OFFSET		3
+#define REG_CR1_OUTSEL_OFFSET		0
+#define REG_CR1_OUTSEL_MASK		GENMASK(1, REG_CR1_OUTSEL_OFFSET)
+
+#define REG_CR2_DAC_MONO		BIT(7)
+#define REG_CR2_DAC_MUTE		BIT(5)
+#define REG_CR2_DAC_NOMAD		BIT(1)
+#define REG_CR2_DAC_RIGHT_ONLY		BIT(0)
+
+#define REG_CR3_ADC_INSEL_OFFSET	2
+#define REG_CR3_ADC_INSEL_MASK		GENMASK(3, REG_CR3_ADC_INSEL_OFFSET)
+#define REG_CR3_MICSTEREO_OFFSET	1
+#define REG_CR3_MICDIFF_OFFSET		0
+
+#define REG_CR4_ADC_HPF_OFFSET		7
+#define REG_CR4_ADC_RIGHT_ONLY		BIT(0)
+
+#define REG_CCR1_CRYSTAL_MASK		GENMASK(3, 0)
+
+#define REG_CCR2_DAC_FREQ_MASK		GENMASK(7, 4)
+#define REG_CCR2_ADC_FREQ_MASK		GENMASK(3, 0)
+
+#define REG_PMR1_SB			BIT(7)
+#define REG_PMR1_SB_SLEEP		BIT(6)
+#define REG_PMR1_SB_AIP_OFFSET		5
+#define REG_PMR1_SB_LINE_OFFSET		4
+#define REG_PMR1_SB_MIC1_OFFSET		3
+#define REG_PMR1_SB_MIC2_OFFSET		2
+#define REG_PMR1_SB_BYPASS_OFFSET	1
+#define REG_PMR1_SB_MICBIAS_OFFSET	0
+
+#define REG_PMR2_SB_ADC_OFFSET		4
+#define REG_PMR2_SB_HP_OFFSET		3
+#define REG_PMR2_SB_BTL_OFFSET		2
+#define REG_PMR2_SB_LOUT_OFFSET		1
+#define REG_PMR2_SB_DAC_OFFSET		0
+
+#define REG_ICR_INT_FORM_MASK		GENMASK(7, 6)
+#define REG_ICR_ALL_MASK		GENMASK(5, 0)
+#define REG_ICR_JACK_MASK		BIT(5)
+#define REG_ICR_SCMC_MASK		BIT(4)
+#define REG_ICR_RUP_MASK		BIT(3)
+#define REG_ICR_RDO_MASK		BIT(2)
+#define REG_ICR_GUP_MASK		BIT(1)
+#define REG_ICR_GDO_MASK		BIT(0)
+
+#define REG_IFR_ALL_MASK		GENMASK(5, 0)
+#define REG_IFR_JACK			BIT(6)
+#define REG_IFR_JACK_EVENT		BIT(5)
+#define REG_IFR_SCMC			BIT(4)
+#define REG_IFR_RUP			BIT(3)
+#define REG_IFR_RDO			BIT(2)
+#define REG_IFR_GUP			BIT(1)
+#define REG_IFR_GDO			BIT(0)
+
+#define REG_GCR_GAIN_OFFSET		0
+#define REG_GCR_GAIN_MAX		0x1f
+
+#define REG_GCR_RL			BIT(7)
+
+#define REG_GCR_GIM1_MASK		GENMASK(5, 3)
+#define REG_GCR_GIM2_MASK		GENMASK(2, 0)
+#define REG_GCR_GIM_GAIN_MAX		7
+
+#define REG_AGC1_EN			BIT(7)
+#define REG_AGC1_TARGET_MASK		GENMASK(5, 2)
+
+#define REG_AGC2_NG_THR_MASK		GENMASK(6, 4)
+#define REG_AGC2_HOLD_MASK		GENMASK(3, 0)
+
+#define REG_AGC3_ATK_MASK		GENMASK(7, 4)
+#define REG_AGC3_DCY_MASK		GENMASK(3, 0)
+
+#define REG_AGC4_AGC_MAX_MASK		GENMASK(4, 0)
+
+#define REG_AGC5_AGC_MIN_MASK		GENMASK(4, 0)
+
+#define REG_MIX1_MIX_REC_MASK		GENMASK(7, 6)
+#define REG_MIX1_GIMIX_MASK		GENMASK(4, 0)
+
+#define REG_MIX2_DAC_MIX_MASK		GENMASK(7, 6)
+#define REG_MIX2_GOMIX_MASK		GENMASK(4, 0)
+
+/* codec private data */
+struct jz_codec {
+	struct device *dev;
+	struct regmap *regmap;
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static int jz4760_codec_set_bias_level(struct snd_soc_component *codec,
+				       enum snd_soc_bias_level level)
+{
+	struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+	struct regmap *regmap = jz_codec->regmap;
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		/* Reset all interrupt flags. */
+		regmap_write(regmap, JZ4760_CODEC_REG_IFR, REG_IFR_ALL_MASK);
+
+		regmap_clear_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB);
+		msleep(250);
+		regmap_clear_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB_SLEEP);
+		msleep(400);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		regmap_set_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB_SLEEP);
+		regmap_set_bits(regmap, JZ4760_CODEC_REG_PMR1, REG_PMR1_SB);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int jz4760_codec_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+	int ret;
+
+	/*
+	 * SYSCLK output from the codec to the AIC is required to keep the
+	 * DMA transfer going during playback when all audible outputs have
+	 * been disabled.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = snd_soc_dapm_force_enable_pin(dapm, "SYSCLK");
+	return 0;
+}
+
+static void jz4760_codec_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_dapm_disable_pin(dapm, "SYSCLK");
+}
+
+
+static int jz4760_codec_pcm_trigger(struct snd_pcm_substream *substream,
+				    int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			snd_soc_component_force_bias_level(codec, SND_SOC_BIAS_ON);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/* do nothing */
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int jz4760_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direction)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+	unsigned int gain_bit = mute ? REG_IFR_GDO : REG_IFR_GUP;
+	unsigned int val, reg;
+	int change, err;
+
+	change = snd_soc_component_update_bits(codec, JZ4760_CODEC_REG_CR2,
+					       REG_CR2_DAC_MUTE,
+					       mute ? REG_CR2_DAC_MUTE : 0);
+	if (change == 1) {
+		regmap_read(jz_codec->regmap, JZ4760_CODEC_REG_PMR2, &val);
+
+		if (val & BIT(REG_PMR2_SB_DAC_OFFSET))
+			return 1;
+
+		err = regmap_read_poll_timeout(jz_codec->regmap,
+					       JZ4760_CODEC_REG_IFR,
+					       val, val & gain_bit,
+					       1000, 1 * USEC_PER_SEC);
+		if (err) {
+			dev_err(jz_codec->dev,
+				"Timeout while setting digital mute: %d", err);
+			return err;
+		}
+
+		/* clear GUP/GDO flag */
+		regmap_write(jz_codec->regmap, JZ4760_CODEC_REG_IFR, gain_bit);
+	}
+
+	regmap_read(jz_codec->regmap, JZ4760_CODEC_REG_CR2, &reg);
+
+	return 0;
+}
+
+/* unit: 0.01dB */
+static const DECLARE_TLV_DB_MINMAX_MUTE(dac_tlv, -3100, 100);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_MINMAX(out_tlv, -2500, 100);
+static const DECLARE_TLV_DB_SCALE(linein_tlv, -2500, 100, 0);
+
+/* Unconditional controls. */
+static const struct snd_kcontrol_new jz4760_codec_snd_controls[] = {
+	/* record gain control */
+	SOC_DOUBLE_R_TLV("PCM Capture Volume",
+			 JZ4760_CODEC_REG_GCR9, JZ4760_CODEC_REG_GCR8,
+			 REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 0, adc_tlv),
+
+	SOC_DOUBLE_R_TLV("Line In Bypass Playback Volume",
+			 JZ4760_CODEC_REG_GCR4, JZ4760_CODEC_REG_GCR3,
+			 REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, linein_tlv),
+
+	SOC_SINGLE("High-Pass Filter Capture Switch",
+		   JZ4760_CODEC_REG_CR4,
+		   REG_CR4_ADC_HPF_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4760_codec_pcm_playback_controls[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Volume",
+		.info = snd_soc_info_volsw,
+		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
+			| SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.tlv.p = dac_tlv,
+		.get = snd_soc_dapm_get_volsw,
+		.put = snd_soc_dapm_put_volsw,
+		.private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR6,
+						    JZ4760_CODEC_REG_GCR5,
+						    REG_GCR_GAIN_OFFSET,
+						    REG_GCR_GAIN_MAX, 1),
+	},
+};
+
+static const struct snd_kcontrol_new jz4760_codec_hp_playback_controls[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Volume",
+		.info = snd_soc_info_volsw,
+		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
+			| SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.tlv.p = out_tlv,
+		.get = snd_soc_dapm_get_volsw,
+		.put = snd_soc_dapm_put_volsw,
+		.private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR2,
+						    JZ4760_CODEC_REG_GCR1,
+						    REG_GCR_GAIN_OFFSET,
+						    REG_GCR_GAIN_MAX, 1),
+	},
+};
+
+static int hpout_event(struct snd_soc_dapm_widget *w,
+		       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+	struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+	unsigned int val;
+	int err;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* unmute HP */
+		regmap_clear_bits(jz_codec->regmap, JZ4760_CODEC_REG_CR1,
+				  REG_CR1_HP_MUTE);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		/* wait for ramp-up complete (RUP) */
+		err = regmap_read_poll_timeout(jz_codec->regmap,
+					       JZ4760_CODEC_REG_IFR,
+					       val, val & REG_IFR_RUP,
+					       1000, 1 * USEC_PER_SEC);
+		if (err) {
+			dev_err(jz_codec->dev, "RUP timeout: %d", err);
+			return err;
+		}
+
+		/* clear RUP flag */
+		regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_IFR,
+				REG_IFR_RUP);
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* mute HP */
+		regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_CR1,
+				REG_CR1_HP_MUTE);
+
+		err = regmap_read_poll_timeout(jz_codec->regmap,
+					       JZ4760_CODEC_REG_IFR,
+					       val, val & REG_IFR_RDO,
+					       1000, 1 * USEC_PER_SEC);
+		if (err) {
+			dev_err(jz_codec->dev, "RDO timeout: %d", err);
+			return err;
+		}
+
+		/* clear RDO flag */
+		regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_IFR,
+				REG_IFR_RDO);
+
+		break;
+	}
+
+	return 0;
+}
+
+static const char * const jz4760_codec_hp_texts[] = {
+	"PCM", "Line In", "Mic 1", "Mic 2"
+};
+
+static const unsigned int jz4760_codec_hp_values[] = { 3, 2, 0, 1 };
+
+static SOC_VALUE_ENUM_SINGLE_DECL(jz4760_codec_hp_enum,
+				  JZ4760_CODEC_REG_CR1,
+				  REG_CR1_OUTSEL_OFFSET,
+				  REG_CR1_OUTSEL_MASK >> REG_CR1_OUTSEL_OFFSET,
+				  jz4760_codec_hp_texts,
+				  jz4760_codec_hp_values);
+static const struct snd_kcontrol_new jz4760_codec_hp_source =
+			SOC_DAPM_ENUM("Route", jz4760_codec_hp_enum);
+
+static const char * const jz4760_codec_cap_texts[] = {
+	"Line In", "Mic 1", "Mic 2"
+};
+
+static const unsigned int jz4760_codec_cap_values[] = { 2, 0, 1 };
+
+static SOC_VALUE_ENUM_SINGLE_DECL(jz4760_codec_cap_enum,
+				  JZ4760_CODEC_REG_CR3,
+				  REG_CR3_ADC_INSEL_OFFSET,
+				  REG_CR3_ADC_INSEL_MASK >> REG_CR3_ADC_INSEL_OFFSET,
+				  jz4760_codec_cap_texts,
+				  jz4760_codec_cap_values);
+static const struct snd_kcontrol_new jz4760_codec_cap_source =
+			SOC_DAPM_ENUM("Route", jz4760_codec_cap_enum);
+
+static const struct snd_kcontrol_new jz4760_codec_mic_controls[] = {
+	SOC_DAPM_SINGLE("Stereo Capture Switch", JZ4760_CODEC_REG_CR3,
+			REG_CR3_MICSTEREO_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4760_codec_line_out_switch =
+	SOC_DAPM_SINGLE("Switch", JZ4760_CODEC_REG_CR1,
+			REG_CR1_LO_MUTE_OFFSET, 0, 0);
+static const struct snd_kcontrol_new jz4760_codec_btl_out_switch =
+	SOC_DAPM_SINGLE("Switch", JZ4760_CODEC_REG_CR1,
+			REG_CR1_BTL_MUTE_OFFSET, 0, 0);
+
+static const struct snd_soc_dapm_widget jz4760_codec_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA_E("HP Out", JZ4760_CODEC_REG_PMR2,
+			   REG_PMR2_SB_HP_OFFSET, 1, NULL, 0, hpout_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SWITCH("Line Out", JZ4760_CODEC_REG_PMR2,
+			    REG_PMR2_SB_LOUT_OFFSET, 1,
+			    &jz4760_codec_line_out_switch),
+
+	SND_SOC_DAPM_SWITCH("BTL Out", JZ4760_CODEC_REG_PMR2,
+			    REG_PMR2_SB_BTL_OFFSET, 1,
+			    &jz4760_codec_btl_out_switch),
+
+	SND_SOC_DAPM_PGA("Line In", JZ4760_CODEC_REG_PMR1,
+			 REG_PMR1_SB_LINE_OFFSET, 1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Headphones Source", SND_SOC_NOPM, 0, 0,
+			 &jz4760_codec_hp_source),
+
+	SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+			 &jz4760_codec_cap_source),
+
+	SND_SOC_DAPM_PGA("Mic 1", JZ4760_CODEC_REG_PMR1,
+			 REG_PMR1_SB_MIC1_OFFSET, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Mic 2", JZ4760_CODEC_REG_PMR1,
+			 REG_PMR1_SB_MIC2_OFFSET, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Mic Diff", JZ4760_CODEC_REG_CR3,
+			 REG_CR3_MICDIFF_OFFSET, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Mic", SND_SOC_NOPM, 0, 0,
+			   jz4760_codec_mic_controls,
+			   ARRAY_SIZE(jz4760_codec_mic_controls)),
+
+	SND_SOC_DAPM_PGA("Line In Bypass", JZ4760_CODEC_REG_PMR1,
+			 REG_PMR1_SB_BYPASS_OFFSET, 1, NULL, 0),
+
+	SND_SOC_DAPM_ADC("ADC", "Capture", JZ4760_CODEC_REG_PMR2,
+			 REG_PMR2_SB_ADC_OFFSET, 1),
+
+	SND_SOC_DAPM_DAC("DAC", "Playback", JZ4760_CODEC_REG_PMR2,
+			 REG_PMR2_SB_DAC_OFFSET, 1),
+
+	SND_SOC_DAPM_MIXER("PCM Playback", SND_SOC_NOPM, 0, 0,
+			   jz4760_codec_pcm_playback_controls,
+			   ARRAY_SIZE(jz4760_codec_pcm_playback_controls)),
+
+	SND_SOC_DAPM_MIXER("Headphones Playback", SND_SOC_NOPM, 0, 0,
+			   jz4760_codec_hp_playback_controls,
+			   ARRAY_SIZE(jz4760_codec_hp_playback_controls)),
+
+	SND_SOC_DAPM_SUPPLY("MICBIAS", JZ4760_CODEC_REG_PMR1,
+			    REG_PMR1_SB_MICBIAS_OFFSET, 1, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("MIC1P"),
+	SND_SOC_DAPM_INPUT("MIC1N"),
+	SND_SOC_DAPM_INPUT("MIC2P"),
+	SND_SOC_DAPM_INPUT("MIC2N"),
+
+	SND_SOC_DAPM_INPUT("LLINEIN"),
+	SND_SOC_DAPM_INPUT("RLINEIN"),
+
+	SND_SOC_DAPM_OUTPUT("LHPOUT"),
+	SND_SOC_DAPM_OUTPUT("RHPOUT"),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+
+	SND_SOC_DAPM_OUTPUT("BTLP"),
+	SND_SOC_DAPM_OUTPUT("BTLN"),
+
+	SND_SOC_DAPM_OUTPUT("SYSCLK"),
+};
+
+/* Unconditional routes. */
+static const struct snd_soc_dapm_route jz4760_codec_dapm_routes[] = {
+	{ "Mic 1", NULL, "MIC1P" },
+	{ "Mic Diff", NULL, "MIC1N" },
+	{ "Mic 1", NULL, "Mic Diff" },
+	{ "Mic 2", NULL, "MIC2P" },
+	{ "Mic Diff", NULL, "MIC2N" },
+	{ "Mic 2", NULL, "Mic Diff" },
+
+	{ "Line In", NULL, "LLINEIN" },
+	{ "Line In", NULL, "RLINEIN" },
+
+	{ "Mic", "Stereo Capture Switch", "Mic 1" },
+	{ "Mic", "Stereo Capture Switch", "Mic 2" },
+	{ "Headphones Source", "Mic 1", "Mic" },
+	{ "Headphones Source", "Mic 2", "Mic" },
+	{ "Capture Source", "Mic 1", "Mic" },
+	{ "Capture Source", "Mic 2", "Mic" },
+
+	{ "Capture Source", "Line In", "Line In" },
+	{ "Capture Source", "Mic 1", "Mic 1" },
+	{ "Capture Source", "Mic 2", "Mic 2" },
+	{ "ADC", NULL, "Capture Source" },
+
+	{ "Line In Bypass", NULL, "Line In" },
+
+	{ "Headphones Source", "Mic 1", "Mic 1" },
+	{ "Headphones Source", "Mic 2", "Mic 2" },
+	{ "Headphones Source", "Line In", "Line In Bypass" },
+	{ "Headphones Source", "PCM", "Headphones Playback" },
+	{ "HP Out", NULL, "Headphones Source" },
+
+	{ "LHPOUT", NULL, "HP Out" },
+	{ "RHPOUT", NULL, "HP Out" },
+	{ "Line Out", "Switch", "HP Out" },
+
+	{ "LOUT", NULL, "Line Out" },
+	{ "ROUT", NULL, "Line Out" },
+	{ "BTL Out", "Switch", "Line Out" },
+
+	{ "BTLP", NULL, "BTL Out"},
+	{ "BTLN", NULL, "BTL Out"},
+
+	{ "PCM Playback", "Volume", "DAC" },
+	{ "Headphones Playback", "Volume", "PCM Playback" },
+
+	{ "SYSCLK", NULL, "DAC" },
+};
+
+static void jz4760_codec_codec_init_regs(struct snd_soc_component *codec)
+{
+	struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+	struct regmap *regmap = jz_codec->regmap;
+
+	/* Collect updates for later sending. */
+	regcache_cache_only(regmap, true);
+
+	/* default Amp output to PCM */
+	regmap_set_bits(regmap, JZ4760_CODEC_REG_CR1, REG_CR1_OUTSEL_MASK);
+
+	/* Disable stereo mic */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_CR3,
+			  BIT(REG_CR3_MICSTEREO_OFFSET));
+
+	/* Set mic 1 as default source for ADC */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_CR3,
+			  REG_CR3_ADC_INSEL_MASK);
+
+	/* ADC/DAC: serial + i2s */
+	regmap_set_bits(regmap, JZ4760_CODEC_REG_AICR,
+			REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S |
+			REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
+
+	/* The generated IRQ is a high level */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_ICR, REG_ICR_INT_FORM_MASK);
+	regmap_update_bits(regmap, JZ4760_CODEC_REG_ICR, REG_ICR_ALL_MASK,
+			   REG_ICR_JACK_MASK | REG_ICR_RUP_MASK |
+			   REG_ICR_RDO_MASK  | REG_ICR_GUP_MASK |
+			   REG_ICR_GDO_MASK);
+
+	/* 12M oscillator */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_CCR1, REG_CCR1_CRYSTAL_MASK);
+
+	/* 0: 16ohm/220uF, 1: 10kohm/1uF */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_CR1, REG_CR1_HP_LOAD);
+
+	/* default to NOMAD */
+	regmap_set_bits(jz_codec->regmap, JZ4760_CODEC_REG_CR2,
+			REG_CR2_DAC_NOMAD);
+
+	/* disable automatic gain */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_AGC1, REG_AGC1_EN);
+
+	/* Independent L/R DAC gain control */
+	regmap_clear_bits(regmap, JZ4760_CODEC_REG_GCR5,
+			  REG_GCR_RL);
+
+	/* Send collected updates. */
+	regcache_cache_only(regmap, false);
+	regcache_sync(regmap);
+}
+
+static int jz4760_codec_codec_probe(struct snd_soc_component *codec)
+{
+	struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+
+	clk_prepare_enable(jz_codec->clk);
+
+	jz4760_codec_codec_init_regs(codec);
+
+	return 0;
+}
+
+static void jz4760_codec_codec_remove(struct snd_soc_component *codec)
+{
+	struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
+
+	clk_disable_unprepare(jz_codec->clk);
+}
+
+static const struct snd_soc_component_driver jz4760_codec_soc_codec_dev = {
+	.probe			= jz4760_codec_codec_probe,
+	.remove			= jz4760_codec_codec_remove,
+	.set_bias_level		= jz4760_codec_set_bias_level,
+	.controls		= jz4760_codec_snd_controls,
+	.num_controls		= ARRAY_SIZE(jz4760_codec_snd_controls),
+	.dapm_widgets		= jz4760_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(jz4760_codec_dapm_widgets),
+	.dapm_routes		= jz4760_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(jz4760_codec_dapm_routes),
+	.suspend_bias_off	= 1,
+	.use_pmdown_time	= 1,
+};
+
+static const unsigned int jz4760_codec_sample_rates[] = {
+	96000, 48000, 44100, 32000,
+	24000, 22050, 16000, 12000,
+	11025, 9600, 8000,
+};
+
+static int jz4760_codec_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct jz_codec *codec = snd_soc_component_get_drvdata(dai->component);
+	unsigned int rate, bit_width;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bit_width = 0;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		bit_width = 1;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		bit_width = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		bit_width = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (rate = 0; rate < ARRAY_SIZE(jz4760_codec_sample_rates); rate++) {
+		if (jz4760_codec_sample_rates[rate] == params_rate(params))
+			break;
+	}
+
+	if (rate == ARRAY_SIZE(jz4760_codec_sample_rates))
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_AICR,
+				   REG_AICR_DAC_ADWL_MASK,
+				   FIELD_PREP(REG_AICR_DAC_ADWL_MASK, bit_width));
+		regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_CCR2,
+				   REG_CCR2_DAC_FREQ_MASK,
+				   FIELD_PREP(REG_CCR2_DAC_FREQ_MASK, rate));
+	} else {
+		regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_AICR,
+				   REG_AICR_ADC_ADWL_MASK,
+				   FIELD_PREP(REG_AICR_ADC_ADWL_MASK, bit_width));
+		regmap_update_bits(codec->regmap, JZ4760_CODEC_REG_CCR2,
+				   REG_CCR2_ADC_FREQ_MASK,
+				   FIELD_PREP(REG_CCR2_ADC_FREQ_MASK, rate));
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops jz4760_codec_dai_ops = {
+	.startup	= jz4760_codec_startup,
+	.shutdown	= jz4760_codec_shutdown,
+	.hw_params	= jz4760_codec_hw_params,
+	.trigger	= jz4760_codec_pcm_trigger,
+	.mute_stream	= jz4760_codec_mute_stream,
+	.no_capture_mute = 1,
+};
+
+#define JZ_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | \
+			  SNDRV_PCM_FMTBIT_S18_3LE | \
+			  SNDRV_PCM_FMTBIT_S20_3LE | \
+			  SNDRV_PCM_FMTBIT_S24_3LE)
+
+static struct snd_soc_dai_driver jz4760_codec_dai = {
+	.name = "jz4760-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = JZ_CODEC_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = JZ_CODEC_FORMATS,
+	},
+	.ops = &jz4760_codec_dai_ops,
+};
+
+static bool jz4760_codec_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == JZ4760_CODEC_REG_SR || reg == JZ4760_CODEC_REG_IFR;
+}
+
+static bool jz4760_codec_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case JZ4760_CODEC_REG_SR:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static int jz4760_codec_io_wait(struct jz_codec *codec)
+{
+	u32 reg;
+
+	return readl_poll_timeout(codec->base + ICDC_RGADW_OFFSET, reg,
+				  !(reg & ICDC_RGADW_RGWR),
+				  1000, 1 * USEC_PER_SEC);
+}
+
+static int jz4760_codec_reg_read(void *context, unsigned int reg,
+				 unsigned int *val)
+{
+	struct jz_codec *codec = context;
+	unsigned int i;
+	u32 tmp;
+	int ret;
+
+	ret = jz4760_codec_io_wait(codec);
+	if (ret)
+		return ret;
+
+	tmp = readl(codec->base + ICDC_RGADW_OFFSET);
+	tmp &= ~ICDC_RGADW_RGADDR_MASK;
+	tmp |= FIELD_PREP(ICDC_RGADW_RGADDR_MASK, reg);
+	writel(tmp, codec->base + ICDC_RGADW_OFFSET);
+
+	/* wait 6+ cycles */
+	for (i = 0; i < 6; i++)
+		*val = readl(codec->base + ICDC_RGDATA_OFFSET) &
+			ICDC_RGDATA_RGDOUT_MASK;
+
+	return 0;
+}
+
+static int jz4760_codec_reg_write(void *context, unsigned int reg,
+				  unsigned int val)
+{
+	struct jz_codec *codec = context;
+	int ret;
+
+	ret = jz4760_codec_io_wait(codec);
+	if (ret)
+		return ret;
+
+	writel(ICDC_RGADW_RGWR | FIELD_PREP(ICDC_RGADW_RGADDR_MASK, reg) | val,
+	       codec->base + ICDC_RGADW_OFFSET);
+
+	ret = jz4760_codec_io_wait(codec);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const u8 jz4760_codec_reg_defaults[] = {
+	0x00, 0xFC, 0x1B, 0x20, 0x00, 0x80, 0x00, 0x00,
+	0xFF, 0x1F, 0x3F, 0x00, 0x06, 0x06, 0x06, 0x06,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x07, 0x44,
+	0x1F, 0x00, 0x00, 0x00
+};
+
+static struct regmap_config jz4760_codec_regmap_config = {
+	.reg_bits = 7,
+	.val_bits = 8,
+
+	.max_register = JZ4760_CODEC_REG_MIX2,
+	.volatile_reg = jz4760_codec_volatile,
+	.writeable_reg = jz4760_codec_writeable,
+
+	.reg_read = jz4760_codec_reg_read,
+	.reg_write = jz4760_codec_reg_write,
+
+	.reg_defaults_raw = jz4760_codec_reg_defaults,
+	.num_reg_defaults_raw = ARRAY_SIZE(jz4760_codec_reg_defaults),
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int jz4760_codec_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct jz_codec *codec;
+	int ret;
+
+	codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
+	if (!codec)
+		return -ENOMEM;
+
+	codec->dev = dev;
+
+	codec->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(codec->base)) {
+		ret = PTR_ERR(codec->base);
+		dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
+		return ret;
+	}
+
+	codec->regmap = devm_regmap_init(dev, NULL, codec,
+					&jz4760_codec_regmap_config);
+	if (IS_ERR(codec->regmap))
+		return PTR_ERR(codec->regmap);
+
+	codec->clk = devm_clk_get(dev, "aic");
+	if (IS_ERR(codec->clk))
+		return PTR_ERR(codec->clk);
+
+	platform_set_drvdata(pdev, codec);
+
+	ret = devm_snd_soc_register_component(dev, &jz4760_codec_soc_codec_dev,
+					      &jz4760_codec_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id jz4760_codec_of_matches[] = {
+	{ .compatible = "ingenic,jz4760-codec", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jz4760_codec_of_matches);
+
+static struct platform_driver jz4760_codec_driver = {
+	.probe			= jz4760_codec_probe,
+	.driver			= {
+		.name		= "jz4760-codec",
+		.of_match_table = jz4760_codec_of_matches,
+	},
+};
+module_platform_driver(jz4760_codec_driver);
+
+MODULE_DESCRIPTION("JZ4760 SoC internal codec driver");
+MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 06ab61f6f7199ccd58ce163021c4e521ca6b0eb2..eb3dd0bd80d9a8dd8144d5e17d59679821d934cb 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1343,7 +1343,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
 			.formats = LM49453_FORMATS,
 		},
 		.ops = &lm49453_headset_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "LM49453 Speaker",
diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c
index 3209b39e46aff54d5ccc8143dfacc9ebad030129..54426a90bc0bfe0a5812c7ed7a64c933397200fd 100644
--- a/sound/soc/codecs/lochnagar-sc.c
+++ b/sound/soc/codecs/lochnagar-sc.c
@@ -166,8 +166,8 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
 			.formats = SNDRV_PCM_FMTBIT_S32_LE,
 		},
 		.ops = &lochnagar_sc_line_ops,
-		.symmetric_rates = true,
-		.symmetric_samplebits = true,
+		.symmetric_rate = true,
+		.symmetric_sample_bits = true,
 	},
 	{
 		.name = "lochnagar-usb1",
@@ -186,8 +186,8 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
 			.formats = SNDRV_PCM_FMTBIT_S32_LE,
 		},
 		.ops = &lochnagar_sc_usb_ops,
-		.symmetric_rates = true,
-		.symmetric_samplebits = true,
+		.symmetric_rate = true,
+		.symmetric_sample_bits = true,
 	},
 	{
 		.name = "lochnagar-usb2",
@@ -206,8 +206,8 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
 			.formats = SNDRV_PCM_FMTBIT_S32_LE,
 		},
 		.ops = &lochnagar_sc_usb_ops,
-		.symmetric_rates = true,
-		.symmetric_samplebits = true,
+		.symmetric_rate = true,
+		.symmetric_sample_bits = true,
 	},
 };
 
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9c21d22c2c454ef6f2e49b30bf54e4ada971fd4
--- /dev/null
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -0,0 +1,3599 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+
+#define CDC_RX_TOP_TOP_CFG0		(0x0000)
+#define CDC_RX_TOP_SWR_CTRL		(0x0008)
+#define CDC_RX_TOP_DEBUG		(0x000C)
+#define CDC_RX_TOP_DEBUG_BUS		(0x0010)
+#define CDC_RX_TOP_DEBUG_EN0		(0x0014)
+#define CDC_RX_TOP_DEBUG_EN1		(0x0018)
+#define CDC_RX_TOP_DEBUG_EN2		(0x001C)
+#define CDC_RX_TOP_HPHL_COMP_WR_LSB	(0x0020)
+#define CDC_RX_TOP_HPHL_COMP_WR_MSB	(0x0024)
+#define CDC_RX_TOP_HPHL_COMP_LUT	(0x0028)
+#define CDC_RX_TOP_HPH_LUT_BYPASS_MASK	BIT(7)
+#define CDC_RX_TOP_HPHL_COMP_RD_LSB	(0x002C)
+#define CDC_RX_TOP_HPHL_COMP_RD_MSB	(0x0030)
+#define CDC_RX_TOP_HPHR_COMP_WR_LSB	(0x0034)
+#define CDC_RX_TOP_HPHR_COMP_WR_MSB	(0x0038)
+#define CDC_RX_TOP_HPHR_COMP_LUT	(0x003C)
+#define CDC_RX_TOP_HPHR_COMP_RD_LSB	(0x0040)
+#define CDC_RX_TOP_HPHR_COMP_RD_MSB	(0x0044)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG0	(0x0070)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG1	(0x0074)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG2	(0x0078)
+#define CDC_RX_TOP_DSD0_DEBUG_CFG3	(0x007C)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG0	(0x0080)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG1	(0x0084)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG2	(0x0088)
+#define CDC_RX_TOP_DSD1_DEBUG_CFG3	(0x008C)
+#define CDC_RX_TOP_RX_I2S_CTL		(0x0090)
+#define CDC_RX_TOP_TX_I2S2_CTL		(0x0094)
+#define CDC_RX_TOP_I2S_CLK		(0x0098)
+#define CDC_RX_TOP_I2S_RESET		(0x009C)
+#define CDC_RX_TOP_I2S_MUX		(0x00A0)
+#define CDC_RX_CLK_RST_CTRL_MCLK_CONTROL	(0x0100)
+#define CDC_RX_CLK_MCLK_EN_MASK		BIT(0)
+#define CDC_RX_CLK_MCLK_ENABLE		BIT(0)
+#define CDC_RX_CLK_MCLK2_EN_MASK	BIT(1)
+#define CDC_RX_CLK_MCLK2_ENABLE		BIT(1)
+#define CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL	(0x0104)
+#define CDC_RX_FS_MCLK_CNT_EN_MASK	BIT(0)
+#define CDC_RX_FS_MCLK_CNT_ENABLE	BIT(0)
+#define CDC_RX_FS_MCLK_CNT_CLR_MASK	BIT(1)
+#define CDC_RX_FS_MCLK_CNT_CLR		BIT(1)
+#define CDC_RX_CLK_RST_CTRL_SWR_CONTROL	(0x0108)
+#define CDC_RX_SWR_CLK_EN_MASK		BIT(0)
+#define CDC_RX_SWR_RESET_MASK		BIT(1)
+#define CDC_RX_SWR_RESET		BIT(1)
+#define CDC_RX_CLK_RST_CTRL_DSD_CONTROL	(0x010C)
+#define CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL	(0x0110)
+#define CDC_RX_SOFTCLIP_CRC		(0x0140)
+#define CDC_RX_SOFTCLIP_CLK_EN_MASK	BIT(0)
+#define CDC_RX_SOFTCLIP_SOFTCLIP_CTRL	(0x0144)
+#define CDC_RX_SOFTCLIP_EN_MASK		BIT(0)
+#define CDC_RX_INP_MUX_RX_INT0_CFG0	(0x0180)
+#define CDC_RX_INTX_1_MIX_INP0_SEL_MASK	GENMASK(3, 0)
+#define CDC_RX_INTX_1_MIX_INP1_SEL_MASK	GENMASK(7, 4)
+#define CDC_RX_INP_MUX_RX_INT0_CFG1	(0x0184)
+#define CDC_RX_INTX_2_SEL_MASK		GENMASK(3, 0)
+#define CDC_RX_INTX_1_MIX_INP2_SEL_MASK	GENMASK(7, 4)
+#define CDC_RX_INP_MUX_RX_INT1_CFG0	(0x0188)
+#define CDC_RX_INP_MUX_RX_INT1_CFG1	(0x018C)
+#define CDC_RX_INP_MUX_RX_INT2_CFG0	(0x0190)
+#define CDC_RX_INP_MUX_RX_INT2_CFG1	(0x0194)
+#define CDC_RX_INP_MUX_RX_MIX_CFG4	(0x0198)
+#define CDC_RX_INP_MUX_RX_MIX_CFG5	(0x019C)
+#define CDC_RX_INP_MUX_SIDETONE_SRC_CFG0	(0x01A0)
+#define CDC_RX_CLSH_CRC			(0x0200)
+#define CDC_RX_CLSH_CLK_EN_MASK		BIT(0)
+#define CDC_RX_CLSH_DLY_CTRL		(0x0204)
+#define CDC_RX_CLSH_DECAY_CTRL		(0x0208)
+#define CDC_RX_CLSH_DECAY_RATE_MASK	GENMASK(2, 0)
+#define CDC_RX_CLSH_HPH_V_PA		(0x020C)
+#define CDC_RX_CLSH_HPH_V_PA_MIN_MASK	GENMASK(5, 0)
+#define CDC_RX_CLSH_EAR_V_PA		(0x0210)
+#define CDC_RX_CLSH_HPH_V_HD		(0x0214)
+#define CDC_RX_CLSH_EAR_V_HD		(0x0218)
+#define CDC_RX_CLSH_K1_MSB		(0x021C)
+#define CDC_RX_CLSH_K1_MSB_COEFF_MASK	GENMASK(3, 0)
+#define CDC_RX_CLSH_K1_LSB		(0x0220)
+#define CDC_RX_CLSH_K2_MSB		(0x0224)
+#define CDC_RX_CLSH_K2_LSB		(0x0228)
+#define CDC_RX_CLSH_IDLE_CTRL		(0x022C)
+#define CDC_RX_CLSH_IDLE_HPH		(0x0230)
+#define CDC_RX_CLSH_IDLE_EAR		(0x0234)
+#define CDC_RX_CLSH_TEST0		(0x0238)
+#define CDC_RX_CLSH_TEST1		(0x023C)
+#define CDC_RX_CLSH_OVR_VREF		(0x0240)
+#define CDC_RX_CLSH_CLSG_CTL		(0x0244)
+#define CDC_RX_CLSH_CLSG_CFG1		(0x0248)
+#define CDC_RX_CLSH_CLSG_CFG2		(0x024C)
+#define CDC_RX_BCL_VBAT_PATH_CTL	(0x0280)
+#define CDC_RX_BCL_VBAT_CFG		(0x0284)
+#define CDC_RX_BCL_VBAT_ADC_CAL1	(0x0288)
+#define CDC_RX_BCL_VBAT_ADC_CAL2	(0x028C)
+#define CDC_RX_BCL_VBAT_ADC_CAL3	(0x0290)
+#define CDC_RX_BCL_VBAT_PK_EST1		(0x0294)
+#define CDC_RX_BCL_VBAT_PK_EST2		(0x0298)
+#define CDC_RX_BCL_VBAT_PK_EST3		(0x029C)
+#define CDC_RX_BCL_VBAT_RF_PROC1	(0x02A0)
+#define CDC_RX_BCL_VBAT_RF_PROC2	(0x02A4)
+#define CDC_RX_BCL_VBAT_TAC1		(0x02A8)
+#define CDC_RX_BCL_VBAT_TAC2		(0x02AC)
+#define CDC_RX_BCL_VBAT_TAC3		(0x02B0)
+#define CDC_RX_BCL_VBAT_TAC4		(0x02B4)
+#define CDC_RX_BCL_VBAT_GAIN_UPD1	(0x02B8)
+#define CDC_RX_BCL_VBAT_GAIN_UPD2	(0x02BC)
+#define CDC_RX_BCL_VBAT_GAIN_UPD3	(0x02C0)
+#define CDC_RX_BCL_VBAT_GAIN_UPD4	(0x02C4)
+#define CDC_RX_BCL_VBAT_GAIN_UPD5	(0x02C8)
+#define CDC_RX_BCL_VBAT_DEBUG1		(0x02CC)
+#define CDC_RX_BCL_VBAT_GAIN_UPD_MON	(0x02D0)
+#define CDC_RX_BCL_VBAT_GAIN_MON_VAL	(0x02D4)
+#define CDC_RX_BCL_VBAT_BAN		(0x02D8)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD1	(0x02DC)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD2	(0x02E0)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD3	(0x02E4)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD4	(0x02E8)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD5	(0x02EC)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD6	(0x02F0)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD7	(0x02F4)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD8	(0x02F8)
+#define CDC_RX_BCL_VBAT_BCL_GAIN_UPD9	(0x02FC)
+#define CDC_RX_BCL_VBAT_ATTN1		(0x0300)
+#define CDC_RX_BCL_VBAT_ATTN2		(0x0304)
+#define CDC_RX_BCL_VBAT_ATTN3		(0x0308)
+#define CDC_RX_BCL_VBAT_DECODE_CTL1	(0x030C)
+#define CDC_RX_BCL_VBAT_DECODE_CTL2	(0x0310)
+#define CDC_RX_BCL_VBAT_DECODE_CFG1	(0x0314)
+#define CDC_RX_BCL_VBAT_DECODE_CFG2	(0x0318)
+#define CDC_RX_BCL_VBAT_DECODE_CFG3	(0x031C)
+#define CDC_RX_BCL_VBAT_DECODE_CFG4	(0x0320)
+#define CDC_RX_BCL_VBAT_DECODE_ST	(0x0324)
+#define CDC_RX_INTR_CTRL_CFG		(0x0340)
+#define CDC_RX_INTR_CTRL_CLR_COMMIT	(0x0344)
+#define CDC_RX_INTR_CTRL_PIN1_MASK0	(0x0360)
+#define CDC_RX_INTR_CTRL_PIN1_STATUS0	(0x0368)
+#define CDC_RX_INTR_CTRL_PIN1_CLEAR0	(0x0370)
+#define CDC_RX_INTR_CTRL_PIN2_MASK0	(0x0380)
+#define CDC_RX_INTR_CTRL_PIN2_STATUS0	(0x0388)
+#define CDC_RX_INTR_CTRL_PIN2_CLEAR0	(0x0390)
+#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_RX0_RX_PATH_CTL		(0x0400)
+#define CDC_RX_PATH_RESET_EN_MASK	BIT(6)
+#define CDC_RX_PATH_CLK_EN_MASK		BIT(5)
+#define CDC_RX_PATH_CLK_ENABLE		BIT(5)
+#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_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_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_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_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_RX0_RX_VOL_CTL		(0x0414)
+#define CDC_RX_RXn_RX_PATH_MIX_CTL(n)	(0x0418 + 0x80 * 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_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_RX0_RX_PATH_SEC4		(0x0430)
+#define CDC_RX_RX0_RX_PATH_SEC7		(0x0434)
+#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_DSM_CLK_EN_MASK	BIT(0)
+#define CDC_RX_RX0_RX_PATH_DSM_CTL	(0x0440)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA1	(0x0444)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA2	(0x0448)
+#define CDC_RX_RX0_RX_PATH_DSM_DATA3	(0x044C)
+#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)
+#define CDC_RX_RX1_RX_PATH_CTL		(0x0480)
+#define CDC_RX_RX1_RX_PATH_CFG0		(0x0484)
+#define CDC_RX_RX1_RX_PATH_CFG1		(0x0488)
+#define CDC_RX_RX1_RX_PATH_CFG2		(0x048C)
+#define CDC_RX_RX1_RX_PATH_CFG3		(0x0490)
+#define CDC_RX_RX1_RX_VOL_CTL		(0x0494)
+#define CDC_RX_RX1_RX_PATH_MIX_CTL	(0x0498)
+#define CDC_RX_RX1_RX_PATH_MIX_CFG	(0x049C)
+#define CDC_RX_RX1_RX_VOL_MIX_CTL	(0x04A0)
+#define CDC_RX_RX1_RX_PATH_SEC1		(0x04A4)
+#define CDC_RX_RX1_RX_PATH_SEC2		(0x04A8)
+#define CDC_RX_RX1_RX_PATH_SEC3		(0x04AC)
+#define CDC_RX_RXn_HD2_ALPHA_MASK	GENMASK(5, 2)
+#define CDC_RX_RX1_RX_PATH_SEC4		(0x04B0)
+#define CDC_RX_RX1_RX_PATH_SEC7		(0x04B4)
+#define CDC_RX_RX1_RX_PATH_MIX_SEC0	(0x04B8)
+#define CDC_RX_RX1_RX_PATH_MIX_SEC1	(0x04BC)
+#define CDC_RX_RX1_RX_PATH_DSM_CTL	(0x04C0)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA1	(0x04C4)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA2	(0x04C8)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA3	(0x04CC)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA4	(0x04D0)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA5	(0x04D4)
+#define CDC_RX_RX1_RX_PATH_DSM_DATA6	(0x04D8)
+#define CDC_RX_RX2_RX_PATH_CTL		(0x0500)
+#define CDC_RX_RX2_RX_PATH_CFG0		(0x0504)
+#define CDC_RX_RX2_CLSH_EN_MASK		BIT(4)
+#define CDC_RX_RX2_DLY_Z_EN_MASK	BIT(3)
+#define CDC_RX_RX2_RX_PATH_CFG1		(0x0508)
+#define CDC_RX_RX2_RX_PATH_CFG2		(0x050C)
+#define CDC_RX_RX2_RX_PATH_CFG3		(0x0510)
+#define CDC_RX_RX2_RX_VOL_CTL		(0x0514)
+#define CDC_RX_RX2_RX_PATH_MIX_CTL	(0x0518)
+#define CDC_RX_RX2_RX_PATH_MIX_CFG	(0x051C)
+#define CDC_RX_RX2_RX_VOL_MIX_CTL	(0x0520)
+#define CDC_RX_RX2_RX_PATH_SEC0		(0x0524)
+#define CDC_RX_RX2_RX_PATH_SEC1		(0x0528)
+#define CDC_RX_RX2_RX_PATH_SEC2		(0x052C)
+#define CDC_RX_RX2_RX_PATH_SEC3		(0x0530)
+#define CDC_RX_RX2_RX_PATH_SEC4		(0x0534)
+#define CDC_RX_RX2_RX_PATH_SEC5		(0x0538)
+#define CDC_RX_RX2_RX_PATH_SEC6		(0x053C)
+#define CDC_RX_RX2_RX_PATH_SEC7		(0x0540)
+#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)
+#define CDC_RX_IDLE_DETECT_PATH_CTL	(0x0780)
+#define CDC_RX_IDLE_DETECT_CFG0		(0x0784)
+#define CDC_RX_IDLE_DETECT_CFG1		(0x0788)
+#define CDC_RX_IDLE_DETECT_CFG2		(0x078C)
+#define CDC_RX_IDLE_DETECT_CFG3		(0x0790)
+#define CDC_RX_COMPANDERn_CTL0(n)	(0x0800 + 0x40 * n)
+#define CDC_RX_COMPANDERn_CLK_EN_MASK	BIT(0)
+#define CDC_RX_COMPANDERn_SOFT_RST_MASK	BIT(1)
+#define CDC_RX_COMPANDERn_HALT_MASK	BIT(2)
+#define CDC_RX_COMPANDER0_CTL0		(0x0800)
+#define CDC_RX_COMPANDER0_CTL1		(0x0804)
+#define CDC_RX_COMPANDER0_CTL2		(0x0808)
+#define CDC_RX_COMPANDER0_CTL3		(0x080C)
+#define CDC_RX_COMPANDER0_CTL4		(0x0810)
+#define CDC_RX_COMPANDER0_CTL5		(0x0814)
+#define CDC_RX_COMPANDER0_CTL6		(0x0818)
+#define CDC_RX_COMPANDER0_CTL7		(0x081C)
+#define CDC_RX_COMPANDER1_CTL0		(0x0840)
+#define CDC_RX_COMPANDER1_CTL1		(0x0844)
+#define CDC_RX_COMPANDER1_CTL2		(0x0848)
+#define CDC_RX_COMPANDER1_CTL3		(0x084C)
+#define CDC_RX_COMPANDER1_CTL4		(0x0850)
+#define CDC_RX_COMPANDER1_CTL5		(0x0854)
+#define CDC_RX_COMPANDER1_CTL6		(0x0858)
+#define CDC_RX_COMPANDER1_CTL7		(0x085C)
+#define CDC_RX_COMPANDER1_HPH_LOW_PWR_MODE_MASK	BIT(5)
+#define CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL	(0x0A00)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL	(0x0A04)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL	(0x0A08)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL	(0x0A0C)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL	(0x0A10)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL	(0x0A14)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL	(0x0A18)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL	(0x0A1C)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL	(0x0A20)
+#define CDC_RX_SIDETONE_IIR0_IIR_CTL		(0x0A24)
+#define CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL	(0x0A28)
+#define CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL	(0x0A2C)
+#define CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL	(0x0A30)
+#define CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL	(0x0A80)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL	(0x0A84)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL	(0x0A88)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL	(0x0A8C)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL	(0x0A90)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL	(0x0A94)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL	(0x0A98)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL	(0x0A9C)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL	(0x0AA0)
+#define CDC_RX_SIDETONE_IIR1_IIR_CTL		(0x0AA4)
+#define CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL	(0x0AA8)
+#define CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL	(0x0AAC)
+#define CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL	(0x0AB0)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0	(0x0B00)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1	(0x0B04)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2	(0x0B08)
+#define CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3	(0x0B0C)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0	(0x0B10)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1	(0x0B14)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2	(0x0B18)
+#define CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3	(0x0B1C)
+#define CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL	(0x0B40)
+#define CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1	(0x0B44)
+#define CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL	(0x0B50)
+#define CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1	(0x0B54)
+#define CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL	(0x0C00)
+#define CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0	(0x0C04)
+#define CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL	(0x0C40)
+#define CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0	(0x0C44)
+#define CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL	(0x0C80)
+#define CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0	(0x0C84)
+#define CDC_RX_EC_ASRC0_CLK_RST_CTL		(0x0D00)
+#define CDC_RX_EC_ASRC0_CTL0			(0x0D04)
+#define CDC_RX_EC_ASRC0_CTL1			(0x0D08)
+#define CDC_RX_EC_ASRC0_FIFO_CTL		(0x0D0C)
+#define CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB	(0x0D10)
+#define CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB	(0x0D14)
+#define CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB	(0x0D18)
+#define CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB	(0x0D1C)
+#define CDC_RX_EC_ASRC0_STATUS_FIFO		(0x0D20)
+#define CDC_RX_EC_ASRC1_CLK_RST_CTL		(0x0D40)
+#define CDC_RX_EC_ASRC1_CTL0			(0x0D44)
+#define CDC_RX_EC_ASRC1_CTL1			(0x0D48)
+#define CDC_RX_EC_ASRC1_FIFO_CTL		(0x0D4C)
+#define CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB	(0x0D50)
+#define CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB	(0x0D54)
+#define CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB	(0x0D58)
+#define CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB	(0x0D5C)
+#define CDC_RX_EC_ASRC1_STATUS_FIFO		(0x0D60)
+#define CDC_RX_EC_ASRC2_CLK_RST_CTL		(0x0D80)
+#define CDC_RX_EC_ASRC2_CTL0			(0x0D84)
+#define CDC_RX_EC_ASRC2_CTL1			(0x0D88)
+#define CDC_RX_EC_ASRC2_FIFO_CTL		(0x0D8C)
+#define CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB	(0x0D90)
+#define CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB	(0x0D94)
+#define CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB	(0x0D98)
+#define CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB	(0x0D9C)
+#define CDC_RX_EC_ASRC2_STATUS_FIFO		(0x0DA0)
+#define CDC_RX_DSD0_PATH_CTL			(0x0F00)
+#define CDC_RX_DSD0_CFG0			(0x0F04)
+#define CDC_RX_DSD0_CFG1			(0x0F08)
+#define CDC_RX_DSD0_CFG2			(0x0F0C)
+#define CDC_RX_DSD1_PATH_CTL			(0x0F80)
+#define CDC_RX_DSD1_CFG0			(0x0F84)
+#define CDC_RX_DSD1_CFG1			(0x0F88)
+#define CDC_RX_DSD1_CFG2			(0x0F8C)
+#define RX_MAX_OFFSET				(0x0F8C)
+
+#define MCLK_FREQ		9600000
+
+#define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+			SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define RX_MACRO_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define RX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define RX_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_48000)
+#define RX_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define RX_MACRO_MAX_DMA_CH_PER_PORT 2
+
+#define RX_MACRO_EC_MIX_TX0_MASK 0xf0
+#define RX_MACRO_EC_MIX_TX1_MASK 0x0f
+#define RX_MACRO_EC_MIX_TX2_MASK 0x0f
+
+#define COMP_MAX_COEFF 25
+#define RX_NUM_CLKS_MAX	5
+
+struct comp_coeff_val {
+	u8 lsb;
+	u8 msb;
+};
+
+enum {
+	HPH_ULP,
+	HPH_LOHIFI,
+	HPH_MODE_MAX,
+};
+
+static const struct comp_coeff_val comp_coeff_table[HPH_MODE_MAX][COMP_MAX_COEFF] = {
+	{
+		{0x40, 0x00},
+		{0x4C, 0x00},
+		{0x5A, 0x00},
+		{0x6B, 0x00},
+		{0x7F, 0x00},
+		{0x97, 0x00},
+		{0xB3, 0x00},
+		{0xD5, 0x00},
+		{0xFD, 0x00},
+		{0x2D, 0x01},
+		{0x66, 0x01},
+		{0xA7, 0x01},
+		{0xF8, 0x01},
+		{0x57, 0x02},
+		{0xC7, 0x02},
+		{0x4B, 0x03},
+		{0xE9, 0x03},
+		{0xA3, 0x04},
+		{0x7D, 0x05},
+		{0x90, 0x06},
+		{0xD1, 0x07},
+		{0x49, 0x09},
+		{0x00, 0x0B},
+		{0x01, 0x0D},
+		{0x59, 0x0F},
+	},
+	{
+		{0x40, 0x00},
+		{0x4C, 0x00},
+		{0x5A, 0x00},
+		{0x6B, 0x00},
+		{0x80, 0x00},
+		{0x98, 0x00},
+		{0xB4, 0x00},
+		{0xD5, 0x00},
+		{0xFE, 0x00},
+		{0x2E, 0x01},
+		{0x66, 0x01},
+		{0xA9, 0x01},
+		{0xF8, 0x01},
+		{0x56, 0x02},
+		{0xC4, 0x02},
+		{0x4F, 0x03},
+		{0xF0, 0x03},
+		{0xAE, 0x04},
+		{0x8B, 0x05},
+		{0x8E, 0x06},
+		{0xBC, 0x07},
+		{0x56, 0x09},
+		{0x0F, 0x0B},
+		{0x13, 0x0D},
+		{0x6F, 0x0F},
+	},
+};
+
+struct rx_macro_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+enum {
+	INTERP_HPHL,
+	INTERP_HPHR,
+	INTERP_AUX,
+	INTERP_MAX
+};
+
+enum {
+	RX_MACRO_RX0,
+	RX_MACRO_RX1,
+	RX_MACRO_RX2,
+	RX_MACRO_RX3,
+	RX_MACRO_RX4,
+	RX_MACRO_RX5,
+	RX_MACRO_PORTS_MAX
+};
+
+enum {
+	RX_MACRO_COMP1, /* HPH_L */
+	RX_MACRO_COMP2, /* HPH_R */
+	RX_MACRO_COMP_MAX
+};
+
+enum {
+	RX_MACRO_EC0_MUX = 0,
+	RX_MACRO_EC1_MUX,
+	RX_MACRO_EC2_MUX,
+	RX_MACRO_EC_MUX_MAX,
+};
+
+enum {
+	INTn_1_INP_SEL_ZERO = 0,
+	INTn_1_INP_SEL_DEC0,
+	INTn_1_INP_SEL_DEC1,
+	INTn_1_INP_SEL_IIR0,
+	INTn_1_INP_SEL_IIR1,
+	INTn_1_INP_SEL_RX0,
+	INTn_1_INP_SEL_RX1,
+	INTn_1_INP_SEL_RX2,
+	INTn_1_INP_SEL_RX3,
+	INTn_1_INP_SEL_RX4,
+	INTn_1_INP_SEL_RX5,
+};
+
+enum {
+	INTn_2_INP_SEL_ZERO = 0,
+	INTn_2_INP_SEL_RX0,
+	INTn_2_INP_SEL_RX1,
+	INTn_2_INP_SEL_RX2,
+	INTn_2_INP_SEL_RX3,
+	INTn_2_INP_SEL_RX4,
+	INTn_2_INP_SEL_RX5,
+};
+
+enum {
+	INTERP_MAIN_PATH,
+	INTERP_MIX_PATH,
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR0 = 0,
+	IIR1,
+	IIR_MAX,
+};
+
+/* Each IIR has 5 Filter Stages */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+#define RX_MACRO_IIR_FILTER_SIZE	(sizeof(u32) * BAND_MAX)
+
+#define RX_MACRO_IIR_FILTER_CTL(xname, iidx, bidx) \
+{ \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = rx_macro_iir_filter_info, \
+	.get = rx_macro_get_iir_band_audio_mixer, \
+	.put = rx_macro_put_iir_band_audio_mixer, \
+	.private_value = (unsigned long)&(struct wcd_iir_filter_ctl) { \
+		.iir_idx = iidx, \
+		.band_idx = bidx, \
+		.bytes_ext = {.max = RX_MACRO_IIR_FILTER_SIZE, }, \
+	} \
+}
+
+struct interp_sample_rate {
+	int sample_rate;
+	int rate_val;
+};
+
+static struct interp_sample_rate sr_val_tbl[] = {
+	{8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5},
+	{192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA},
+	{176400, 0xB}, {352800, 0xC},
+};
+
+enum {
+	RX_MACRO_AIF_INVALID = 0,
+	RX_MACRO_AIF1_PB,
+	RX_MACRO_AIF2_PB,
+	RX_MACRO_AIF3_PB,
+	RX_MACRO_AIF4_PB,
+	RX_MACRO_AIF_ECHO,
+	RX_MACRO_MAX_DAIS,
+};
+
+enum {
+	RX_MACRO_AIF1_CAP = 0,
+	RX_MACRO_AIF2_CAP,
+	RX_MACRO_AIF3_CAP,
+	RX_MACRO_MAX_AIF_CAP_DAIS
+};
+
+struct rx_macro {
+	struct device *dev;
+	int comp_enabled[RX_MACRO_COMP_MAX];
+	/* Main path clock users count */
+	int main_clk_users[INTERP_MAX];
+	int rx_port_value[RX_MACRO_PORTS_MAX];
+	u16 prim_int_users[INTERP_MAX];
+	int rx_mclk_users;
+	bool reset_swr;
+	int clsh_users;
+	int rx_mclk_cnt;
+	bool is_ear_mode_on;
+	bool hph_pwr_mode;
+	bool hph_hd2_mode;
+	struct snd_soc_component *component;
+	unsigned long active_ch_mask[RX_MACRO_MAX_DAIS];
+	unsigned long active_ch_cnt[RX_MACRO_MAX_DAIS];
+	u16 bit_width[RX_MACRO_MAX_DAIS];
+	int is_softclip_on;
+	int is_aux_hpf_on;
+	int softclip_clk_users;
+
+	struct regmap *regmap;
+	struct clk_bulk_data clks[RX_NUM_CLKS_MAX];
+	struct clk_hw hw;
+};
+#define to_rx_macro(_hw) container_of(_hw, struct rx_macro, hw)
+
+struct wcd_iir_filter_ctl {
+	unsigned int iir_idx;
+	unsigned int band_idx;
+	struct soc_bytes_ext bytes_ext;
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+static const char * const rx_int_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5"
+};
+
+static const char * const rx_prim_mix_text[] = {
+	"ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+	"RX3", "RX4", "RX5"
+};
+
+static const char * const rx_sidetone_mix_text[] = {
+	"ZERO", "SRC0", "SRC1", "SRC_SUM"
+};
+
+static const char * const iir_inp_mux_text[] = {
+	"ZERO", "DEC0", "DEC1", "DEC2", "DEC3",
+	"RX0", "RX1", "RX2", "RX3", "RX4", "RX5"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+	"NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_1_interp_mux_text[] = {
+	"ZERO", "RX INT0_1 MIX1",
+};
+
+static const char * const rx_int1_1_interp_mux_text[] = {
+	"ZERO", "RX INT1_1 MIX1",
+};
+
+static const char * const rx_int2_1_interp_mux_text[] = {
+	"ZERO", "RX INT2_1 MIX1",
+};
+
+static const char * const rx_int0_2_interp_mux_text[] = {
+	"ZERO", "RX INT0_2 MUX",
+};
+
+static const char * const rx_int1_2_interp_mux_text[] = {
+	"ZERO", "RX INT1_2 MUX",
+};
+
+static const char * const rx_int2_2_interp_mux_text[] = {
+	"ZERO", "RX INT2_2 MUX",
+};
+
+static const char *const rx_macro_mux_text[] = {
+	"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB"
+};
+
+static const char *const rx_macro_hph_pwr_mode_text[] = {
+	"ULP", "LOHIFI"
+};
+
+static const char * const rx_echo_mux_text[] = {
+	"ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2"
+};
+
+static const struct soc_enum rx_macro_hph_pwr_mode_enum =
+		SOC_ENUM_SINGLE_EXT(2, rx_macro_hph_pwr_mode_text);
+static const struct soc_enum rx_mix_tx2_mux_enum =
+		SOC_ENUM_SINGLE(CDC_RX_INP_MUX_RX_MIX_CFG5, 0, 4, rx_echo_mux_text);
+static const struct soc_enum rx_mix_tx1_mux_enum =
+		SOC_ENUM_SINGLE(CDC_RX_INP_MUX_RX_MIX_CFG4, 0, 4, rx_echo_mux_text);
+static const struct soc_enum rx_mix_tx0_mux_enum =
+		SOC_ENUM_SINGLE(CDC_RX_INP_MUX_RX_MIX_CFG4, 4, 4, rx_echo_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_2_enum, CDC_RX_INP_MUX_RX_INT0_CFG1, 0,
+			    rx_int_mix_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_2_enum, CDC_RX_INP_MUX_RX_INT1_CFG1, 0,
+			    rx_int_mix_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_2_enum, CDC_RX_INP_MUX_RX_INT2_CFG1, 0,
+			    rx_int_mix_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_mix_inp0_enum, CDC_RX_INP_MUX_RX_INT0_CFG0, 0,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_mix_inp1_enum, CDC_RX_INP_MUX_RX_INT0_CFG0, 4,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_mix_inp2_enum, CDC_RX_INP_MUX_RX_INT0_CFG1, 4,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_mix_inp0_enum, CDC_RX_INP_MUX_RX_INT1_CFG0, 0,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_mix_inp1_enum, CDC_RX_INP_MUX_RX_INT1_CFG0, 4,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_mix_inp2_enum, CDC_RX_INP_MUX_RX_INT1_CFG1, 4,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_mix_inp0_enum, CDC_RX_INP_MUX_RX_INT2_CFG0, 0,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_mix_inp1_enum, CDC_RX_INP_MUX_RX_INT2_CFG0, 4,
+			    rx_prim_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_mix_inp2_enum, CDC_RX_INP_MUX_RX_INT2_CFG1, 4,
+			    rx_prim_mix_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_mix2_inp_enum, CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2,
+			    rx_sidetone_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_mix2_inp_enum, CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4,
+			    rx_sidetone_mix_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_mix2_inp_enum, CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6,
+			    rx_sidetone_mix_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp0_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp1_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp2_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir0_inp3_enum, CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp0_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp1_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp2_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0,
+			    iir_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(iir1_inp3_enum, CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0,
+			    iir_inp_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rx_int0_1_interp_enum, SND_SOC_NOPM, 0,
+			    rx_int0_1_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_1_interp_enum, SND_SOC_NOPM, 0,
+			    rx_int1_1_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_1_interp_enum, SND_SOC_NOPM, 0,
+			    rx_int2_1_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int0_2_interp_enum, SND_SOC_NOPM, 0,
+			    rx_int0_2_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int1_2_interp_enum, SND_SOC_NOPM, 0,
+			    rx_int1_2_interp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_int2_2_interp_enum, SND_SOC_NOPM, 0,
+			    rx_int2_2_interp_mux_text);
+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_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);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx2_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx3_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx4_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_macro_rx5_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
+
+static const struct snd_kcontrol_new rx_mix_tx1_mux =
+		SOC_DAPM_ENUM("RX MIX TX1_MUX Mux", rx_mix_tx1_mux_enum);
+static const struct snd_kcontrol_new rx_mix_tx2_mux = 
+		SOC_DAPM_ENUM("RX MIX TX2_MUX Mux", rx_mix_tx2_mux_enum);
+static const struct snd_kcontrol_new rx_int0_2_mux =
+		SOC_DAPM_ENUM("rx_int0_2", rx_int0_2_enum);
+static const struct snd_kcontrol_new rx_int1_2_mux =
+		SOC_DAPM_ENUM("rx_int1_2", rx_int1_2_enum);
+static const struct snd_kcontrol_new rx_int2_2_mux =
+		SOC_DAPM_ENUM("rx_int2_2", rx_int2_2_enum);
+static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux =
+		SOC_DAPM_ENUM("rx_int0_1_mix_inp0", rx_int0_1_mix_inp0_enum);
+static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux =
+		SOC_DAPM_ENUM("rx_int0_1_mix_inp1", rx_int0_1_mix_inp1_enum);
+static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux =
+		SOC_DAPM_ENUM("rx_int0_1_mix_inp2", rx_int0_1_mix_inp2_enum);
+static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux =
+		SOC_DAPM_ENUM("rx_int1_1_mix_inp0", rx_int1_1_mix_inp0_enum);
+static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux =
+		SOC_DAPM_ENUM("rx_int1_1_mix_inp1", rx_int1_1_mix_inp1_enum);
+static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux =
+		SOC_DAPM_ENUM("rx_int1_1_mix_inp2", rx_int1_1_mix_inp2_enum);
+static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux =
+		SOC_DAPM_ENUM("rx_int2_1_mix_inp0", rx_int2_1_mix_inp0_enum);
+static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux =
+		SOC_DAPM_ENUM("rx_int2_1_mix_inp1", rx_int2_1_mix_inp1_enum);
+static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux =
+		SOC_DAPM_ENUM("rx_int2_1_mix_inp2", rx_int2_1_mix_inp2_enum);
+static const struct snd_kcontrol_new rx_int0_mix2_inp_mux =
+		SOC_DAPM_ENUM("rx_int0_mix2_inp", rx_int0_mix2_inp_enum);
+static const struct snd_kcontrol_new rx_int1_mix2_inp_mux =
+		SOC_DAPM_ENUM("rx_int1_mix2_inp", rx_int1_mix2_inp_enum);
+static const struct snd_kcontrol_new rx_int2_mix2_inp_mux =
+		SOC_DAPM_ENUM("rx_int2_mix2_inp", rx_int2_mix2_inp_enum);
+static const struct snd_kcontrol_new iir0_inp0_mux =
+		SOC_DAPM_ENUM("iir0_inp0", iir0_inp0_enum);
+static const struct snd_kcontrol_new iir0_inp1_mux =
+		SOC_DAPM_ENUM("iir0_inp1", iir0_inp1_enum);
+static const struct snd_kcontrol_new iir0_inp2_mux =
+		SOC_DAPM_ENUM("iir0_inp2", iir0_inp2_enum);
+static const struct snd_kcontrol_new iir0_inp3_mux =
+		SOC_DAPM_ENUM("iir0_inp3", iir0_inp3_enum);
+static const struct snd_kcontrol_new iir1_inp0_mux =
+		SOC_DAPM_ENUM("iir1_inp0", iir1_inp0_enum);
+static const struct snd_kcontrol_new iir1_inp1_mux =
+		SOC_DAPM_ENUM("iir1_inp1", iir1_inp1_enum);
+static const struct snd_kcontrol_new iir1_inp2_mux =
+		SOC_DAPM_ENUM("iir1_inp2", iir1_inp2_enum);
+static const struct snd_kcontrol_new iir1_inp3_mux =
+		SOC_DAPM_ENUM("iir1_inp3", iir1_inp3_enum);
+static const struct snd_kcontrol_new rx_int0_1_interp_mux =
+		SOC_DAPM_ENUM("rx_int0_1_interp", rx_int0_1_interp_enum);
+static const struct snd_kcontrol_new rx_int1_1_interp_mux =
+		SOC_DAPM_ENUM("rx_int1_1_interp", rx_int1_1_interp_enum);
+static const struct snd_kcontrol_new rx_int2_1_interp_mux =
+		SOC_DAPM_ENUM("rx_int2_1_interp", rx_int2_1_interp_enum);
+static const struct snd_kcontrol_new rx_int0_2_interp_mux =
+		SOC_DAPM_ENUM("rx_int0_2_interp", rx_int0_2_interp_enum);
+static const struct snd_kcontrol_new rx_int1_2_interp_mux =
+		SOC_DAPM_ENUM("rx_int1_2_interp", rx_int1_2_interp_enum);
+static const struct snd_kcontrol_new rx_int2_2_interp_mux =
+		SOC_DAPM_ENUM("rx_int2_2_interp", rx_int2_2_interp_enum);
+static const struct snd_kcontrol_new rx_mix_tx0_mux =
+		SOC_DAPM_ENUM("RX MIX TX0_MUX Mux", rx_mix_tx0_mux_enum);
+
+static const struct reg_default rx_defaults[] = {
+	/* RX Macro */
+	{ CDC_RX_TOP_TOP_CFG0, 0x00 },
+	{ CDC_RX_TOP_SWR_CTRL, 0x00 },
+	{ CDC_RX_TOP_DEBUG, 0x00 },
+	{ CDC_RX_TOP_DEBUG_BUS, 0x00 },
+	{ CDC_RX_TOP_DEBUG_EN0, 0x00 },
+	{ CDC_RX_TOP_DEBUG_EN1, 0x00 },
+	{ CDC_RX_TOP_DEBUG_EN2, 0x00 },
+	{ CDC_RX_TOP_HPHL_COMP_WR_LSB, 0x00 },
+	{ CDC_RX_TOP_HPHL_COMP_WR_MSB, 0x00 },
+	{ CDC_RX_TOP_HPHL_COMP_LUT, 0x00 },
+	{ CDC_RX_TOP_HPHL_COMP_RD_LSB, 0x00 },
+	{ CDC_RX_TOP_HPHL_COMP_RD_MSB, 0x00 },
+	{ CDC_RX_TOP_HPHR_COMP_WR_LSB, 0x00 },
+	{ CDC_RX_TOP_HPHR_COMP_WR_MSB, 0x00 },
+	{ CDC_RX_TOP_HPHR_COMP_LUT, 0x00 },
+	{ CDC_RX_TOP_HPHR_COMP_RD_LSB, 0x00 },
+	{ CDC_RX_TOP_HPHR_COMP_RD_MSB, 0x00 },
+	{ CDC_RX_TOP_DSD0_DEBUG_CFG0, 0x11 },
+	{ CDC_RX_TOP_DSD0_DEBUG_CFG1, 0x20 },
+	{ CDC_RX_TOP_DSD0_DEBUG_CFG2, 0x00 },
+	{ CDC_RX_TOP_DSD0_DEBUG_CFG3, 0x00 },
+	{ CDC_RX_TOP_DSD1_DEBUG_CFG0, 0x11 },
+	{ CDC_RX_TOP_DSD1_DEBUG_CFG1, 0x20 },
+	{ CDC_RX_TOP_DSD1_DEBUG_CFG2, 0x00 },
+	{ CDC_RX_TOP_DSD1_DEBUG_CFG3, 0x00 },
+	{ CDC_RX_TOP_RX_I2S_CTL, 0x0C },
+	{ CDC_RX_TOP_TX_I2S2_CTL, 0x0C },
+	{ CDC_RX_TOP_I2S_CLK, 0x0C },
+	{ CDC_RX_TOP_I2S_RESET, 0x00 },
+	{ CDC_RX_TOP_I2S_MUX, 0x00 },
+	{ CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+	{ CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+	{ CDC_RX_CLK_RST_CTRL_SWR_CONTROL, 0x00 },
+	{ CDC_RX_CLK_RST_CTRL_DSD_CONTROL, 0x00 },
+	{ CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x08 },
+	{ CDC_RX_SOFTCLIP_CRC, 0x00 },
+	{ CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x38 },
+	{ CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00 },
+	{ CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00 },
+	{ CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00 },
+	{ CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00 },
+	{ CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00 },
+	{ CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00 },
+	{ CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00 },
+	{ CDC_RX_INP_MUX_RX_MIX_CFG5, 0x00 },
+	{ CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00 },
+	{ CDC_RX_CLSH_CRC, 0x00 },
+	{ CDC_RX_CLSH_DLY_CTRL, 0x03 },
+	{ CDC_RX_CLSH_DECAY_CTRL, 0x02 },
+	{ CDC_RX_CLSH_HPH_V_PA, 0x1C },
+	{ CDC_RX_CLSH_EAR_V_PA, 0x39 },
+	{ CDC_RX_CLSH_HPH_V_HD, 0x0C },
+	{ CDC_RX_CLSH_EAR_V_HD, 0x0C },
+	{ CDC_RX_CLSH_K1_MSB, 0x01 },
+	{ CDC_RX_CLSH_K1_LSB, 0x00 },
+	{ CDC_RX_CLSH_K2_MSB, 0x00 },
+	{ CDC_RX_CLSH_K2_LSB, 0x80 },
+	{ CDC_RX_CLSH_IDLE_CTRL, 0x00 },
+	{ CDC_RX_CLSH_IDLE_HPH, 0x00 },
+	{ CDC_RX_CLSH_IDLE_EAR, 0x00 },
+	{ CDC_RX_CLSH_TEST0, 0x07 },
+	{ CDC_RX_CLSH_TEST1, 0x00 },
+	{ CDC_RX_CLSH_OVR_VREF, 0x00 },
+	{ CDC_RX_CLSH_CLSG_CTL, 0x02 },
+	{ CDC_RX_CLSH_CLSG_CFG1, 0x9A },
+	{ CDC_RX_CLSH_CLSG_CFG2, 0x10 },
+	{ CDC_RX_BCL_VBAT_PATH_CTL, 0x00 },
+	{ CDC_RX_BCL_VBAT_CFG, 0x10 },
+	{ CDC_RX_BCL_VBAT_ADC_CAL1, 0x00 },
+	{ CDC_RX_BCL_VBAT_ADC_CAL2, 0x00 },
+	{ CDC_RX_BCL_VBAT_ADC_CAL3, 0x04 },
+	{ CDC_RX_BCL_VBAT_PK_EST1, 0xE0 },
+	{ CDC_RX_BCL_VBAT_PK_EST2, 0x01 },
+	{ CDC_RX_BCL_VBAT_PK_EST3, 0x40 },
+	{ CDC_RX_BCL_VBAT_RF_PROC1, 0x2A },
+	{ CDC_RX_BCL_VBAT_RF_PROC1, 0x00 },
+	{ CDC_RX_BCL_VBAT_TAC1, 0x00 },
+	{ CDC_RX_BCL_VBAT_TAC2, 0x18 },
+	{ CDC_RX_BCL_VBAT_TAC3, 0x18 },
+	{ CDC_RX_BCL_VBAT_TAC4, 0x03 },
+	{ CDC_RX_BCL_VBAT_GAIN_UPD1, 0x01 },
+	{ CDC_RX_BCL_VBAT_GAIN_UPD2, 0x00 },
+	{ CDC_RX_BCL_VBAT_GAIN_UPD3, 0x00 },
+	{ CDC_RX_BCL_VBAT_GAIN_UPD4, 0x64 },
+	{ CDC_RX_BCL_VBAT_GAIN_UPD5, 0x01 },
+	{ CDC_RX_BCL_VBAT_DEBUG1, 0x00 },
+	{ CDC_RX_BCL_VBAT_GAIN_UPD_MON, 0x00 },
+	{ CDC_RX_BCL_VBAT_GAIN_MON_VAL, 0x00 },
+	{ CDC_RX_BCL_VBAT_BAN, 0x0C },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, 0x00 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, 0x77 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, 0x01 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, 0x00 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, 0x4B },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, 0x00 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, 0x01 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, 0x00 },
+	{ CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, 0x00 },
+	{ CDC_RX_BCL_VBAT_ATTN1, 0x04 },
+	{ CDC_RX_BCL_VBAT_ATTN2, 0x08 },
+	{ CDC_RX_BCL_VBAT_ATTN3, 0x0C },
+	{ CDC_RX_BCL_VBAT_DECODE_CTL1, 0xE0 },
+	{ CDC_RX_BCL_VBAT_DECODE_CTL2, 0x00 },
+	{ CDC_RX_BCL_VBAT_DECODE_CFG1, 0x00 },
+	{ CDC_RX_BCL_VBAT_DECODE_CFG2, 0x00 },
+	{ CDC_RX_BCL_VBAT_DECODE_CFG3, 0x00 },
+	{ CDC_RX_BCL_VBAT_DECODE_CFG4, 0x00 },
+	{ CDC_RX_BCL_VBAT_DECODE_ST, 0x00 },
+	{ CDC_RX_INTR_CTRL_CFG, 0x00 },
+	{ CDC_RX_INTR_CTRL_CLR_COMMIT, 0x00 },
+	{ CDC_RX_INTR_CTRL_PIN1_MASK0, 0xFF },
+	{ CDC_RX_INTR_CTRL_PIN1_STATUS0, 0x00 },
+	{ CDC_RX_INTR_CTRL_PIN1_CLEAR0, 0x00 },
+	{ CDC_RX_INTR_CTRL_PIN2_MASK0, 0xFF },
+	{ CDC_RX_INTR_CTRL_PIN2_STATUS0, 0x00 },
+	{ CDC_RX_INTR_CTRL_PIN2_CLEAR0, 0x00 },
+	{ CDC_RX_INTR_CTRL_LEVEL0, 0x00 },
+	{ CDC_RX_INTR_CTRL_BYPASS0, 0x00 },
+	{ CDC_RX_INTR_CTRL_SET0, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_CTL, 0x04 },
+	{ CDC_RX_RX0_RX_PATH_CFG0, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_CFG1, 0x64 },
+	{ CDC_RX_RX0_RX_PATH_CFG2, 0x8F },
+	{ CDC_RX_RX0_RX_PATH_CFG3, 0x00 },
+	{ CDC_RX_RX0_RX_VOL_CTL, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_MIX_CTL, 0x04 },
+	{ CDC_RX_RX0_RX_PATH_MIX_CFG, 0x7E },
+	{ CDC_RX_RX0_RX_VOL_MIX_CTL, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_SEC1, 0x08 },
+	{ CDC_RX_RX0_RX_PATH_SEC2, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_SEC3, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_SEC4, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_SEC7, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_MIX_SEC0, 0x08 },
+	{ CDC_RX_RX0_RX_PATH_MIX_SEC1, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_DSM_CTL, 0x08 },
+	{ CDC_RX_RX0_RX_PATH_DSM_DATA1, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_DSM_DATA2, 0x00 },
+	{ CDC_RX_RX0_RX_PATH_DSM_DATA3, 0x00 },
+	{ 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 },
+	{ CDC_RX_IDLE_DETECT_CFG2, 0x00 },
+	{ CDC_RX_IDLE_DETECT_CFG3, 0x00 },
+	{ CDC_RX_COMPANDER0_CTL0, 0x60 },
+	{ CDC_RX_COMPANDER0_CTL1, 0xDB },
+	{ CDC_RX_COMPANDER0_CTL2, 0xFF },
+	{ CDC_RX_COMPANDER0_CTL3, 0x35 },
+	{ CDC_RX_COMPANDER0_CTL4, 0xFF },
+	{ CDC_RX_COMPANDER0_CTL5, 0x00 },
+	{ CDC_RX_COMPANDER0_CTL6, 0x01 },
+	{ CDC_RX_COMPANDER0_CTL7, 0x28 },
+	{ CDC_RX_COMPANDER1_CTL0, 0x60 },
+	{ CDC_RX_COMPANDER1_CTL1, 0xDB },
+	{ CDC_RX_COMPANDER1_CTL2, 0xFF },
+	{ CDC_RX_COMPANDER1_CTL3, 0x35 },
+	{ CDC_RX_COMPANDER1_CTL4, 0xFF },
+	{ CDC_RX_COMPANDER1_CTL5, 0x00 },
+	{ CDC_RX_COMPANDER1_CTL6, 0x01 },
+	{ CDC_RX_COMPANDER1_CTL7, 0x28 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_CTL, 0x40 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_CTL, 0x40 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00 },
+	{ CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 },
+	{ CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 },
+	{ CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04 },
+	{ CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00 },
+	{ CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04 },
+	{ CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00 },
+	{ CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00 },
+	{ CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01 },
+	{ CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00 },
+	{ CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01 },
+	{ CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL, 0x00 },
+	{ CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0, 0x01 },
+	{ CDC_RX_EC_ASRC0_CLK_RST_CTL, 0x00 },
+	{ CDC_RX_EC_ASRC0_CTL0, 0x00 },
+	{ CDC_RX_EC_ASRC0_CTL1, 0x00 },
+	{ CDC_RX_EC_ASRC0_FIFO_CTL, 0xA8 },
+	{ CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 },
+	{ CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 },
+	{ CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 },
+	{ CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 },
+	{ CDC_RX_EC_ASRC0_STATUS_FIFO, 0x00 },
+	{ CDC_RX_EC_ASRC1_CLK_RST_CTL, 0x00 },
+	{ CDC_RX_EC_ASRC1_CTL0, 0x00 },
+	{ CDC_RX_EC_ASRC1_CTL1, 0x00 },
+	{ CDC_RX_EC_ASRC1_FIFO_CTL, 0xA8 },
+	{ CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 },
+	{ CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 },
+	{ CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 },
+	{ CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 },
+	{ CDC_RX_EC_ASRC1_STATUS_FIFO, 0x00 },
+	{ CDC_RX_EC_ASRC2_CLK_RST_CTL, 0x00 },
+	{ CDC_RX_EC_ASRC2_CTL0, 0x00 },
+	{ CDC_RX_EC_ASRC2_CTL1, 0x00 },
+	{ CDC_RX_EC_ASRC2_FIFO_CTL, 0xA8 },
+	{ CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB, 0x00 },
+	{ CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB, 0x00 },
+	{ CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB, 0x00 },
+	{ CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB, 0x00 },
+	{ CDC_RX_EC_ASRC2_STATUS_FIFO, 0x00 },
+	{ CDC_RX_DSD0_PATH_CTL, 0x00 },
+	{ CDC_RX_DSD0_CFG0, 0x00 },
+	{ CDC_RX_DSD0_CFG1, 0x62 },
+	{ CDC_RX_DSD0_CFG2, 0x96 },
+	{ CDC_RX_DSD1_PATH_CTL, 0x00 },
+	{ CDC_RX_DSD1_CFG0, 0x00 },
+	{ CDC_RX_DSD1_CFG1, 0x62 },
+	{ CDC_RX_DSD1_CFG2, 0x96 },
+};
+
+static bool rx_is_wronly_register(struct device *dev,
+					unsigned int reg)
+{
+	switch (reg) {
+	case CDC_RX_BCL_VBAT_GAIN_UPD_MON:
+	case CDC_RX_INTR_CTRL_CLR_COMMIT:
+	case CDC_RX_INTR_CTRL_PIN1_CLEAR0:
+	case CDC_RX_INTR_CTRL_PIN2_CLEAR0:
+		return true;
+	}
+
+	return false;
+}
+
+static bool rx_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	/* Update volatile list for rx/tx macros */
+	switch (reg) {
+	case CDC_RX_TOP_HPHL_COMP_RD_LSB:
+	case CDC_RX_TOP_HPHL_COMP_WR_LSB:
+	case CDC_RX_TOP_HPHL_COMP_RD_MSB:
+	case CDC_RX_TOP_HPHL_COMP_WR_MSB:
+	case CDC_RX_TOP_HPHR_COMP_RD_LSB:
+	case CDC_RX_TOP_HPHR_COMP_WR_LSB:
+	case CDC_RX_TOP_HPHR_COMP_RD_MSB:
+	case CDC_RX_TOP_HPHR_COMP_WR_MSB:
+	case CDC_RX_TOP_DSD0_DEBUG_CFG2:
+	case CDC_RX_TOP_DSD1_DEBUG_CFG2:
+	case CDC_RX_BCL_VBAT_GAIN_MON_VAL:
+	case CDC_RX_BCL_VBAT_DECODE_ST:
+	case CDC_RX_INTR_CTRL_PIN1_STATUS0:
+	case CDC_RX_INTR_CTRL_PIN2_STATUS0:
+	case CDC_RX_COMPANDER0_CTL6:
+	case CDC_RX_COMPANDER1_CTL6:
+	case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB:
+	case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB:
+	case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB:
+	case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB:
+	case CDC_RX_EC_ASRC0_STATUS_FIFO:
+	case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB:
+	case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB:
+	case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB:
+	case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB:
+	case CDC_RX_EC_ASRC1_STATUS_FIFO:
+	case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB:
+	case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB:
+	case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB:
+	case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB:
+	case CDC_RX_EC_ASRC2_STATUS_FIFO:
+		return true;
+	}
+	return false;
+}
+
+static bool rx_is_rw_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_RX_TOP_TOP_CFG0:
+	case CDC_RX_TOP_SWR_CTRL:
+	case CDC_RX_TOP_DEBUG:
+	case CDC_RX_TOP_DEBUG_BUS:
+	case CDC_RX_TOP_DEBUG_EN0:
+	case CDC_RX_TOP_DEBUG_EN1:
+	case CDC_RX_TOP_DEBUG_EN2:
+	case CDC_RX_TOP_HPHL_COMP_WR_LSB:
+	case CDC_RX_TOP_HPHL_COMP_WR_MSB:
+	case CDC_RX_TOP_HPHL_COMP_LUT:
+	case CDC_RX_TOP_HPHR_COMP_WR_LSB:
+	case CDC_RX_TOP_HPHR_COMP_WR_MSB:
+	case CDC_RX_TOP_HPHR_COMP_LUT:
+	case CDC_RX_TOP_DSD0_DEBUG_CFG0:
+	case CDC_RX_TOP_DSD0_DEBUG_CFG1:
+	case CDC_RX_TOP_DSD0_DEBUG_CFG3:
+	case CDC_RX_TOP_DSD1_DEBUG_CFG0:
+	case CDC_RX_TOP_DSD1_DEBUG_CFG1:
+	case CDC_RX_TOP_DSD1_DEBUG_CFG3:
+	case CDC_RX_TOP_RX_I2S_CTL:
+	case CDC_RX_TOP_TX_I2S2_CTL:
+	case CDC_RX_TOP_I2S_CLK:
+	case CDC_RX_TOP_I2S_RESET:
+	case CDC_RX_TOP_I2S_MUX:
+	case CDC_RX_CLK_RST_CTRL_MCLK_CONTROL:
+	case CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL:
+	case CDC_RX_CLK_RST_CTRL_SWR_CONTROL:
+	case CDC_RX_CLK_RST_CTRL_DSD_CONTROL:
+	case CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL:
+	case CDC_RX_SOFTCLIP_CRC:
+	case CDC_RX_SOFTCLIP_SOFTCLIP_CTRL:
+	case CDC_RX_INP_MUX_RX_INT0_CFG0:
+	case CDC_RX_INP_MUX_RX_INT0_CFG1:
+	case CDC_RX_INP_MUX_RX_INT1_CFG0:
+	case CDC_RX_INP_MUX_RX_INT1_CFG1:
+	case CDC_RX_INP_MUX_RX_INT2_CFG0:
+	case CDC_RX_INP_MUX_RX_INT2_CFG1:
+	case CDC_RX_INP_MUX_RX_MIX_CFG4:
+	case CDC_RX_INP_MUX_RX_MIX_CFG5:
+	case CDC_RX_INP_MUX_SIDETONE_SRC_CFG0:
+	case CDC_RX_CLSH_CRC:
+	case CDC_RX_CLSH_DLY_CTRL:
+	case CDC_RX_CLSH_DECAY_CTRL:
+	case CDC_RX_CLSH_HPH_V_PA:
+	case CDC_RX_CLSH_EAR_V_PA:
+	case CDC_RX_CLSH_HPH_V_HD:
+	case CDC_RX_CLSH_EAR_V_HD:
+	case CDC_RX_CLSH_K1_MSB:
+	case CDC_RX_CLSH_K1_LSB:
+	case CDC_RX_CLSH_K2_MSB:
+	case CDC_RX_CLSH_K2_LSB:
+	case CDC_RX_CLSH_IDLE_CTRL:
+	case CDC_RX_CLSH_IDLE_HPH:
+	case CDC_RX_CLSH_IDLE_EAR:
+	case CDC_RX_CLSH_TEST0:
+	case CDC_RX_CLSH_TEST1:
+	case CDC_RX_CLSH_OVR_VREF:
+	case CDC_RX_CLSH_CLSG_CTL:
+	case CDC_RX_CLSH_CLSG_CFG1:
+	case CDC_RX_CLSH_CLSG_CFG2:
+	case CDC_RX_BCL_VBAT_PATH_CTL:
+	case CDC_RX_BCL_VBAT_CFG:
+	case CDC_RX_BCL_VBAT_ADC_CAL1:
+	case CDC_RX_BCL_VBAT_ADC_CAL2:
+	case CDC_RX_BCL_VBAT_ADC_CAL3:
+	case CDC_RX_BCL_VBAT_PK_EST1:
+	case CDC_RX_BCL_VBAT_PK_EST2:
+	case CDC_RX_BCL_VBAT_PK_EST3:
+	case CDC_RX_BCL_VBAT_RF_PROC1:
+	case CDC_RX_BCL_VBAT_RF_PROC2:
+	case CDC_RX_BCL_VBAT_TAC1:
+	case CDC_RX_BCL_VBAT_TAC2:
+	case CDC_RX_BCL_VBAT_TAC3:
+	case CDC_RX_BCL_VBAT_TAC4:
+	case CDC_RX_BCL_VBAT_GAIN_UPD1:
+	case CDC_RX_BCL_VBAT_GAIN_UPD2:
+	case CDC_RX_BCL_VBAT_GAIN_UPD3:
+	case CDC_RX_BCL_VBAT_GAIN_UPD4:
+	case CDC_RX_BCL_VBAT_GAIN_UPD5:
+	case CDC_RX_BCL_VBAT_DEBUG1:
+	case CDC_RX_BCL_VBAT_BAN:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD1:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD2:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD3:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD4:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD5:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD6:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD7:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD8:
+	case CDC_RX_BCL_VBAT_BCL_GAIN_UPD9:
+	case CDC_RX_BCL_VBAT_ATTN1:
+	case CDC_RX_BCL_VBAT_ATTN2:
+	case CDC_RX_BCL_VBAT_ATTN3:
+	case CDC_RX_BCL_VBAT_DECODE_CTL1:
+	case CDC_RX_BCL_VBAT_DECODE_CTL2:
+	case CDC_RX_BCL_VBAT_DECODE_CFG1:
+	case CDC_RX_BCL_VBAT_DECODE_CFG2:
+	case CDC_RX_BCL_VBAT_DECODE_CFG3:
+	case CDC_RX_BCL_VBAT_DECODE_CFG4:
+	case CDC_RX_INTR_CTRL_CFG:
+	case CDC_RX_INTR_CTRL_PIN1_MASK0:
+	case CDC_RX_INTR_CTRL_PIN2_MASK0:
+	case CDC_RX_INTR_CTRL_LEVEL0:
+	case CDC_RX_INTR_CTRL_BYPASS0:
+	case CDC_RX_INTR_CTRL_SET0:
+	case CDC_RX_RX0_RX_PATH_CTL:
+	case CDC_RX_RX0_RX_PATH_CFG0:
+	case CDC_RX_RX0_RX_PATH_CFG1:
+	case CDC_RX_RX0_RX_PATH_CFG2:
+	case CDC_RX_RX0_RX_PATH_CFG3:
+	case CDC_RX_RX0_RX_VOL_CTL:
+	case CDC_RX_RX0_RX_PATH_MIX_CTL:
+	case CDC_RX_RX0_RX_PATH_MIX_CFG:
+	case CDC_RX_RX0_RX_VOL_MIX_CTL:
+	case CDC_RX_RX0_RX_PATH_SEC1:
+	case CDC_RX_RX0_RX_PATH_SEC2:
+	case CDC_RX_RX0_RX_PATH_SEC3:
+	case CDC_RX_RX0_RX_PATH_SEC4:
+	case CDC_RX_RX0_RX_PATH_SEC7:
+	case CDC_RX_RX0_RX_PATH_MIX_SEC0:
+	case CDC_RX_RX0_RX_PATH_MIX_SEC1:
+	case CDC_RX_RX0_RX_PATH_DSM_CTL:
+	case CDC_RX_RX0_RX_PATH_DSM_DATA1:
+	case CDC_RX_RX0_RX_PATH_DSM_DATA2:
+	case CDC_RX_RX0_RX_PATH_DSM_DATA3:
+	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:
+	case CDC_RX_IDLE_DETECT_CFG2:
+	case CDC_RX_IDLE_DETECT_CFG3:
+	case CDC_RX_COMPANDER0_CTL0:
+	case CDC_RX_COMPANDER0_CTL1:
+	case CDC_RX_COMPANDER0_CTL2:
+	case CDC_RX_COMPANDER0_CTL3:
+	case CDC_RX_COMPANDER0_CTL4:
+	case CDC_RX_COMPANDER0_CTL5:
+	case CDC_RX_COMPANDER0_CTL7:
+	case CDC_RX_COMPANDER1_CTL0:
+	case CDC_RX_COMPANDER1_CTL1:
+	case CDC_RX_COMPANDER1_CTL2:
+	case CDC_RX_COMPANDER1_CTL3:
+	case CDC_RX_COMPANDER1_CTL4:
+	case CDC_RX_COMPANDER1_CTL5:
+	case CDC_RX_COMPANDER1_CTL7:
+	case CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL:
+	case CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL:
+	case CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL:
+	case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0:
+	case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1:
+	case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2:
+	case CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3:
+	case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0:
+	case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1:
+	case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2:
+	case CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3:
+	case CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL:
+	case CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1:
+	case CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL:
+	case CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1:
+	case CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL:
+	case CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0:
+	case CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL:
+	case CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0:
+	case CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL:
+	case CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0:
+	case CDC_RX_EC_ASRC0_CLK_RST_CTL:
+	case CDC_RX_EC_ASRC0_CTL0:
+	case CDC_RX_EC_ASRC0_CTL1:
+	case CDC_RX_EC_ASRC0_FIFO_CTL:
+	case CDC_RX_EC_ASRC1_CLK_RST_CTL:
+	case CDC_RX_EC_ASRC1_CTL0:
+	case CDC_RX_EC_ASRC1_CTL1:
+	case CDC_RX_EC_ASRC1_FIFO_CTL:
+	case CDC_RX_EC_ASRC2_CLK_RST_CTL:
+	case CDC_RX_EC_ASRC2_CTL0:
+	case CDC_RX_EC_ASRC2_CTL1:
+	case CDC_RX_EC_ASRC2_FIFO_CTL:
+	case CDC_RX_DSD0_PATH_CTL:
+	case CDC_RX_DSD0_CFG0:
+	case CDC_RX_DSD0_CFG1:
+	case CDC_RX_DSD0_CFG2:
+	case CDC_RX_DSD1_PATH_CTL:
+	case CDC_RX_DSD1_CFG0:
+	case CDC_RX_DSD1_CFG1:
+	case CDC_RX_DSD1_CFG2:
+		return true;
+	}
+
+	return false;
+}
+
+static bool rx_is_writeable_register(struct device *dev, unsigned int reg)
+{
+	bool ret;
+
+	ret = rx_is_rw_register(dev, reg);
+	if (!ret)
+		return rx_is_wronly_register(dev, reg);
+
+	return ret;
+}
+
+static bool rx_is_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_RX_TOP_HPHL_COMP_RD_LSB:
+	case CDC_RX_TOP_HPHL_COMP_RD_MSB:
+	case CDC_RX_TOP_HPHR_COMP_RD_LSB:
+	case CDC_RX_TOP_HPHR_COMP_RD_MSB:
+	case CDC_RX_TOP_DSD0_DEBUG_CFG2:
+	case CDC_RX_TOP_DSD1_DEBUG_CFG2:
+	case CDC_RX_BCL_VBAT_GAIN_MON_VAL:
+	case CDC_RX_BCL_VBAT_DECODE_ST:
+	case CDC_RX_INTR_CTRL_PIN1_STATUS0:
+	case CDC_RX_INTR_CTRL_PIN2_STATUS0:
+	case CDC_RX_COMPANDER0_CTL6:
+	case CDC_RX_COMPANDER1_CTL6:
+	case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB:
+	case CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB:
+	case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB:
+	case CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB:
+	case CDC_RX_EC_ASRC0_STATUS_FIFO:
+	case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB:
+	case CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB:
+	case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB:
+	case CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB:
+	case CDC_RX_EC_ASRC1_STATUS_FIFO:
+	case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB:
+	case CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB:
+	case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB:
+	case CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB:
+	case CDC_RX_EC_ASRC2_STATUS_FIFO:
+		return true;
+	}
+
+	return rx_is_rw_register(dev, reg);
+}
+
+static const struct regmap_config rx_regmap_config = {
+	.name = "rx_macro",
+	.reg_bits = 16,
+	.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,
+	.readable_reg = rx_is_readable_register,
+};
+
+static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	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;
+
+	/* Set Look Ahead Delay */
+	if (val)
+		snd_soc_component_update_bits(component, look_ahead_dly_reg,
+					      CDC_RX_DLY_ZN_EN_MASK,
+					      CDC_RX_DLY_ZN_ENABLE);
+	else
+		snd_soc_component_update_bits(component, look_ahead_dly_reg,
+					      CDC_RX_DLY_ZN_EN_MASK, 0);
+	/* Set DEM INP Select */
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new rx_int0_dem_inp_mux =
+		SOC_DAPM_ENUM_EXT("rx_int0_dem_inp", rx_int0_dem_inp_enum,
+		  snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+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 int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+					       int rate_reg_val, u32 sample_rate)
+{
+
+	u8 int_1_mix1_inp;
+	u32 j, port;
+	u16 int_mux_cfg0, int_mux_cfg1;
+	u16 int_fs_reg;
+	u8 inp0_sel, inp1_sel, inp2_sel;
+	struct snd_soc_component *component = dai->component;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	for_each_set_bit(port, &rx->active_ch_mask[dai->id], RX_MACRO_PORTS_MAX) {
+		int_1_mix1_inp = port;
+		int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0;
+		/*
+		 * Loop through all interpolator MUX inputs and find out
+		 * to which interpolator input, the rx port
+		 * is connected
+		 */
+		for (j = 0; j < INTERP_MAX; j++) {
+			int_mux_cfg1 = int_mux_cfg0 + 4;
+
+			inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+								CDC_RX_INTX_1_MIX_INP0_SEL_MASK);
+			inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+								CDC_RX_INTX_1_MIX_INP1_SEL_MASK);
+			inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
+								CDC_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) ||
+			    (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
+				int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(j);
+				/* sample_rate is in Hz */
+				snd_soc_component_update_bits(component, int_fs_reg,
+							      CDC_RX_PATH_PCM_RATE_MASK,
+							      rate_reg_val);
+			}
+			int_mux_cfg0 += 8;
+		}
+	}
+
+	return 0;
+}
+
+static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+					      int rate_reg_val, u32 sample_rate)
+{
+
+	u8 int_2_inp;
+	u32 j, port;
+	u16 int_mux_cfg1, int_fs_reg;
+	u8 int_mux_cfg1_val;
+	struct snd_soc_component *component = dai->component;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	for_each_set_bit(port, &rx->active_ch_mask[dai->id], RX_MACRO_PORTS_MAX) {
+		int_2_inp = port;
+
+		int_mux_cfg1 = CDC_RX_INP_MUX_RX_INT0_CFG1;
+		for (j = 0; j < INTERP_MAX; j++) {
+			int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1,
+									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);
+				snd_soc_component_update_bits(component, int_fs_reg,
+							      CDC_RX_RXn_MIX_PCM_RATE_MASK,
+							      rate_reg_val);
+			}
+			int_mux_cfg1 += 8;
+		}
+	}
+	return 0;
+}
+
+static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai,
+					  u32 sample_rate)
+{
+	int rate_val = 0;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++)
+		if (sample_rate == sr_val_tbl[i].sample_rate)
+			rate_val = sr_val_tbl[i].rate_val;
+
+	ret = rx_macro_set_prim_interpolator_rate(dai, rate_val, sample_rate);
+	if (ret)
+		return ret;
+
+	ret = rx_macro_set_mix_interpolator_rate(dai, rate_val, sample_rate);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int rx_macro_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = rx_macro_set_interpolator_rate(dai, params_rate(params));
+		if (ret) {
+			dev_err(component->dev, "%s: cannot set sample rate: %u\n",
+				__func__, params_rate(params));
+			return ret;
+		}
+		rx->bit_width[dai->id] = params_width(params);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
+				    unsigned int *tx_num, unsigned int *tx_slot,
+				    unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+	u16 val, mask = 0, cnt = 0, temp;
+
+	switch (dai->id) {
+	case RX_MACRO_AIF1_PB:
+	case RX_MACRO_AIF2_PB:
+	case RX_MACRO_AIF3_PB:
+	case RX_MACRO_AIF4_PB:
+		for_each_set_bit(temp, &rx->active_ch_mask[dai->id],
+			 RX_MACRO_PORTS_MAX) {
+			mask |= (1 << temp);
+			if (++cnt == RX_MACRO_MAX_DMA_CH_PER_PORT)
+				break;
+		}
+		/*
+		 * CDC_DMA_RX_0 port drives RX0/RX1 -- ch_mask 0x1/0x2/0x3
+		 * CDC_DMA_RX_1 port drives RX2/RX3 -- ch_mask 0x1/0x2/0x3
+		 * CDC_DMA_RX_2 port drives RX4     -- ch_mask 0x1
+		 * CDC_DMA_RX_3 port drives RX5     -- ch_mask 0x1
+		 * AIFn can pair to any CDC_DMA_RX_n port.
+		 * In general, below convention is used::
+		 * CDC_DMA_RX_0(AIF1)/CDC_DMA_RX_1(AIF2)/
+		 * CDC_DMA_RX_2(AIF3)/CDC_DMA_RX_3(AIF4)
+		 */
+		if (mask & 0x0C)
+			mask = mask >> 2;
+		if ((mask & 0x10) || (mask & 0x20))
+			mask = 0x1;
+		*rx_slot = mask;
+		*rx_num = rx->active_ch_cnt[dai->id];
+		break;
+	case RX_MACRO_AIF_ECHO:
+		val = snd_soc_component_read(component,	CDC_RX_INP_MUX_RX_MIX_CFG4);
+		if (val & RX_MACRO_EC_MIX_TX0_MASK) {
+			mask |= 0x1;
+			cnt++;
+		}
+		if (val & RX_MACRO_EC_MIX_TX1_MASK) {
+			mask |= 0x2;
+			cnt++;
+		}
+		val = snd_soc_component_read(component,
+			CDC_RX_INP_MUX_RX_MIX_CFG5);
+		if (val & RX_MACRO_EC_MIX_TX2_MASK) {
+			mask |= 0x4;
+			cnt++;
+		}
+		*tx_slot = mask;
+		*tx_num = cnt;
+		break;
+	default:
+		dev_err(component->dev, "%s: Invalid AIF\n", __func__);
+		break;
+	}
+	return 0;
+}
+
+static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->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;
+
+	switch (dai->id) {
+	case RX_MACRO_AIF1_PB:
+	case RX_MACRO_AIF2_PB:
+	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);
+
+		if (mute) {
+			snd_soc_component_update_bits(component, reg,
+						      CDC_RX_PATH_PGA_MUTE_MASK,
+						      CDC_RX_PATH_PGA_MUTE_ENABLE);
+			snd_soc_component_update_bits(component, mix_reg,
+						      CDC_RX_PATH_PGA_MUTE_MASK,
+						      CDC_RX_PATH_PGA_MUTE_ENABLE);
+		} else {
+			snd_soc_component_update_bits(component, reg,
+						      CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
+			snd_soc_component_update_bits(component, mix_reg,
+						      CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
+		}
+
+		if (j == INTERP_AUX)
+			dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+
+		int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
+		int_mux_cfg1 = int_mux_cfg0 + 4;
+		int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+		int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+		if (snd_soc_component_read(component, dsm_reg) & 0x01) {
+			if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0))
+				snd_soc_component_update_bits(component, reg, 0x20, 0x20);
+			if (int_mux_cfg1_val & 0x0F) {
+				snd_soc_component_update_bits(component, reg, 0x20, 0x20);
+				snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20);
+			}
+		}
+	}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static struct snd_soc_dai_ops rx_macro_dai_ops = {
+	.hw_params = rx_macro_hw_params,
+	.get_channel_map = rx_macro_get_channel_map,
+	.mute_stream = rx_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver rx_macro_dai[] = {
+	{
+		.name = "rx_macro_rx1",
+		.id = RX_MACRO_AIF1_PB,
+		.playback = {
+			.stream_name = "RX_MACRO_AIF1 Playback",
+			.rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+			.formats = RX_MACRO_FORMATS,
+			.rate_max = 384000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &rx_macro_dai_ops,
+	},
+	{
+		.name = "rx_macro_rx2",
+		.id = RX_MACRO_AIF2_PB,
+		.playback = {
+			.stream_name = "RX_MACRO_AIF2 Playback",
+			.rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+			.formats = RX_MACRO_FORMATS,
+			.rate_max = 384000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &rx_macro_dai_ops,
+	},
+	{
+		.name = "rx_macro_rx3",
+		.id = RX_MACRO_AIF3_PB,
+		.playback = {
+			.stream_name = "RX_MACRO_AIF3 Playback",
+			.rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+			.formats = RX_MACRO_FORMATS,
+			.rate_max = 384000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &rx_macro_dai_ops,
+	},
+	{
+		.name = "rx_macro_rx4",
+		.id = RX_MACRO_AIF4_PB,
+		.playback = {
+			.stream_name = "RX_MACRO_AIF4 Playback",
+			.rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+			.formats = RX_MACRO_FORMATS,
+			.rate_max = 384000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &rx_macro_dai_ops,
+	},
+	{
+		.name = "rx_macro_echo",
+		.id = RX_MACRO_AIF_ECHO,
+		.capture = {
+			.stream_name = "RX_AIF_ECHO Capture",
+			.rates = RX_MACRO_ECHO_RATES,
+			.formats = RX_MACRO_ECHO_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 3,
+		},
+		.ops = &rx_macro_dai_ops,
+	},
+};
+
+static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
+{
+	struct regmap *regmap = rx->regmap;
+
+	if (mclk_enable) {
+		if (rx->rx_mclk_users == 0) {
+			regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
+					   CDC_RX_CLK_MCLK_EN_MASK |
+					   CDC_RX_CLK_MCLK2_EN_MASK,
+					   CDC_RX_CLK_MCLK_ENABLE |
+					   CDC_RX_CLK_MCLK2_ENABLE);
+			regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_RX_FS_MCLK_CNT_CLR_MASK, 0x00);
+			regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_RX_FS_MCLK_CNT_EN_MASK,
+					   CDC_RX_FS_MCLK_CNT_ENABLE);
+			regcache_mark_dirty(regmap);
+			regcache_sync(regmap);
+		}
+		rx->rx_mclk_users++;
+	} else {
+		if (rx->rx_mclk_users <= 0) {
+			dev_err(rx->dev, "%s: clock already disabled\n", __func__);
+			rx->rx_mclk_users = 0;
+			return;
+		}
+		rx->rx_mclk_users--;
+		if (rx->rx_mclk_users == 0) {
+			regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_RX_FS_MCLK_CNT_EN_MASK, 0x0);
+			regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_RX_FS_MCLK_CNT_CLR_MASK,
+					   CDC_RX_FS_MCLK_CNT_CLR);
+			regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
+					   CDC_RX_CLK_MCLK_EN_MASK |
+					   CDC_RX_CLK_MCLK2_EN_MASK, 0x0);
+		}
+	}
+}
+
+static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		rx_macro_mclk_enable(rx, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		rx_macro_mclk_enable(rx, false);
+		break;
+	default:
+		dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static bool rx_macro_adie_lb(struct snd_soc_component *component,
+			     int interp_idx)
+{
+	u16 int_mux_cfg0, int_mux_cfg1;
+	u8 int_n_inp0, int_n_inp1, int_n_inp2;
+
+	int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
+	int_mux_cfg1 = int_mux_cfg0 + 4;
+
+	int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
+						  CDC_RX_INTX_1_MIX_INP0_SEL_MASK);
+	int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
+						  CDC_RX_INTX_1_MIX_INP1_SEL_MASK);
+	int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
+						  CDC_RX_INTX_1_MIX_INP2_SEL_MASK);
+
+	if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
+		int_n_inp0 == INTn_1_INP_SEL_DEC1 ||
+		int_n_inp0 == INTn_1_INP_SEL_IIR0 ||
+		int_n_inp0 == INTn_1_INP_SEL_IIR1)
+		return true;
+
+	if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
+		int_n_inp1 == INTn_1_INP_SEL_DEC1 ||
+		int_n_inp1 == INTn_1_INP_SEL_IIR0 ||
+		int_n_inp1 == INTn_1_INP_SEL_IIR1)
+		return true;
+
+	if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
+		int_n_inp2 == INTn_1_INP_SEL_DEC1 ||
+		int_n_inp2 == INTn_1_INP_SEL_IIR0 ||
+		int_n_inp2 == INTn_1_INP_SEL_IIR1)
+		return true;
+
+	return false;
+}
+
+static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
+				      int event, int interp_idx);
+static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 gain_reg, reg;
+
+	reg = CDC_RX_RXn_RX_PATH_CTL(w->shift);
+	gain_reg = CDC_RX_RXn_RX_VOL_CTL(w->shift);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		rx_macro_enable_interp_clk(component, event, w->shift);
+		if (rx_macro_adie_lb(component, w->shift))
+			snd_soc_component_update_bits(component, reg,
+						      CDC_RX_PATH_CLK_EN_MASK,
+						      CDC_RX_PATH_CLK_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, gain_reg,
+			snd_soc_component_read(component, gain_reg));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		rx_macro_enable_interp_clk(component, event, w->shift);
+		break;
+	}
+
+	return 0;
+}
+
+static int rx_macro_config_compander(struct snd_soc_component *component,
+				struct rx_macro *rx,
+				int comp, int event)
+{
+	u8 pcm_rate, val;
+
+	/* AUX does not have compander */
+	if (comp == INTERP_AUX)
+		return 0;
+
+	pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(comp)) & 0x0F;
+	if (pcm_rate < 0x06)
+		val = 0x03;
+	else if (pcm_rate < 0x08)
+		val = 0x01;
+	else if (pcm_rate < 0x0B)
+		val = 0x02;
+	else
+		val = 0x00;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(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),
+					      CDC_RX_DC_COEFF_SEL_MASK, 0x3);
+	if (!rx->comp_enabled[comp])
+		return 0;
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+					      CDC_RX_COMPANDERn_CLK_EN_MASK, 0x1);
+		snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+					      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),
+					      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),
+					      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);
+		snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
+					      CDC_RX_COMPANDERn_HALT_MASK, 0x0);
+	}
+
+	return 0;
+}
+
+static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
+					 struct rx_macro *rx,
+					 int comp, int event)
+{
+	u16 comp_coeff_lsb_reg, comp_coeff_msb_reg;
+	int i;
+	int hph_pwr_mode = HPH_LOHIFI;
+
+	if (!rx->comp_enabled[comp])
+		return 0;
+
+	if (comp == INTERP_HPHL) {
+		comp_coeff_lsb_reg = CDC_RX_TOP_HPHL_COMP_WR_LSB;
+		comp_coeff_msb_reg = CDC_RX_TOP_HPHL_COMP_WR_MSB;
+	} else if (comp == INTERP_HPHR) {
+		comp_coeff_lsb_reg = CDC_RX_TOP_HPHR_COMP_WR_LSB;
+		comp_coeff_msb_reg = CDC_RX_TOP_HPHR_COMP_WR_MSB;
+	} else {
+		/* compander coefficients are loaded only for hph path */
+		return 0;
+	}
+
+	hph_pwr_mode = rx->hph_pwr_mode;
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Load Compander Coeff */
+		for (i = 0; i < COMP_MAX_COEFF; i++) {
+			snd_soc_component_write(component, comp_coeff_lsb_reg,
+					comp_coeff_table[hph_pwr_mode][i].lsb);
+			snd_soc_component_write(component, comp_coeff_msb_reg,
+					comp_coeff_table[hph_pwr_mode][i].msb);
+		}
+	}
+
+	return 0;
+}
+
+static void rx_macro_enable_softclip_clk(struct snd_soc_component *component,
+					 struct rx_macro *rx, bool enable)
+{
+	if (enable) {
+		if (rx->softclip_clk_users == 0)
+			snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_CRC,
+						      CDC_RX_SOFTCLIP_CLK_EN_MASK, 1);
+		rx->softclip_clk_users++;
+	} else {
+		rx->softclip_clk_users--;
+		if (rx->softclip_clk_users == 0)
+			snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_CRC,
+						      CDC_RX_SOFTCLIP_CLK_EN_MASK, 0);
+	}
+}
+
+static int rx_macro_config_softclip(struct snd_soc_component *component,
+				    struct rx_macro *rx, int event)
+{
+
+	if (!rx->is_softclip_on)
+		return 0;
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Softclip clock */
+		rx_macro_enable_softclip_clk(component, rx, true);
+		/* Enable Softclip control */
+		snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_SOFTCLIP_CTRL,
+					     CDC_RX_SOFTCLIP_EN_MASK, 0x01);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_write_field(component, CDC_RX_SOFTCLIP_SOFTCLIP_CTRL,
+					     CDC_RX_SOFTCLIP_EN_MASK, 0x0);
+		rx_macro_enable_softclip_clk(component, rx, false);
+	}
+
+	return 0;
+}
+
+static int rx_macro_config_aux_hpf(struct snd_soc_component *component,
+				   struct rx_macro *rx, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Update Aux HPF control */
+		if (!rx->is_aux_hpf_on)
+			snd_soc_component_update_bits(component,
+				CDC_RX_RX2_RX_PATH_CFG1, 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);
+	}
+
+	return 0;
+}
+
+static inline void rx_macro_enable_clsh_block(struct rx_macro *rx, bool enable)
+{
+	if ((enable && ++rx->clsh_users == 1) || (!enable && --rx->clsh_users == 0))
+		snd_soc_component_update_bits(rx->component, CDC_RX_CLSH_CRC,
+					     CDC_RX_CLSH_CLK_EN_MASK, enable);
+	if (rx->clsh_users < 0)
+		rx->clsh_users = 0;
+}
+
+static int rx_macro_config_classh(struct snd_soc_component *component,
+				struct rx_macro *rx,
+				int interp_n, int event)
+{
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		rx_macro_enable_clsh_block(rx, false);
+		return 0;
+	}
+
+	if (!SND_SOC_DAPM_EVENT_ON(event))
+		return 0;
+
+	rx_macro_enable_clsh_block(rx, true);
+	if (interp_n == INTERP_HPHL ||
+		interp_n == INTERP_HPHR) {
+		/*
+		 * These K1 values depend on the Headphone Impedance
+		 * For now it is assumed to be 16 ohm
+		 */
+		snd_soc_component_write(component, CDC_RX_CLSH_K1_LSB, 0xc0);
+		snd_soc_component_write_field(component, CDC_RX_CLSH_K1_MSB,
+					      CDC_RX_CLSH_K1_MSB_COEFF_MASK, 0);
+	}
+	switch (interp_n) {
+	case INTERP_HPHL:
+		if (rx->is_ear_mode_on)
+			snd_soc_component_update_bits(component,
+				CDC_RX_CLSH_HPH_V_PA,
+				CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x39);
+		else
+			snd_soc_component_update_bits(component,
+				CDC_RX_CLSH_HPH_V_PA,
+				CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x1c);
+		snd_soc_component_update_bits(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_CLSH_EN_MASK, 0x1);
+		break;
+	case INTERP_HPHR:
+		if (rx->is_ear_mode_on)
+			snd_soc_component_update_bits(component,
+				CDC_RX_CLSH_HPH_V_PA,
+				CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x39);
+		else
+			snd_soc_component_update_bits(component,
+				CDC_RX_CLSH_HPH_V_PA,
+				CDC_RX_CLSH_HPH_V_PA_MIN_MASK, 0x1c);
+		snd_soc_component_update_bits(component,
+				CDC_RX_CLSH_DECAY_CTRL,
+				CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
+		snd_soc_component_update_bits(component,
+				CDC_RX_RX1_RX_PATH_CFG0,
+				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_RX2_DLY_Z_EN_MASK, 1);
+		snd_soc_component_write_field(component,
+				CDC_RX_RX2_RX_PATH_CFG0,
+				CDC_RX_RX2_CLSH_EN_MASK, 1);
+		break;
+	}
+
+	return 0;
+}
+
+static void rx_macro_hd2_control(struct snd_soc_component *component,
+				 u16 interp_idx, int event)
+{
+	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;
+		break;
+	case INTERP_HPHR:
+		hd2_scale_reg = CDC_RX_RX1_RX_PATH_SEC3;
+		hd2_enable_reg = CDC_RX_RX1_RX_PATH_CFG0;
+		break;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+				CDC_RX_RXn_HD2_ALPHA_MASK, 0x14);
+		snd_soc_component_write_field(component, hd2_enable_reg,
+					      CDC_RX_RXn_HD2_EN_MASK, 1);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_write_field(component, hd2_enable_reg,
+					      CDC_RX_RXn_HD2_EN_MASK, 0);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+				CDC_RX_RXn_HD2_ALPHA_MASK, 0x0);
+	}
+}
+
+static int rx_macro_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rx->comp_enabled[comp];
+	return 0;
+}
+
+static int rx_macro_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int comp = ((struct soc_mixer_control *)  kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	rx->comp_enabled[comp] = value;
+
+	return 0;
+}
+
+static int rx_macro_mux_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] =
+			rx->rx_port_value[widget->shift];
+	return 0;
+}
+
+static int rx_macro_mux_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+	u32 rx_port_value = ucontrol->value.integer.value[0];
+	u32 aif_rst;
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	aif_rst = rx->rx_port_value[widget->shift];
+	if (!rx_port_value) {
+		if (aif_rst == 0) {
+			dev_err(component->dev, "%s:AIF reset already\n", __func__);
+			return 0;
+		}
+		if (aif_rst > RX_MACRO_AIF4_PB) {
+			dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
+			return 0;
+		}
+	}
+	rx->rx_port_value[widget->shift] = rx_port_value;
+
+	switch (rx_port_value) {
+	case 0:
+		if (rx->active_ch_cnt[aif_rst]) {
+			clear_bit(widget->shift,
+				&rx->active_ch_mask[aif_rst]);
+			rx->active_ch_cnt[aif_rst]--;
+		}
+		break;
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		set_bit(widget->shift,
+			&rx->active_ch_mask[rx_port_value]);
+		rx->active_ch_cnt[rx_port_value]++;
+		break;
+	default:
+		dev_err(component->dev,
+			"%s:Invalid AIF_ID for RX_MACRO MUX %d\n",
+			__func__, rx_port_value);
+		goto err;
+	}
+
+	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+					rx_port_value, e, update);
+	return 0;
+err:
+	return -EINVAL;
+}
+
+static const struct snd_kcontrol_new rx_macro_rx0_mux =
+		SOC_DAPM_ENUM_EXT("rx_macro_rx0", rx_macro_rx0_enum,
+		  rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx1_mux =
+		SOC_DAPM_ENUM_EXT("rx_macro_rx1", rx_macro_rx1_enum,
+		  rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx2_mux =
+		SOC_DAPM_ENUM_EXT("rx_macro_rx2", rx_macro_rx2_enum,
+		  rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx3_mux =
+		SOC_DAPM_ENUM_EXT("rx_macro_rx3", rx_macro_rx3_enum,
+		  rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx4_mux =
+		SOC_DAPM_ENUM_EXT("rx_macro_rx4", rx_macro_rx4_enum,
+		  rx_macro_mux_get, rx_macro_mux_put);
+static const struct snd_kcontrol_new rx_macro_rx5_mux =
+		SOC_DAPM_ENUM_EXT("rx_macro_rx5", rx_macro_rx5_enum,
+		  rx_macro_mux_get, rx_macro_mux_put);
+
+static int rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rx->is_ear_mode_on;
+	return 0;
+}
+
+static int rx_macro_put_ear_mode(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	rx->is_ear_mode_on = (!ucontrol->value.integer.value[0] ? false : true);
+	return 0;
+}
+
+static int rx_macro_get_hph_hd2_mode(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rx->hph_hd2_mode;
+	return 0;
+}
+
+static int rx_macro_put_hph_hd2_mode(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	rx->hph_hd2_mode = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rx->hph_pwr_mode;
+	return 0;
+}
+
+static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	rx->hph_pwr_mode = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int rx_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rx->is_softclip_on;
+
+	return 0;
+}
+
+static int rx_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	rx->is_softclip_on = ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int rx_macro_aux_hpf_mode_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rx->is_aux_hpf_on;
+
+	return 0;
+}
+
+static int rx_macro_aux_hpf_mode_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	rx->is_aux_hpf_on = ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
+					struct rx_macro *rx,
+					u16 interp_idx, int event)
+{
+	u16 hph_lut_bypass_reg;
+	u16 hph_comp_ctrl7;
+
+	switch (interp_idx) {
+	case INTERP_HPHL:
+		hph_lut_bypass_reg = CDC_RX_TOP_HPHL_COMP_LUT;
+		hph_comp_ctrl7 = CDC_RX_COMPANDER0_CTL7;
+		break;
+	case INTERP_HPHR:
+		hph_lut_bypass_reg = CDC_RX_TOP_HPHR_COMP_LUT;
+		hph_comp_ctrl7 = CDC_RX_COMPANDER1_CTL7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		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_RX0_HPH_L_EAR_SEL_MASK, 0x1);
+			else
+				snd_soc_component_write_field(component,
+					hph_lut_bypass_reg,
+					CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 1);
+		} else {
+			snd_soc_component_write_field(component, hph_lut_bypass_reg,
+					CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 1);
+		}
+		if (rx->hph_pwr_mode)
+			snd_soc_component_write_field(component, hph_comp_ctrl7,
+					CDC_RX_COMPANDER1_HPH_LOW_PWR_MODE_MASK, 0x0);
+	}
+
+	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_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);
+		snd_soc_component_write_field(component, hph_comp_ctrl7,
+					CDC_RX_COMPANDER1_HPH_LOW_PWR_MODE_MASK, 0x1);
+	}
+
+	return 0;
+}
+
+static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
+				      int event, int interp_idx)
+{
+	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);
+	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);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (rx->main_clk_users[interp_idx] == 0) {
+			/* Main path PGA mute enable */
+			snd_soc_component_write_field(component, main_reg,
+						      CDC_RX_PATH_PGA_MUTE_MASK, 0x1);
+			snd_soc_component_write_field(component, dsm_reg,
+						      CDC_RX_RXn_DSM_CLK_EN_MASK, 0x1);
+			snd_soc_component_update_bits(component, rx_cfg2_reg,
+					CDC_RX_RXn_HPF_CUT_FREQ_MASK, 0x03);
+			rx_macro_load_compander_coeff(component, rx, interp_idx, event);
+			if (rx->hph_hd2_mode)
+				rx_macro_hd2_control(component, interp_idx, event);
+			rx_macro_hphdelay_lutbypass(component, rx, interp_idx, event);
+			rx_macro_config_compander(component, rx, interp_idx, event);
+			if (interp_idx == INTERP_AUX) {
+				rx_macro_config_softclip(component, rx,	event);
+				rx_macro_config_aux_hpf(component, rx, event);
+			}
+			rx_macro_config_classh(component, rx, interp_idx, event);
+		}
+		rx->main_clk_users[interp_idx]++;
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		rx->main_clk_users[interp_idx]--;
+		if (rx->main_clk_users[interp_idx] <= 0) {
+			rx->main_clk_users[interp_idx] = 0;
+			/* Main path PGA mute enable */
+			snd_soc_component_write_field(component, main_reg,
+						      CDC_RX_PATH_PGA_MUTE_MASK, 0x1);
+			/* Clk Disable */
+			snd_soc_component_write_field(component, dsm_reg,
+						      CDC_RX_RXn_DSM_CLK_EN_MASK, 0);
+			snd_soc_component_write_field(component, main_reg,
+						      CDC_RX_PATH_CLK_EN_MASK, 0);
+			/* Reset enable and disable */
+			snd_soc_component_write_field(component, main_reg,
+						      CDC_RX_PATH_RESET_EN_MASK, 1);
+			snd_soc_component_write_field(component, main_reg,
+						      CDC_RX_PATH_RESET_EN_MASK, 0);
+			/* Reset rate to 48K*/
+			snd_soc_component_update_bits(component, main_reg,
+						      CDC_RX_PATH_PCM_RATE_MASK,
+						      0x04);
+			snd_soc_component_update_bits(component, rx_cfg2_reg,
+						      CDC_RX_RXn_HPF_CUT_FREQ_MASK, 0x00);
+			rx_macro_config_classh(component, rx, interp_idx, event);
+			rx_macro_config_compander(component, rx, interp_idx, event);
+			if (interp_idx ==  INTERP_AUX) {
+				rx_macro_config_softclip(component, rx,	event);
+				rx_macro_config_aux_hpf(component, rx, event);
+			}
+			rx_macro_hphdelay_lutbypass(component, rx, interp_idx, event);
+			if (rx->hph_hd2_mode)
+				rx_macro_hd2_control(component, interp_idx, event);
+		}
+	}
+
+	return rx->main_clk_users[interp_idx];
+}
+
+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);
+	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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		rx_macro_enable_interp_clk(component, event, w->shift);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, gain_reg,
+					snd_soc_component_read(component, gain_reg));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Clk Disable */
+		snd_soc_component_update_bits(component, mix_reg,
+					      CDC_RX_RXn_MIX_CLK_EN_MASK, 0x00);
+		rx_macro_enable_interp_clk(component, event, w->shift);
+		/* Reset enable and disable */
+		snd_soc_component_update_bits(component, mix_reg,
+					      CDC_RX_RXn_MIX_RESET_MASK,
+					      CDC_RX_RXn_MIX_RESET);
+		snd_soc_component_update_bits(component, mix_reg,
+					      CDC_RX_RXn_MIX_RESET_MASK, 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+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);
+
+	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),
+					      CDC_RX_RXn_SIDETONE_EN_MASK, 1);
+		snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(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),
+					      CDC_RX_RXn_SIDETONE_EN_MASK, 0);
+		rx_macro_enable_interp_clk(component, event, w->shift);
+		break;
+	default:
+		break;
+	};
+	return 0;
+}
+
+static int rx_macro_set_iir_gain(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU: /* fall through */
+	case SND_SOC_DAPM_PRE_PMD:
+		if (strnstr(w->name, "IIR0", sizeof("IIR0"))) {
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL));
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL));
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL));
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL));
+		} else {
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL));
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL));
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL));
+			snd_soc_component_write(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL,
+			snd_soc_component_read(component,
+				CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL));
+		}
+		break;
+	}
+	return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
+				   int iir_idx, int band_idx, int coeff_idx)
+{
+	u32 value;
+	int reg, b2_reg;
+
+	/* Address does not automatically update if reading */
+	reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+	b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+
+	snd_soc_component_write(component, reg,
+				((band_idx * BAND_MAX + coeff_idx) *
+				 sizeof(uint32_t)) & 0x7F);
+
+	value = snd_soc_component_read(component, b2_reg);
+	snd_soc_component_write(component, reg,
+				((band_idx * BAND_MAX + coeff_idx)
+				 * sizeof(uint32_t) + 1) & 0x7F);
+
+	value |= (snd_soc_component_read(component, b2_reg) << 8);
+	snd_soc_component_write(component, reg,
+				((band_idx * BAND_MAX + coeff_idx)
+				 * sizeof(uint32_t) + 2) & 0x7F);
+
+	value |= (snd_soc_component_read(component, b2_reg) << 16);
+	snd_soc_component_write(component, reg,
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 3) & 0x7F);
+
+	/* Mask bits top 2 bits since they are reserved */
+	value |= (snd_soc_component_read(component, b2_reg) << 24);
+	return value;
+}
+
+static void set_iir_band_coeff(struct snd_soc_component *component,
+			       int iir_idx, int band_idx, uint32_t value)
+{
+	int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+
+	snd_soc_component_write(component, reg, (value & 0xFF));
+	snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
+	snd_soc_component_write(component, reg, (value >> 16) & 0xFF);
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_component_write(component, reg, (value >> 24) & 0x3F);
+}
+
+static int rx_macro_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wcd_iir_filter_ctl *ctl =
+			(struct wcd_iir_filter_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	int iir_idx = ctl->iir_idx;
+	int band_idx = ctl->band_idx;
+	u32 coeff[BAND_MAX];
+	int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+
+	memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
+
+	/* Mask top bit it is reserved */
+	/* Updates addr automatically for each B2 write */
+	snd_soc_component_write(component, reg, (band_idx * BAND_MAX *
+						 sizeof(uint32_t)) & 0x7F);
+
+	set_iir_band_coeff(component, iir_idx, band_idx, coeff[0]);
+	set_iir_band_coeff(component, iir_idx, band_idx, coeff[1]);
+	set_iir_band_coeff(component, iir_idx, band_idx, coeff[2]);
+	set_iir_band_coeff(component, iir_idx, band_idx, coeff[3]);
+	set_iir_band_coeff(component, iir_idx, band_idx, coeff[4]);
+
+	return 0;
+}
+
+static int rx_macro_get_iir_band_audio_mixer(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wcd_iir_filter_ctl *ctl =
+			(struct wcd_iir_filter_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	int iir_idx = ctl->iir_idx;
+	int band_idx = ctl->band_idx;
+	u32 coeff[BAND_MAX];
+
+	coeff[0] = get_iir_band_coeff(component, iir_idx, band_idx, 0);
+	coeff[1] = get_iir_band_coeff(component, iir_idx, band_idx, 1);
+	coeff[2] = get_iir_band_coeff(component, iir_idx, band_idx, 2);
+	coeff[3] = get_iir_band_coeff(component, iir_idx, band_idx, 3);
+	coeff[4] = get_iir_band_coeff(component, iir_idx, band_idx, 4);
+
+	memcpy(ucontrol->value.bytes.data, &coeff[0], params->max);
+
+	return 0;
+}
+
+static int rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *ucontrol)
+{
+	struct wcd_iir_filter_ctl *ctl =
+		(struct wcd_iir_filter_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+	ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	ucontrol->count = params->max;
+
+	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),
+	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),
+
+	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,
+		rx_macro_get_compander, rx_macro_set_compander),
+
+	SOC_SINGLE_EXT("RX_EAR Mode Switch", SND_SOC_NOPM, 0, 1, 0,
+		rx_macro_get_ear_mode, rx_macro_put_ear_mode),
+
+	SOC_SINGLE_EXT("RX_HPH HD2 Mode Switch", SND_SOC_NOPM, 0, 1, 0,
+		rx_macro_get_hph_hd2_mode, rx_macro_put_hph_hd2_mode),
+
+	SOC_ENUM_EXT("RX_HPH PWR Mode", rx_macro_hph_pwr_mode_enum,
+		rx_macro_get_hph_pwr_mode, rx_macro_put_hph_pwr_mode),
+
+	SOC_SINGLE_EXT("RX_Softclip Switch", SND_SOC_NOPM, 0, 1, 0,
+		     rx_macro_soft_clip_enable_get,
+		     rx_macro_soft_clip_enable_put),
+	SOC_SINGLE_EXT("AUX_HPF Switch", SND_SOC_NOPM, 0, 1, 0,
+			rx_macro_aux_hpf_mode_get,
+			rx_macro_aux_hpf_mode_put),
+
+	SOC_SINGLE_S8_TLV("IIR0 INP0 Volume",
+		CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR0 INP1 Volume",
+		CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR0 INP2 Volume",
+		CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR0 INP3 Volume",
+		CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP0 Volume",
+		CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+		CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+		CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+		CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40,
+		digital_gain),
+
+	SOC_SINGLE("IIR1 Band1 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+		   0, 1, 0),
+	SOC_SINGLE("IIR1 Band2 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+		   1, 1, 0),
+	SOC_SINGLE("IIR1 Band3 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+		   2, 1, 0),
+	SOC_SINGLE("IIR1 Band4 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+		   3, 1, 0),
+	SOC_SINGLE("IIR1 Band5 Switch", CDC_RX_SIDETONE_IIR0_IIR_CTL,
+		   4, 1, 0),
+	SOC_SINGLE("IIR2 Band1 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+		   0, 1, 0),
+	SOC_SINGLE("IIR2 Band2 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+		   1, 1, 0),
+	SOC_SINGLE("IIR2 Band3 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+		   2, 1, 0),
+	SOC_SINGLE("IIR2 Band4 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+		   3, 1, 0),
+	SOC_SINGLE("IIR2 Band5 Switch", CDC_RX_SIDETONE_IIR1_IIR_CTL,
+		   4, 1, 0),
+
+	RX_MACRO_IIR_FILTER_CTL("IIR0 Band1", IIR0, BAND1),
+	RX_MACRO_IIR_FILTER_CTL("IIR0 Band2", IIR0, BAND2),
+	RX_MACRO_IIR_FILTER_CTL("IIR0 Band3", IIR0, BAND3),
+	RX_MACRO_IIR_FILTER_CTL("IIR0 Band4", IIR0, BAND4),
+	RX_MACRO_IIR_FILTER_CTL("IIR0 Band5", IIR0, BAND5),
+
+	RX_MACRO_IIR_FILTER_CTL("IIR1 Band1", IIR1, BAND1),
+	RX_MACRO_IIR_FILTER_CTL("IIR1 Band2", IIR1, BAND2),
+	RX_MACRO_IIR_FILTER_CTL("IIR1 Band3", IIR1, BAND3),
+	RX_MACRO_IIR_FILTER_CTL("IIR1 Band4", IIR1, BAND4),
+	RX_MACRO_IIR_FILTER_CTL("IIR1 Band5", IIR1, BAND5),
+
+};
+
+static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 val, ec_hq_reg;
+	int ec_tx;
+
+	val = snd_soc_component_read(component,
+			CDC_RX_INP_MUX_RX_MIX_CFG4);
+	if (!(strcmp(w->name, "RX MIX TX0 MUX")))
+		ec_tx = ((val & 0xf0) >> 0x4) - 1;
+	else if (!(strcmp(w->name, "RX MIX TX1 MUX")))
+		ec_tx = (val & 0x0f) - 1;
+
+	val = snd_soc_component_read(component,
+			CDC_RX_INP_MUX_RX_MIX_CFG5);
+	if (!(strcmp(w->name, "RX MIX TX2 MUX")))
+		ec_tx = (val & 0x0f) - 1;
+
+	if (ec_tx < 0 || (ec_tx >= RX_MACRO_EC_MUX_MAX)) {
+		dev_err(component->dev, "%s: EC mix control not set correctly\n",
+			__func__);
+		return -EINVAL;
+	}
+	ec_hq_reg = CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL +
+			    0x40 * ec_tx;
+	snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01);
+	ec_hq_reg = CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0 +
+				0x40 * ec_tx;
+	/* default set to 48k */
+	snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08);
+
+	return 0;
+}
+
+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),
+
+	SND_SOC_DAPM_AIF_IN("RX AIF2 PB", "RX_MACRO_AIF2 Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_IN("RX AIF3 PB", "RX_MACRO_AIF3 Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_IN("RX AIF4 PB", "RX_MACRO_AIF4 Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("RX AIF_ECHO", "RX_AIF_ECHO Capture", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("RX_MACRO RX0 MUX", SND_SOC_NOPM, RX_MACRO_RX0, 0,
+			 &rx_macro_rx0_mux),
+	SND_SOC_DAPM_MUX("RX_MACRO RX1 MUX", SND_SOC_NOPM, RX_MACRO_RX1, 0,
+			 &rx_macro_rx1_mux),
+	SND_SOC_DAPM_MUX("RX_MACRO RX2 MUX", SND_SOC_NOPM, RX_MACRO_RX2, 0,
+			 &rx_macro_rx2_mux),
+	SND_SOC_DAPM_MUX("RX_MACRO RX3 MUX", SND_SOC_NOPM, RX_MACRO_RX3, 0,
+			 &rx_macro_rx3_mux),
+	SND_SOC_DAPM_MUX("RX_MACRO RX4 MUX", SND_SOC_NOPM, RX_MACRO_RX4, 0,
+			 &rx_macro_rx4_mux),
+	SND_SOC_DAPM_MUX("RX_MACRO RX5 MUX", SND_SOC_NOPM, RX_MACRO_RX5, 0,
+			 &rx_macro_rx5_mux),
+
+	SND_SOC_DAPM_MIXER("RX_RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX_RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX_RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX_RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX_RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX_RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("IIR0 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp0_mux),
+	SND_SOC_DAPM_MUX("IIR0 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp1_mux),
+	SND_SOC_DAPM_MUX("IIR0 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp2_mux),
+	SND_SOC_DAPM_MUX("IIR0 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp3_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp0_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp2_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp3_mux),
+
+	SND_SOC_DAPM_MUX_E("RX MIX TX0 MUX", SND_SOC_NOPM,
+			   RX_MACRO_EC0_MUX, 0,
+			   &rx_mix_tx0_mux, rx_macro_enable_echo,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX MIX TX1 MUX", SND_SOC_NOPM,
+			   RX_MACRO_EC1_MUX, 0,
+			   &rx_mix_tx1_mux, rx_macro_enable_echo,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX MIX TX2 MUX", SND_SOC_NOPM,
+			   RX_MACRO_EC2_MUX, 0,
+			   &rx_mix_tx2_mux, rx_macro_enable_echo,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("IIR0", CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL,
+		4, 0, NULL, 0, rx_macro_set_iir_gain,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER_E("IIR1", CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL,
+		4, 0, NULL, 0, rx_macro_set_iir_gain,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER("SRC0", CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SRC1", CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL,
+		4, 0, NULL, 0),
+
+	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,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0,
+		&rx_int1_2_mux, rx_macro_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_AUX, 0,
+		&rx_int2_2_mux, rx_macro_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, &rx_int0_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_int0_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, &rx_int0_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, &rx_int1_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_int1_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, &rx_int1_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, &rx_int2_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, &rx_int2_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, &rx_int2_1_mix_inp2_mux),
+
+	SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0,
+		&rx_int0_1_interp_mux, rx_macro_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0,
+		&rx_int1_1_interp_mux, rx_macro_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_AUX, 0,
+		&rx_int2_1_interp_mux, rx_macro_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("RX INT0_2 INTERP", SND_SOC_NOPM, 0, 0,
+			 &rx_int0_2_interp_mux),
+	SND_SOC_DAPM_MUX("RX INT1_2 INTERP", SND_SOC_NOPM, 0, 0,
+			 &rx_int1_2_interp_mux),
+	SND_SOC_DAPM_MUX("RX INT2_2 INTERP", SND_SOC_NOPM, 0, 0,
+			 &rx_int2_2_interp_mux),
+
+	SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL,
+		0, &rx_int0_mix2_inp_mux, rx_macro_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR,
+		0, &rx_int1_mix2_inp_mux, rx_macro_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_AUX,
+		0, &rx_int2_mix2_inp_mux, rx_macro_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPHL_OUT"),
+	SND_SOC_DAPM_OUTPUT("HPHR_OUT"),
+	SND_SOC_DAPM_OUTPUT("AUX_OUT"),
+
+	SND_SOC_DAPM_INPUT("RX_TX DEC0_INP"),
+	SND_SOC_DAPM_INPUT("RX_TX DEC1_INP"),
+	SND_SOC_DAPM_INPUT("RX_TX DEC2_INP"),
+	SND_SOC_DAPM_INPUT("RX_TX DEC3_INP"),
+
+	SND_SOC_DAPM_SUPPLY_S("RX_MCLK", 0, SND_SOC_NOPM, 0, 0,
+	rx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route rx_audio_map[] = {
+	{"RX AIF1 PB", NULL, "RX_MCLK"},
+	{"RX AIF2 PB", NULL, "RX_MCLK"},
+	{"RX AIF3 PB", NULL, "RX_MCLK"},
+	{"RX AIF4 PB", NULL, "RX_MCLK"},
+
+	{"RX_MACRO RX0 MUX", "AIF1_PB", "RX AIF1 PB"},
+	{"RX_MACRO RX1 MUX", "AIF1_PB", "RX AIF1 PB"},
+	{"RX_MACRO RX2 MUX", "AIF1_PB", "RX AIF1 PB"},
+	{"RX_MACRO RX3 MUX", "AIF1_PB", "RX AIF1 PB"},
+	{"RX_MACRO RX4 MUX", "AIF1_PB", "RX AIF1 PB"},
+	{"RX_MACRO RX5 MUX", "AIF1_PB", "RX AIF1 PB"},
+
+	{"RX_MACRO RX0 MUX", "AIF2_PB", "RX AIF2 PB"},
+	{"RX_MACRO RX1 MUX", "AIF2_PB", "RX AIF2 PB"},
+	{"RX_MACRO RX2 MUX", "AIF2_PB", "RX AIF2 PB"},
+	{"RX_MACRO RX3 MUX", "AIF2_PB", "RX AIF2 PB"},
+	{"RX_MACRO RX4 MUX", "AIF2_PB", "RX AIF2 PB"},
+	{"RX_MACRO RX5 MUX", "AIF2_PB", "RX AIF2 PB"},
+
+	{"RX_MACRO RX0 MUX", "AIF3_PB", "RX AIF3 PB"},
+	{"RX_MACRO RX1 MUX", "AIF3_PB", "RX AIF3 PB"},
+	{"RX_MACRO RX2 MUX", "AIF3_PB", "RX AIF3 PB"},
+	{"RX_MACRO RX3 MUX", "AIF3_PB", "RX AIF3 PB"},
+	{"RX_MACRO RX4 MUX", "AIF3_PB", "RX AIF3 PB"},
+	{"RX_MACRO RX5 MUX", "AIF3_PB", "RX AIF3 PB"},
+
+	{"RX_MACRO RX0 MUX", "AIF4_PB", "RX AIF4 PB"},
+	{"RX_MACRO RX1 MUX", "AIF4_PB", "RX AIF4 PB"},
+	{"RX_MACRO RX2 MUX", "AIF4_PB", "RX AIF4 PB"},
+	{"RX_MACRO RX3 MUX", "AIF4_PB", "RX AIF4 PB"},
+	{"RX_MACRO RX4 MUX", "AIF4_PB", "RX AIF4 PB"},
+	{"RX_MACRO RX5 MUX", "AIF4_PB", "RX AIF4 PB"},
+
+	{"RX_RX0", NULL, "RX_MACRO RX0 MUX"},
+	{"RX_RX1", NULL, "RX_MACRO RX1 MUX"},
+	{"RX_RX2", NULL, "RX_MACRO RX2 MUX"},
+	{"RX_RX3", NULL, "RX_MACRO RX3 MUX"},
+	{"RX_RX4", NULL, "RX_MACRO RX4 MUX"},
+	{"RX_RX5", NULL, "RX_MACRO RX5 MUX"},
+
+	{"RX INT0_1 MIX1 INP0", "RX0", "RX_RX0"},
+	{"RX INT0_1 MIX1 INP0", "RX1", "RX_RX1"},
+	{"RX INT0_1 MIX1 INP0", "RX2", "RX_RX2"},
+	{"RX INT0_1 MIX1 INP0", "RX3", "RX_RX3"},
+	{"RX INT0_1 MIX1 INP0", "RX4", "RX_RX4"},
+	{"RX INT0_1 MIX1 INP0", "RX5", "RX_RX5"},
+	{"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT0_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
+	{"RX INT0_1 MIX1 INP1", "RX0", "RX_RX0"},
+	{"RX INT0_1 MIX1 INP1", "RX1", "RX_RX1"},
+	{"RX INT0_1 MIX1 INP1", "RX2", "RX_RX2"},
+	{"RX INT0_1 MIX1 INP1", "RX3", "RX_RX3"},
+	{"RX INT0_1 MIX1 INP1", "RX4", "RX_RX4"},
+	{"RX INT0_1 MIX1 INP1", "RX5", "RX_RX5"},
+	{"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT0_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
+	{"RX INT0_1 MIX1 INP2", "RX0", "RX_RX0"},
+	{"RX INT0_1 MIX1 INP2", "RX1", "RX_RX1"},
+	{"RX INT0_1 MIX1 INP2", "RX2", "RX_RX2"},
+	{"RX INT0_1 MIX1 INP2", "RX3", "RX_RX3"},
+	{"RX INT0_1 MIX1 INP2", "RX4", "RX_RX4"},
+	{"RX INT0_1 MIX1 INP2", "RX5", "RX_RX5"},
+	{"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT0_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
+
+	{"RX INT1_1 MIX1 INP0", "RX0", "RX_RX0"},
+	{"RX INT1_1 MIX1 INP0", "RX1", "RX_RX1"},
+	{"RX INT1_1 MIX1 INP0", "RX2", "RX_RX2"},
+	{"RX INT1_1 MIX1 INP0", "RX3", "RX_RX3"},
+	{"RX INT1_1 MIX1 INP0", "RX4", "RX_RX4"},
+	{"RX INT1_1 MIX1 INP0", "RX5", "RX_RX5"},
+	{"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT1_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
+	{"RX INT1_1 MIX1 INP1", "RX0", "RX_RX0"},
+	{"RX INT1_1 MIX1 INP1", "RX1", "RX_RX1"},
+	{"RX INT1_1 MIX1 INP1", "RX2", "RX_RX2"},
+	{"RX INT1_1 MIX1 INP1", "RX3", "RX_RX3"},
+	{"RX INT1_1 MIX1 INP1", "RX4", "RX_RX4"},
+	{"RX INT1_1 MIX1 INP1", "RX5", "RX_RX5"},
+	{"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT1_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
+	{"RX INT1_1 MIX1 INP2", "RX0", "RX_RX0"},
+	{"RX INT1_1 MIX1 INP2", "RX1", "RX_RX1"},
+	{"RX INT1_1 MIX1 INP2", "RX2", "RX_RX2"},
+	{"RX INT1_1 MIX1 INP2", "RX3", "RX_RX3"},
+	{"RX INT1_1 MIX1 INP2", "RX4", "RX_RX4"},
+	{"RX INT1_1 MIX1 INP2", "RX5", "RX_RX5"},
+	{"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT1_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
+
+	{"RX INT2_1 MIX1 INP0", "RX0", "RX_RX0"},
+	{"RX INT2_1 MIX1 INP0", "RX1", "RX_RX1"},
+	{"RX INT2_1 MIX1 INP0", "RX2", "RX_RX2"},
+	{"RX INT2_1 MIX1 INP0", "RX3", "RX_RX3"},
+	{"RX INT2_1 MIX1 INP0", "RX4", "RX_RX4"},
+	{"RX INT2_1 MIX1 INP0", "RX5", "RX_RX5"},
+	{"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT2_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
+	{"RX INT2_1 MIX1 INP1", "RX0", "RX_RX0"},
+	{"RX INT2_1 MIX1 INP1", "RX1", "RX_RX1"},
+	{"RX INT2_1 MIX1 INP1", "RX2", "RX_RX2"},
+	{"RX INT2_1 MIX1 INP1", "RX3", "RX_RX3"},
+	{"RX INT2_1 MIX1 INP1", "RX4", "RX_RX4"},
+	{"RX INT2_1 MIX1 INP1", "RX5", "RX_RX5"},
+	{"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT2_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
+	{"RX INT2_1 MIX1 INP2", "RX0", "RX_RX0"},
+	{"RX INT2_1 MIX1 INP2", "RX1", "RX_RX1"},
+	{"RX INT2_1 MIX1 INP2", "RX2", "RX_RX2"},
+	{"RX INT2_1 MIX1 INP2", "RX3", "RX_RX3"},
+	{"RX INT2_1 MIX1 INP2", "RX4", "RX_RX4"},
+	{"RX INT2_1 MIX1 INP2", "RX5", "RX_RX5"},
+	{"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+	{"RX INT2_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
+
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"},
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"},
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"},
+
+	{"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX AIF_ECHO", NULL, "RX MIX TX0 MUX"},
+	{"RX AIF_ECHO", NULL, "RX MIX TX1 MUX"},
+	{"RX AIF_ECHO", NULL, "RX MIX TX2 MUX"},
+	{"RX AIF_ECHO", NULL, "RX_MCLK"},
+
+	/* Mixing path INT0 */
+	{"RX INT0_2 MUX", "RX0", "RX_RX0"},
+	{"RX INT0_2 MUX", "RX1", "RX_RX1"},
+	{"RX INT0_2 MUX", "RX2", "RX_RX2"},
+	{"RX INT0_2 MUX", "RX3", "RX_RX3"},
+	{"RX INT0_2 MUX", "RX4", "RX_RX4"},
+	{"RX INT0_2 MUX", "RX5", "RX_RX5"},
+	{"RX INT0_2 INTERP", NULL, "RX INT0_2 MUX"},
+	{"RX INT0 SEC MIX", NULL, "RX INT0_2 INTERP"},
+
+	/* Mixing path INT1 */
+	{"RX INT1_2 MUX", "RX0", "RX_RX0"},
+	{"RX INT1_2 MUX", "RX1", "RX_RX1"},
+	{"RX INT1_2 MUX", "RX2", "RX_RX2"},
+	{"RX INT1_2 MUX", "RX3", "RX_RX3"},
+	{"RX INT1_2 MUX", "RX4", "RX_RX4"},
+	{"RX INT1_2 MUX", "RX5", "RX_RX5"},
+	{"RX INT1_2 INTERP", NULL, "RX INT1_2 MUX"},
+	{"RX INT1 SEC MIX", NULL, "RX INT1_2 INTERP"},
+
+	/* Mixing path INT2 */
+	{"RX INT2_2 MUX", "RX0", "RX_RX0"},
+	{"RX INT2_2 MUX", "RX1", "RX_RX1"},
+	{"RX INT2_2 MUX", "RX2", "RX_RX2"},
+	{"RX INT2_2 MUX", "RX3", "RX_RX3"},
+	{"RX INT2_2 MUX", "RX4", "RX_RX4"},
+	{"RX INT2_2 MUX", "RX5", "RX_RX5"},
+	{"RX INT2_2 INTERP", NULL, "RX INT2_2 MUX"},
+	{"RX INT2 SEC MIX", NULL, "RX INT2_2 INTERP"},
+
+	{"RX INT0_1 INTERP", NULL, "RX INT0_1 MIX1"},
+	{"RX INT0 SEC MIX", NULL, "RX INT0_1 INTERP"},
+	{"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"},
+	{"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"},
+	{"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"},
+	{"HPHL_OUT", NULL, "RX INT0 DEM MUX"},
+	{"HPHL_OUT", NULL, "RX_MCLK"},
+
+	{"RX INT1_1 INTERP", NULL, "RX INT1_1 MIX1"},
+	{"RX INT1 SEC MIX", NULL, "RX INT1_1 INTERP"},
+	{"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"},
+	{"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"},
+	{"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX2"},
+	{"HPHR_OUT", NULL, "RX INT1 DEM MUX"},
+	{"HPHR_OUT", NULL, "RX_MCLK"},
+
+	{"RX INT2_1 INTERP", NULL, "RX INT2_1 MIX1"},
+
+	{"RX INT2 SEC MIX", NULL, "RX INT2_1 INTERP"},
+	{"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"},
+	{"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"},
+	{"AUX_OUT", NULL, "RX INT2 MIX2"},
+	{"AUX_OUT", NULL, "RX_MCLK"},
+
+	{"IIR0", NULL, "RX_MCLK"},
+	{"IIR0", NULL, "IIR0 INP0 MUX"},
+	{"IIR0 INP0 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR0 INP0 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR0 INP0 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR0 INP0 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR0 INP0 MUX", "RX0", "RX_RX0"},
+	{"IIR0 INP0 MUX", "RX1", "RX_RX1"},
+	{"IIR0 INP0 MUX", "RX2", "RX_RX2"},
+	{"IIR0 INP0 MUX", "RX3", "RX_RX3"},
+	{"IIR0 INP0 MUX", "RX4", "RX_RX4"},
+	{"IIR0 INP0 MUX", "RX5", "RX_RX5"},
+	{"IIR0", NULL, "IIR0 INP1 MUX"},
+	{"IIR0 INP1 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR0 INP1 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR0 INP1 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR0 INP1 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR0 INP1 MUX", "RX0", "RX_RX0"},
+	{"IIR0 INP1 MUX", "RX1", "RX_RX1"},
+	{"IIR0 INP1 MUX", "RX2", "RX_RX2"},
+	{"IIR0 INP1 MUX", "RX3", "RX_RX3"},
+	{"IIR0 INP1 MUX", "RX4", "RX_RX4"},
+	{"IIR0 INP1 MUX", "RX5", "RX_RX5"},
+	{"IIR0", NULL, "IIR0 INP2 MUX"},
+	{"IIR0 INP2 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR0 INP2 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR0 INP2 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR0 INP2 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR0 INP2 MUX", "RX0", "RX_RX0"},
+	{"IIR0 INP2 MUX", "RX1", "RX_RX1"},
+	{"IIR0 INP2 MUX", "RX2", "RX_RX2"},
+	{"IIR0 INP2 MUX", "RX3", "RX_RX3"},
+	{"IIR0 INP2 MUX", "RX4", "RX_RX4"},
+	{"IIR0 INP2 MUX", "RX5", "RX_RX5"},
+	{"IIR0", NULL, "IIR0 INP3 MUX"},
+	{"IIR0 INP3 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR0 INP3 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR0 INP3 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR0 INP3 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR0 INP3 MUX", "RX0", "RX_RX0"},
+	{"IIR0 INP3 MUX", "RX1", "RX_RX1"},
+	{"IIR0 INP3 MUX", "RX2", "RX_RX2"},
+	{"IIR0 INP3 MUX", "RX3", "RX_RX3"},
+	{"IIR0 INP3 MUX", "RX4", "RX_RX4"},
+	{"IIR0 INP3 MUX", "RX5", "RX_RX5"},
+
+	{"IIR1", NULL, "RX_MCLK"},
+	{"IIR1", NULL, "IIR1 INP0 MUX"},
+	{"IIR1 INP0 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR1 INP0 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR1 INP0 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR1 INP0 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR1 INP0 MUX", "RX0", "RX_RX0"},
+	{"IIR1 INP0 MUX", "RX1", "RX_RX1"},
+	{"IIR1 INP0 MUX", "RX2", "RX_RX2"},
+	{"IIR1 INP0 MUX", "RX3", "RX_RX3"},
+	{"IIR1 INP0 MUX", "RX4", "RX_RX4"},
+	{"IIR1 INP0 MUX", "RX5", "RX_RX5"},
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR1 INP1 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR1 INP1 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR1 INP1 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR1 INP1 MUX", "RX0", "RX_RX0"},
+	{"IIR1 INP1 MUX", "RX1", "RX_RX1"},
+	{"IIR1 INP1 MUX", "RX2", "RX_RX2"},
+	{"IIR1 INP1 MUX", "RX3", "RX_RX3"},
+	{"IIR1 INP1 MUX", "RX4", "RX_RX4"},
+	{"IIR1 INP1 MUX", "RX5", "RX_RX5"},
+	{"IIR1", NULL, "IIR1 INP2 MUX"},
+	{"IIR1 INP2 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR1 INP2 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR1 INP2 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR1 INP2 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR1 INP2 MUX", "RX0", "RX_RX0"},
+	{"IIR1 INP2 MUX", "RX1", "RX_RX1"},
+	{"IIR1 INP2 MUX", "RX2", "RX_RX2"},
+	{"IIR1 INP2 MUX", "RX3", "RX_RX3"},
+	{"IIR1 INP2 MUX", "RX4", "RX_RX4"},
+	{"IIR1 INP2 MUX", "RX5", "RX_RX5"},
+	{"IIR1", NULL, "IIR1 INP3 MUX"},
+	{"IIR1 INP3 MUX", "DEC0", "RX_TX DEC0_INP"},
+	{"IIR1 INP3 MUX", "DEC1", "RX_TX DEC1_INP"},
+	{"IIR1 INP3 MUX", "DEC2", "RX_TX DEC2_INP"},
+	{"IIR1 INP3 MUX", "DEC3", "RX_TX DEC3_INP"},
+	{"IIR1 INP3 MUX", "RX0", "RX_RX0"},
+	{"IIR1 INP3 MUX", "RX1", "RX_RX1"},
+	{"IIR1 INP3 MUX", "RX2", "RX_RX2"},
+	{"IIR1 INP3 MUX", "RX3", "RX_RX3"},
+	{"IIR1 INP3 MUX", "RX4", "RX_RX4"},
+	{"IIR1 INP3 MUX", "RX5", "RX_RX5"},
+
+	{"SRC0", NULL, "IIR0"},
+	{"SRC1", NULL, "IIR1"},
+	{"RX INT0 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT0 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT1 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT1 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT2 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT2 MIX2 INP", "SRC1", "SRC1"},
+};
+
+static int rx_macro_component_probe(struct snd_soc_component *component)
+{
+	struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_init_regmap(component, rx->regmap);
+
+	snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_SEC7,
+				      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,
+				      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,
+				      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,
+				      CDC_RX_DC_COEFF_SEL_MASK,
+				      CDC_RX_DC_COEFF_SEL_TWO);
+	snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_CFG3,
+				      CDC_RX_DC_COEFF_SEL_MASK,
+				      CDC_RX_DC_COEFF_SEL_TWO);
+	snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_CFG3,
+				      CDC_RX_DC_COEFF_SEL_MASK,
+				      CDC_RX_DC_COEFF_SEL_TWO);
+
+	rx->component = component;
+
+	return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+	struct rx_macro *rx = to_rx_macro(hw);
+
+	rx_macro_mclk_enable(rx, true);
+	if (rx->reset_swr)
+		regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+				   CDC_RX_SWR_RESET_MASK,
+				   CDC_RX_SWR_RESET);
+
+	regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+			   CDC_RX_SWR_CLK_EN_MASK, 1);
+
+	if (rx->reset_swr)
+		regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+				   CDC_RX_SWR_RESET_MASK, 0);
+	rx->reset_swr = false;
+
+	return 0;
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+	struct rx_macro *rx = to_rx_macro(hw);
+
+	regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, 
+			   CDC_RX_SWR_CLK_EN_MASK, 0);
+
+	rx_macro_mclk_enable(rx, false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct rx_macro *rx = to_rx_macro(hw);
+	int ret, val;
+
+	regmap_read(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, &val);
+	ret = val & BIT(0);
+
+	return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+	.prepare = swclk_gate_enable,
+	.unprepare = swclk_gate_disable,
+	.is_enabled = swclk_gate_is_enabled,
+	.recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx)
+{
+	struct device *dev = rx->dev;
+	struct device_node *np = dev->of_node;
+	const char *parent_clk_name = NULL;
+	const char *clk_name = "lpass-rx-mclk";
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	parent_clk_name = __clk_get_name(rx->clks[2].clk);
+
+	init.name = clk_name;
+	init.ops = &swclk_gate_ops;
+	init.flags = 0;
+	init.parent_names = &parent_clk_name;
+	init.num_parents = 1;
+	rx->hw.init = &init;
+	hw = &rx->hw;
+	ret = clk_hw_register(rx->dev, hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+	return NULL;
+}
+
+static const struct snd_soc_component_driver rx_macro_component_drv = {
+	.name = "RX-MACRO",
+	.probe = rx_macro_component_probe,
+	.controls = rx_macro_snd_controls,
+	.num_controls = ARRAY_SIZE(rx_macro_snd_controls),
+	.dapm_widgets = rx_macro_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rx_macro_dapm_widgets),
+	.dapm_routes = rx_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(rx_audio_map),
+};
+
+static int rx_macro_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rx_macro *rx;
+	void __iomem *base;
+	int ret;
+
+	rx = devm_kzalloc(dev, sizeof(*rx), GFP_KERNEL);
+	if (!rx)
+		return -ENOMEM;
+
+	rx->clks[0].id = "macro";
+	rx->clks[1].id = "dcodec";
+	rx->clks[2].id = "mclk";
+	rx->clks[3].id = "npl";
+	rx->clks[4].id = "fsgen";
+
+	ret = devm_clk_bulk_get(dev, RX_NUM_CLKS_MAX, rx->clks);
+	if (ret) {
+		dev_err(dev, "Error getting RX Clocks (%d)\n", ret);
+		return ret;
+	}
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config);
+
+	dev_set_drvdata(dev, rx);
+
+	rx->reset_swr = true;
+	rx->dev = dev;
+
+	/* set MCLK and NPL rates */
+	clk_set_rate(rx->clks[2].clk, MCLK_FREQ);
+	clk_set_rate(rx->clks[3].clk, MCLK_FREQ);
+
+	ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks);
+	if (ret)
+		return ret;
+
+	rx_macro_register_mclk_output(rx);
+
+	ret = devm_snd_soc_register_component(dev, &rx_macro_component_drv,
+					      rx_macro_dai,
+					      ARRAY_SIZE(rx_macro_dai));
+	if (ret)
+		clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks);
+
+	return ret;
+}
+
+static int rx_macro_remove(struct platform_device *pdev)
+{
+	struct rx_macro *rx = dev_get_drvdata(&pdev->dev);
+
+	of_clk_del_provider(pdev->dev.of_node);
+	clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks);
+	return 0;
+}
+
+static const struct of_device_id rx_macro_dt_match[] = {
+	{ .compatible = "qcom,sm8250-lpass-rx-macro" },
+	{ }
+};
+
+static struct platform_driver rx_macro_driver = {
+	.driver = {
+		.name = "rx_macro",
+		.owner = THIS_MODULE,
+		.of_match_table = rx_macro_dt_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rx_macro_probe,
+	.remove = rx_macro_remove,
+};
+
+module_platform_driver(rx_macro_driver);
+
+MODULE_DESCRIPTION("RX macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
new file mode 100644
index 0000000000000000000000000000000000000000..36d7a6442cdbc512302e4ce4213af90f505e5223
--- /dev/null
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -0,0 +1,1862 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+
+#define CDC_TX_CLK_RST_CTRL_MCLK_CONTROL (0x0000)
+#define CDC_TX_MCLK_EN_MASK		BIT(0)
+#define CDC_TX_MCLK_ENABLE		BIT(0)
+#define CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004)
+#define CDC_TX_FS_CNT_EN_MASK		BIT(0)
+#define CDC_TX_FS_CNT_ENABLE		BIT(0)
+#define CDC_TX_CLK_RST_CTRL_SWR_CONTROL	(0x0008)
+#define CDC_TX_SWR_RESET_MASK		BIT(1)
+#define CDC_TX_SWR_RESET_ENABLE		BIT(1)
+#define CDC_TX_SWR_CLK_EN_MASK		BIT(0)
+#define CDC_TX_SWR_CLK_ENABLE		BIT(0)
+#define CDC_TX_TOP_CSR_TOP_CFG0		(0x0080)
+#define CDC_TX_TOP_CSR_ANC_CFG		(0x0084)
+#define CDC_TX_TOP_CSR_SWR_CTRL		(0x0088)
+#define CDC_TX_TOP_CSR_FREQ_MCLK	(0x0090)
+#define CDC_TX_TOP_CSR_DEBUG_BUS	(0x0094)
+#define CDC_TX_TOP_CSR_DEBUG_EN		(0x0098)
+#define CDC_TX_TOP_CSR_TX_I2S_CTL	(0x00A4)
+#define CDC_TX_TOP_CSR_I2S_CLK		(0x00A8)
+#define CDC_TX_TOP_CSR_I2S_RESET	(0x00AC)
+#define CDC_TX_TOP_CSR_SWR_DMICn_CTL(n)	(0x00C0 + n * 0x4)
+#define CDC_TX_TOP_CSR_SWR_DMIC0_CTL	(0x00C0)
+#define CDC_TX_SWR_DMIC_CLK_SEL_MASK	GENMASK(3, 1)
+#define CDC_TX_TOP_CSR_SWR_DMIC1_CTL	(0x00C4)
+#define CDC_TX_TOP_CSR_SWR_DMIC2_CTL	(0x00C8)
+#define CDC_TX_TOP_CSR_SWR_DMIC3_CTL	(0x00CC)
+#define CDC_TX_TOP_CSR_SWR_AMIC0_CTL	(0x00D0)
+#define CDC_TX_TOP_CSR_SWR_AMIC1_CTL	(0x00D4)
+#define CDC_TX_INP_MUX_ADC_MUXn_CFG0(n)	(0x0100 + 0x8 * n)
+#define CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK GENMASK(3, 0)
+#define CDC_TX_INP_MUX_ADC_MUX0_CFG0	(0x0100)
+#define CDC_TX_INP_MUX_ADC_MUXn_CFG1(n)	(0x0104 + 0x8 * n)
+#define CDC_TX_INP_MUX_ADC_MUX0_CFG1	(0x0104)
+#define CDC_TX_INP_MUX_ADC_MUX1_CFG0	(0x0108)
+#define CDC_TX_INP_MUX_ADC_MUX1_CFG1	(0x010C)
+#define CDC_TX_INP_MUX_ADC_MUX2_CFG0	(0x0110)
+#define CDC_TX_INP_MUX_ADC_MUX2_CFG1	(0x0114)
+#define CDC_TX_INP_MUX_ADC_MUX3_CFG0	(0x0118)
+#define CDC_TX_INP_MUX_ADC_MUX3_CFG1	(0x011C)
+#define CDC_TX_INP_MUX_ADC_MUX4_CFG0	(0x0120)
+#define CDC_TX_INP_MUX_ADC_MUX4_CFG1	(0x0124)
+#define CDC_TX_INP_MUX_ADC_MUX5_CFG0	(0x0128)
+#define CDC_TX_INP_MUX_ADC_MUX5_CFG1	(0x012C)
+#define CDC_TX_INP_MUX_ADC_MUX6_CFG0	(0x0130)
+#define CDC_TX_INP_MUX_ADC_MUX6_CFG1	(0x0134)
+#define CDC_TX_INP_MUX_ADC_MUX7_CFG0	(0x0138)
+#define CDC_TX_INP_MUX_ADC_MUX7_CFG1	(0x013C)
+#define CDC_TX_ANC0_CLK_RESET_CTL	(0x0200)
+#define CDC_TX_ANC0_MODE_1_CTL		(0x0204)
+#define CDC_TX_ANC0_MODE_2_CTL		(0x0208)
+#define CDC_TX_ANC0_FF_SHIFT		(0x020C)
+#define CDC_TX_ANC0_FB_SHIFT		(0x0210)
+#define CDC_TX_ANC0_LPF_FF_A_CTL	(0x0214)
+#define CDC_TX_ANC0_LPF_FF_B_CTL	(0x0218)
+#define CDC_TX_ANC0_LPF_FB_CTL		(0x021C)
+#define CDC_TX_ANC0_SMLPF_CTL		(0x0220)
+#define CDC_TX_ANC0_DCFLT_SHIFT_CTL	(0x0224)
+#define CDC_TX_ANC0_IIR_ADAPT_CTL	(0x0228)
+#define CDC_TX_ANC0_IIR_COEFF_1_CTL	(0x022C)
+#define CDC_TX_ANC0_IIR_COEFF_2_CTL	(0x0230)
+#define CDC_TX_ANC0_FF_A_GAIN_CTL	(0x0234)
+#define CDC_TX_ANC0_FF_B_GAIN_CTL	(0x0238)
+#define CDC_TX_ANC0_FB_GAIN_CTL		(0x023C)
+#define CDC_TXn_TX_PATH_CTL(n)		(0x0400 + 0x80 * n)
+#define CDC_TXn_PCM_RATE_MASK		GENMASK(3, 0)
+#define CDC_TXn_PGA_MUTE_MASK		BIT(4)
+#define CDC_TXn_CLK_EN_MASK		BIT(5)
+#define CDC_TX0_TX_PATH_CTL		(0x0400)
+#define CDC_TXn_TX_PATH_CFG0(n)		(0x0404 + 0x80 * n)
+#define CDC_TX0_TX_PATH_CFG0		(0x0404)
+#define CDC_TXn_PH_EN_MASK		BIT(0)
+#define CDC_TXn_ADC_MODE_MASK		GENMASK(2, 1)
+#define CDC_TXn_HPF_CUT_FREQ_MASK	GENMASK(6, 5)
+#define CDC_TXn_ADC_DMIC_SEL_MASK	BIT(7)
+#define CDC_TX0_TX_PATH_CFG1		(0x0408)
+#define CDC_TXn_TX_VOL_CTL(n)		(0x040C + 0x80 * n)
+#define CDC_TX0_TX_VOL_CTL		(0x040C)
+#define CDC_TX0_TX_PATH_SEC0		(0x0410)
+#define CDC_TX0_TX_PATH_SEC1		(0x0414)
+#define CDC_TXn_TX_PATH_SEC2(n)		(0x0418 + 0x80 * n)
+#define CDC_TXn_HPF_F_CHANGE_MASK	 BIT(1)
+#define CDC_TXn_HPF_ZERO_GATE_MASK	 BIT(0)
+#define CDC_TX0_TX_PATH_SEC2		(0x0418)
+#define CDC_TX0_TX_PATH_SEC3		(0x041C)
+#define CDC_TX0_TX_PATH_SEC4		(0x0420)
+#define CDC_TX0_TX_PATH_SEC5		(0x0424)
+#define CDC_TX0_TX_PATH_SEC6		(0x0428)
+#define CDC_TX0_TX_PATH_SEC7		(0x042C)
+#define CDC_TX0_MBHC_CTL_EN_MASK	BIT(6)
+#define CDC_TX1_TX_PATH_CTL		(0x0480)
+#define CDC_TX1_TX_PATH_CFG0		(0x0484)
+#define CDC_TX1_TX_PATH_CFG1		(0x0488)
+#define CDC_TX1_TX_VOL_CTL		(0x048C)
+#define CDC_TX1_TX_PATH_SEC0		(0x0490)
+#define CDC_TX1_TX_PATH_SEC1		(0x0494)
+#define CDC_TX1_TX_PATH_SEC2		(0x0498)
+#define CDC_TX1_TX_PATH_SEC3		(0x049C)
+#define CDC_TX1_TX_PATH_SEC4		(0x04A0)
+#define CDC_TX1_TX_PATH_SEC5		(0x04A4)
+#define CDC_TX1_TX_PATH_SEC6		(0x04A8)
+#define CDC_TX2_TX_PATH_CTL		(0x0500)
+#define CDC_TX2_TX_PATH_CFG0		(0x0504)
+#define CDC_TX2_TX_PATH_CFG1		(0x0508)
+#define CDC_TX2_TX_VOL_CTL		(0x050C)
+#define CDC_TX2_TX_PATH_SEC0		(0x0510)
+#define CDC_TX2_TX_PATH_SEC1		(0x0514)
+#define CDC_TX2_TX_PATH_SEC2		(0x0518)
+#define CDC_TX2_TX_PATH_SEC3		(0x051C)
+#define CDC_TX2_TX_PATH_SEC4		(0x0520)
+#define CDC_TX2_TX_PATH_SEC5		(0x0524)
+#define CDC_TX2_TX_PATH_SEC6		(0x0528)
+#define CDC_TX3_TX_PATH_CTL		(0x0580)
+#define CDC_TX3_TX_PATH_CFG0		(0x0584)
+#define CDC_TX3_TX_PATH_CFG1		(0x0588)
+#define CDC_TX3_TX_VOL_CTL		(0x058C)
+#define CDC_TX3_TX_PATH_SEC0		(0x0590)
+#define CDC_TX3_TX_PATH_SEC1		(0x0594)
+#define CDC_TX3_TX_PATH_SEC2		(0x0598)
+#define CDC_TX3_TX_PATH_SEC3		(0x059C)
+#define CDC_TX3_TX_PATH_SEC4		(0x05A0)
+#define CDC_TX3_TX_PATH_SEC5		(0x05A4)
+#define CDC_TX3_TX_PATH_SEC6		(0x05A8)
+#define CDC_TX4_TX_PATH_CTL		(0x0600)
+#define CDC_TX4_TX_PATH_CFG0		(0x0604)
+#define CDC_TX4_TX_PATH_CFG1		(0x0608)
+#define CDC_TX4_TX_VOL_CTL		(0x060C)
+#define CDC_TX4_TX_PATH_SEC0		(0x0610)
+#define CDC_TX4_TX_PATH_SEC1		(0x0614)
+#define CDC_TX4_TX_PATH_SEC2		(0x0618)
+#define CDC_TX4_TX_PATH_SEC3		(0x061C)
+#define CDC_TX4_TX_PATH_SEC4		(0x0620)
+#define CDC_TX4_TX_PATH_SEC5		(0x0624)
+#define CDC_TX4_TX_PATH_SEC6		(0x0628)
+#define CDC_TX5_TX_PATH_CTL		(0x0680)
+#define CDC_TX5_TX_PATH_CFG0		(0x0684)
+#define CDC_TX5_TX_PATH_CFG1		(0x0688)
+#define CDC_TX5_TX_VOL_CTL		(0x068C)
+#define CDC_TX5_TX_PATH_SEC0		(0x0690)
+#define CDC_TX5_TX_PATH_SEC1		(0x0694)
+#define CDC_TX5_TX_PATH_SEC2		(0x0698)
+#define CDC_TX5_TX_PATH_SEC3		(0x069C)
+#define CDC_TX5_TX_PATH_SEC4		(0x06A0)
+#define CDC_TX5_TX_PATH_SEC5		(0x06A4)
+#define CDC_TX5_TX_PATH_SEC6		(0x06A8)
+#define CDC_TX6_TX_PATH_CTL		(0x0700)
+#define CDC_TX6_TX_PATH_CFG0		(0x0704)
+#define CDC_TX6_TX_PATH_CFG1		(0x0708)
+#define CDC_TX6_TX_VOL_CTL		(0x070C)
+#define CDC_TX6_TX_PATH_SEC0		(0x0710)
+#define CDC_TX6_TX_PATH_SEC1		(0x0714)
+#define CDC_TX6_TX_PATH_SEC2		(0x0718)
+#define CDC_TX6_TX_PATH_SEC3		(0x071C)
+#define CDC_TX6_TX_PATH_SEC4		(0x0720)
+#define CDC_TX6_TX_PATH_SEC5		(0x0724)
+#define CDC_TX6_TX_PATH_SEC6		(0x0728)
+#define CDC_TX7_TX_PATH_CTL		(0x0780)
+#define CDC_TX7_TX_PATH_CFG0		(0x0784)
+#define CDC_TX7_TX_PATH_CFG1		(0x0788)
+#define CDC_TX7_TX_VOL_CTL		(0x078C)
+#define CDC_TX7_TX_PATH_SEC0		(0x0790)
+#define CDC_TX7_TX_PATH_SEC1		(0x0794)
+#define CDC_TX7_TX_PATH_SEC2		(0x0798)
+#define CDC_TX7_TX_PATH_SEC3		(0x079C)
+#define CDC_TX7_TX_PATH_SEC4		(0x07A0)
+#define CDC_TX7_TX_PATH_SEC5		(0x07A4)
+#define CDC_TX7_TX_PATH_SEC6		(0x07A8)
+#define TX_MAX_OFFSET			(0x07A8)
+
+#define TX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define TX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S24_LE |\
+			SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+#define	TX_ADC_MAX	5
+#define TX_ADC_TO_DMIC(n) ((n - TX_ADC_MAX)/2)
+#define NUM_DECIMATORS 8
+#define TX_NUM_CLKS_MAX	5
+#define TX_MACRO_DMIC_UNMUTE_DELAY_MS	40
+#define TX_MACRO_AMIC_UNMUTE_DELAY_MS	100
+#define TX_MACRO_DMIC_HPF_DELAY_MS	300
+#define TX_MACRO_AMIC_HPF_DELAY_MS	300
+#define MCLK_FREQ		9600000
+
+enum {
+	TX_MACRO_AIF_INVALID = 0,
+	TX_MACRO_AIF1_CAP,
+	TX_MACRO_AIF2_CAP,
+	TX_MACRO_AIF3_CAP,
+	TX_MACRO_MAX_DAIS
+};
+
+enum {
+	TX_MACRO_DEC0,
+	TX_MACRO_DEC1,
+	TX_MACRO_DEC2,
+	TX_MACRO_DEC3,
+	TX_MACRO_DEC4,
+	TX_MACRO_DEC5,
+	TX_MACRO_DEC6,
+	TX_MACRO_DEC7,
+	TX_MACRO_DEC_MAX,
+};
+
+enum {
+	TX_MACRO_CLK_DIV_2,
+	TX_MACRO_CLK_DIV_3,
+	TX_MACRO_CLK_DIV_4,
+	TX_MACRO_CLK_DIV_6,
+	TX_MACRO_CLK_DIV_8,
+	TX_MACRO_CLK_DIV_16,
+};
+
+enum {
+	MSM_DMIC,
+	SWR_MIC,
+	ANC_FB_TUNE1
+};
+
+struct tx_mute_work {
+	struct tx_macro *tx;
+	u32 decimator;
+	struct delayed_work dwork;
+};
+
+struct hpf_work {
+	struct tx_macro *tx;
+	u8 decimator;
+	u8 hpf_cut_off_freq;
+	struct delayed_work dwork;
+};
+
+struct tx_macro {
+	struct device *dev;
+	struct snd_soc_component *component;
+	struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+	struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
+	unsigned long active_ch_mask[TX_MACRO_MAX_DAIS];
+	unsigned long active_ch_cnt[TX_MACRO_MAX_DAIS];
+	unsigned long active_decimator[TX_MACRO_MAX_DAIS];
+	struct regmap *regmap;
+	struct clk_bulk_data clks[TX_NUM_CLKS_MAX];
+	struct clk_hw hw;
+	bool dec_active[NUM_DECIMATORS];
+	bool reset_swr;
+	int tx_mclk_users;
+	u16 dmic_clk_div;
+	bool bcs_enable;
+	int dec_mode[NUM_DECIMATORS];
+	bool bcs_clk_en;
+};
+#define to_tx_macro(_hw) container_of(_hw, struct tx_macro, hw)
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+static const struct reg_default tx_defaults[] = {
+	/* TX Macro */
+	{ CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+	{ CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+	{ CDC_TX_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+	{ CDC_TX_TOP_CSR_TOP_CFG0, 0x00},
+	{ CDC_TX_TOP_CSR_ANC_CFG, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_CTRL, 0x00},
+	{ CDC_TX_TOP_CSR_FREQ_MCLK, 0x00},
+	{ CDC_TX_TOP_CSR_DEBUG_BUS, 0x00},
+	{ CDC_TX_TOP_CSR_DEBUG_EN, 0x00},
+	{ CDC_TX_TOP_CSR_TX_I2S_CTL, 0x0C},
+	{ CDC_TX_TOP_CSR_I2S_CLK, 0x00},
+	{ CDC_TX_TOP_CSR_I2S_RESET, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_DMIC0_CTL, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_DMIC1_CTL, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_DMIC2_CTL, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_DMIC3_CTL, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_AMIC0_CTL, 0x00},
+	{ CDC_TX_TOP_CSR_SWR_AMIC1_CTL, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX4_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX5_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX6_CFG1, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00},
+	{ CDC_TX_INP_MUX_ADC_MUX7_CFG1, 0x00},
+	{ CDC_TX_ANC0_CLK_RESET_CTL, 0x00},
+	{ CDC_TX_ANC0_MODE_1_CTL, 0x00},
+	{ CDC_TX_ANC0_MODE_2_CTL, 0x00},
+	{ CDC_TX_ANC0_FF_SHIFT, 0x00},
+	{ CDC_TX_ANC0_FB_SHIFT, 0x00},
+	{ CDC_TX_ANC0_LPF_FF_A_CTL, 0x00},
+	{ CDC_TX_ANC0_LPF_FF_B_CTL, 0x00},
+	{ CDC_TX_ANC0_LPF_FB_CTL, 0x00},
+	{ CDC_TX_ANC0_SMLPF_CTL, 0x00},
+	{ CDC_TX_ANC0_DCFLT_SHIFT_CTL, 0x00},
+	{ CDC_TX_ANC0_IIR_ADAPT_CTL, 0x00},
+	{ CDC_TX_ANC0_IIR_COEFF_1_CTL, 0x00},
+	{ CDC_TX_ANC0_IIR_COEFF_2_CTL, 0x00},
+	{ CDC_TX_ANC0_FF_A_GAIN_CTL, 0x00},
+	{ CDC_TX_ANC0_FF_B_GAIN_CTL, 0x00},
+	{ CDC_TX_ANC0_FB_GAIN_CTL, 0x00},
+	{ CDC_TX0_TX_PATH_CTL, 0x04},
+	{ CDC_TX0_TX_PATH_CFG0, 0x10},
+	{ CDC_TX0_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX0_TX_VOL_CTL, 0x00},
+	{ CDC_TX0_TX_PATH_SEC0, 0x00},
+	{ CDC_TX0_TX_PATH_SEC1, 0x00},
+	{ CDC_TX0_TX_PATH_SEC2, 0x01},
+	{ CDC_TX0_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX0_TX_PATH_SEC4, 0x20},
+	{ CDC_TX0_TX_PATH_SEC5, 0x00},
+	{ CDC_TX0_TX_PATH_SEC6, 0x00},
+	{ CDC_TX0_TX_PATH_SEC7, 0x25},
+	{ CDC_TX1_TX_PATH_CTL, 0x04},
+	{ CDC_TX1_TX_PATH_CFG0, 0x10},
+	{ CDC_TX1_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX1_TX_VOL_CTL, 0x00},
+	{ CDC_TX1_TX_PATH_SEC0, 0x00},
+	{ CDC_TX1_TX_PATH_SEC1, 0x00},
+	{ CDC_TX1_TX_PATH_SEC2, 0x01},
+	{ CDC_TX1_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX1_TX_PATH_SEC4, 0x20},
+	{ CDC_TX1_TX_PATH_SEC5, 0x00},
+	{ CDC_TX1_TX_PATH_SEC6, 0x00},
+	{ CDC_TX2_TX_PATH_CTL, 0x04},
+	{ CDC_TX2_TX_PATH_CFG0, 0x10},
+	{ CDC_TX2_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX2_TX_VOL_CTL, 0x00},
+	{ CDC_TX2_TX_PATH_SEC0, 0x00},
+	{ CDC_TX2_TX_PATH_SEC1, 0x00},
+	{ CDC_TX2_TX_PATH_SEC2, 0x01},
+	{ CDC_TX2_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX2_TX_PATH_SEC4, 0x20},
+	{ CDC_TX2_TX_PATH_SEC5, 0x00},
+	{ CDC_TX2_TX_PATH_SEC6, 0x00},
+	{ CDC_TX3_TX_PATH_CTL, 0x04},
+	{ CDC_TX3_TX_PATH_CFG0, 0x10},
+	{ CDC_TX3_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX3_TX_VOL_CTL, 0x00},
+	{ CDC_TX3_TX_PATH_SEC0, 0x00},
+	{ CDC_TX3_TX_PATH_SEC1, 0x00},
+	{ CDC_TX3_TX_PATH_SEC2, 0x01},
+	{ CDC_TX3_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX3_TX_PATH_SEC4, 0x20},
+	{ CDC_TX3_TX_PATH_SEC5, 0x00},
+	{ CDC_TX3_TX_PATH_SEC6, 0x00},
+	{ CDC_TX4_TX_PATH_CTL, 0x04},
+	{ CDC_TX4_TX_PATH_CFG0, 0x10},
+	{ CDC_TX4_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX4_TX_VOL_CTL, 0x00},
+	{ CDC_TX4_TX_PATH_SEC0, 0x00},
+	{ CDC_TX4_TX_PATH_SEC1, 0x00},
+	{ CDC_TX4_TX_PATH_SEC2, 0x01},
+	{ CDC_TX4_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX4_TX_PATH_SEC4, 0x20},
+	{ CDC_TX4_TX_PATH_SEC5, 0x00},
+	{ CDC_TX4_TX_PATH_SEC6, 0x00},
+	{ CDC_TX5_TX_PATH_CTL, 0x04},
+	{ CDC_TX5_TX_PATH_CFG0, 0x10},
+	{ CDC_TX5_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX5_TX_VOL_CTL, 0x00},
+	{ CDC_TX5_TX_PATH_SEC0, 0x00},
+	{ CDC_TX5_TX_PATH_SEC1, 0x00},
+	{ CDC_TX5_TX_PATH_SEC2, 0x01},
+	{ CDC_TX5_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX5_TX_PATH_SEC4, 0x20},
+	{ CDC_TX5_TX_PATH_SEC5, 0x00},
+	{ CDC_TX5_TX_PATH_SEC6, 0x00},
+	{ CDC_TX6_TX_PATH_CTL, 0x04},
+	{ CDC_TX6_TX_PATH_CFG0, 0x10},
+	{ CDC_TX6_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX6_TX_VOL_CTL, 0x00},
+	{ CDC_TX6_TX_PATH_SEC0, 0x00},
+	{ CDC_TX6_TX_PATH_SEC1, 0x00},
+	{ CDC_TX6_TX_PATH_SEC2, 0x01},
+	{ CDC_TX6_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX6_TX_PATH_SEC4, 0x20},
+	{ CDC_TX6_TX_PATH_SEC5, 0x00},
+	{ CDC_TX6_TX_PATH_SEC6, 0x00},
+	{ CDC_TX7_TX_PATH_CTL, 0x04},
+	{ CDC_TX7_TX_PATH_CFG0, 0x10},
+	{ CDC_TX7_TX_PATH_CFG1, 0x0B},
+	{ CDC_TX7_TX_VOL_CTL, 0x00},
+	{ CDC_TX7_TX_PATH_SEC0, 0x00},
+	{ CDC_TX7_TX_PATH_SEC1, 0x00},
+	{ CDC_TX7_TX_PATH_SEC2, 0x01},
+	{ CDC_TX7_TX_PATH_SEC3, 0x3C},
+	{ CDC_TX7_TX_PATH_SEC4, 0x20},
+	{ CDC_TX7_TX_PATH_SEC5, 0x00},
+	{ CDC_TX7_TX_PATH_SEC6, 0x00},
+};
+
+static bool tx_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	/* Update volatile list for tx/tx macros */
+	switch (reg) {
+	case CDC_TX_TOP_CSR_SWR_DMIC0_CTL:
+	case CDC_TX_TOP_CSR_SWR_DMIC1_CTL:
+	case CDC_TX_TOP_CSR_SWR_DMIC2_CTL:
+	case CDC_TX_TOP_CSR_SWR_DMIC3_CTL:
+		return true;
+	}
+	return false;
+}
+
+static bool tx_is_rw_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_TX_CLK_RST_CTRL_MCLK_CONTROL:
+	case CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL:
+	case CDC_TX_CLK_RST_CTRL_SWR_CONTROL:
+	case CDC_TX_TOP_CSR_TOP_CFG0:
+	case CDC_TX_TOP_CSR_ANC_CFG:
+	case CDC_TX_TOP_CSR_SWR_CTRL:
+	case CDC_TX_TOP_CSR_FREQ_MCLK:
+	case CDC_TX_TOP_CSR_DEBUG_BUS:
+	case CDC_TX_TOP_CSR_DEBUG_EN:
+	case CDC_TX_TOP_CSR_TX_I2S_CTL:
+	case CDC_TX_TOP_CSR_I2S_CLK:
+	case CDC_TX_TOP_CSR_I2S_RESET:
+	case CDC_TX_TOP_CSR_SWR_DMIC0_CTL:
+	case CDC_TX_TOP_CSR_SWR_DMIC1_CTL:
+	case CDC_TX_TOP_CSR_SWR_DMIC2_CTL:
+	case CDC_TX_TOP_CSR_SWR_DMIC3_CTL:
+	case CDC_TX_TOP_CSR_SWR_AMIC0_CTL:
+	case CDC_TX_TOP_CSR_SWR_AMIC1_CTL:
+	case CDC_TX_ANC0_CLK_RESET_CTL:
+	case CDC_TX_ANC0_MODE_1_CTL:
+	case CDC_TX_ANC0_MODE_2_CTL:
+	case CDC_TX_ANC0_FF_SHIFT:
+	case CDC_TX_ANC0_FB_SHIFT:
+	case CDC_TX_ANC0_LPF_FF_A_CTL:
+	case CDC_TX_ANC0_LPF_FF_B_CTL:
+	case CDC_TX_ANC0_LPF_FB_CTL:
+	case CDC_TX_ANC0_SMLPF_CTL:
+	case CDC_TX_ANC0_DCFLT_SHIFT_CTL:
+	case CDC_TX_ANC0_IIR_ADAPT_CTL:
+	case CDC_TX_ANC0_IIR_COEFF_1_CTL:
+	case CDC_TX_ANC0_IIR_COEFF_2_CTL:
+	case CDC_TX_ANC0_FF_A_GAIN_CTL:
+	case CDC_TX_ANC0_FF_B_GAIN_CTL:
+	case CDC_TX_ANC0_FB_GAIN_CTL:
+	case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX0_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX1_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX1_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX2_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX2_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX3_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX3_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX4_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX4_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX5_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX5_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX6_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX6_CFG1:
+	case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
+	case CDC_TX_INP_MUX_ADC_MUX7_CFG1:
+	case CDC_TX0_TX_PATH_CTL:
+	case CDC_TX0_TX_PATH_CFG0:
+	case CDC_TX0_TX_PATH_CFG1:
+	case CDC_TX0_TX_VOL_CTL:
+	case CDC_TX0_TX_PATH_SEC0:
+	case CDC_TX0_TX_PATH_SEC1:
+	case CDC_TX0_TX_PATH_SEC2:
+	case CDC_TX0_TX_PATH_SEC3:
+	case CDC_TX0_TX_PATH_SEC4:
+	case CDC_TX0_TX_PATH_SEC5:
+	case CDC_TX0_TX_PATH_SEC6:
+	case CDC_TX0_TX_PATH_SEC7:
+	case CDC_TX1_TX_PATH_CTL:
+	case CDC_TX1_TX_PATH_CFG0:
+	case CDC_TX1_TX_PATH_CFG1:
+	case CDC_TX1_TX_VOL_CTL:
+	case CDC_TX1_TX_PATH_SEC0:
+	case CDC_TX1_TX_PATH_SEC1:
+	case CDC_TX1_TX_PATH_SEC2:
+	case CDC_TX1_TX_PATH_SEC3:
+	case CDC_TX1_TX_PATH_SEC4:
+	case CDC_TX1_TX_PATH_SEC5:
+	case CDC_TX1_TX_PATH_SEC6:
+	case CDC_TX2_TX_PATH_CTL:
+	case CDC_TX2_TX_PATH_CFG0:
+	case CDC_TX2_TX_PATH_CFG1:
+	case CDC_TX2_TX_VOL_CTL:
+	case CDC_TX2_TX_PATH_SEC0:
+	case CDC_TX2_TX_PATH_SEC1:
+	case CDC_TX2_TX_PATH_SEC2:
+	case CDC_TX2_TX_PATH_SEC3:
+	case CDC_TX2_TX_PATH_SEC4:
+	case CDC_TX2_TX_PATH_SEC5:
+	case CDC_TX2_TX_PATH_SEC6:
+	case CDC_TX3_TX_PATH_CTL:
+	case CDC_TX3_TX_PATH_CFG0:
+	case CDC_TX3_TX_PATH_CFG1:
+	case CDC_TX3_TX_VOL_CTL:
+	case CDC_TX3_TX_PATH_SEC0:
+	case CDC_TX3_TX_PATH_SEC1:
+	case CDC_TX3_TX_PATH_SEC2:
+	case CDC_TX3_TX_PATH_SEC3:
+	case CDC_TX3_TX_PATH_SEC4:
+	case CDC_TX3_TX_PATH_SEC5:
+	case CDC_TX3_TX_PATH_SEC6:
+	case CDC_TX4_TX_PATH_CTL:
+	case CDC_TX4_TX_PATH_CFG0:
+	case CDC_TX4_TX_PATH_CFG1:
+	case CDC_TX4_TX_VOL_CTL:
+	case CDC_TX4_TX_PATH_SEC0:
+	case CDC_TX4_TX_PATH_SEC1:
+	case CDC_TX4_TX_PATH_SEC2:
+	case CDC_TX4_TX_PATH_SEC3:
+	case CDC_TX4_TX_PATH_SEC4:
+	case CDC_TX4_TX_PATH_SEC5:
+	case CDC_TX4_TX_PATH_SEC6:
+	case CDC_TX5_TX_PATH_CTL:
+	case CDC_TX5_TX_PATH_CFG0:
+	case CDC_TX5_TX_PATH_CFG1:
+	case CDC_TX5_TX_VOL_CTL:
+	case CDC_TX5_TX_PATH_SEC0:
+	case CDC_TX5_TX_PATH_SEC1:
+	case CDC_TX5_TX_PATH_SEC2:
+	case CDC_TX5_TX_PATH_SEC3:
+	case CDC_TX5_TX_PATH_SEC4:
+	case CDC_TX5_TX_PATH_SEC5:
+	case CDC_TX5_TX_PATH_SEC6:
+	case CDC_TX6_TX_PATH_CTL:
+	case CDC_TX6_TX_PATH_CFG0:
+	case CDC_TX6_TX_PATH_CFG1:
+	case CDC_TX6_TX_VOL_CTL:
+	case CDC_TX6_TX_PATH_SEC0:
+	case CDC_TX6_TX_PATH_SEC1:
+	case CDC_TX6_TX_PATH_SEC2:
+	case CDC_TX6_TX_PATH_SEC3:
+	case CDC_TX6_TX_PATH_SEC4:
+	case CDC_TX6_TX_PATH_SEC5:
+	case CDC_TX6_TX_PATH_SEC6:
+	case CDC_TX7_TX_PATH_CTL:
+	case CDC_TX7_TX_PATH_CFG0:
+	case CDC_TX7_TX_PATH_CFG1:
+	case CDC_TX7_TX_VOL_CTL:
+	case CDC_TX7_TX_PATH_SEC0:
+	case CDC_TX7_TX_PATH_SEC1:
+	case CDC_TX7_TX_PATH_SEC2:
+	case CDC_TX7_TX_PATH_SEC3:
+	case CDC_TX7_TX_PATH_SEC4:
+	case CDC_TX7_TX_PATH_SEC5:
+	case CDC_TX7_TX_PATH_SEC6:
+		return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config tx_regmap_config = {
+	.name = "tx_macro",
+	.reg_bits = 16,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.cache_type = REGCACHE_FLAT,
+	.max_register = TX_MAX_OFFSET,
+	.reg_defaults = tx_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tx_defaults),
+	.writeable_reg = tx_is_rw_register,
+	.volatile_reg = tx_is_volatile_register,
+	.readable_reg = tx_is_rw_register,
+};
+
+static int tx_macro_mclk_enable(struct tx_macro *tx,
+				bool mclk_enable)
+{
+	struct regmap *regmap = tx->regmap;
+
+	if (mclk_enable) {
+		if (tx->tx_mclk_users == 0) {
+			/* 9.6MHz MCLK, set value 0x00 if other frequency */
+			regmap_update_bits(regmap, CDC_TX_TOP_CSR_FREQ_MCLK, 0x01, 0x01);
+			regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+					   CDC_TX_MCLK_EN_MASK,
+					   CDC_TX_MCLK_ENABLE);
+			regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_TX_FS_CNT_EN_MASK,
+					   CDC_TX_FS_CNT_ENABLE);
+			regcache_mark_dirty(regmap);
+			regcache_sync(regmap);
+		}
+		tx->tx_mclk_users++;
+	} else {
+		if (tx->tx_mclk_users <= 0) {
+			dev_err(tx->dev, "clock already disabled\n");
+			tx->tx_mclk_users = 0;
+			goto exit;
+		}
+		tx->tx_mclk_users--;
+		if (tx->tx_mclk_users == 0) {
+			regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_TX_FS_CNT_EN_MASK, 0x0);
+			regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+					   CDC_TX_MCLK_EN_MASK, 0x0);
+		}
+	}
+exit:
+	return 0;
+}
+
+static bool is_amic_enabled(struct snd_soc_component *component, int decimator)
+{
+	u16 adc_mux_reg, adc_reg, adc_n;
+
+	adc_mux_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG1(decimator);
+
+	if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) {
+		adc_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG0(decimator);
+		adc_n = snd_soc_component_read_field(component, adc_reg,
+					     CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK);
+		if (adc_n < TX_ADC_MAX)
+			return true;
+	}
+
+	return false;
+}
+
+static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct tx_macro *tx;
+	struct snd_soc_component *component;
+	u16 dec_cfg_reg, hpf_gate_reg;
+	u8 hpf_cut_off_freq;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	tx = hpf_work->tx;
+	component = tx->component;
+	hpf_cut_off_freq = hpf_work->hpf_cut_off_freq;
+
+	dec_cfg_reg = CDC_TXn_TX_PATH_CFG0(hpf_work->decimator);
+	hpf_gate_reg = CDC_TXn_TX_PATH_SEC2(hpf_work->decimator);
+
+	if (is_amic_enabled(component, hpf_work->decimator)) {
+		snd_soc_component_write_field(component,
+				dec_cfg_reg,
+				CDC_TXn_HPF_CUT_FREQ_MASK,
+				hpf_cut_off_freq);
+		snd_soc_component_update_bits(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x02);
+		snd_soc_component_update_bits(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x01);
+	} else {
+		snd_soc_component_write_field(component, dec_cfg_reg,
+					      CDC_TXn_HPF_CUT_FREQ_MASK,
+					      hpf_cut_off_freq);
+		snd_soc_component_write_field(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK, 0x1);
+		/* Minimum 1 clk cycle delay is required as per HW spec */
+		usleep_range(1000, 1010);
+		snd_soc_component_write_field(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK, 0x0);
+	}
+}
+
+static void tx_macro_mute_update_callback(struct work_struct *work)
+{
+	struct tx_mute_work *tx_mute_dwork;
+	struct snd_soc_component *component;
+	struct tx_macro *tx;
+	struct delayed_work *delayed_work;
+	u8 decimator;
+
+	delayed_work = to_delayed_work(work);
+	tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork);
+	tx = tx_mute_dwork->tx;
+	component = tx->component;
+	decimator = tx_mute_dwork->decimator;
+
+	snd_soc_component_write_field(component, CDC_TXn_TX_PATH_CTL(decimator),
+				      CDC_TXn_PGA_MUTE_MASK, 0x0);
+}
+
+static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tx_macro_mclk_enable(tx, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tx_macro_mclk_enable(tx, false);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val, dmic;
+	u16 mic_sel_reg;
+	u16 dmic_clk_reg;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	val = ucontrol->value.enumerated.item[0];
+
+	switch (e->reg) {
+	case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
+		mic_sel_reg = CDC_TX0_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX1_CFG0:
+		mic_sel_reg = CDC_TX1_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX2_CFG0:
+		mic_sel_reg = CDC_TX2_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX3_CFG0:
+		mic_sel_reg = CDC_TX3_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX4_CFG0:
+		mic_sel_reg = CDC_TX4_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX5_CFG0:
+		mic_sel_reg = CDC_TX5_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX6_CFG0:
+		mic_sel_reg = CDC_TX6_TX_PATH_CFG0;
+		break;
+	case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
+		mic_sel_reg = CDC_TX7_TX_PATH_CFG0;
+		break;
+	}
+
+	if (val != 0) {
+		if (val < 5) {
+			snd_soc_component_write_field(component, mic_sel_reg,
+						      CDC_TXn_ADC_DMIC_SEL_MASK, 0);
+		} else {
+			snd_soc_component_write_field(component, mic_sel_reg,
+						      CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+			dmic = TX_ADC_TO_DMIC(val);
+			dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+			snd_soc_component_write_field(component, dmic_clk_reg,
+						CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+						tx->dmic_clk_div);
+		}
+	}
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+	u32 dai_id = widget->shift;
+	u32 dec_id = mc->shift;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	if (test_bit(dec_id, &tx->active_ch_mask[dai_id]))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct snd_soc_dapm_update *update = NULL;
+	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+	u32 dai_id = widget->shift;
+	u32 dec_id = mc->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	if (enable) {
+		set_bit(dec_id, &tx->active_ch_mask[dai_id]);
+		tx->active_ch_cnt[dai_id]++;
+		tx->active_decimator[dai_id] = dec_id;
+	} else {
+		tx->active_ch_cnt[dai_id]--;
+		clear_bit(dec_id, &tx->active_ch_mask[dai_id]);
+		tx->active_decimator[dai_id] = -1;
+	}
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
+
+	return 0;
+}
+
+static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int decimator;
+	u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg, tx_gain_ctl_reg;
+	u8 hpf_cut_off_freq;
+	int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS;
+	int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS;
+	u16 adc_mux_reg, adc_reg, adc_n, dmic;
+	u16 dmic_clk_reg;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	decimator = w->shift;
+	tx_vol_ctl_reg = CDC_TXn_TX_PATH_CTL(decimator);
+	hpf_gate_reg = CDC_TXn_TX_PATH_SEC2(decimator);
+	dec_cfg_reg = CDC_TXn_TX_PATH_CFG0(decimator);
+	tx_gain_ctl_reg = CDC_TXn_TX_VOL_CTL(decimator);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		adc_mux_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG1(decimator);
+		if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) {
+			adc_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG0(decimator);
+			adc_n = snd_soc_component_read(component, adc_reg) &
+				CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK;
+			if (adc_n >= TX_ADC_MAX) {
+				dmic = TX_ADC_TO_DMIC(adc_n);
+				dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+
+				snd_soc_component_write_field(component, dmic_clk_reg,
+							CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+							tx->dmic_clk_div);
+			}
+		}
+		snd_soc_component_write_field(component, dec_cfg_reg,
+					      CDC_TXn_ADC_MODE_MASK,
+					      tx->dec_mode[decimator]);
+		/* Enable TX PGA Mute */
+		snd_soc_component_write_field(component, tx_vol_ctl_reg,
+					      CDC_TXn_PGA_MUTE_MASK, 0x1);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write_field(component, tx_vol_ctl_reg,
+					     CDC_TXn_CLK_EN_MASK, 0x1);
+		if (!is_amic_enabled(component, decimator)) {
+			snd_soc_component_update_bits(component, hpf_gate_reg, 0x01, 0x00);
+			/* Minimum 1 clk cycle delay is required as per HW spec */
+			usleep_range(1000, 1010);
+		}
+		hpf_cut_off_freq = snd_soc_component_read_field(component, dec_cfg_reg,
+								CDC_TXn_HPF_CUT_FREQ_MASK);
+
+		tx->tx_hpf_work[decimator].hpf_cut_off_freq =
+						hpf_cut_off_freq;
+
+		if (hpf_cut_off_freq != CF_MIN_3DB_150HZ)
+			snd_soc_component_write_field(component, dec_cfg_reg,
+						      CDC_TXn_HPF_CUT_FREQ_MASK,
+						      CF_MIN_3DB_150HZ);
+
+		if (is_amic_enabled(component, decimator)) {
+			hpf_delay = TX_MACRO_AMIC_HPF_DELAY_MS;
+			unmute_delay = TX_MACRO_AMIC_UNMUTE_DELAY_MS;
+		}
+		/* schedule work queue to Remove Mute */
+		queue_delayed_work(system_freezable_wq,
+				   &tx->tx_mute_dwork[decimator].dwork,
+				   msecs_to_jiffies(unmute_delay));
+		if (tx->tx_hpf_work[decimator].hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+			queue_delayed_work(system_freezable_wq,
+				&tx->tx_hpf_work[decimator].dwork,
+				msecs_to_jiffies(hpf_delay));
+			snd_soc_component_update_bits(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x02);
+			if (!is_amic_enabled(component, decimator))
+				snd_soc_component_update_bits(component, hpf_gate_reg,
+						      CDC_TXn_HPF_F_CHANGE_MASK |
+						      CDC_TXn_HPF_ZERO_GATE_MASK,
+						      0x00);
+			snd_soc_component_update_bits(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x01);
+
+			/*
+			 * 6ms delay is required as per HW spec
+			 */
+			usleep_range(6000, 6010);
+		}
+		/* apply gain after decimator is enabled */
+		snd_soc_component_write(component, tx_gain_ctl_reg,
+			      snd_soc_component_read(component,
+					tx_gain_ctl_reg));
+		if (tx->bcs_enable) {
+			snd_soc_component_update_bits(component, dec_cfg_reg,
+					0x01, 0x01);
+			tx->bcs_clk_en = true;
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		hpf_cut_off_freq =
+			tx->tx_hpf_work[decimator].hpf_cut_off_freq;
+		snd_soc_component_write_field(component, tx_vol_ctl_reg,
+					      CDC_TXn_PGA_MUTE_MASK, 0x1);
+		if (cancel_delayed_work_sync(
+		    &tx->tx_hpf_work[decimator].dwork)) {
+			if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+				snd_soc_component_write_field(
+						component, dec_cfg_reg,
+						CDC_TXn_HPF_CUT_FREQ_MASK,
+						hpf_cut_off_freq);
+				if (is_amic_enabled(component, decimator))
+					snd_soc_component_update_bits(component,
+					      hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x02);
+				else
+					snd_soc_component_update_bits(component,
+					      hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x03);
+
+				/*
+				 * Minimum 1 clk cycle delay is required
+				 * as per HW spec
+				 */
+				usleep_range(1000, 1010);
+				snd_soc_component_update_bits(component, hpf_gate_reg,
+					      CDC_TXn_HPF_F_CHANGE_MASK |
+					      CDC_TXn_HPF_ZERO_GATE_MASK,
+					      0x1);
+			}
+		}
+		cancel_delayed_work_sync(&tx->tx_mute_dwork[decimator].dwork);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write_field(component, tx_vol_ctl_reg,
+					      CDC_TXn_CLK_EN_MASK, 0x0);
+		snd_soc_component_write_field(component, dec_cfg_reg,
+					      CDC_TXn_ADC_MODE_MASK, 0x0);
+		snd_soc_component_write_field(component, tx_vol_ctl_reg,
+					      CDC_TXn_PGA_MUTE_MASK, 0x0);
+		if (tx->bcs_enable) {
+			snd_soc_component_write_field(component, dec_cfg_reg,
+						      CDC_TXn_PH_EN_MASK, 0x0);
+			snd_soc_component_write_field(component,
+						      CDC_TX0_TX_PATH_SEC7,
+						      CDC_TX0_MBHC_CTL_EN_MASK,
+						      0x0);
+			tx->bcs_clk_en = false;
+		}
+		break;
+	}
+	return 0;
+}
+
+static int tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int path = e->shift_l;
+
+	ucontrol->value.integer.value[0] = tx->dec_mode[path];
+
+	return 0;
+}
+
+static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int value = ucontrol->value.integer.value[0];
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int path = e->shift_l;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	tx->dec_mode[path] = value;
+
+	return 0;
+}
+
+static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = tx->bcs_enable;
+
+	return 0;
+}
+
+static int tx_macro_set_bcs(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int value = ucontrol->value.integer.value[0];
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	tx->bcs_enable = value;
+
+	return 0;
+}
+
+static int tx_macro_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u32 decimator, sample_rate;
+	int tx_fs_rate;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	sample_rate = params_rate(params);
+	switch (sample_rate) {
+	case 8000:
+		tx_fs_rate = 0;
+		break;
+	case 16000:
+		tx_fs_rate = 1;
+		break;
+	case 32000:
+		tx_fs_rate = 3;
+		break;
+	case 48000:
+		tx_fs_rate = 4;
+		break;
+	case 96000:
+		tx_fs_rate = 5;
+		break;
+	case 192000:
+		tx_fs_rate = 6;
+		break;
+	case 384000:
+		tx_fs_rate = 7;
+		break;
+	default:
+		dev_err(component->dev, "%s: Invalid TX sample rate: %d\n",
+			__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	for_each_set_bit(decimator, &tx->active_ch_mask[dai->id], TX_MACRO_DEC_MAX)
+		snd_soc_component_update_bits(component, CDC_TXn_TX_PATH_CTL(decimator),
+					      CDC_TXn_PCM_RATE_MASK,
+					      tx_fs_rate);
+	return 0;
+}
+
+static int tx_macro_get_channel_map(struct snd_soc_dai *dai,
+				    unsigned int *tx_num, unsigned int *tx_slot,
+				    unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+	switch (dai->id) {
+	case TX_MACRO_AIF1_CAP:
+	case TX_MACRO_AIF2_CAP:
+	case TX_MACRO_AIF3_CAP:
+		*tx_slot = tx->active_ch_mask[dai->id];
+		*tx_num = tx->active_ch_cnt[dai->id];
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+	u16 decimator;
+
+	decimator = tx->active_decimator[dai->id];
+
+	if (mute)
+		snd_soc_component_write_field(component,
+					      CDC_TXn_TX_PATH_CTL(decimator),
+					      CDC_TXn_PGA_MUTE_MASK, 0x1);
+	else
+		snd_soc_component_update_bits(component,
+					      CDC_TXn_TX_PATH_CTL(decimator),
+					      CDC_TXn_PGA_MUTE_MASK, 0x0);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops tx_macro_dai_ops = {
+	.hw_params = tx_macro_hw_params,
+	.get_channel_map = tx_macro_get_channel_map,
+	.mute_stream = tx_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver tx_macro_dai[] = {
+	{
+		.name = "tx_macro_tx1",
+		.id = TX_MACRO_AIF1_CAP,
+		.capture = {
+			.stream_name = "TX_AIF1 Capture",
+			.rates = TX_MACRO_RATES,
+			.formats = TX_MACRO_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &tx_macro_dai_ops,
+	},
+	{
+		.name = "tx_macro_tx2",
+		.id = TX_MACRO_AIF2_CAP,
+		.capture = {
+			.stream_name = "TX_AIF2 Capture",
+			.rates = TX_MACRO_RATES,
+			.formats = TX_MACRO_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &tx_macro_dai_ops,
+	},
+	{
+		.name = "tx_macro_tx3",
+		.id = TX_MACRO_AIF3_CAP,
+		.capture = {
+			.stream_name = "TX_AIF3 Capture",
+			.rates = TX_MACRO_RATES,
+			.formats = TX_MACRO_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &tx_macro_dai_ops,
+	},
+};
+
+static const char * const adc_mux_text[] = {
+	"MSM_DMIC", "SWR_MIC", "ANC_FB_TUNE1"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_dec0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(tx_dec7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG1,
+		   0, adc_mux_text);
+
+static const struct snd_kcontrol_new tx_dec0_mux = SOC_DAPM_ENUM("tx_dec0", tx_dec0_enum);
+static const struct snd_kcontrol_new tx_dec1_mux = SOC_DAPM_ENUM("tx_dec1", tx_dec1_enum);
+static const struct snd_kcontrol_new tx_dec2_mux = SOC_DAPM_ENUM("tx_dec2", tx_dec2_enum);
+static const struct snd_kcontrol_new tx_dec3_mux = SOC_DAPM_ENUM("tx_dec3", tx_dec3_enum);
+static const struct snd_kcontrol_new tx_dec4_mux = SOC_DAPM_ENUM("tx_dec4", tx_dec4_enum);
+static const struct snd_kcontrol_new tx_dec5_mux = SOC_DAPM_ENUM("tx_dec5", tx_dec5_enum);
+static const struct snd_kcontrol_new tx_dec6_mux = SOC_DAPM_ENUM("tx_dec6", tx_dec6_enum);
+static const struct snd_kcontrol_new tx_dec7_mux = SOC_DAPM_ENUM("tx_dec7", tx_dec7_enum);
+
+static const char * const smic_mux_text[] = {
+	"ZERO", "ADC0", "ADC1", "ADC2", "ADC3", "SWR_DMIC0",
+	"SWR_DMIC1", "SWR_DMIC2", "SWR_DMIC3", "SWR_DMIC4",
+	"SWR_DMIC5", "SWR_DMIC6", "SWR_DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_smic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+			0, smic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+			0, smic_mux_text);
+
+static const struct snd_kcontrol_new tx_smic0_mux = SOC_DAPM_ENUM_EXT("tx_smic0", tx_smic0_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic1_mux = SOC_DAPM_ENUM_EXT("tx_smic1", tx_smic1_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic2_mux = SOC_DAPM_ENUM_EXT("tx_smic2", tx_smic2_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic3_mux = SOC_DAPM_ENUM_EXT("tx_smic3", tx_smic3_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic4_mux = SOC_DAPM_ENUM_EXT("tx_smic4", tx_smic4_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic5_mux = SOC_DAPM_ENUM_EXT("tx_smic5", tx_smic5_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6", tx_smic6_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum,
+			snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
+static const char * const dec_mode_mux_text[] = {
+	"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum[] = {
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 2,  ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 4, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 5, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 6, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 7, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+};
+
+static const struct snd_kcontrol_new tx_aif1_cap_mixer[] = {
+	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new tx_aif2_cap_mixer[] = {
+	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new tx_aif3_cap_mixer[] = {
+	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0,
+			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0,
+		SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0),
+
+	SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP", "TX_AIF2 Capture", 0,
+		SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0),
+
+	SND_SOC_DAPM_AIF_OUT("TX_AIF3 CAP", "TX_AIF3 Capture", 0,
+		SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0),
+
+	SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0,
+		tx_aif1_cap_mixer, ARRAY_SIZE(tx_aif1_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0,
+		tx_aif2_cap_mixer, ARRAY_SIZE(tx_aif2_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0,
+		tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)),
+
+	SND_SOC_DAPM_MUX("TX SMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_smic0_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_smic1_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_smic2_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_smic3_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_smic4_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_smic5_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux),
+	SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux),
+
+	SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
+	SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
+	SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
+	SND_SOC_DAPM_INPUT("TX SWR_ADC3"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC0"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC1"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC2"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC3"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC4"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
+	SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
+
+	SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC0, 0,
+			   &tx_dec0_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC1 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC1, 0,
+			   &tx_dec1_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC2 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC2, 0,
+			   &tx_dec2_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC3 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC3, 0,
+			   &tx_dec3_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC4 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC4, 0,
+			   &tx_dec4_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC5 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC5, 0,
+			   &tx_dec5_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC6 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC6, 0,
+			   &tx_dec6_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("TX DEC7 MUX", SND_SOC_NOPM,
+			   TX_MACRO_DEC7, 0,
+			   &tx_dec7_mux, tx_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0,
+	tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+};
+
+static const struct snd_soc_dapm_route tx_audio_map[] = {
+	{"TX_AIF1 CAP", NULL, "TX_MCLK"},
+	{"TX_AIF2 CAP", NULL, "TX_MCLK"},
+	{"TX_AIF3 CAP", NULL, "TX_MCLK"},
+
+	{"TX_AIF1 CAP", NULL, "TX_AIF1_CAP Mixer"},
+	{"TX_AIF2 CAP", NULL, "TX_AIF2_CAP Mixer"},
+	{"TX_AIF3 CAP", NULL, "TX_AIF3_CAP Mixer"},
+
+	{"TX_AIF1_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+	{"TX_AIF1_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+	{"TX_AIF2_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+	{"TX_AIF2_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+	{"TX_AIF3_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+	{"TX_AIF3_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+	{"TX DEC0 MUX", NULL, "TX_MCLK"},
+	{"TX DEC1 MUX", NULL, "TX_MCLK"},
+	{"TX DEC2 MUX", NULL, "TX_MCLK"},
+	{"TX DEC3 MUX", NULL, "TX_MCLK"},
+	{"TX DEC4 MUX", NULL, "TX_MCLK"},
+	{"TX DEC5 MUX", NULL, "TX_MCLK"},
+	{"TX DEC6 MUX", NULL, "TX_MCLK"},
+	{"TX DEC7 MUX", NULL, "TX_MCLK"},
+
+	{"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
+	{"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX0", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX0", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX0", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX0", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX0", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX0", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX0", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX0", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX0", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
+	{"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX1", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX1", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX1", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX1", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX1", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX1", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX1", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX1", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX1", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
+	{"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX2", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX2", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX2", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX2", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX2", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX2", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX2", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX2", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX2", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
+	{"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX3", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX3", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX3", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX3", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX3", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX3", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX3", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX3", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX3", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
+	{"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX4", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX4", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX4", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX4", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX4", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX4", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX4", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX4", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX4", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
+	{"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX5", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX5", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX5", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX5", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX5", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX5", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX5", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX5", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX5", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
+	{"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX6", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX6", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX6", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX6", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX6", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX6", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX6", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX6", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX6", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"},
+
+	{"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
+	{"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
+	{"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
+	{"TX SMIC MUX7", "ADC1", "TX SWR_ADC1"},
+	{"TX SMIC MUX7", "ADC2", "TX SWR_ADC2"},
+	{"TX SMIC MUX7", "ADC3", "TX SWR_ADC3"},
+	{"TX SMIC MUX7", "SWR_DMIC0", "TX SWR_DMIC0"},
+	{"TX SMIC MUX7", "SWR_DMIC1", "TX SWR_DMIC1"},
+	{"TX SMIC MUX7", "SWR_DMIC2", "TX SWR_DMIC2"},
+	{"TX SMIC MUX7", "SWR_DMIC3", "TX SWR_DMIC3"},
+	{"TX SMIC MUX7", "SWR_DMIC4", "TX SWR_DMIC4"},
+	{"TX SMIC MUX7", "SWR_DMIC5", "TX SWR_DMIC5"},
+	{"TX SMIC MUX7", "SWR_DMIC6", "TX SWR_DMIC6"},
+	{"TX SMIC MUX7", "SWR_DMIC7", "TX SWR_DMIC7"},
+};
+
+static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
+	SOC_SINGLE_S8_TLV("TX_DEC0 Volume",
+			  CDC_TX0_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC1 Volume",
+			  CDC_TX1_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC2 Volume",
+			  CDC_TX2_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC3 Volume",
+			  CDC_TX3_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC4 Volume",
+			  CDC_TX4_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC5 Volume",
+			  CDC_TX5_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC6 Volume",
+			  CDC_TX6_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC7 Volume",
+			  CDC_TX7_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+
+	SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum[0],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum[1],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum[2],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum[3],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum[4],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum[5],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum[6],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum[7],
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0,
+		       tx_macro_get_bcs, tx_macro_set_bcs),
+};
+
+static int tx_macro_component_probe(struct snd_soc_component *comp)
+{
+	struct tx_macro *tx = snd_soc_component_get_drvdata(comp);
+	int i;
+
+	snd_soc_component_init_regmap(comp, tx->regmap);
+
+	for (i = 0; i < NUM_DECIMATORS; i++) {
+		tx->tx_hpf_work[i].tx = tx;
+		tx->tx_hpf_work[i].decimator = i;
+		INIT_DELAYED_WORK(&tx->tx_hpf_work[i].dwork,
+			tx_macro_tx_hpf_corner_freq_callback);
+	}
+
+	for (i = 0; i < NUM_DECIMATORS; i++) {
+		tx->tx_mute_dwork[i].tx = tx;
+		tx->tx_mute_dwork[i].decimator = i;
+		INIT_DELAYED_WORK(&tx->tx_mute_dwork[i].dwork,
+			  tx_macro_mute_update_callback);
+	}
+	tx->component = comp;
+
+	snd_soc_component_update_bits(comp, CDC_TX0_TX_PATH_SEC7, 0x3F,
+				      0x0A);
+
+	return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+	struct tx_macro *tx = to_tx_macro(hw);
+	struct regmap *regmap = tx->regmap;
+
+	tx_macro_mclk_enable(tx, true);
+	if (tx->reset_swr)
+		regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+				   CDC_TX_SWR_RESET_MASK,
+				   CDC_TX_SWR_RESET_ENABLE);
+
+	regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+			   CDC_TX_SWR_CLK_EN_MASK,
+			   CDC_TX_SWR_CLK_ENABLE);
+	if (tx->reset_swr)
+		regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+				   CDC_TX_SWR_RESET_MASK, 0x0);
+	tx->reset_swr = false;
+
+	return 0;
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+	struct tx_macro *tx = to_tx_macro(hw);
+	struct regmap *regmap = tx->regmap;
+
+	regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+			   CDC_TX_SWR_CLK_EN_MASK, 0x0);
+
+	tx_macro_mclk_enable(tx, false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct tx_macro *tx = to_tx_macro(hw);
+	int ret, val;
+
+	regmap_read(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, &val);
+	ret = val & BIT(0);
+
+	return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+	.prepare = swclk_gate_enable,
+	.unprepare = swclk_gate_disable,
+	.is_enabled = swclk_gate_is_enabled,
+	.recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *tx_macro_register_mclk_output(struct tx_macro *tx)
+{
+	struct device *dev = tx->dev;
+	struct device_node *np = dev->of_node;
+	const char *parent_clk_name = NULL;
+	const char *clk_name = "lpass-tx-mclk";
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	parent_clk_name = __clk_get_name(tx->clks[2].clk);
+
+	init.name = clk_name;
+	init.ops = &swclk_gate_ops;
+	init.flags = 0;
+	init.parent_names = &parent_clk_name;
+	init.num_parents = 1;
+	tx->hw.init = &init;
+	hw = &tx->hw;
+	ret = clk_hw_register(tx->dev, hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+	return NULL;
+}
+
+static const struct snd_soc_component_driver tx_macro_component_drv = {
+	.name = "RX-MACRO",
+	.probe = tx_macro_component_probe,
+	.controls = tx_macro_snd_controls,
+	.num_controls = ARRAY_SIZE(tx_macro_snd_controls),
+	.dapm_widgets = tx_macro_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tx_macro_dapm_widgets),
+	.dapm_routes = tx_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(tx_audio_map),
+};
+
+static int tx_macro_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tx_macro *tx;
+	void __iomem *base;
+	int ret;
+
+	tx = devm_kzalloc(dev, sizeof(*tx), GFP_KERNEL);
+	if (!tx)
+		return -ENOMEM;
+
+	tx->clks[0].id = "macro";
+	tx->clks[1].id = "dcodec";
+	tx->clks[2].id = "mclk";
+	tx->clks[3].id = "npl";
+	tx->clks[4].id = "fsgen";
+
+	ret = devm_clk_bulk_get(dev, TX_NUM_CLKS_MAX, tx->clks);
+	if (ret) {
+		dev_err(dev, "Error getting RX Clocks (%d)\n", ret);
+		return ret;
+	}
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	tx->regmap = devm_regmap_init_mmio(dev, base, &tx_regmap_config);
+
+	dev_set_drvdata(dev, tx);
+
+	tx->reset_swr = true;
+	tx->dev = dev;
+
+	/* set MCLK and NPL rates */
+	clk_set_rate(tx->clks[2].clk, MCLK_FREQ);
+	clk_set_rate(tx->clks[3].clk, MCLK_FREQ);
+
+	ret = clk_bulk_prepare_enable(TX_NUM_CLKS_MAX, tx->clks);
+	if (ret)
+		return ret;
+
+	tx_macro_register_mclk_output(tx);
+
+	ret = devm_snd_soc_register_component(dev, &tx_macro_component_drv,
+					      tx_macro_dai,
+					      ARRAY_SIZE(tx_macro_dai));
+	if (ret)
+		goto err;
+	return ret;
+err:
+	clk_bulk_disable_unprepare(TX_NUM_CLKS_MAX, tx->clks);
+
+	return ret;
+}
+
+static int tx_macro_remove(struct platform_device *pdev)
+{
+	struct tx_macro *tx = dev_get_drvdata(&pdev->dev);
+
+	of_clk_del_provider(pdev->dev.of_node);
+
+	clk_bulk_disable_unprepare(TX_NUM_CLKS_MAX, tx->clks);
+
+	return 0;
+}
+
+static const struct of_device_id tx_macro_dt_match[] = {
+	{ .compatible = "qcom,sm8250-lpass-tx-macro" },
+	{ }
+};
+static struct platform_driver tx_macro_driver = {
+	.driver = {
+		.name = "tx_macro",
+		.of_match_table = tx_macro_dt_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = tx_macro_probe,
+	.remove = tx_macro_remove,
+};
+
+module_platform_driver(tx_macro_driver);
+
+MODULE_DESCRIPTION("TX macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 25f1df214ca5d119cde8d85c3099d07d8a9777b7..5ebcd935ba898e7367c3387a594976d631599182 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -40,9 +40,11 @@
 #define CDC_WSA_TOP_I2S_CLK			(0x00A4)
 #define CDC_WSA_TOP_I2S_RESET			(0x00A8)
 #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0		(0x0100)
-#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK	GENMASK(5, 3)
-#define CDC_WSA_RX_INTX_2_SEL_MASK		GENMASK(2, 0)
+#define CDC_WSA_RX_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)
@@ -229,8 +231,6 @@
 #define NUM_INTERPOLATORS 2
 #define WSA_NUM_CLKS_MAX	5
 #define WSA_MACRO_MCLK_FREQ 19200000
-#define WSA_MACRO_MUX_INP_SHFT 0x3
-#define WSA_MACRO_MUX_INP_MASK1 0x07
 #define WSA_MACRO_MUX_INP_MASK2 0x38
 #define WSA_MACRO_MUX_CFG_OFFSET 0x8
 #define WSA_MACRO_MUX_CFG1_OFFSET 0x4
@@ -843,7 +843,6 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
 	u32 j, port;
 	u16 int_mux_cfg0, int_mux_cfg1;
 	u16 int_fs_reg;
-	u8 int_mux_cfg0_val, int_mux_cfg1_val;
 	u8 inp0_sel, inp1_sel, inp2_sel;
 	struct snd_soc_component *component = dai->component;
 	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -865,15 +864,13 @@ 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;
-			int_mux_cfg0_val = snd_soc_component_read(component,
-								  int_mux_cfg0);
-			int_mux_cfg1_val = snd_soc_component_read(component,
-								  int_mux_cfg1);
-			inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1;
-			inp1_sel = (int_mux_cfg0_val >> WSA_MACRO_MUX_INP_SHFT) &
-						WSA_MACRO_MUX_INP_MASK1;
-			inp2_sel = (int_mux_cfg1_val >> WSA_MACRO_MUX_INP_SHFT) &
-						WSA_MACRO_MUX_INP_MASK1;
+			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);
+			inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
+								CDC_WSA_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) ||
 			    (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
@@ -912,9 +909,9 @@ 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(component,
-							int_mux_cfg1) &
-							WSA_MACRO_MUX_INP_MASK1;
+			int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1,
+									CDC_WSA_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 +
 					WSA_MACRO_RX_PATH_OFFSET * j;
@@ -1410,25 +1407,25 @@ static bool wsa_macro_adie_lb(struct snd_soc_component *component,
 			      int interp_idx)
 {
 	u16 int_mux_cfg0,  int_mux_cfg1;
-	u8 int_mux_cfg0_val, int_mux_cfg1_val;
 	u8 int_n_inp0, int_n_inp1, int_n_inp2;
 
 	int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
 	int_mux_cfg1 = int_mux_cfg0 + 4;
-	int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
-	int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
 
-	int_n_inp0 = int_mux_cfg0_val & 0x0F;
+	int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
+						  CDC_WSA_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 = int_mux_cfg0_val >> 4;
+	int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
+						  CDC_WSA_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 = int_mux_cfg1_val >> 4;
+	int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
+						  CDC_WSA_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;
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index b8d471d79e939e885553691565cbf036d3afaa4c..d8c47667a9ea2f8c6a67881fb16b28b6a5916ce7 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -262,6 +262,8 @@ static __maybe_unused int max98373_suspend(struct device *dev)
 	return 0;
 }
 
+#define MAX98373_PROBE_TIMEOUT 5000
+
 static __maybe_unused int max98373_resume(struct device *dev)
 {
 	struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -275,7 +277,7 @@ static __maybe_unused int max98373_resume(struct device *dev)
 		goto regmap_sync;
 
 	time = wait_for_completion_timeout(&slave->initialization_complete,
-					   msecs_to_jiffies(2000));
+					   msecs_to_jiffies(MAX98373_PROBE_TIMEOUT));
 	if (!time) {
 		dev_err(dev, "Initialization not complete, timed out\n");
 		return -ETIMEDOUT;
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index 31d571d4fac1ce590e51386759ede696ab7ddba6..746c829312b87029680bf80ba3105278f503a750 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -190,7 +190,7 @@ static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
 		}
 	}
 
-	return snd_soc_put_volsw(kcontrol, ucontrol);
+	return snd_soc_get_volsw(kcontrol, ucontrol);
 }
 
 static const struct snd_kcontrol_new max98373_snd_controls[] = {
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index d5925c42b4b572142dee65a0b1bdc9a4def2f4ff..dd29b183ecd6c89f0b17e70214ae82d7a9b1047c 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -489,7 +489,7 @@ static struct snd_soc_dai_driver max9860_dai = {
 			   SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.ops = &max9860_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int max9860_set_bias_level(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 512e6f2513d34e5ad552d068f885cd8a14032517..09b2d730e9fd30ac785fd1ab5b5068b07ef1d73d 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -520,7 +520,7 @@ static struct snd_soc_dai_driver max9867_dai[] = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.ops = &max9867_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	}
 };
 
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 9e6a0cda43d0b023bb27bf346c19ede4b0ed612a..a21072503cb95367c2be842bf49292193ac1d95b 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -712,7 +712,7 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
 			.formats = MC13783_FORMATS,
 		},
 		.ops = &mc13783_ops_sync,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	}
 };
 
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 70c17be455cae424bdbe9c2e22dbe59559e940d2..4d7c0be2a4aa7486d46e8c67b783412359e81ee0 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -513,7 +513,7 @@ static struct snd_soc_dai_driver ml26124_dai = {
 		.rates = ML26124_RATES,
 		.formats = ML26124_FORMATS,},
 	.ops = &ml26124_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int ml26124_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c
index 6de0d744fa9eb3611eabbbd35a02f29853e8273a..6f4b1da52082db35745e53f548e58d3e35fd738a 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -2754,7 +2754,8 @@ static int mt6359_parse_dt(struct mt6359_priv *priv)
 	ret = of_property_read_u32(np, "mediatek,dmic-mode",
 				   &priv->dmic_one_wire_mode);
 	if (ret) {
-		dev_warn(priv->dev, "%s() failed to read dmic-mode\n",
+		dev_info(priv->dev,
+			 "%s() failed to read dmic-mode, use default (0)\n",
 			 __func__);
 		priv->dmic_one_wire_mode = 0;
 	}
@@ -2762,24 +2763,27 @@ static int mt6359_parse_dt(struct mt6359_priv *priv)
 	ret = of_property_read_u32(np, "mediatek,mic-type-0",
 				   &priv->mux_select[MUX_MIC_TYPE_0]);
 	if (ret) {
-		dev_warn(priv->dev, "%s() failed to read mic-type-0\n",
-			 __func__);
+		dev_info(priv->dev,
+			 "%s() failed to read mic-type-0, use default (%d)\n",
+			 __func__, MIC_TYPE_MUX_IDLE);
 		priv->mux_select[MUX_MIC_TYPE_0] = MIC_TYPE_MUX_IDLE;
 	}
 
 	ret = of_property_read_u32(np, "mediatek,mic-type-1",
 				   &priv->mux_select[MUX_MIC_TYPE_1]);
 	if (ret) {
-		dev_warn(priv->dev, "%s() failed to read mic-type-1\n",
-			 __func__);
+		dev_info(priv->dev,
+			 "%s() failed to read mic-type-1, use default (%d)\n",
+			 __func__, MIC_TYPE_MUX_IDLE);
 		priv->mux_select[MUX_MIC_TYPE_1] = MIC_TYPE_MUX_IDLE;
 	}
 
 	ret = of_property_read_u32(np, "mediatek,mic-type-2",
 				   &priv->mux_select[MUX_MIC_TYPE_2]);
 	if (ret) {
-		dev_warn(priv->dev, "%s() failed to read mic-type-2\n",
-			 __func__);
+		dev_info(priv->dev,
+			 "%s() failed to read mic-type-2, use default (%d)\n",
+			 __func__, MIC_TYPE_MUX_IDLE);
 		priv->mux_select[MUX_MIC_TYPE_2] = MIC_TYPE_MUX_IDLE;
 	}
 
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
index d1797003c83dda96c60342da78473984816b8954..358c500377dff283ccfcd3fbc8ff2b3679a0fce2 100644
--- a/sound/soc/codecs/mt6660.c
+++ b/sound/soc/codecs/mt6660.c
@@ -404,9 +404,9 @@ static struct snd_soc_dai_driver mt6660_codec_dai = {
 		.formats = STUB_FORMATS,
 	},
 	/* dai properties */
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	.symmetric_channels = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_sample_bits = 1,
 	/* dai operations */
 	.ops = &mt6660_component_aif_ops,
 };
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index 33ebc63984265f5d3f5aaf81dc50cf24fb9c18b6..13676b544f58a09f92baed1e86d1afe858718c25 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -837,7 +837,7 @@ static struct snd_soc_dai_driver nau8810_dai = {
 		.formats = NAU8810_FORMATS,
 	},
 	.ops = &nau8810_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct regmap_config nau8810_regmap_config = {
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index 609aeeb27818939d24a5636bbcde79895f47fdee..58123390c7a3189e908853a6b53faef2eb66da69 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -991,7 +991,7 @@ static struct snd_soc_dai_driver nau8822_dai = {
 		.formats = NAU8822_FORMATS,
 	},
 	.ops = &nau8822_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int nau8822_suspend(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 32e6bcf763d1d95ca280a1974fe531e2d0259769..37b5795b00d138eb9ee8043dbc364f9be086004c 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -24,10 +24,10 @@
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/rt1015.h>
 #include <sound/soc-dapm.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <sound/rt1015.h>
 
 #include "rl6231.h"
 #include "rt1015.h"
@@ -444,10 +444,9 @@ static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
 		snd_soc_kcontrol_component(kcontrol);
 	struct rt1015_priv *rt1015 =
 		snd_soc_component_get_drvdata(component);
+	int boost_mode = ucontrol->value.integer.value[0];
 
-	rt1015->boost_mode = ucontrol->value.integer.value[0];
-
-	switch (rt1015->boost_mode) {
+	switch (boost_mode) {
 	case BYPASS:
 		snd_soc_component_update_bits(component,
 			RT1015_SMART_BST_CTRL1, RT1015_ABST_AUTO_EN_MASK |
@@ -471,8 +470,11 @@ static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
 		break;
 	default:
 		dev_err(component->dev, "Unknown boost control.\n");
+		return -EINVAL;
 	}
 
+	rt1015->boost_mode = boost_mode;
+
 	return 0;
 }
 
@@ -497,40 +499,20 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
 	snd_soc_dapm_mutex_lock(&component->dapm);
 	regcache_cache_bypass(regmap, true);
 
-	regmap_write(regmap, RT1015_PWR9, 0xAA60);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0089);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008A);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008C);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008D);
-	regmap_write(regmap, RT1015_PWR4, 0x80B2);
-	regmap_write(regmap, RT1015_CLASSD_SEQ, 0x5797);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2100);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0100);
-	regmap_write(regmap, RT1015_PWR5, 0x2175);
-	regmap_write(regmap, RT1015_MIXER1, 0x005D);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12F7);
-	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x1205);
-	msleep(200);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2000);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0180);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
-	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x0A05);
-	msleep(200);
+	regmap_write(regmap, RT1015_CLK_DET, 0x0000);
 	regmap_write(regmap, RT1015_PWR4, 0x00B2);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0009);
+	msleep(100);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000A);
+	msleep(100);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000C);
+	msleep(100);
 	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028);
 	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
-	regmap_write(regmap, RT1015_PWR5, 0x0175);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x1721);
-	regmap_write(regmap, RT1015_CLASSD_SEQ, 0x570E);
-	regmap_write(regmap, RT1015_MIXER1, 0x203D);
-	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5A01);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12FF);
-	regmap_write(regmap, RT1015_GAT_BOOST, 0x0eFE);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008E);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0088);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000D);
+	msleep(300);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008);
 	regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
-	regmap_write(regmap, RT1015_SYS_RST2, 0x0b9a);
 
 	regcache_cache_bypass(regmap, false);
 	regcache_mark_dirty(regmap);
@@ -546,17 +528,19 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
 	struct rt1015_priv *rt1015 =
 		snd_soc_component_get_drvdata(component);
 
-	if (!rt1015->dac_is_used) {
-		rt1015->bypass_boost = ucontrol->value.integer.value[0];
-		if (rt1015->bypass_boost == RT1015_Bypass_Boost &&
+	if (rt1015->dac_is_used) {
+		dev_err(component->dev, "DAC is being used!\n");
+		return -EBUSY;
+	}
+
+	rt1015->bypass_boost = ucontrol->value.integer.value[0];
+	if (rt1015->bypass_boost == RT1015_Bypass_Boost &&
 			!rt1015->cali_done) {
-			rt1015_calibrate(rt1015);
-			rt1015->cali_done = 1;
+		rt1015_calibrate(rt1015);
+		rt1015->cali_done = 1;
 
-			regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL, 0x0010);
-		}
-	} else
-		dev_err(component->dev, "DAC is being used!\n");
+		regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL, 0x0010);
+	}
 
 	return 0;
 }
@@ -566,15 +550,14 @@ static void rt1015_flush_work(struct work_struct *work)
 	struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv,
 						flush_work.work);
 	struct snd_soc_component *component = rt1015->component;
-	unsigned int val, i = 0, count = 200;
+	unsigned int val, i;
 
-	while (i < count) {
+	for (i = 0; i < 200; ++i) {
 		usleep_range(1000, 1500);
 		dev_dbg(component->dev, "Flush DAC (retry:%u)\n", i);
 		regmap_read(rt1015->regmap, RT1015_CLK_DET, &val);
 		if (val & 0x800)
 			break;
-		i++;
 	}
 
 	regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597);
@@ -721,11 +704,11 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_component *component = dai->component;
 	struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
-	int pre_div, bclk_ms, frame_size;
+	int pre_div, bclk_ms, frame_size, lrck;
 	unsigned int val_len = 0;
 
-	rt1015->lrck = params_rate(params);
-	pre_div = rl6231_get_clk_info(rt1015->sysclk, rt1015->lrck);
+	lrck = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt1015->sysclk, lrck);
 	if (pre_div < 0) {
 		dev_err(component->dev, "Unsupported clock rate\n");
 		return -EINVAL;
@@ -739,13 +722,12 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	bclk_ms = frame_size > 32;
-	rt1015->bclk = rt1015->lrck * (32 << bclk_ms);
 
 	dev_dbg(component->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
 				bclk_ms, pre_div, dai->id);
 
 	dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
-				rt1015->lrck, pre_div, dai->id);
+				lrck, pre_div, dai->id);
 
 	switch (params_width(params)) {
 	case 16:
@@ -882,14 +864,6 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
 		freq_out == rt1015->pll_out)
 		return 0;
 
-	if (source == RT1015_PLL_S_BCLK) {
-		if (rt1015->bclk_ratio == 0) {
-			dev_err(component->dev,
-				"Can not support bclk ratio as 0.\n");
-			return -EINVAL;
-		}
-	}
-
 	switch (source) {
 	case RT1015_PLL_S_MCLK:
 		snd_soc_component_update_bits(component, RT1015_CLK2,
@@ -929,23 +903,6 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
 	return 0;
 }
 
-static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
-{
-	struct snd_soc_component *component = dai->component;
-	struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
-
-	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
-
-	rt1015->bclk_ratio = ratio;
-
-	if (ratio == 50) {
-		dev_dbg(component->dev, "Unsupport bclk ratio\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static int rt1015_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
@@ -1052,9 +1009,6 @@ static int rt1015_probe(struct snd_soc_component *component)
 		snd_soc_component_get_drvdata(component);
 
 	rt1015->component = component;
-	rt1015->bclk_ratio = 0;
-	rt1015->cali_done = 0;
-
 	INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work);
 
 	return 0;
@@ -1075,7 +1029,6 @@ static void rt1015_remove(struct snd_soc_component *component)
 static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
 	.hw_params = rt1015_hw_params,
 	.set_fmt = rt1015_set_dai_fmt,
-	.set_bclk_ratio = rt1015_set_bclk_ratio,
 	.set_tdm_slot = rt1015_set_tdm_slot,
 };
 
@@ -1111,6 +1064,10 @@ static int rt1015_resume(struct snd_soc_component *component)
 
 	regcache_cache_only(rt1015->regmap, false);
 	regcache_sync(rt1015->regmap);
+
+	if (rt1015->cali_done)
+		rt1015_calibrate(rt1015);
+
 	return 0;
 }
 #else
@@ -1183,9 +1140,8 @@ static int rt1015_i2c_probe(struct i2c_client *i2c,
 	int ret;
 	unsigned int val;
 
-	rt1015 = devm_kzalloc(&i2c->dev, sizeof(struct rt1015_priv),
-				GFP_KERNEL);
-	if (rt1015 == NULL)
+	rt1015 = devm_kzalloc(&i2c->dev, sizeof(*rt1015), GFP_KERNEL);
+	if (!rt1015)
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, rt1015);
diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h
index b6ea753014e1fdee54c45d3caae8249262b8a14a..2aeaf65ba7931af21ba4e39c07bab400da7b6c73 100644
--- a/sound/soc/codecs/rt1015.h
+++ b/sound/soc/codecs/rt1015.h
@@ -427,16 +427,11 @@ struct rt1015_priv {
 	struct regmap *regmap;
 	int sysclk;
 	int sysclk_src;
-	int lrck;
-	int bclk;
-	int bclk_ratio;
-	int id;
 	int pll_src;
 	int pll_in;
 	int pll_out;
 	int boost_mode;
 	int bypass_boost;
-	int amp_ver;
 	int dac_is_used;
 	int cali_done;
 	int hw_config;
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index ec5564f780e8c68fd648a6d24cb7afc55489f38b..afd2c3b687ccb0af96a682e8d22b03d30a42e31a 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -701,7 +701,7 @@ static int __maybe_unused rt1308_dev_suspend(struct device *dev)
 	return 0;
 }
 
-#define RT1308_PROBE_TIMEOUT 2000
+#define RT1308_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt1308_dev_resume(struct device *dev)
 {
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index 70cf17c0aa99ec13a1c557b5bae2fd324629386d..0d3773c576f8c91835d2c913ed2d3bc7286c26bd 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -1056,7 +1056,7 @@ static struct snd_soc_dai_driver rt274_dai[] = {
 			.formats = RT274_FORMATS,
 		},
 		.ops = &rt274_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 5fb9653d9131f313d0b4f4c00bf6107be9f9f7a4..8abe232ca4a4c03795318c33f4678a2b1826d38a 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1017,7 +1017,7 @@ static struct snd_soc_dai_driver rt286_dai[] = {
 			.formats = RT286_FORMATS,
 		},
 		.ops = &rt286_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "rt286-aif2",
@@ -1037,7 +1037,7 @@ static struct snd_soc_dai_driver rt286_dai[] = {
 			.formats = RT286_FORMATS,
 		},
 		.ops = &rt286_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 
 };
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index dc0273a5a11f7d9a2c0fb2e45432429fded5628f..32cc9b6287d21d95e0fd5dbd29dffda7ea6ddbee 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1084,7 +1084,7 @@ static struct snd_soc_dai_driver rt298_dai[] = {
 			.formats = RT298_FORMATS,
 		},
 		.ops = &rt298_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "rt298-aif2",
@@ -1104,7 +1104,7 @@ static struct snd_soc_dai_driver rt298_dai[] = {
 			.formats = RT298_FORMATS,
 		},
 		.ops = &rt298_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 
 };
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 420003d062c7f782aef04687149bbe4f62d8c7d1..63a7e052eaa03f633d700708c6933931ec061c27 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -34,6 +34,7 @@
 #define QUIRK_INV_JD1_1(q)	((q) & 1)
 #define QUIRK_LEVEL_IRQ(q)	(((q) >> 1) & 1)
 #define QUIRK_IN2_DIFF(q)	(((q) >> 2) & 1)
+#define QUIRK_INV_HP_POL(q)	(((q) >> 3) & 1)
 #define QUIRK_JD_MODE(q)	(((q) >> 4) & 7)
 #define QUIRK_DMIC1_DATA_PIN(q)	(((q) >> 8) & 3)
 #define QUIRK_DMIC2_DATA_PIN(q)	(((q) >> 12) & 3)
@@ -42,6 +43,8 @@ static unsigned int quirk = -1;
 module_param(quirk, uint, 0444);
 MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override");
 
+static const struct acpi_gpio_mapping *cht_rt5645_gpios;
+
 #define RT5645_DEVICE_ID 0x6308
 #define RT5650_DEVICE_ID 0x6419
 
@@ -435,7 +438,6 @@ struct rt5645_priv {
 
 	int jack_type;
 	bool en_button_func;
-	bool hp_on;
 	int v_id;
 };
 
@@ -1645,6 +1647,7 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
 {
 	static int hp_amp_power_count;
 	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	int i, val;
 
 	if (on) {
 		if (hp_amp_power_count <= 0) {
@@ -1655,7 +1658,13 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
 				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x000d);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					RT5645_HP_DCC_INT1, 0x9f01);
-				msleep(20);
+				for (i = 0; i < 20; i++) {
+					usleep_range(1000, 1500);
+					regmap_read(rt5645->regmap, RT5645_PR_BASE +
+						RT5645_HP_DCC_INT1, &val);
+					if (!(val & 0x8000))
+						break;
+				}
 				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 					RT5645_HP_CO_MASK, RT5645_HP_CO_EN);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
@@ -1665,7 +1674,6 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
 					RT5645_MAMP_INT_REG2, 0xfc00);
 				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
 				msleep(90);
-				rt5645->hp_on = true;
 			} else {
 				/* depop parameters */
 				snd_soc_component_update_bits(component, RT5645_DEPOP_M2,
@@ -1885,27 +1893,6 @@ static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *k, int  event)
-{
-	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		if (rt5645->hp_on) {
-			msleep(100);
-			rt5645->hp_on = false;
-		}
-		break;
-
-	default:
-		return 0;
-	}
-
-	return 0;
-}
-
 static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
@@ -2242,7 +2229,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("PDM1R"),
 	SND_SOC_DAPM_OUTPUT("SPOL"),
 	SND_SOC_DAPM_OUTPUT("SPOR"),
-	SND_SOC_DAPM_POST("DAPM_POST", rt5650_hp_event),
 };
 
 static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = {
@@ -3261,6 +3247,8 @@ static void rt5645_jack_detect_work(struct work_struct *work)
 	case 0: /* Not using rt5645 JD */
 		if (rt5645->gpiod_hp_det) {
 			gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
+			if (rt5645->pdata.inv_hp_pol)
+				gpio_state ^= 1;
 			dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
 				gpio_state);
 			report = rt5645_jack_detect(rt5645->component, gpio_state);
@@ -3651,6 +3639,25 @@ static const struct rt5645_platform_data kahlee_platform_data = {
 	.jd_mode = 3,
 };
 
+static const struct rt5645_platform_data ecs_ef20_platform_data = {
+	.dmic1_data_pin = RT5645_DMIC1_DISABLE,
+	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+	.inv_hp_pol = 1,
+};
+
+static const struct acpi_gpio_params ef20_hp_detect = { 1, 0, false };
+
+static const struct acpi_gpio_mapping cht_rt5645_ef20_gpios[] = {
+	{ "hp-detect-gpios", &ef20_hp_detect, 1 },
+	{ },
+};
+
+static int cht_rt5645_ef20_quirk_cb(const struct dmi_system_id *id)
+{
+	cht_rt5645_gpios = cht_rt5645_ef20_gpios;
+	return 1;
+}
+
 static const struct dmi_system_id dmi_platform_data[] = {
 	{
 		.ident = "Chrome Buddy",
@@ -3780,6 +3787,22 @@ static const struct dmi_system_id dmi_platform_data[] = {
 		},
 		.driver_data = (void *)&intel_braswell_platform_data,
 	},
+	{
+		.ident = "EF20",
+		.callback = cht_rt5645_ef20_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "EF20"),
+		},
+		.driver_data = (void *)&ecs_ef20_platform_data,
+	},
+	{
+		.ident = "EF20EA",
+		.callback = cht_rt5645_ef20_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
+		},
+		.driver_data = (void *)&ecs_ef20_platform_data,
+	},
 	{ }
 };
 
@@ -3843,11 +3866,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 		rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
 		rt5645->pdata.level_trigger_irq = QUIRK_LEVEL_IRQ(quirk);
 		rt5645->pdata.inv_jd1_1 = QUIRK_INV_JD1_1(quirk);
+		rt5645->pdata.inv_hp_pol = QUIRK_INV_HP_POL(quirk);
 		rt5645->pdata.jd_mode = QUIRK_JD_MODE(quirk);
 		rt5645->pdata.dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk);
 		rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
 	}
 
+	if (cht_rt5645_gpios && has_acpi_companion(&i2c->dev))
+		if (devm_acpi_dev_add_driver_gpios(&i2c->dev, cht_rt5645_gpios))
+			dev_dbg(&i2c->dev, "Failed to add driver gpios\n");
+
 	rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
 						       GPIOD_IN);
 
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index a0c8f58d729b3ece5ae88a7770d2afe0f394475d..c29317ea5df2fa0699ad9bec092a7158d64fb87c 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2741,7 +2741,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
 			.formats = RT5670_FORMATS,
 		},
 		.ops = &rt5670_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "rt5670-aif2",
@@ -2761,7 +2761,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
 			.formats = RT5670_FORMATS,
 		},
 		.ops = &rt5670_aif_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index 37d13120f5ba86d45ad72a9ba09ae2dba182722c..93c1603b42f10901e70738c5ea2873eaa257ee79 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -273,6 +273,9 @@ static void rt5682_i2c_shutdown(struct i2c_client *client)
 {
 	struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
 
+	cancel_delayed_work_sync(&rt5682->jack_detect_work);
+	cancel_delayed_work_sync(&rt5682->jd_check_work);
+
 	rt5682_reset(rt5682);
 }
 
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index 4d707e854875bd148e2eb5cc57148506ee594817..b49f1e16125d49676ada14347c2cbfe8d00f356e 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -375,18 +375,12 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
 static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
 {
 	struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
-	int ret = 0;
+	int ret = 0, loop = 10;
 	unsigned int val;
 
 	if (rt5682->hw_init)
 		return 0;
 
-	regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
-	if (val != DEVICE_ID) {
-		dev_err(dev, "Device with ID register %x is not rt5682\n", val);
-		return -ENODEV;
-	}
-
 	/*
 	 * PM runtime is only enabled when a Slave reports as Attached
 	 */
@@ -406,6 +400,19 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
 
 	pm_runtime_get_noresume(&slave->dev);
 
+	while (loop > 0) {
+		regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
+		if (val == DEVICE_ID)
+			break;
+		dev_warn(dev, "Device with ID register %x is not rt5682\n", val);
+		usleep_range(30000, 30005);
+		loop--;
+	}
+	if (val != DEVICE_ID) {
+		dev_err(dev, "Device with ID register %x is not rt5682\n", val);
+		return -ENODEV;
+	}
+
 	if (rt5682->first_hw_init) {
 		regcache_cache_only(rt5682->regmap, false);
 		regcache_cache_bypass(rt5682->regmap, true);
@@ -703,7 +710,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
 	struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
 
 	if (rt5682 && rt5682->hw_init)
-		cancel_delayed_work(&rt5682->jack_detect_work);
+		cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
 	return 0;
 }
@@ -721,6 +728,8 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
 	if (!rt5682->hw_init)
 		return 0;
 
+	cancel_delayed_work_sync(&rt5682->jack_detect_work);
+
 	regcache_cache_only(rt5682->regmap, true);
 	regcache_mark_dirty(rt5682->regmap);
 
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 4d865edadd7eb94a4ed3e0af1686adf0454167eb..b306ac4b9b2e07a18538c3c59b3d88aeeaf5f130 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -953,6 +953,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
 		case 0x1:
 		case 0x2:
 			rt5682->jack_type = SND_JACK_HEADSET;
+			snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+				RT5682_FAST_OFF_MASK, RT5682_FAST_OFF_EN);
 			rt5682_enable_push_button_irq(component, true);
 			break;
 		default:
@@ -982,6 +984,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
 		snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
 			RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
 			RT5682_PWR_CLK25M_PD | RT5682_PWR_CLK1M_PD);
+		snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+			RT5682_FAST_OFF_MASK, RT5682_FAST_OFF_DIS);
 
 		rt5682->jack_type = 0;
 	}
@@ -1011,11 +1015,13 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
 	if (!rt5682->is_sdw) {
 		switch (rt5682->pdata.jd_src) {
 		case RT5682_JD1:
+			snd_soc_component_update_bits(component,
+				RT5682_CBJ_CTRL_5, 0x0700, 0x0600);
 			snd_soc_component_update_bits(component,
 				RT5682_CBJ_CTRL_2, RT5682_EXT_JD_SRC,
 				RT5682_EXT_JD_SRC_MANUAL);
 			snd_soc_component_write(component, RT5682_CBJ_CTRL_1,
-				0xd042);
+				0xd142);
 			snd_soc_component_update_bits(component,
 				RT5682_CBJ_CTRL_3, RT5682_CBJ_IN_BUF_EN,
 				RT5682_CBJ_IN_BUF_EN);
@@ -1848,8 +1854,6 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
 
 	{"CLKDET SYS", NULL, "CLKDET"},
 
-	{"IN1P", NULL, "LDO2"},
-
 	{"BST1 CBJ", NULL, "IN1P"},
 
 	{"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
@@ -2906,6 +2910,9 @@ static int rt5682_suspend(struct snd_soc_component *component)
 {
 	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
+	if (rt5682->is_sdw)
+		return 0;
+
 	regcache_cache_only(rt5682->regmap, true);
 	regcache_mark_dirty(rt5682->regmap);
 	return 0;
@@ -2915,6 +2922,9 @@ static int rt5682_resume(struct snd_soc_component *component)
 {
 	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
+	if (rt5682->is_sdw)
+		return 0;
+
 	regcache_cache_only(rt5682->regmap, false);
 	regcache_sync(rt5682->regmap);
 
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index 99b85cfe6248d7d25dfccf7c4ff4f4fbfdab69a5..1f9c51a5b9bfc52aa8804c7b0178b0184aabc847 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -1356,7 +1356,7 @@
 #define RT5682_SAR_SOUR_TYPE			(0x0)
 
 /* soundwire timeout */
-#define RT5682_PROBE_TIMEOUT			2000
+#define RT5682_PROBE_TIMEOUT			5000
 
 
 #define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index fb77e77a4ebd5a621be72e1d6a672cf44300db95..4001612dfd7378c9d101736e1d33aaade2e47bd6 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -462,8 +462,8 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
 	struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
 
 	if (rt700 && rt700->hw_init) {
-		cancel_delayed_work(&rt700->jack_detect_work);
-		cancel_delayed_work(&rt700->jack_btn_check_work);
+		cancel_delayed_work_sync(&rt700->jack_detect_work);
+		cancel_delayed_work_sync(&rt700->jack_btn_check_work);
 	}
 
 	return 0;
@@ -490,7 +490,7 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev)
 	return 0;
 }
 
-#define RT700_PROBE_TIMEOUT 2000
+#define RT700_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt700_dev_resume(struct device *dev)
 {
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index fc7df79c3b9189d5a8d2a5b116cbb6f2c3940035..2beb4286d997bf5d050881bb7f0288ec480f5d16 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -463,8 +463,8 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
 	struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev);
 
 	if (rt711 && rt711->hw_init) {
-		cancel_delayed_work(&rt711->jack_detect_work);
-		cancel_delayed_work(&rt711->jack_btn_check_work);
+		cancel_delayed_work_sync(&rt711->jack_detect_work);
+		cancel_delayed_work_sync(&rt711->jack_btn_check_work);
 		cancel_work_sync(&rt711->calibration_work);
 	}
 
@@ -493,7 +493,7 @@ static int __maybe_unused rt711_dev_suspend(struct device *dev)
 	return 0;
 }
 
-#define RT711_PROBE_TIMEOUT 2000
+#define RT711_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt711_dev_resume(struct device *dev)
 {
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 8f0aa1e8a27371312cdbd7843cd375f3dcaa49f0..71dd3b97a459040eaf2d04c436a383f945a8072d 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -533,7 +533,7 @@ static int __maybe_unused rt715_dev_suspend(struct device *dev)
 	return 0;
 }
 
-#define RT715_PROBE_TIMEOUT 2000
+#define RT715_PROBE_TIMEOUT 5000
 
 static int __maybe_unused rt715_dev_resume(struct device *dev)
 {
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 4d6ff811462287c0c32ba730ffc184564085ee8d..73551e36695e98123a35de8ee4dac3e6d96a5caa 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1187,7 +1187,7 @@ static struct snd_soc_dai_driver sgtl5000_dai = {
 		.formats = SGTL5000_FORMATS,
 	},
 	.ops = &sgtl5000_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static bool sgtl5000_volatile(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
deleted file mode 100644
index a061d78473ac4e812faab7759cb80d472e9131ff..0000000000000000000000000000000000000000
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ /dev/null
@@ -1,575 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF audio codec driver
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/regmap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "sirf-audio-codec.h"
-
-struct sirf_audio_codec {
-	struct clk *clk;
-	struct regmap *regmap;
-	u32 reg_ctrl0, reg_ctrl1;
-};
-
-static const char * const input_mode_mux[] = {"Single-ended",
-	"Differential"};
-
-static const struct soc_enum input_mode_mux_enum =
-	SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
-
-static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
-	SOC_DAPM_ENUM("Route", input_mode_mux_enum);
-
-static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
-static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
-static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
-	0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
-	0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
-);
-
-static struct snd_kcontrol_new volume_controls_atlas6[] = {
-	SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
-			0x7F, 0, playback_vol_tlv),
-	SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
-			0x3F, 0, capture_vol_tlv_atlas6),
-};
-
-static struct snd_kcontrol_new volume_controls_prima2[] = {
-	SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
-			0x7F, 0, playback_vol_tlv),
-	SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
-			0x1F, 0, capture_vol_tlv_prima2),
-};
-
-static struct snd_kcontrol_new left_input_path_controls[] = {
-	SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
-	SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
-};
-
-static struct snd_kcontrol_new right_input_path_controls[] = {
-	SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
-	SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
-};
-
-static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
-	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
-
-static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
-	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
-
-static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
-	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
-
-static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
-	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
-
-static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
-	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
-
-static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
-	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
-
-/* After enable adc, Delay 200ms to avoid pop noise */
-static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		msleep(200);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static void enable_and_reset_codec(struct regmap *regmap,
-		u32 codec_enable_bits, u32 codec_reset_bits)
-{
-	regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
-			codec_enable_bits | codec_reset_bits,
-			codec_enable_bits);
-	msleep(20);
-	regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
-			codec_reset_bits, codec_reset_bits);
-}
-
-static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
-#define ATLAS6_CODEC_RESET_BITS (1 << 28)
-	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		enable_and_reset_codec(sirf_audio_codec->regmap,
-			ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		regmap_update_bits(sirf_audio_codec->regmap,
-			AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
-#define PRIMA2_CODEC_RESET_BITS (1 << 26)
-	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		enable_and_reset_codec(sirf_audio_codec->regmap,
-			PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		regmap_update_bits(sirf_audio_codec->regmap,
-			AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
-	SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
-			25, 0, NULL, 0),
-	SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
-			26, 0, NULL, 0),
-	SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
-			27, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
-	SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
-			23, 0, NULL, 0),
-	SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
-			24, 0, NULL, 0),
-	SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
-			25, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
-	SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
-			atlas6_codec_enable_and_reset_event,
-			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
-
-static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
-	SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
-			prima2_codec_enable_and_reset_event,
-			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
-
-static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
-	SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
-	SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
-	SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
-			&left_dac_to_hp_left_amp_switch_control),
-	SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
-			&left_dac_to_hp_right_amp_switch_control),
-	SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
-			&right_dac_to_hp_left_amp_switch_control),
-	SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
-			&right_dac_to_hp_right_amp_switch_control),
-	SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
-			NULL, 0),
-	SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
-			NULL, 0),
-
-	SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
-			&left_dac_to_speaker_lineout_switch_control),
-	SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
-			&right_dac_to_speaker_lineout_switch_control),
-	SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
-			NULL, 0),
-
-	SND_SOC_DAPM_OUTPUT("HPOUTL"),
-	SND_SOC_DAPM_OUTPUT("HPOUTR"),
-	SND_SOC_DAPM_OUTPUT("SPKOUT"),
-
-	SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
-			adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
-			adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
-		&left_input_path_controls[0],
-		ARRAY_SIZE(left_input_path_controls)),
-	SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
-		&right_input_path_controls[0],
-		ARRAY_SIZE(right_input_path_controls)),
-
-	SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
-			&sirf_audio_codec_input_mode_control),
-	SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
-	SND_SOC_DAPM_INPUT("MICIN1"),
-	SND_SOC_DAPM_INPUT("MICIN2"),
-	SND_SOC_DAPM_INPUT("LINEIN1"),
-	SND_SOC_DAPM_INPUT("LINEIN2"),
-
-	SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
-			30, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
-	{"SPKOUT", NULL, "Speaker Driver"},
-	{"Speaker Driver", NULL, "Speaker amp driver"},
-	{"Speaker amp driver", NULL, "Left dac to speaker lineout"},
-	{"Speaker amp driver", NULL, "Right dac to speaker lineout"},
-	{"Left dac to speaker lineout", "Switch", "DAC left"},
-	{"Right dac to speaker lineout", "Switch", "DAC right"},
-	{"HPOUTL", NULL, "HP Left Driver"},
-	{"HPOUTR", NULL, "HP Right Driver"},
-	{"HP Left Driver", NULL, "HP amp left driver"},
-	{"HP Right Driver", NULL, "HP amp right driver"},
-	{"HP amp left driver", NULL, "Right dac to hp left amp"},
-	{"HP amp right driver", NULL , "Right dac to hp right amp"},
-	{"HP amp left driver", NULL, "Left dac to hp left amp"},
-	{"HP amp right driver", NULL , "Right dac to hp right amp"},
-	{"Right dac to hp left amp", "Switch", "DAC left"},
-	{"Right dac to hp right amp", "Switch", "DAC right"},
-	{"Left dac to hp left amp", "Switch", "DAC left"},
-	{"Left dac to hp right amp", "Switch", "DAC right"},
-	{"DAC left", NULL, "codecclk"},
-	{"DAC right", NULL, "codecclk"},
-	{"DAC left", NULL, "Playback"},
-	{"DAC right", NULL, "Playback"},
-	{"DAC left", NULL, "HSL Phase Opposite"},
-	{"DAC right", NULL, "HSL Phase Opposite"},
-
-	{"Capture", NULL, "ADC left"},
-	{"Capture", NULL, "ADC right"},
-	{"ADC left", NULL, "codecclk"},
-	{"ADC right", NULL, "codecclk"},
-	{"ADC left", NULL, "Left PGA mixer"},
-	{"ADC right", NULL, "Right PGA mixer"},
-	{"Left PGA mixer", "Line Left Switch", "LINEIN2"},
-	{"Right PGA mixer", "Line Right Switch", "LINEIN1"},
-	{"Left PGA mixer", "Mic Left Switch", "MICIN2"},
-	{"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
-	{"Mic input mode mux", "Single-ended", "MICIN1"},
-	{"Mic input mode mux", "Differential", "MICIN1"},
-};
-
-static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
-{
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-		AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-		AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
-	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
-	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
-		AUDIO_FIFO_START, AUDIO_FIFO_START);
-	regmap_update_bits(sirf_audio_codec->regmap,
-		AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
-}
-
-static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
-{
-	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
-	regmap_update_bits(sirf_audio_codec->regmap,
-		AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
-}
-
-static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
-	int channels)
-{
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-		AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-		AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
-	regmap_write(sirf_audio_codec->regmap,
-		AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
-	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
-		AUDIO_FIFO_START, AUDIO_FIFO_START);
-	if (channels == 1)
-		regmap_update_bits(sirf_audio_codec->regmap,
-			AUDIO_PORT_IC_CODEC_RX_CTRL,
-			IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
-	else
-		regmap_update_bits(sirf_audio_codec->regmap,
-			AUDIO_PORT_IC_CODEC_RX_CTRL,
-			IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
-}
-
-static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
-{
-	regmap_update_bits(sirf_audio_codec->regmap,
-			AUDIO_PORT_IC_CODEC_RX_CTRL,
-			IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
-}
-
-static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
-		int cmd,
-		struct snd_soc_dai *dai)
-{
-	struct snd_soc_component *component = dai->component;
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
-	int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-
-	/*
-	 * This is a workaround, When stop playback,
-	 * need disable HP amp, avoid the current noise.
-	 */
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (playback) {
-			snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
-				IC_HSLEN | IC_HSREN, 0);
-			sirf_audio_codec_tx_disable(sirf_audio_codec);
-		} else
-			sirf_audio_codec_rx_disable(sirf_audio_codec);
-		break;
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (playback) {
-			sirf_audio_codec_tx_enable(sirf_audio_codec);
-			snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
-				IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
-		} else
-			sirf_audio_codec_rx_enable(sirf_audio_codec,
-				substream->runtime->channels);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
-	.trigger = sirf_audio_codec_trigger,
-};
-
-static struct snd_soc_dai_driver sirf_audio_codec_dai = {
-	.name = "sirf-audio-codec",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.stream_name = "Capture",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &sirf_audio_codec_dai_ops,
-};
-
-static int sirf_audio_codec_probe(struct snd_soc_component *component)
-{
-	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
-
-	pm_runtime_enable(component->dev);
-
-	if (of_device_is_compatible(component->dev->of_node, "sirf,prima2-audio-codec")) {
-		snd_soc_dapm_new_controls(dapm,
-			prima2_output_driver_dapm_widgets,
-			ARRAY_SIZE(prima2_output_driver_dapm_widgets));
-		snd_soc_dapm_new_controls(dapm,
-			&prima2_codec_clock_dapm_widget, 1);
-		return snd_soc_add_component_controls(component,
-			volume_controls_prima2,
-			ARRAY_SIZE(volume_controls_prima2));
-	}
-	if (of_device_is_compatible(component->dev->of_node, "sirf,atlas6-audio-codec")) {
-		snd_soc_dapm_new_controls(dapm,
-			atlas6_output_driver_dapm_widgets,
-			ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
-		snd_soc_dapm_new_controls(dapm,
-			&atlas6_codec_clock_dapm_widget, 1);
-		return snd_soc_add_component_controls(component,
-			volume_controls_atlas6,
-			ARRAY_SIZE(volume_controls_atlas6));
-	}
-
-	return -EINVAL;
-}
-
-static void sirf_audio_codec_remove(struct snd_soc_component *component)
-{
-	pm_runtime_disable(component->dev);
-}
-
-static const struct snd_soc_component_driver soc_codec_device_sirf_audio_codec = {
-	.probe			= sirf_audio_codec_probe,
-	.remove			= sirf_audio_codec_remove,
-	.dapm_widgets		= sirf_audio_codec_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
-	.dapm_routes		= sirf_audio_codec_map,
-	.num_dapm_routes	= ARRAY_SIZE(sirf_audio_codec_map),
-	.use_pmdown_time	= 1,
-	.endianness		= 1,
-	.non_legacy_dai_naming	= 1,
-};
-
-static const struct of_device_id sirf_audio_codec_of_match[] = {
-	{ .compatible = "sirf,prima2-audio-codec" },
-	{ .compatible = "sirf,atlas6-audio-codec" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
-
-static const struct regmap_config sirf_audio_codec_regmap_config = {
-	.reg_bits = 32,
-	.reg_stride = 4,
-	.val_bits = 32,
-	.max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
-	.cache_type = REGCACHE_NONE,
-};
-
-static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct sirf_audio_codec *sirf_audio_codec;
-	void __iomem *base;
-
-	sirf_audio_codec = devm_kzalloc(&pdev->dev,
-		sizeof(struct sirf_audio_codec), GFP_KERNEL);
-	if (!sirf_audio_codec)
-		return -ENOMEM;
-
-	platform_set_drvdata(pdev, sirf_audio_codec);
-
-	base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
-
-	sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-					    &sirf_audio_codec_regmap_config);
-	if (IS_ERR(sirf_audio_codec->regmap))
-		return PTR_ERR(sirf_audio_codec->regmap);
-
-	sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(sirf_audio_codec->clk)) {
-		dev_err(&pdev->dev, "Get clock failed.\n");
-		return PTR_ERR(sirf_audio_codec->clk);
-	}
-
-	ret = clk_prepare_enable(sirf_audio_codec->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "Enable clock failed.\n");
-		return ret;
-	}
-
-	ret = devm_snd_soc_register_component(&(pdev->dev),
-			&soc_codec_device_sirf_audio_codec,
-			&sirf_audio_codec_dai, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
-		goto err_clk_put;
-	}
-
-	/*
-	 * Always open charge pump, if not, when the charge pump closed the
-	 * adc will not stable
-	 */
-	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
-		IC_CPFREQ, IC_CPFREQ);
-
-	if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
-		regmap_update_bits(sirf_audio_codec->regmap,
-				AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
-	return 0;
-
-err_clk_put:
-	clk_disable_unprepare(sirf_audio_codec->clk);
-	return ret;
-}
-
-static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
-{
-	struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
-
-	clk_disable_unprepare(sirf_audio_codec->clk);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int sirf_audio_codec_suspend(struct device *dev)
-{
-	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
-
-	regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
-		&sirf_audio_codec->reg_ctrl0);
-	regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
-		&sirf_audio_codec->reg_ctrl1);
-	clk_disable_unprepare(sirf_audio_codec->clk);
-
-	return 0;
-}
-
-static int sirf_audio_codec_resume(struct device *dev)
-{
-	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
-	int ret;
-
-	ret = clk_prepare_enable(sirf_audio_codec->clk);
-	if (ret)
-		return ret;
-
-	regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
-		sirf_audio_codec->reg_ctrl0);
-	regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
-		sirf_audio_codec->reg_ctrl1);
-
-	return 0;
-}
-#endif
-
-static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
-};
-
-static struct platform_driver sirf_audio_codec_driver = {
-	.driver = {
-		.name = "sirf-audio-codec",
-		.of_match_table = sirf_audio_codec_of_match,
-		.pm = &sirf_audio_codec_pm_ops,
-	},
-	.probe = sirf_audio_codec_driver_probe,
-	.remove = sirf_audio_codec_driver_remove,
-};
-
-module_platform_driver(sirf_audio_codec_driver);
-
-MODULE_DESCRIPTION("SiRF audio codec driver");
-MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 90516024661463ad32feee2a01b2bf220ff2d289..7964e922b07f6532363a721ca2dfd284de65b3e2 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -526,8 +526,8 @@ static struct snd_soc_dai_driver ssm2602_dai = {
 		.rates = SSM2602_RATES,
 		.formats = SSM2602_FORMATS,},
 	.ops = &ssm2602_dai_ops,
-	.symmetric_rates = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_rate = 1,
+	.symmetric_sample_bits = 1,
 };
 
 static int ssm2602_resume(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 14a193e48dc767c93c69ba691207a5791a219091..8ff4d9e8d568193a2cc480b23330432bc30bfd58 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -490,7 +490,7 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = {
 			.formats = TAS2764_FORMATS,
 		},
 		.ops = &tas2764_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index a91a0a31e74d1c07f7489cf1a948d214e09a95be..15fca5109e1497a9b54af408713822318ab05237 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -499,7 +499,7 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = {
 			.formats    = TAS2770_FORMATS,
 		},
 		.ops = &tas2770_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 3f027c8234a6022c395737250b86880903856705..32b120d624b25f68050b2c850fba08138066bd85 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -1069,7 +1069,7 @@ static struct snd_soc_dai_driver adcx140_dai_driver[] = {
 			.formats	 = ADCX140_FORMATS,
 		},
 		.ops = &adcx140_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	}
 };
 
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 5ac7ce26443117268ed5b647cde097d20e2164f0..51870d50f4195e348e600905602ee3cc7620e5ff 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1395,7 +1395,7 @@ static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
 			.formats	 = AIC31XX_FORMATS,
 		},
 		.ops = &aic31xx_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	}
 };
 
@@ -1417,7 +1417,7 @@ static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
 			.formats	 = AIC31XX_FORMATS,
 		},
 		.ops = &aic31xx_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	}
 };
 
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 9e3de9ded0efbdf620129487e79100b333c62c40..f04f88c8d42510b4cb3f3e6246970e8a410f18e9 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -916,7 +916,7 @@ static struct snd_soc_dai_driver aic32x4_dai = {
 			.rates = AIC32X4_RATES,
 			.formats = AIC32X4_FORMATS,},
 	.ops = &aic32x4_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static void aic32x4_setup_gpios(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 6d066bc58ac8adc0bf6ae4e7bc636cdcc3250ef9..db14441274441709f3e4840745e340c470482ed1 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1503,7 +1503,7 @@ static struct snd_soc_dai_driver aic3x_dai = {
 		.rates = AIC3X_RATES,
 		.formats = AIC3X_FORMATS,},
 	.ops = &aic3x_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static void aic3x_mono_init(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index 6200fab7896ffeba261b5f0396cd93b9fa09b6d6..fb861baf50e852601de8a6ca55aaed54280a6085 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -1397,9 +1397,9 @@ static struct snd_soc_dai_driver tscs42xx_dai = {
 		.rates = TSCS42XX_RATES,
 		.formats = TSCS42XX_FORMATS,},
 	.ops = &tscs42xx_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	.symmetric_channels = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_sample_bits = 1,
 };
 
 static const struct reg_sequence tscs42xx_patch[] = {
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index cd1f1a592386c05a95565a1dffc9f1d63f315524..1bafc9d1101c1fdc2381792fd5a1524726dc7d35 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -3346,9 +3346,9 @@ static struct snd_soc_dai_driver tscs454_dais[] = {
 			.rates = TSCS454_RATES,
 			.formats = TSCS454_FORMATS,},
 		.ops = &tscs454_dai1_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 		.symmetric_channels = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "tscs454-dai2",
@@ -3366,9 +3366,9 @@ static struct snd_soc_dai_driver tscs454_dais[] = {
 			.rates = TSCS454_RATES,
 			.formats = TSCS454_FORMATS,},
 		.ops = &tscs454_dai23_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 		.symmetric_channels = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "tscs454-dai3",
@@ -3386,9 +3386,9 @@ static struct snd_soc_dai_driver tscs454_dais[] = {
 			.rates = TSCS454_RATES,
 			.formats = TSCS454_FORMATS,},
 		.ops = &tscs454_dai23_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 		.symmetric_channels = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_sample_bits = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 70d353b63fe034e3cac9914346747e60bb116eca..fe33f2d88f557c0dd1c132131cf98f03ff763fd3 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -1780,8 +1780,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
 			 .formats = WM5102_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm5102-aif2",
@@ -1802,8 +1802,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
 			 .formats = WM5102_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm5102-aif3",
@@ -1824,8 +1824,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
 			 .formats = WM5102_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm5102-slim1",
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 4238929b237510a41d96fae7dc97d4e5becb36cb..52c0a575cc4f62c1f9e25ae72b57ec65080a1f01 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2089,8 +2089,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 			 .formats = WM5110_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm5110-aif2",
@@ -2111,8 +2111,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 			 .formats = WM5110_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm5110-aif3",
@@ -2133,8 +2133,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 			 .formats = WM5110_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm5110-slim1",
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 73c4a8b9f59e333bff00e7f45e2149c934e8e27f..a18e2290b8c8896c11bddd485b68b5e07deeb420 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -569,7 +569,7 @@ static struct snd_soc_dai_driver wm8510_dai = {
 		.rates = WM8510_RATES,
 		.formats = WM8510_FORMATS,},
 	.ops = &wm8510_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8510_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 304bf725a6132524731db01f0931f6207c1cafa6..dcee7b2bd3d79decf5cf3daf2f3498ab0ee0ea14 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -567,7 +567,7 @@ static struct snd_soc_dai_driver wm8731_dai = {
 		.rates = WM8731_RATES,
 		.formats = WM8731_FORMATS,},
 	.ops = &wm8731_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8731_request_supplies(struct device *dev,
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index 1176a6ad269d4eadc8268f6e9b701f4f40592c0b..5f394065030d27ceaeed4efb0d0e3eeafc6e600f 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -562,7 +562,7 @@ static struct snd_soc_dai_driver wm8770_dai = {
 		.formats = WM8770_FORMATS
 	},
 	.ops = &wm8770_dai_ops,
-	.symmetric_rates = 1
+	.symmetric_rate = 1
 };
 
 static int wm8770_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 4ddb5e32df5df23f29e3ed5569ddc6771e9098c3..21bf0cfa1e7e7ca625394d084d34a287a795b6e8 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -536,7 +536,7 @@ static struct snd_soc_dai_driver wm8804_dai = {
 		.formats = WM8804_FORMATS,
 	},
 	.ops = &wm8804_dai_ops,
-	.symmetric_rates = 1
+	.symmetric_rate = 1
 };
 
 static const struct snd_soc_component_driver soc_component_dev_wm8804 = {
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 09f4980630c7e9cefadfa2e125324576ce3bc2c6..026603ae44ce0f5415cb2daf0e6eea6d54c7235b 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1760,7 +1760,7 @@ static struct snd_soc_dai_driver wm8903_dai = {
 		 .formats = WM8903_FORMATS,
 	 },
 	.ops = &wm8903_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8903_resume(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 1c360bae5652c56fa8f954c1a30dca603ec36a5c..a02a77fef360ba1436d8ee28d5f51f2ade1342aa 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1983,7 +1983,7 @@ static struct snd_soc_dai_driver wm8904_dai = {
 		.formats = WM8904_FORMATS,
 	},
 	.ops = &wm8904_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 016cd8aeef37c6892715f5680f96519d7eab243a..440d048ef0c02c6cd73572da0636c4dcee2477f5 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -688,7 +688,7 @@ static struct snd_soc_dai_driver wm8940_dai = {
 		.formats = WM8940_FORMATS,
 	},
 	.ops = &wm8940_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8940_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 660ec46eecf2588d7a277c8ff4a2b63a67242145..df351519a3a6bd4efcef1c5b94ea2dbb0b57020c 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1338,7 +1338,7 @@ static struct snd_soc_dai_driver wm8960_dai = {
 		.rates = WM8960_RATES,
 		.formats = WM8960_FORMATS,},
 	.ops = &wm8960_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8960_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 3af456010b9c59e0f3cde623d648ab12bb5e59f2..ce4666a74793e35884e67dc6724bf36ab3246f01 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2973,7 +2973,7 @@ static struct snd_soc_dai_driver wm8962_dai = {
 		.formats = WM8962_FORMATS,
 	},
 	.ops = &wm8962_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static void wm8962_mic_work(struct work_struct *work)
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index c86231dfcf4f84d68cf127addfe704c203b4bab8..fdc68ab4974274d9fea2a1b84a276f5bd24eb33c 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -643,7 +643,7 @@ static struct snd_soc_dai_driver wm8974_dai = {
 		.rates = WM8974_RATES,
 		.formats = WM8974_FORMATS,},
 	.ops = &wm8974_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct regmap_config wm8974_regmap = {
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index a7acb898171592cad66d75f73628b767cae1448a..4b5ecd1422492705089d50e296b845dd559dbd6e 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -918,7 +918,7 @@ static struct snd_soc_dai_driver wm8978_dai = {
 		.formats = WM8978_FORMATS,
 	},
 	.ops = &wm8978_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8978_suspend(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index d1d2d408ad952fd8f7ad63c0243ad70bac43acf2..d8ed22a9caac1ae8c4daa64bd30ae47b19ae05c4 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -971,7 +971,7 @@ static struct snd_soc_dai_driver wm8983_dai = {
 		.formats = WM8983_FORMATS,
 	},
 	.ops = &wm8983_dai_ops,
-	.symmetric_rates = 1
+	.symmetric_rate = 1
 };
 
 static const struct snd_soc_component_driver soc_component_dev_wm8983 = {
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 3f27482349b2a36438bd7e1d8406d386f84a6a95..a7e01106fbc0a18afb6631369c03b1b9af8a8ea7 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1100,7 +1100,7 @@ static struct snd_soc_dai_driver wm8985_dai = {
 		.formats = WM8985_FORMATS,
 	},
 	.ops = &wm8985_dai_ops,
-	.symmetric_rates = 1
+	.symmetric_rate = 1
 };
 
 static const struct snd_soc_component_driver soc_component_dev_wm8985 = {
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index d2c2d0d943f09ecc408ad00fd81f77d667d6d3de..1d2f881bbcae6bb72a619d3237b205012ad4e27a 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -787,7 +787,7 @@ static struct snd_soc_dai_driver wm8988_dai = {
 		.formats = WM8988_FORMATS,
 	 },
 	.ops = &wm8988_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8988_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 9f310082e3c1a0653df367bc6a8ae128a53b0b07..c4f41692b806d72aacafe0d8196cd663595a8115 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1476,7 +1476,7 @@ static struct snd_soc_dai_driver wm8993_dai = {
 		 .sig_bits = 24,
 	 },
 	.ops = &wm8993_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static int wm8993_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index f57884113406b8f180252b09b6629a3481b0c507..f117ec0c489f03af6f5d20bee93f8ff7a68cad09 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4351,7 +4351,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
 	}
 	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
 		wm8994->lrclk_shared[0] = 1;
-		wm8994_dai[0].symmetric_rates = 1;
+		wm8994_dai[0].symmetric_rate = 1;
 	} else {
 		wm8994->lrclk_shared[0] = 0;
 	}
@@ -4363,7 +4363,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
 	}
 	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
 		wm8994->lrclk_shared[1] = 1;
-		wm8994_dai[1].symmetric_rates = 1;
+		wm8994_dai[1].symmetric_rate = 1;
 	} else {
 		wm8994->lrclk_shared[1] = 0;
 	}
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 229f2986cd96b22ffaeadd1630783aa12c0453d8..99c3ebae6ba698e5516a75ede9610e78e0d10495 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -969,8 +969,8 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
 			 .formats = WM8997_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm8997-aif2",
@@ -991,8 +991,8 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
 			 .formats = WM8997_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm8997-slim1",
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 5413254295b70dfe608fd39f31eb521fb63aefd2..b6f717aa5478a29299654e9077a678a90d251f13 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -1161,8 +1161,8 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
 			 .formats = WM8998_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm8998-aif2",
@@ -1183,8 +1183,8 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
 			 .formats = WM8998_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm8998-aif3",
@@ -1205,8 +1205,8 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
 			 .formats = WM8998_FORMATS,
 		 },
 		.ops = &arizona_dai_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "wm8998-slim1",
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index f333e2ff4a168960829c8bd6317e06fe7c0977f9..e0ce32dd4a811517828278f5b803ecb20169981a 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1134,7 +1134,7 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
 		.rates = WM9713_PCM_RATES,
 		.formats = WM9713_PCM_FORMATS,},
 	.ops = &wm9713_dai_ops_voice,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 985b2dcecf138c18f6cc6f562e2dfadb119f48dc..070ca7d8c661003dec4dba893ef21a40e945c58e 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -595,13 +595,6 @@ static const struct {
 	[WM_ADSP_FW_MISC] =     { .file = "misc" },
 };
 
-struct wm_coeff_ctl_ops {
-	int (*xget)(struct snd_kcontrol *kcontrol,
-		    struct snd_ctl_elem_value *ucontrol);
-	int (*xput)(struct snd_kcontrol *kcontrol,
-		    struct snd_ctl_elem_value *ucontrol);
-};
-
 struct wm_coeff_ctl {
 	const char *name;
 	const char *fw_name;
@@ -609,7 +602,6 @@ struct wm_coeff_ctl {
 	const char *subname;
 	unsigned int subname_len;
 	struct wm_adsp_alg_region alg_region;
-	struct wm_coeff_ctl_ops ops;
 	struct wm_adsp *dsp;
 	unsigned int enabled:1;
 	struct list_head list;
@@ -619,7 +611,7 @@ struct wm_coeff_ctl {
 	unsigned int set:1;
 	struct soc_bytes_ext bytes_ext;
 	unsigned int flags;
-	unsigned int type;
+	snd_ctl_elem_type_t type;
 };
 
 static const char *wm_adsp_mem_region_name(unsigned int type)
@@ -980,7 +972,7 @@ static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
 					unsigned int event_id)
 {
 	struct wm_adsp *dsp = ctl->dsp;
-	u32 val = cpu_to_be32(event_id);
+	__be32 val = cpu_to_be32(event_id);
 	unsigned int reg;
 	int i, ret;
 
@@ -1420,7 +1412,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
 				  const struct wm_adsp_alg_region *alg_region,
 				  unsigned int offset, unsigned int len,
 				  const char *subname, unsigned int subname_len,
-				  unsigned int flags, unsigned int type)
+				  unsigned int flags, snd_ctl_elem_type_t type)
 {
 	struct wm_coeff_ctl *ctl;
 	struct wmfw_ctl_work *ctl_work;
@@ -1497,8 +1489,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
 	}
 	ctl->enabled = 1;
 	ctl->set = 0;
-	ctl->ops.xget = wm_coeff_get;
-	ctl->ops.xput = wm_coeff_put;
 	ctl->dsp = dsp;
 
 	ctl->flags = flags;
@@ -1554,7 +1544,7 @@ struct wm_coeff_parsed_coeff {
 	int mem_type;
 	const u8 *name;
 	int name_len;
-	int ctl_type;
+	snd_ctl_elem_type_t ctl_type;
 	int flags;
 	int len;
 };
@@ -1649,7 +1639,7 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
 		blk->mem_type = le16_to_cpu(raw->hdr.type);
 		blk->name = raw->name;
 		blk->name_len = strlen(raw->name);
-		blk->ctl_type = le16_to_cpu(raw->ctl_type);
+		blk->ctl_type = (__force snd_ctl_elem_type_t)le16_to_cpu(raw->ctl_type);
 		blk->flags = le16_to_cpu(raw->flags);
 		blk->len = le32_to_cpu(raw->len);
 		break;
@@ -1662,7 +1652,9 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
 						      &blk->name);
 		wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
 		wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
-		blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
+		blk->ctl_type =
+			(__force snd_ctl_elem_type_t)wm_coeff_parse_int(sizeof(raw->ctl_type),
+									&tmp);
 		blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
 		blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
 
@@ -3667,12 +3659,12 @@ int wm_adsp_compr_get_caps(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
 
-static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
-				   unsigned int mem_addr,
-				   unsigned int num_words, u32 *data)
+static int wm_adsp_read_raw_data_block(struct wm_adsp *dsp, int mem_type,
+				       unsigned int mem_addr,
+				       unsigned int num_words, __be32 *data)
 {
 	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
-	unsigned int i, reg;
+	unsigned int reg;
 	int ret;
 
 	if (!mem)
@@ -3685,22 +3677,29 @@ static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < num_words; ++i)
-		data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
-
 	return 0;
 }
 
 static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
 					 unsigned int mem_addr, u32 *data)
 {
-	return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
+	__be32 raw;
+	int ret;
+
+	ret = wm_adsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw);
+	if (ret < 0)
+		return ret;
+
+	*data = be32_to_cpu(raw) & 0x00ffffffu;
+
+	return 0;
 }
 
 static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
 				   unsigned int mem_addr, u32 data)
 {
 	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+	__be32 val = cpu_to_be32(data & 0x00ffffffu);
 	unsigned int reg;
 
 	if (!mem)
@@ -3708,9 +3707,7 @@ static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
 
 	reg = dsp->ops->region_to_reg(mem, mem_addr);
 
-	data = cpu_to_be32(data & 0x00ffffffu);
-
-	return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
+	return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
 }
 
 static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
@@ -3727,18 +3724,22 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
 				       buf->host_buf_ptr + field_offset, data);
 }
 
-static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
+static void wm_adsp_remove_padding(u32 *buf, int nwords)
 {
-	u8 *pack_in = (u8 *)buf;
+	const __be32 *pack_in = (__be32 *)buf;
 	u8 *pack_out = (u8 *)buf;
-	int i, j;
+	int i;
 
-	/* Remove the padding bytes from the data read from the DSP */
+	/*
+	 * DSP words from the register map have pad bytes and the data bytes
+	 * are in swapped order. This swaps back to the original little-endian
+	 * order and strips the pad bytes.
+	 */
 	for (i = 0; i < nwords; i++) {
-		for (j = 0; j < data_word_size; j++)
-			*pack_out++ = *pack_in++;
-
-		pack_in += sizeof(*buf) - data_word_size;
+		u32 word = be32_to_cpu(*pack_in++);
+		*pack_out++ = (u8)word;
+		*pack_out++ = (u8)(word >> 8);
+		*pack_out++ = (u8)(word >> 16);
 	}
 }
 
@@ -3863,7 +3864,8 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
 {
 	struct wm_adsp_host_buf_coeff_v1 coeff_v1;
 	struct wm_adsp_compr_buf *buf;
-	unsigned int val, reg;
+	unsigned int reg, version;
+	__be32 bufp;
 	int ret, i;
 
 	ret = wm_coeff_base_reg(ctl, &reg);
@@ -3871,17 +3873,17 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
 		return ret;
 
 	for (i = 0; i < 5; ++i) {
-		ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
+		ret = regmap_raw_read(ctl->dsp->regmap, reg, &bufp, sizeof(bufp));
 		if (ret < 0)
 			return ret;
 
-		if (val)
+		if (bufp)
 			break;
 
 		usleep_range(1000, 2000);
 	}
 
-	if (!val) {
+	if (!bufp) {
 		adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
 		return -EIO;
 	}
@@ -3891,7 +3893,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
 		return -ENOMEM;
 
 	buf->host_buf_mem_type = ctl->alg_region.type;
-	buf->host_buf_ptr = be32_to_cpu(val);
+	buf->host_buf_ptr = be32_to_cpu(bufp);
 
 	ret = wm_adsp_buffer_populate(buf);
 	if (ret < 0)
@@ -3911,31 +3913,25 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
 	if (ret < 0)
 		return ret;
 
-	coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
-	val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
-	val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
+	version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK;
+	version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
 
-	if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
+	if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
 		adsp_err(ctl->dsp,
 			 "Host buffer coeff ver %u > supported version %u\n",
-			 val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
+			 version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
 		return -EINVAL;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
-		coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
-
-	wm_adsp_remove_padding((u32 *)&coeff_v1.name,
-			       ARRAY_SIZE(coeff_v1.name),
-			       WM_ADSP_DATA_WORD_SIZE);
+	wm_adsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
 
 	buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
 			      (char *)&coeff_v1.name);
 
 	compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
-		  buf->host_buf_ptr, val);
+		  buf->host_buf_ptr, version);
 
-	return val;
+	return version;
 }
 
 static int wm_adsp_buffer_init(struct wm_adsp *dsp)
@@ -4266,12 +4262,12 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
 		return 0;
 
 	/* Read data from DSP */
-	ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
-				      nwords, compr->raw_buf);
+	ret = wm_adsp_read_raw_data_block(buf->dsp, mem_type, adsp_addr,
+					  nwords, (__be32 *)compr->raw_buf);
 	if (ret < 0)
 		return ret;
 
-	wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
+	wm_adsp_remove_padding(compr->raw_buf, nwords);
 
 	/* update read index to account for words read */
 	buf->read_index += nwords;
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index 7423272c30e94245d7058f766a436402e680eda8..f3d51602f85c76d86efd22be62256f5e07558fe3 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -24,9 +24,9 @@
 #define WMFW_CTL_FLAG_READABLE    0x0001
 
 /* Non-ALSA coefficient types start at 0x1000 */
-#define WMFW_CTL_TYPE_ACKED       0x1000 /* acked control */
-#define WMFW_CTL_TYPE_HOSTEVENT   0x1001 /* event control */
-#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
+#define WMFW_CTL_TYPE_ACKED       ((__force snd_ctl_elem_type_t)0x1000) /* acked control */
+#define WMFW_CTL_TYPE_HOSTEVENT   ((__force snd_ctl_elem_type_t)0x1001) /* event control */
+#define WMFW_CTL_TYPE_HOST_BUFFER ((__force snd_ctl_elem_type_t)0x1002) /* host buffer pointer */
 
 struct wmfw_header {
 	char magic[4];
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 4530b74f5921b74a52667c65b32396f8426e8520..db87e07b11c94eca195731b0b6a8cccb712302f6 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -640,6 +640,7 @@ static struct regmap_config wsa881x_regmap_config = {
 	.val_bits = 8,
 	.cache_type = REGCACHE_RBTREE,
 	.reg_defaults = wsa881x_defaults,
+	.max_register = WSA881X_SPKR_STATUS3,
 	.num_reg_defaults = ARRAY_SIZE(wsa881x_defaults),
 	.volatile_reg = wsa881x_volatile_register,
 	.readable_reg = wsa881x_readable_register,
diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c
index 42726dc0ba39a2d9f259b4100616ba75f7042dbf..d21a72314d377057d2f8a83527b724b83b131fba 100644
--- a/sound/soc/codecs/zl38060.c
+++ b/sound/soc/codecs/zl38060.c
@@ -360,8 +360,8 @@ static struct snd_soc_dai_driver zl38_dai = {
 		.formats = ZL38_FORMATS,
 	},
 	.ops = &zl38_dai_ops,
-	.symmetric_rates = 1,
-	.symmetric_samplebits = 1,
+	.symmetric_rate = 1,
+	.symmetric_sample_bits = 1,
 	.symmetric_channels = 1,
 };
 
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
deleted file mode 100644
index 16d44efb132df87d232cc20a413c4e69a6e622ef..0000000000000000000000000000000000000000
--- a/sound/soc/codecs/zx_aud96p22.c
+++ /dev/null
@@ -1,401 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2017 Sanechips Technology Co., Ltd.
- * Copyright 2017 Linaro Ltd.
- *
- * Author: Baoyou Xie <baoyou.xie@linaro.org>
- */
-
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/regmap.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-#include <sound/tlv.h>
-
-#define AUD96P22_RESET			0x00
-#define RST_DAC_DPZ			BIT(0)
-#define RST_ADC_DPZ			BIT(1)
-#define AUD96P22_I2S1_CONFIG_0		0x03
-#define I2S1_MS_MODE			BIT(3)
-#define I2S1_MODE_MASK			0x7
-#define I2S1_MODE_RIGHT_J		0x0
-#define I2S1_MODE_I2S			0x1
-#define I2S1_MODE_LEFT_J		0x2
-#define AUD96P22_PD_0			0x15
-#define AUD96P22_PD_1			0x16
-#define AUD96P22_PD_3			0x18
-#define AUD96P22_PD_4			0x19
-#define AUD96P22_MUTE_0			0x1d
-#define AUD96P22_MUTE_2			0x1f
-#define AUD96P22_MUTE_4			0x21
-#define AUD96P22_RECVOL_0		0x24
-#define AUD96P22_RECVOL_1		0x25
-#define AUD96P22_PGA1VOL_0		0x26
-#define AUD96P22_PGA1VOL_1		0x27
-#define AUD96P22_LMVOL_0		0x34
-#define AUD96P22_LMVOL_1		0x35
-#define AUD96P22_HS1VOL_0		0x38
-#define AUD96P22_HS1VOL_1		0x39
-#define AUD96P22_PGA1SEL_0		0x47
-#define AUD96P22_PGA1SEL_1		0x48
-#define AUD96P22_LDR1SEL_0		0x59
-#define AUD96P22_LDR1SEL_1		0x60
-#define AUD96P22_LDR2SEL_0		0x5d
-#define AUD96P22_REG_MAX		0xfb
-
-struct aud96p22_priv {
-	struct regmap *regmap;
-};
-
-static int aud96p22_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 aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
-	struct regmap *regmap = priv->regmap;
-
-	if (event != SND_SOC_DAPM_POST_PMU)
-		return -EINVAL;
-
-	/* Assert/de-assert the bit to reset ADC data path  */
-	regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0);
-	regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ);
-
-	return 0;
-}
-
-static int aud96p22_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 aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
-	struct regmap *regmap = priv->regmap;
-
-	if (event != SND_SOC_DAPM_POST_PMU)
-		return -EINVAL;
-
-	/* Assert/de-assert the bit to reset DAC data path  */
-	regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0);
-	regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ);
-
-	return 0;
-}
-
-static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0);
-static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0);
-static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0);
-static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0);
-
-static const struct snd_kcontrol_new aud96p22_snd_controls[] = {
-	/* Volume control */
-	SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0,
-			 AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv),
-	SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0,
-			 AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv),
-	SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0,
-			 AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv),
-	SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0,
-			 AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv),
-
-	/* Mute control */
-	SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1),
-	SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1),
-	SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1),
-	SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1),
-	SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1),
-	SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1),
-};
-
-/* Input mux kcontrols */
-static const unsigned int ain_mux_values[] = {
-	0, 1, 3, 4, 5,
-};
-
-static const char * const ainl_mux_texts[] = {
-	"AINL1 differential",
-	"AINL1 single-ended",
-	"AINL3 single-ended",
-	"AINL2 differential",
-	"AINL2 single-ended",
-};
-
-static const char * const ainr_mux_texts[] = {
-	"AINR1 differential",
-	"AINR1 single-ended",
-	"AINR3 single-ended",
-	"AINR2 differential",
-	"AINR2 single-ended",
-};
-
-static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0,
-				  0, 0x7, ainl_mux_texts, ain_mux_values);
-static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1,
-				  0, 0x7, ainr_mux_texts, ain_mux_values);
-
-static const struct snd_kcontrol_new ainl_mux_kcontrol =
-			SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum);
-static const struct snd_kcontrol_new ainr_mux_kcontrol =
-			SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum);
-
-/* Output mixer kcontrols */
-static const struct snd_kcontrol_new ld1_left_kcontrols[] = {
-	SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0),
-	SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0),
-	SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0),
-};
-
-static const struct snd_kcontrol_new ld1_right_kcontrols[] = {
-	SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0),
-	SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0),
-	SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0),
-};
-
-static const struct snd_kcontrol_new ld2_kcontrols[] = {
-	SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0),
-	SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0),
-	SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = {
-	/* Overall power bit */
-	SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0),
-
-	/* Input pins */
-	SND_SOC_DAPM_INPUT("AINL1P"),
-	SND_SOC_DAPM_INPUT("AINL2P"),
-	SND_SOC_DAPM_INPUT("AINL3"),
-	SND_SOC_DAPM_INPUT("AINL1N"),
-	SND_SOC_DAPM_INPUT("AINL2N"),
-	SND_SOC_DAPM_INPUT("AINR2N"),
-	SND_SOC_DAPM_INPUT("AINR1N"),
-	SND_SOC_DAPM_INPUT("AINR3"),
-	SND_SOC_DAPM_INPUT("AINR2P"),
-	SND_SOC_DAPM_INPUT("AINR1P"),
-
-	/* Input muxes */
-	SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol),
-	SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol),
-
-	/* ADCs */
-	SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0,
-			   aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0,
-			   aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
-
-	/* DACs */
-	SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0,
-			   aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0,
-			   aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
-
-	/* Output mixers */
-	SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols,
-			   ARRAY_SIZE(ld1_left_kcontrols)),
-	SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols,
-			   ARRAY_SIZE(ld1_right_kcontrols)),
-	SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols,
-			   ARRAY_SIZE(ld2_kcontrols)),
-
-	/* Headset power switch */
-	SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0),
-
-	/* Output pins */
-	SND_SOC_DAPM_OUTPUT("HSOUTL"),
-	SND_SOC_DAPM_OUTPUT("LINEOUTL"),
-	SND_SOC_DAPM_OUTPUT("LINEOUTMP"),
-	SND_SOC_DAPM_OUTPUT("LINEOUTMN"),
-	SND_SOC_DAPM_OUTPUT("LINEOUTR"),
-	SND_SOC_DAPM_OUTPUT("HSOUTR"),
-};
-
-static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
-	{ "AINLMUX", "AINL1 differential", "AINL1N" },
-	{ "AINLMUX", "AINL1 single-ended", "AINL1P" },
-	{ "AINLMUX", "AINL3 single-ended", "AINL3" },
-	{ "AINLMUX", "AINL2 differential", "AINL2N" },
-	{ "AINLMUX", "AINL2 single-ended", "AINL2P" },
-
-	{ "AINRMUX", "AINR1 differential", "AINR1N" },
-	{ "AINRMUX", "AINR1 single-ended", "AINR1P" },
-	{ "AINRMUX", "AINR3 single-ended", "AINR3" },
-	{ "AINRMUX", "AINR2 differential", "AINR2N" },
-	{ "AINRMUX", "AINR2 single-ended", "AINR2P" },
-
-	{ "ADCL", NULL, "AINLMUX" },
-	{ "ADCR", NULL, "AINRMUX" },
-
-	{ "ADCL", NULL, "POWER" },
-	{ "ADCR", NULL, "POWER" },
-	{ "DACL", NULL, "POWER" },
-	{ "DACR", NULL, "POWER" },
-
-	{ "LD1L", "DACL LD1L Switch", "DACL" },
-	{ "LD1L", "AINL LD1L Switch", "AINLMUX" },
-	{ "LD1L", "AINR LD1L Switch", "AINRMUX" },
-
-	{ "LD1R", "DACR LD1R Switch", "DACR" },
-	{ "LD1R", "AINR LD1R Switch", "AINRMUX" },
-	{ "LD1R", "AINL LD1R Switch", "AINLMUX" },
-
-	{ "LD2", "DACL LD2 Switch", "DACL" },
-	{ "LD2", "AINL LD2 Switch", "AINLMUX" },
-	{ "LD2", "DACR LD2 Switch", "DACR" },
-
-	{ "HSOUTL", NULL, "LD1L" },
-	{ "HSOUTR", NULL, "LD1R" },
-	{ "HSOUTL", NULL, "HS1L" },
-	{ "HSOUTR", NULL, "HS1R" },
-
-	{ "LINEOUTL", NULL, "LD1L" },
-	{ "LINEOUTR", NULL, "LD1R" },
-
-	{ "LINEOUTMP", NULL, "LD2" },
-	{ "LINEOUTMN", NULL, "LD2" },
-};
-
-static const struct snd_soc_component_driver aud96p22_driver = {
-	.controls		= aud96p22_snd_controls,
-	.num_controls		= ARRAY_SIZE(aud96p22_snd_controls),
-	.dapm_widgets		= aud96p22_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(aud96p22_dapm_widgets),
-	.dapm_routes		= aud96p22_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(aud96p22_dapm_routes),
-	.idle_bias_on		= 1,
-	.use_pmdown_time	= 1,
-	.endianness		= 1,
-	.non_legacy_dai_naming	= 1,
-};
-
-static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(dai->component);
-	struct regmap *regmap = priv->regmap;
-	unsigned int val;
-
-	/* Master/slave mode */
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		val = 0;
-		break;
-	case SND_SOC_DAIFMT_CBM_CFM:
-		val = I2S1_MS_MODE;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val);
-
-	/* Audio format */
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_RIGHT_J:
-		val = I2S1_MODE_RIGHT_J;
-		break;
-	case SND_SOC_DAIFMT_I2S:
-		val = I2S1_MODE_I2S;
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		val = I2S1_MODE_LEFT_J;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val);
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops aud96p22_dai_ops = {
-	.set_fmt = aud96p22_set_fmt,
-};
-
-#define AUD96P22_RATES	SNDRV_PCM_RATE_8000_192000
-#define AUD96P22_FORMATS (\
-		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
-		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_driver aud96p22_dai = {
-	.name = "aud96p22-dai",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = AUD96P22_RATES,
-		.formats = AUD96P22_FORMATS,
-	},
-	.capture = {
-		.stream_name = "Capture",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = AUD96P22_RATES,
-		.formats = AUD96P22_FORMATS,
-	},
-	.ops = &aud96p22_dai_ops,
-};
-
-static const struct regmap_config aud96p22_regmap = {
-	.reg_bits = 8,
-	.val_bits = 8,
-	.max_register = AUD96P22_REG_MAX,
-	.cache_type = REGCACHE_RBTREE,
-};
-
-static int aud96p22_i2c_probe(struct i2c_client *i2c,
-			      const struct i2c_device_id *id)
-{
-	struct device *dev = &i2c->dev;
-	struct aud96p22_priv *priv;
-	int ret;
-
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (priv == NULL)
-		return -ENOMEM;
-
-	priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap);
-	if (IS_ERR(priv->regmap)) {
-		ret = PTR_ERR(priv->regmap);
-		dev_err(dev, "failed to init i2c regmap: %d\n", ret);
-		return ret;
-	}
-
-	i2c_set_clientdata(i2c, priv);
-
-	ret = devm_snd_soc_register_component(dev, &aud96p22_driver, &aud96p22_dai, 1);
-	if (ret) {
-		dev_err(dev, "failed to register component: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int aud96p22_i2c_remove(struct i2c_client *i2c)
-{
-	return 0;
-}
-
-static const struct of_device_id aud96p22_dt_ids[] = {
-	{ .compatible = "zte,zx-aud96p22", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, aud96p22_dt_ids);
-
-static struct i2c_driver aud96p22_i2c_driver = {
-	.driver = {
-		.name = "zx_aud96p22",
-		.of_match_table = aud96p22_dt_ids,
-	},
-	.probe = aud96p22_i2c_probe,
-	.remove = aud96p22_i2c_remove,
-};
-module_i2c_driver(aud96p22_i2c_driver);
-
-MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver");
-MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 84db0b7b9d593c6e18bd731b7a9ffe343a5d577a..d7f30036d4343ef338f14eb7c1867a482ef5b058 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -108,6 +108,7 @@ config SND_SOC_FSL_XCVR
 config SND_SOC_FSL_AUD2HTX
 	tristate "AUDIO TO HDMI TX module support"
 	depends on ARCH_MXC || COMPILE_TEST
+	select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
 	help
 	  Say Y if you want to add AUDIO TO HDMI TX support for NXP.
 
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 02c81d2e34ad00f5437a46d5f264679552507a24..c325c984d165939263e42a9d606ee1adcef54c5f 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1083,11 +1083,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 	}
 
 	asrc_priv->soc = of_device_get_match_data(&pdev->dev);
-	if (!asrc_priv->soc) {
-		dev_err(&pdev->dev, "failed to get soc data\n");
-		return -ENODEV;
-	}
-
 	asrc->use_edma = asrc_priv->soc->use_edma;
 	asrc->get_dma_channel = fsl_asrc_get_dma_channel;
 	asrc->request_pair = fsl_asrc_request_pair;
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 60951a8aabd309a36a0740caa0a19d023c3c27fe..636a702f37a62ec0ad11bbf00ca13738eaebd944 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1530,7 +1530,7 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
 	.startup = fsl_easrc_startup,
 	.trigger = fsl_easrc_trigger,
 	.hw_params = fsl_easrc_hw_params,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 39637ca78cdbbe1c03792fa7244829dddf7eaf6b..08056fa0a0fa5ff1f5e18db91569224b7958b33f 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -23,11 +23,9 @@
 
 /**
  * struct fsl_esai_soc_data - soc specific data
- * @imx: for imx platform
  * @reset_at_xrun: flags for enable reset operaton
  */
 struct fsl_esai_soc_data {
-	bool imx;
 	bool reset_at_xrun;
 };
 
@@ -86,17 +84,14 @@ struct fsl_esai {
 };
 
 static struct fsl_esai_soc_data fsl_esai_vf610 = {
-	.imx = false,
 	.reset_at_xrun = true,
 };
 
 static struct fsl_esai_soc_data fsl_esai_imx35 = {
-	.imx = true,
 	.reset_at_xrun = true,
 };
 
 static struct fsl_esai_soc_data fsl_esai_imx6ull = {
-	.imx = true,
 	.reset_at_xrun = false,
 };
 
@@ -967,10 +962,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
 	snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np);
 
 	esai_priv->soc = of_device_get_match_data(&pdev->dev);
-	if (!esai_priv->soc) {
-		dev_err(&pdev->dev, "failed to get soc data\n");
-		return -ENODEV;
-	}
 
 	/* Get the addresses and IRQ */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1042,9 +1033,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
 
 	/* Implement full symmetry for synchronous mode */
 	if (esai_priv->synchronous) {
-		fsl_esai_dai.symmetric_rates = 1;
+		fsl_esai_dai.symmetric_rate = 1;
 		fsl_esai_dai.symmetric_channels = 1;
-		fsl_esai_dai.symmetric_samplebits = 1;
+		fsl_esai_dai.symmetric_sample_bits = 1;
 	}
 
 	dev_set_drvdata(&pdev->dev, esai_priv);
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index efc5daf53bbae504c654dae1a423107f57855ff6..5935af2e5ff478adeb9f056e3cbeb8899d3ec8c2 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -381,7 +381,7 @@ static int fsl_micfil_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	return ret;
 }
 
-static struct snd_soc_dai_ops fsl_micfil_dai_ops = {
+static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
 	.startup = fsl_micfil_startup,
 	.trigger = fsl_micfil_trigger,
 	.hw_params = fsl_micfil_hw_params,
@@ -637,7 +637,6 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
 static int fsl_micfil_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	const struct of_device_id *of_id;
 	struct fsl_micfil *micfil;
 	struct resource *res;
 	void __iomem *regs;
@@ -651,11 +650,7 @@ static int fsl_micfil_probe(struct platform_device *pdev)
 	micfil->pdev = pdev;
 	strncpy(micfil->name, np->name, sizeof(micfil->name) - 1);
 
-	of_id = of_match_device(fsl_micfil_dt_ids, &pdev->dev);
-	if (!of_id || !of_id->data)
-		return -EINVAL;
-
-	micfil->soc = of_id->data;
+	micfil->soc = of_device_get_match_data(&pdev->dev);
 
 	/* ipg_clk is used to control the registers
 	 * ipg_clk_app is used to operate the filter
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index f3d3d20d35d7918964e2beac90a19698655e9a71..5e65b456d3e21b3143256d4bf3473a6ae47b5080 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -1079,9 +1079,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
 	/* Sync Tx with Rx as default by following old DT binding */
 	sai->synchronous[RX] = true;
 	sai->synchronous[TX] = false;
-	sai->cpu_dai_drv.symmetric_rates = 1;
+	sai->cpu_dai_drv.symmetric_rate = 1;
 	sai->cpu_dai_drv.symmetric_channels = 1;
-	sai->cpu_dai_drv.symmetric_samplebits = 1;
+	sai->cpu_dai_drv.symmetric_sample_bits = 1;
 
 	if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
 	    of_find_property(np, "fsl,sai-asynchronous", NULL)) {
@@ -1098,9 +1098,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_rates = 0;
+		sai->cpu_dai_drv.symmetric_rate = 0;
 		sai->cpu_dai_drv.symmetric_channels = 0;
-		sai->cpu_dai_drv.symmetric_samplebits = 0;
+		sai->cpu_dai_drv.symmetric_sample_bits = 0;
 	}
 
 	if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 5fa178f3f49775f7c9cab32d33258f049e687353..174e558224d8c346285508dfd55b2a4be2a9308c 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1255,7 +1255,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
 
 	for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
 		sprintf(tmp, "rxtx%d", i);
-		clk = devm_clk_get(&pdev->dev, tmp);
+		clk = devm_clk_get(dev, tmp);
 		if (IS_ERR(clk)) {
 			dev_err(dev, "no rxtx%d clock in devicetree\n", i);
 			return PTR_ERR(clk);
@@ -1277,14 +1277,14 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
 			break;
 	}
 
-	dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
+	dev_dbg(dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
 			spdif_priv->txclk_src[index], rate[index]);
-	dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
+	dev_dbg(dev, "use txclk df %d for %dHz sample rate\n",
 			spdif_priv->txclk_df[index], rate[index]);
 	if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk))
-		dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
+		dev_dbg(dev, "use sysclk df %d for %dHz sample rate\n",
 				spdif_priv->sysclk_df[index], rate[index]);
-	dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
+	dev_dbg(dev, "the best rate for %dHz sample rate is %dHz\n",
 			rate[index], spdif_priv->txrate[index]);
 
 	return 0;
@@ -1305,10 +1305,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 	spdif_priv->pdev = pdev;
 
 	spdif_priv->soc = of_device_get_match_data(&pdev->dev);
-	if (!spdif_priv->soc) {
-		dev_err(&pdev->dev, "failed to get soc data\n");
-		return -ENODEV;
-	}
 
 	/* Initialize this copy of the CPU DAI driver structure */
 	memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 404be27c15fed87b1083e2258a91fdb9dfd885c7..57811743c2948b7ab5591e7f9ec60801eda55a65 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1397,18 +1397,11 @@ static int fsl_ssi_probe_from_dt(struct fsl_ssi *ssi)
 {
 	struct device *dev = ssi->dev;
 	struct device_node *np = dev->of_node;
-	const struct of_device_id *of_id;
 	const char *p, *sprop;
 	const __be32 *iprop;
 	u32 dmas[4];
 	int ret;
 
-	of_id = of_match_device(fsl_ssi_ids, dev);
-	if (!of_id || !of_id->data)
-		return -EINVAL;
-
-	ssi->soc = of_id->data;
-
 	ret = of_property_match_string(np, "clock-names", "ipg");
 	/* Get error code if not found */
 	ssi->has_ipg_clk_name = ret >= 0;
@@ -1492,6 +1485,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	ssi->dev = dev;
+	ssi->soc = of_device_get_match_data(&pdev->dev);
 
 	/* Probe from DT */
 	ret = fsl_ssi_probe_from_dt(ssi);
@@ -1537,9 +1531,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
 	/* Set software limitations for synchronous mode except AC97 */
 	if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) {
-		ssi->cpu_dai_drv.symmetric_rates = 1;
+		ssi->cpu_dai_drv.symmetric_rate = 1;
 		ssi->cpu_dai_drv.symmetric_channels = 1;
-		ssi->cpu_dai_drv.symmetric_samplebits = 1;
+		ssi->cpu_dai_drv.symmetric_sample_bits = 1;
 	}
 
 	/*
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 3d58c88ea603d7c0dbb2158428d372a26a6a50ea..6dd0a5fcd4556af99c1a631447db31d1ef930d1d 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -857,7 +857,7 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
 	},
 };
 
-static struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
 	.prepare = fsl_xcvr_prepare,
 	.startup = fsl_xcvr_startup,
 	.shutdown = fsl_xcvr_shutdown,
@@ -1130,16 +1130,11 @@ MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
 static int fsl_xcvr_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	const struct of_device_id *of_id;
 	struct fsl_xcvr *xcvr;
 	struct resource *ram_res, *regs_res, *rx_res, *tx_res;
 	void __iomem *regs;
 	int ret, irq;
 
-	of_id = of_match_device(fsl_xcvr_dt_ids, dev);
-	if (!of_id)
-		return -EINVAL;
-
 	xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL);
 	if (!xcvr)
 		return -ENOMEM;
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 16a04a67882829003aa7ee6a4fc2139b157e48a0..8c5cdcdc8713c6a1fdbdafacc357a3e2ca5de613 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -532,7 +532,7 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
 static void graph_get_dais_count(struct asoc_simple_priv *priv,
 				 struct link_info *li);
 
-int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
+int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 {
 	struct snd_soc_card *card = simple_priv_to_card(priv);
 	struct link_info li;
@@ -608,7 +608,7 @@ int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(graph_parse_of);
+EXPORT_SYMBOL_GPL(audio_graph_parse_of);
 
 static int graph_count_noml(struct asoc_simple_priv *priv,
 			    struct device_node *cpu_ep,
@@ -705,7 +705,7 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv,
 		li->link, li->dais, li->conf);
 }
 
-int graph_card_probe(struct snd_soc_card *card)
+int audio_graph_card_probe(struct snd_soc_card *card)
 {
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 	int ret;
@@ -720,7 +720,7 @@ int graph_card_probe(struct snd_soc_card *card)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(graph_card_probe);
+EXPORT_SYMBOL_GPL(audio_graph_card_probe);
 
 static int graph_probe(struct platform_device *pdev)
 {
@@ -736,20 +736,21 @@ static int graph_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
-	card->probe		= graph_card_probe;
+	card->probe		= audio_graph_card_probe;
 
 	if (of_device_get_match_data(dev))
 		priv->dpcm_selectable = 1;
 
-	return graph_parse_of(priv, dev);
+	return audio_graph_parse_of(priv, dev);
 }
 
-static int graph_remove(struct platform_device *pdev)
+int audio_graph_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 
 	return asoc_simple_clean_reference(card);
 }
+EXPORT_SYMBOL_GPL(audio_graph_remove);
 
 static const struct of_device_id graph_of_match[] = {
 	{ .compatible = "audio-graph-card", },
@@ -766,7 +767,7 @@ static struct platform_driver graph_card = {
 		.of_match_table = graph_of_match,
 	},
 	.probe = graph_probe,
-	.remove = graph_remove,
+	.remove = audio_graph_remove,
 };
 module_platform_driver(graph_card);
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 6cada4c1e283befe3c52848bda0340f082696a88..ab31045cfc9525f6cf9d2ce08e4086196e6e3214 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -172,16 +172,15 @@ int asoc_simple_parse_clk(struct device *dev,
 	 *  or device's module clock.
 	 */
 	clk = devm_get_clk_from_child(dev, node, NULL);
-	if (!IS_ERR(clk)) {
-		simple_dai->sysclk = clk_get_rate(clk);
+	if (IS_ERR(clk))
+		clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
 
+	if (!IS_ERR(clk)) {
 		simple_dai->clk = clk;
-	} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
+		simple_dai->sysclk = clk_get_rate(clk);
+	} else if (!of_property_read_u32(node, "system-clock-frequency",
+					 &val)) {
 		simple_dai->sysclk = val;
-	} else {
-		clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
-		if (!IS_ERR(clk))
-			simple_dai->sysclk = clk_get_rate(clk);
 	}
 
 	if (of_property_read_bool(node, "system-clock-direction-out"))
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 0c6404fc12b34832721ac75f108155ad468e5680..f3a4a907b29d341ce0eee4f59199fb3c6d61bc8a 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -203,6 +203,8 @@ config SND_SOC_INTEL_KEEMBAY
 	tristate "Keembay Platforms"
 	depends on ARCH_KEEMBAY || COMPILE_TEST
 	depends on COMMON_CLK
+	select SND_DMAENGINE_PCM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	  If you have a Intel Keembay platform then enable this option
 	  by saying Y or m.
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index b58b9b60d37e323d05418ff034c7b003e8690d6b..d1d28129a32b942a04dc597a9c343e0729c85785 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -111,6 +111,18 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_BYTCR_WM5102_MACH
+	tristate "Baytrail and Baytrail-CR with WM5102 codec"
+	depends on MFD_ARIZONA && MFD_WM5102 && SPI_MASTER && ACPI
+	depends on X86_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_ACPI
+	select SND_SOC_WM5102
+	help
+	  This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+	  platforms with WM5102 audio codec.
+	  Say Y if you have such a device.
+	  If unsure select "N".
+
 config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
 	tristate "Cherrytrail & Braswell with RT5672 codec"
 	depends on I2C && ACPI
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 5f03e484b21591e8b8ea5ca8fb8536373b0a6e48..616c5fbab7d5a80ecd0d9d0e235e216860ad464f 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -10,6 +10,7 @@ snd-soc-sst-sof-wm8804-objs := sof_wm8804.o
 snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o
 snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
 snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
+snd-soc-sst-bytcr-wm5102-objs := bytcr_wm5102.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
@@ -51,6 +52,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
+obj-$(CONFIG_SND_SOC_INTEL_BYTCR_WM5102_MACH) += snd-soc-sst-bytcr-wm5102.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 892cf684216e31945fc6477ab38407fb7725f4c9..06df2d46d910bcadaa48874d9f9870b53959b588 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -331,9 +331,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
 
 		/* back ends */
 	{
-		/* Only SSP2 has been tested here, so BYT-CR platforms that
-		 * require SSP0 will not work.
-		 */
 		.name = "SSP2-Codec",
 		.id = 0,
 		.no_pcm = 1,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 5520d7c800196eac4645b02876a14a0f9757e85e..782f2b4d72ad959d6332916255349e0eca3237d0 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -35,6 +35,7 @@ enum {
 	BYT_RT5640_DMIC2_MAP,
 	BYT_RT5640_IN1_MAP,
 	BYT_RT5640_IN3_MAP,
+	BYT_RT5640_NO_INTERNAL_MIC_MAP,
 };
 
 enum {
@@ -71,6 +72,7 @@ enum {
 #define BYT_RT5640_SSP0_AIF2		BIT(21)
 #define BYT_RT5640_MCLK_EN		BIT(22)
 #define BYT_RT5640_MCLK_25MHZ		BIT(23)
+#define BYT_RT5640_NO_SPEAKERS		BIT(24)
 
 #define BYTCR_INPUT_DEFAULTS				\
 	(BYT_RT5640_IN3_MAP |				\
@@ -116,6 +118,9 @@ static void log_quirks(struct device *dev)
 	case BYT_RT5640_IN3_MAP:
 		dev_info(dev, "quirk IN3_MAP enabled\n");
 		break;
+	case BYT_RT5640_NO_INTERNAL_MIC_MAP:
+		dev_info(dev, "quirk NO_INTERNAL_MIC_MAP enabled\n");
+		break;
 	default:
 		dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
 		break;
@@ -132,6 +137,8 @@ static void log_quirks(struct device *dev)
 		dev_info(dev, "quirk JD_NOT_INV enabled\n");
 	if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
 		dev_info(dev, "quirk MONO_SPEAKER enabled\n");
+	if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)
+		dev_info(dev, "quirk NO_SPEAKERS enabled\n");
 	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
 		dev_info(dev, "quirk DIFF_MIC enabled\n");
 	if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
@@ -399,6 +406,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 					BYT_RT5640_SSP0_AIF1 |
 					BYT_RT5640_MCLK_EN),
 	},
+	{	/* Acer One 10 S1002 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "One S1002"),
+		},
+		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
+					BYT_RT5640_JD_SRC_JD2_IN4N |
+					BYT_RT5640_OVCD_TH_2000UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_DIFF_MIC |
+					BYT_RT5640_SSP0_AIF2 |
+					BYT_RT5640_MCLK_EN),
+	},
 	{
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -524,6 +544,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 					BYT_RT5640_MONO_SPEAKER |
 					BYT_RT5640_MCLK_EN),
 	},
+	{	/* Estar Beauty HD MID 7316R */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Estar"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "eSTAR BEAUTY HD Intel Quad core"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
 	{
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
@@ -613,6 +643,15 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 					BYT_RT5640_SSP0_AIF1 |
 					BYT_RT5640_MCLK_EN),
 	},
+	{	/* Mele PCG03 Mini PC */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Mini PC"),
+		},
+		.driver_data = (void *)(BYT_RT5640_NO_INTERNAL_MIC_MAP |
+					BYT_RT5640_NO_SPEAKERS |
+					BYT_RT5640_SSP0_AIF1),
+	},
 	{	/* MPMAN Converter 9, similar hw as the I.T.Works TW891 2-in-1 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "MPMAN"),
@@ -798,6 +837,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 					BYT_RT5640_SSP0_AIF2 |
 					BYT_RT5640_MCLK_EN),
 	},
+	{	/* Voyo Winpad A15 */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+			/* Above strings are too generic, also match on BIOS date */
+			DMI_MATCH(DMI_BIOS_DATE, "11/20/2014"),
+		},
+		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
+					BYT_RT5640_JD_SRC_JD2_IN4N |
+					BYT_RT5640_OVCD_TH_2000UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_DIFF_MIC |
+					BYT_RT5640_MCLK_EN),
+	},
 	{	/* Catch-all for generic Insyde tablets, must be last */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
@@ -873,8 +926,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 	struct snd_soc_card *card = runtime->card;
 	struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
 	struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
-	const struct snd_soc_dapm_route *custom_map;
-	int num_routes;
+	const struct snd_soc_dapm_route *custom_map = NULL;
+	int num_routes = 0;
 	int ret;
 
 	card->dapm.idle_bias_off = true;
@@ -909,13 +962,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 		custom_map = byt_rt5640_intmic_in3_map;
 		num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map);
 		break;
+	case BYT_RT5640_DMIC1_MAP:
+		custom_map = byt_rt5640_intmic_dmic1_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+		break;
 	case BYT_RT5640_DMIC2_MAP:
 		custom_map = byt_rt5640_intmic_dmic2_map;
 		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
 		break;
-	default:
-		custom_map = byt_rt5640_intmic_dmic1_map;
-		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
 	}
 
 	ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
@@ -946,7 +1000,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 		ret = snd_soc_dapm_add_routes(&card->dapm,
 					byt_rt5640_mono_spk_map,
 					ARRAY_SIZE(byt_rt5640_mono_spk_map));
-	} else {
+	} else if (!(byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)) {
 		ret = snd_soc_dapm_add_routes(&card->dapm,
 					byt_rt5640_stereo_spk_map,
 					ARRAY_SIZE(byt_rt5640_stereo_spk_map));
@@ -1187,7 +1241,8 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" };
+	static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3", "none" };
+	__maybe_unused const char *spk_type;
 	const struct dmi_system_id *dmi_id;
 	struct byt_rt5640_private *priv;
 	struct snd_soc_acpi_mach *mach;
@@ -1196,7 +1251,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 	bool sof_parent;
 	int ret_val = 0;
 	int dai_index = 0;
-	int i;
+	int i, cfg_spk;
 
 	is_bytcr = false;
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -1335,16 +1390,24 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) {
+		cfg_spk = 0;
+		spk_type = "none";
+	} else if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
+		cfg_spk = 1;
+		spk_type = "mono";
+	} else {
+		cfg_spk = 2;
+		spk_type = "stereo";
+	}
+
 	snprintf(byt_rt5640_components, sizeof(byt_rt5640_components),
-		 "cfg-spk:%s cfg-mic:%s",
-		 (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "1" : "2",
+		 "cfg-spk:%d cfg-mic:%s", cfg_spk,
 		 map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
 	byt_rt5640_card.components = byt_rt5640_components;
 #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
 	snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
-		 "bytcr-rt5640-%s-spk-%s-mic",
-		 (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ?
-			"mono" : "stereo",
+		 "bytcr-rt5640-%s-spk-%s-mic", spk_type,
 		 map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
 	byt_rt5640_card.long_name = byt_rt5640_long_name;
 #endif
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index f289ec8563a11840ff77039982a88a5573cca4a6..148b7b1bd3e8c0a66ec08e957b3db4a80e6c32b7 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -435,6 +435,19 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
 					BYT_RT5651_SSP0_AIF1 |
 					BYT_RT5651_MONO_SPEAKER),
 	},
+	{
+		/* Jumper EZpad 7 */
+		.callback = byt_rt5651_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Jumper"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"),
+			/* Jumper12x.WJ2012.bsBKRCP05 with the version dropped */
+			DMI_MATCH(DMI_BIOS_VERSION, "Jumper12x.WJ2012.bsBKRCP"),
+		},
+		.driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+					BYT_RT5651_IN2_MAP |
+					BYT_RT5651_JD_NOT_INV),
+	},
 	{
 		/* KIANO SlimNote 14.2 */
 		.callback = byt_rt5651_quirk_cb,
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
new file mode 100644
index 0000000000000000000000000000000000000000..f38850eb2eaf8ee6335b9b7c79be5aabc3cf6d8a
--- /dev/null
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  bytcr_wm5102.c - ASoc Machine driver for Intel Baytrail platforms with a
+ *                   Wolfson Microelectronics WM5102 codec
+ *
+ *  Copyright (C) 2020 Hans de Goede <hdegoede@redhat.com>
+ *  Loosely based on bytcr_rt5640.c which is:
+ *  Copyright (C) 2014-2020 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/wm5102.h"
+#include "../atom/sst-atom-controls.h"
+
+#define MCLK_FREQ		25000000
+
+#define WM5102_MAX_SYSCLK_4K	49152000 /* max sysclk for 4K family */
+#define WM5102_MAX_SYSCLK_11025	45158400 /* max sysclk for 11.025K family */
+
+struct byt_wm5102_private {
+	struct clk *mclk;
+	struct gpio_desc *spkvdd_en_gpio;
+};
+
+static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_card *card = w->dapm->card;
+	struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+
+	gpiod_set_value_cansleep(priv->spkvdd_en_gpio,
+				 !!SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate)
+{
+	struct snd_soc_component *codec_component = codec_dai->component;
+	int sr_mult = ((rate % 4000) == 0) ?
+		(WM5102_MAX_SYSCLK_4K / rate) :
+		(WM5102_MAX_SYSCLK_11025 / rate);
+	int ret;
+
+	/* Reset FLL1 */
+	snd_soc_dai_set_pll(codec_dai, WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0);
+	snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
+
+	/* Configure the FLL1 PLL before selecting it */
+	ret = snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_CLK_SRC_MCLK1,
+				  MCLK_FREQ, rate * sr_mult);
+	if (ret) {
+		dev_err(codec_component->dev, "Error setting PLL: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_set_sysclk(codec_component, ARIZONA_CLK_SYSCLK,
+					   ARIZONA_CLK_SRC_FLL1, rate * sr_mult,
+					   SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(codec_component->dev, "Error setting SYSCLK: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, ARIZONA_CLK_SYSCLK,
+				     rate * 512, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(codec_component->dev, "Error setting clock: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	codec_dai = snd_soc_card_get_codec_dai(card, "wm5102-aif1");
+	if (!codec_dai) {
+		dev_err(card->dev, "Error codec DAI not found\n");
+		return -EIO;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = clk_prepare_enable(priv->mclk);
+		if (ret) {
+			dev_err(card->dev, "Error enabling MCLK: %d\n", ret);
+			return ret;
+		}
+		ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000);
+		if (ret) {
+			dev_err(card->dev, "Error setting codec sysclk: %d\n", ret);
+			return ret;
+		}
+	} else {
+		/*
+		 * The WM5102 has a separate 32KHz clock for jack-detect
+		 * so we can disable the PLL, followed by disabling the
+		 * platform clock which is the source-clock for the PLL.
+		 */
+		snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
+		clk_disable_unprepare(priv->mclk);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Internal Mic", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+			    platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("Speaker VDD", SND_SOC_NOPM, 0, 0,
+			    byt_wm5102_spkvdd_power_event,
+			    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
+	{"Headphone", NULL, "Platform Clock"},
+	{"Headset Mic", NULL, "Platform Clock"},
+	{"Internal Mic", NULL, "Platform Clock"},
+	{"Speaker", NULL, "Platform Clock"},
+
+	{"Speaker", NULL, "SPKOUTLP"},
+	{"Speaker", NULL, "SPKOUTLN"},
+	{"Speaker", NULL, "SPKOUTRP"},
+	{"Speaker", NULL, "SPKOUTRN"},
+	{"Speaker", NULL, "Speaker VDD"},
+
+	{"Headphone", NULL, "HPOUT1L"},
+	{"Headphone", NULL, "HPOUT1R"},
+
+	{"Internal Mic", NULL, "MICBIAS3"},
+	{"IN3L", NULL, "Internal Mic"},
+
+	/*
+	 * The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset
+	 * is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch.
+	 */
+	{"Headset Mic", NULL, "MICBIAS1"},
+	{"Headset Mic", NULL, "MICBIAS2"},
+	{"IN1L", NULL, "Headset Mic"},
+
+	{"AIF1 Playback", NULL, "ssp0 Tx"},
+	{"ssp0 Tx", NULL, "modem_out"},
+
+	{"modem_in", NULL, "ssp0 Rx"},
+	{"ssp0 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_kcontrol_new byt_wm5102_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Internal Mic"),
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_card *card = runtime->card;
+	struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	card->dapm.idle_bias_off = true;
+
+	ret = snd_soc_add_card_controls(card, byt_wm5102_controls,
+					ARRAY_SIZE(byt_wm5102_controls));
+	if (ret) {
+		dev_err(card->dev, "Error adding card controls: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * The firmware might enable the clock at boot (this information
+	 * may or may not be reflected in the enable clock register).
+	 * To change the rate we must disable the clock first to cover these
+	 * cases. Due to common clock framework restrictions that do not allow
+	 * to disable a clock that has not been enabled, we need to enable
+	 * the clock first.
+	 */
+	ret = clk_prepare_enable(priv->mclk);
+	if (!ret)
+		clk_disable_unprepare(priv->mclk);
+
+	ret = clk_set_rate(priv->mclk, MCLK_FREQ);
+	if (ret) {
+		dev_err(card->dev, "Error setting MCLK rate: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_pcm_stream byt_wm5102_dai_params = {
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+				  struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+						      SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+							  SNDRV_PCM_HW_PARAM_CHANNELS);
+	int ret;
+
+	/* The DSP will covert the FE rate to 48k, stereo */
+	rate->min = 48000;
+	rate->max = 48000;
+	channels->min = 2;
+	channels->max = 2;
+
+	/* set SSP0 to 16-bit */
+	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+	/*
+	 * Default mode for SSP configuration is TDM 4 slot, override config
+	 * with explicit setting to I2S 2ch 16-bit. The word length is set with
+	 * dai_set_tdm_slot() since there is no other API exposed
+	 */
+	ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+				  SND_SOC_DAIFMT_I2S     |
+				  SND_SOC_DAIFMT_NB_NF   |
+				  SND_SOC_DAIFMT_CBS_CFS);
+	if (ret) {
+		dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
+	if (ret) {
+		dev_err(rtd->dev, "Error setting I2S config: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int byt_wm5102_aif1_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_single(substream->runtime,
+					    SNDRV_PCM_HW_PARAM_RATE, 48000);
+}
+
+static const struct snd_soc_ops byt_wm5102_aif1_ops = {
+	.startup = byt_wm5102_aif1_startup,
+};
+
+SND_SOC_DAILINK_DEF(dummy,
+	DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+SND_SOC_DAILINK_DEF(media,
+	DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
+
+SND_SOC_DAILINK_DEF(deepbuffer,
+	DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
+
+SND_SOC_DAILINK_DEF(ssp0_port,
+	DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
+SND_SOC_DAILINK_DEF(ssp0_codec,
+	DAILINK_COMP_ARRAY(COMP_CODEC(
+	/*
+	 * Note there is no need to overwrite the codec-name as is done in
+	 * other bytcr machine drivers, because the codec is a MFD child-dev.
+	 */
+	"wm5102-codec",
+	"wm5102-aif1")));
+
+SND_SOC_DAILINK_DEF(platform,
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
+
+static struct snd_soc_dai_link byt_wm5102_dais[] = {
+	[MERR_DPCM_AUDIO] = {
+		.name = "Baytrail Audio Port",
+		.stream_name = "Baytrail Audio",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ops = &byt_wm5102_aif1_ops,
+		SND_SOC_DAILINK_REG(media, dummy, platform),
+
+	},
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &byt_wm5102_aif1_ops,
+		SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
+	},
+		/* back ends */
+	{
+		/*
+		 * This must be named SSP2-Codec even though this machine driver
+		 * always uses SSP0. Most machine drivers support both and dynamically
+		 * update the dailink to point to SSP0 or SSP2, while keeping the name
+		 * as "SSP2-Codec". The SOF tplg files hardcode the "SSP2-Codec" even
+		 * in the byt-foo-ssp0.tplg versions because the other machine-drivers
+		 * use "SSP2-Codec" even when SSP0 is used.
+		 */
+		.name = "SSP2-Codec",
+		.id = 0,
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+						| SND_SOC_DAIFMT_CBS_CFS,
+		.be_hw_params_fixup = byt_wm5102_codec_fixup,
+		.nonatomic = true,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.init = byt_wm5102_init,
+		SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform),
+	},
+};
+
+/* use space before codec name to simplify card ID, and simplify driver name */
+#define SOF_CARD_NAME "bytcht wm5102" /* card name will be 'sof-bytcht wm5102' */
+#define SOF_DRIVER_NAME "SOF"
+
+#define CARD_NAME "bytcr-wm5102"
+#define DRIVER_NAME NULL /* card name will be used for driver name */
+
+/* SoC card */
+static struct snd_soc_card byt_wm5102_card = {
+	.owner = THIS_MODULE,
+	.dai_link = byt_wm5102_dais,
+	.num_links = ARRAY_SIZE(byt_wm5102_dais),
+	.dapm_widgets = byt_wm5102_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(byt_wm5102_widgets),
+	.dapm_routes = byt_wm5102_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(byt_wm5102_audio_map),
+	.fully_routed = true,
+};
+
+static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
+{
+	char codec_name[SND_ACPI_I2C_ID_LEN];
+	struct device *dev = &pdev->dev;
+	struct byt_wm5102_private *priv;
+	struct snd_soc_acpi_mach *mach;
+	const char *platform_name;
+	struct acpi_device *adev;
+	struct device *codec_dev;
+	bool sof_parent;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_ATOMIC);
+	if (!priv)
+		return -ENOMEM;
+
+	/* Get MCLK */
+	priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3");
+	if (IS_ERR(priv->mclk))
+		return dev_err_probe(dev, PTR_ERR(priv->mclk), "getting pmc_plt_clk_3\n");
+
+	/*
+	 * Get speaker VDD enable GPIO:
+	 * 1. Get codec-device-name
+	 * 2. Get codec-device
+	 * 3. Get GPIO from codec-device
+	 */
+	mach = dev->platform_data;
+	adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
+	if (!adev) {
+		dev_err(dev, "Error cannot find acpi-dev for codec\n");
+		return -ENOENT;
+	}
+	snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev));
+	put_device(&adev->dev);
+
+	codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name);
+	if (!codec_dev)
+		return -EPROBE_DEFER;
+
+	/* Note no devm_ here since we call gpiod_get on codec_dev rather then dev */
+	priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW);
+	put_device(codec_dev);
+
+	if (IS_ERR(priv->spkvdd_en_gpio))
+		return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n");
+
+	/* override platform name, if required */
+	byt_wm5102_card.dev = dev;
+	platform_name = mach->mach_params.platform;
+	ret = snd_soc_fixup_dai_links_platform_name(&byt_wm5102_card, platform_name);
+	if (ret)
+		goto out_put_gpio;
+
+	/* set card and driver name and pm-ops */
+	sof_parent = snd_soc_acpi_sof_parent(dev);
+	if (sof_parent) {
+		byt_wm5102_card.name = SOF_CARD_NAME;
+		byt_wm5102_card.driver_name = SOF_DRIVER_NAME;
+		dev->driver->pm = &snd_soc_pm_ops;
+	} else {
+		byt_wm5102_card.name = CARD_NAME;
+		byt_wm5102_card.driver_name = DRIVER_NAME;
+	}
+
+	snd_soc_card_set_drvdata(&byt_wm5102_card, priv);
+	ret = devm_snd_soc_register_card(dev, &byt_wm5102_card);
+	if (ret) {
+		dev_err_probe(dev, ret, "registering card\n");
+		goto out_put_gpio;
+	}
+
+	platform_set_drvdata(pdev, &byt_wm5102_card);
+	return 0;
+
+out_put_gpio:
+	gpiod_put(priv->spkvdd_en_gpio);
+	return ret;
+}
+
+static int snd_byt_wm5102_mc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
+
+	gpiod_put(priv->spkvdd_en_gpio);
+	return 0;
+}
+
+static struct platform_driver snd_byt_wm5102_mc_driver = {
+	.driver = {
+		.name = "bytcr_wm5102",
+	},
+	.probe = snd_byt_wm5102_mc_probe,
+	.remove = snd_byt_wm5102_mc_remove,
+};
+
+module_platform_driver(snd_byt_wm5102_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Baytrail with WM5102 codec machine driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcr_wm5102");
diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c
index fd5e25ca05f7f1f0582315d5391c5f73b287622f..da5a5cbc875908e28014b930d957b38268181fb1 100644
--- a/sound/soc/intel/boards/cht_bsw_nau8824.c
+++ b/sound/soc/intel/boards/cht_bsw_nau8824.c
@@ -100,13 +100,6 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 	struct snd_soc_component *component = codec_dai->component;
 	int ret, jack_type;
 
-	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
-	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xf, 0x1, 4, 24);
-	if (ret < 0) {
-		dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
-		return ret;
-	}
-
 	/* NAU88L24 supports 4 butons headset detection
 	 * KEY_PLAYPAUSE
 	 * KEY_VOICECOMMAND
@@ -141,6 +134,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 		SNDRV_PCM_HW_PARAM_CHANNELS);
 	struct snd_mask *fmt =
 		hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+	int ret;
 
 	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
 	rate->min = rate->max = 48000;
@@ -150,6 +144,13 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 	snd_mask_none(fmt);
 	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
 
+	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+	ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c
index c2a9757181fe16195d02fc53850e532fcb0a1173..437d205627539734a8c92f87515836da25446de9 100644
--- a/sound/soc/intel/boards/sof_maxim_common.c
+++ b/sound/soc/intel/boards/sof_maxim_common.c
@@ -63,6 +63,7 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_dai *codec_dai;
+	struct snd_soc_dai *cpu_dai;
 	int j;
 	int ret = 0;
 
@@ -70,10 +71,10 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd)
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		return 0;
 
+	cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
-		struct snd_soc_component *component = codec_dai->component;
 		struct snd_soc_dapm_context *dapm =
-				snd_soc_component_get_dapm(component);
+				snd_soc_component_get_dapm(cpu_dai->component);
 		char pin_name[MAX_98373_PIN_NAME];
 
 		snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 8b1ca2da9bb9e2091b3a40a5e560ed00481ddc73..55505e207bc009e4c62053d4abe0ad3124af990a 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -323,13 +323,6 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream,
 		fs = 64;
 
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
-		/* Set tdm/i2s1 master bclk ratio */
-		ret = snd_soc_dai_set_bclk_ratio(codec_dai, fs);
-		if (ret < 0) {
-			dev_err(card->dev, "failed to set bclk ratio\n");
-			return ret;
-		}
-
 		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
 					  params_rate(params) * fs,
 					  params_rate(params) * 256);
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 6d0d6ef711e0f3129019829d1f35e9e7348e69af..8adce6417b0213b9ed3784221bc6f397bb71e589 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -48,34 +48,14 @@ static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
 }
 
 static const struct dmi_system_id sof_sdw_quirk_table[] = {
+	/* CometLake devices */
 	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
-		},
-		.driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
-					SOF_RT715_DAI_ID_FIX |
-					SOF_SDW_FOUR_SPK),
-	},
-	{
-		.callback = sof_sdw_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
-		},
-		.driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
-					SOF_RT715_DAI_ID_FIX),
-	},
-	{
-		.callback = sof_sdw_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
 		},
-		.driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
-					SOF_RT715_DAI_ID_FIX |
-					SOF_SDW_FOUR_SPK),
+		.driver_data = (void *)SOF_SDW_PCH_DMIC,
 	},
 	{
 		.callback = sof_sdw_quirk_cb,
@@ -106,7 +86,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 					SOF_RT715_DAI_ID_FIX |
 					SOF_SDW_FOUR_SPK),
 	},
-		{
+	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
@@ -116,6 +96,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 					SOF_RT715_DAI_ID_FIX |
 					SOF_SDW_FOUR_SPK),
 	},
+	/* IceLake devices */
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+		},
+		.driver_data = (void *)SOF_SDW_PCH_DMIC,
+	},
+	/* TigerLake devices */
 	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
@@ -123,25 +113,31 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME,
 				  "Tiger Lake Client Platform"),
 		},
-		.driver_data = (void *)(SOF_RT711_JD_SRC_JD1 |
-				SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
-				SOF_SSP_PORT(SOF_I2S_SSP2)),
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_RT711_JD_SRC_JD1 |
+					SOF_SDW_PCH_DMIC |
+					SOF_SSP_PORT(SOF_I2S_SSP2)),
 	},
 	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
 		},
-		.driver_data = (void *)SOF_SDW_PCH_DMIC,
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_RT711_JD_SRC_JD2 |
+					SOF_RT715_DAI_ID_FIX),
 	},
 	{
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
 		},
-		.driver_data = (void *)SOF_SDW_PCH_DMIC,
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_RT711_JD_SRC_JD2 |
+					SOF_RT715_DAI_ID_FIX |
+					SOF_SDW_FOUR_SPK),
 	},
 	{
 		.callback = sof_sdw_quirk_cb,
@@ -149,7 +145,8 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
 		},
-		.driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_SDW_PCH_DMIC |
 					SOF_SDW_FOUR_SPK),
 	},
 	{
@@ -158,10 +155,38 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
 		},
-		.driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_SDW_PCH_DMIC |
+					SOF_SDW_FOUR_SPK),
+	},
+	{
+		/*
+		 * this entry covers multiple HP SKUs. The family name
+		 * does not seem robust enough, so we use a partial
+		 * match that ignores the product name suffix
+		 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
+		 */
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"),
+		},
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_SDW_PCH_DMIC |
+					SOF_RT711_JD_SRC_JD2),
+	},
+	/* TigerLake-SDCA devices */
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
+		},
+		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
+					SOF_RT711_JD_SRC_JD2 |
+					SOF_RT715_DAI_ID_FIX |
 					SOF_SDW_FOUR_SPK),
 	},
-
 	{}
 };
 
@@ -451,15 +476,14 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links,
 	return 0;
 }
 
-static void init_dai_link(struct snd_soc_dai_link *dai_links, int be_id,
-			  char *name, int playback, int capture,
-			  struct snd_soc_dai_link_component *cpus,
-			  int cpus_num,
-			  struct snd_soc_dai_link_component *codecs,
-			  int codecs_num,
+static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
+			  int be_id, char *name, int playback, int capture,
+			  struct snd_soc_dai_link_component *cpus, int cpus_num,
+			  struct snd_soc_dai_link_component *codecs, int codecs_num,
 			  int (*init)(struct snd_soc_pcm_runtime *rtd),
 			  const struct snd_soc_ops *ops)
 {
+	dev_dbg(dev, "create dai link %s, id %d\n", name, be_id);
 	dai_links->id = be_id;
 	dai_links->name = name;
 	dai_links->platforms = platform_component;
@@ -797,7 +821,7 @@ static int create_sdw_dailink(struct device *dev, int *be_index,
 
 		playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
 		capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
-		init_dai_link(dai_links + *be_index, *be_index, name,
+		init_dai_link(dev, dai_links + *be_index, *be_index, name,
 			      playback, capture,
 			      cpus + *cpu_id, cpu_dai_num,
 			      codecs, codec_num,
@@ -930,7 +954,7 @@ static int sof_card_dai_links_create(struct device *dev,
 		ctx->idisp_codec = true;
 
 	/* enable dmic01 & dmic16k */
-	dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC) ? 2 : 0;
+	dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
 	comp_num += dmic_num;
 
 	dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
@@ -1036,7 +1060,7 @@ static int sof_card_dai_links_create(struct device *dev,
 
 		playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
 		capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
-		init_dai_link(links + link_id, be_id, name,
+		init_dai_link(dev, links + link_id, be_id, name,
 			      playback, capture,
 			      cpus + cpu_id, 1,
 			      ssp_components, 1,
@@ -1053,7 +1077,7 @@ static int sof_card_dai_links_create(struct device *dev,
 	/* dmic */
 	if (dmic_num > 0) {
 		cpus[cpu_id].dai_name = "DMIC01 Pin";
-		init_dai_link(links + link_id, be_id, "dmic01",
+		init_dai_link(dev, links + link_id, be_id, "dmic01",
 			      0, 1, // DMIC only supports capture
 			      cpus + cpu_id, 1,
 			      dmic_component, 1,
@@ -1061,7 +1085,7 @@ static int sof_card_dai_links_create(struct device *dev,
 		INC_ID(be_id, cpu_id, link_id);
 
 		cpus[cpu_id].dai_name = "DMIC16k Pin";
-		init_dai_link(links + link_id, be_id, "dmic16k",
+		init_dai_link(dev, links + link_id, be_id, "dmic16k",
 			      0, 1, // DMIC only supports capture
 			      cpus + cpu_id, 1,
 			      dmic_component, 1,
@@ -1104,7 +1128,7 @@ static int sof_card_dai_links_create(struct device *dev,
 			return -ENOMEM;
 
 		cpus[cpu_id].dai_name = cpu_name;
-		init_dai_link(links + link_id, be_id, name,
+		init_dai_link(dev, links + link_id, be_id, name,
 			      1, 0, // HDMI only supports playback
 			      cpus + cpu_id, 1,
 			      idisp_components + i, 1,
@@ -1197,6 +1221,15 @@ static int mc_probe(struct platform_device *pdev)
 	if (!card->components)
 		return -ENOMEM;
 
+	if (mach->mach_params.dmic_num) {
+		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+						  "%s mic:dmic cfg-mics:%d",
+						  card->components,
+						  mach->mach_params.dmic_num);
+		if (!card->components)
+			return -ENOMEM;
+	}
+
 	card->long_name = sdw_card_long_name;
 
 	/* Register the card */
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index e5d54bb1c42acce16de57f4313d0ee338088f929..ebb27daeb1c7760ad44a6bccbae5dc3643d99290 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -331,7 +331,7 @@ static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
 {
 	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
 	struct snd_soc_component *component = dai->component;
-	struct snd_kcontrol *pos, *kctl = NULL;
+	struct snd_kcontrol *pos;
 	const char *name;
 	int ret;
 	u32 id = stream->info.stream_hw_id;
@@ -352,21 +352,19 @@ static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
 		break;
 	default:
 		return 0;
-	};
+	}
 
 	list_for_each_entry(pos, &component->card->snd_card->controls, list) {
 		if (pos->private_data == component &&
-		    !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
-			kctl = pos;
+		    !strncmp(name, pos->id.name, sizeof(pos->id.name)))
 			break;
-		}
 	}
-	if (!kctl)
+	if (list_entry_is_head(pos, &component->card->snd_card->controls, list))
 		return -ENOENT;
 
 	if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
-		return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
-	ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
+		return catpt_set_dspvol(cdev, id, (long *)pos->private_value);
+	ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)pos->private_value);
 	if (ret)
 		return CATPT_IPC_ERROR(ret);
 	return 0;
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index 06b233d63b73aafa8e5bb509c0593a3ecae406eb..0aca340ebc258447907a55a4a0a08c7cdb58d6a1 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -44,7 +44,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
 		.link_mask = 0x1, /* link0 required */
 		.links = adl_rvp,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-adl.ri",
 		.sof_tplg_filename = "sof-adl-rt711.tplg",
 	},
 	{},
diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
index 32f77e29c2ff5b36306f29ce55b7f8a63533fbc5..398cc771c8351a13fac583eac70f985c433cd632 100644
--- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
@@ -85,6 +85,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_bxt_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
index c348607b49a5989a13d462b9c06567e79dd7448a..d1febbb53b706201d35d79eb0bbaa45c16988363 100644
--- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
@@ -154,6 +154,22 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
 		.sof_fw_filename = "sof-byt.ri",
 		.sof_tplg_filename = "sof-byt-rt5651.tplg",
 	},
+	{
+		.id = "WM510204",
+		.drv_name = "bytcr_wm5102",
+		.fw_filename = "intel/fw_sst_0f28.bin",
+		.board = "bytcr_wm5102",
+		.sof_fw_filename = "sof-byt.ri",
+		.sof_tplg_filename = "sof-byt-wm5102.tplg",
+	},
+	{
+		.id = "WM510205",
+		.drv_name = "bytcr_wm5102",
+		.fw_filename = "intel/fw_sst_0f28.bin",
+		.board = "bytcr_wm5102",
+		.sof_fw_filename = "sof-byt.ri",
+		.sof_tplg_filename = "sof-byt-wm5102.tplg",
+	},
 	{
 		.id = "DLGS7212",
 		.drv_name = "bytcht_da7213",
@@ -233,6 +249,3 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_baytrail_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c
index 27b4b73d94d48c99781e22872cfeef89aebb6d32..1733dfb23e797ec682905f1784ecd8560b0e81aa 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c
@@ -18,6 +18,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[] = {
 	{}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
index 2752dc9557334eb84345c82988549f2e2b077fa5..227424236fd577b031fb86d8d4d2409d0d20f0fa 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -196,6 +196,3 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cherrytrail_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
index adddc91918dfeb1e9c53e7fd7df0878157ba1dac..2161b3b85b4a117ae5143fa166d25ab1e8fa6de5 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -309,6 +309,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = {
 	{}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
index b80f032a8b76dd9cf4148d551d575f7ae006b57f..ec77a57a07ba0249cb1b540a5bbc1f02f52c41e9 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
@@ -63,6 +63,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[] = {
 	{}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
index badafc1d54d20f49aa3fdc52909d65cc53e20dd0..6222708a98e70d1645d44a99bc937ace618db710 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-ehl-match.c - tables and support for EHL ACPI enumeration.
+ * soc-acpi-intel-ehl-match.c - tables and support for EHL ACPI enumeration.
  *
  * Copyright (c) 2019, Intel Corporation.
  *
@@ -20,6 +20,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ehl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
index 26cb3b16cdd34fa0be479633b64cece931290c6d..6ceaab19ccb6388def37cca7c1ba189581152ecd 100644
--- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
@@ -43,6 +43,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
index 35958553652ec533cd199fec8f8c6286c90ba16b..fe343a95b5ff71e40cea67d99d702520ae8a13e8 100644
--- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
@@ -53,6 +53,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
 	{}
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_broadwell_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
index 9a529a785288568a15bcc672de8e4cdd4e59b915..d38ff7d187c4daf41a97698c8dcad27273b3685c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -185,6 +185,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
index 34f5fcad5701f841f0e7e10a4c5a2e287aa8cbe6..52238db0bcb53b1446126cd900a31ee41df3ac1c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -63,6 +63,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
index a4fbe6707ca76ce265fe15fc294ded8657e5fa6d..47dadc9d5d2a081d12bb97d24adf2c697d8727ec 100644
--- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
@@ -128,6 +128,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
index 26f9ce146523027a5bc026f1fe1c63c91735ec13..961df8d6b5e40cf921e64372985487e2219f2a4f 100644
--- a/sound/soc/intel/common/soc-acpi-intel-skl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
@@ -42,6 +42,3 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = {
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_skl_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
index 98196e9fad62fc664e6b6463eb169c88187db0d3..40f31c8a3aba00b793c6260979bf4d13f5ec00f1 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-tgl-match.c - tables and support for ICL ACPI enumeration.
+ * soc-acpi-intel-tgl-match.c - tables and support for TGL ACPI enumeration.
  *
  * Copyright (c) 2019, Intel Corporation.
  *
@@ -205,6 +205,20 @@ static const struct snd_soc_acpi_link_adr tgl_rvp[] = {
 	{}
 };
 
+static const struct snd_soc_acpi_link_adr tgl_hp[] = {
+	{
+		.mask = BIT(0),
+		.num_adr = ARRAY_SIZE(rt711_0_adr),
+		.adr_d = rt711_0_adr,
+	},
+	{
+		.mask = BIT(1),
+		.num_adr = ARRAY_SIZE(rt1308_1_single_adr),
+		.adr_d = rt1308_1_single_adr,
+	},
+	{}
+};
+
 static const struct snd_soc_acpi_link_adr tgl_chromebook_base[] = {
 	{
 		.mask = BIT(0),
@@ -358,14 +372,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
 		.link_mask = 0x7,
 		.links = tgl_sdw_rt711_link1_rt1308_link2_rt715_link0,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg",
 	},
 	{
 		.link_mask = 0xF, /* 4 active links required */
 		.links = tgl_3_in_1_default,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg",
 	},
 	{
@@ -377,40 +389,38 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
 		.link_mask = 0xF,
 		.links = tgl_3_in_1_mono_amp,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg",
 	},
 	{
 		.link_mask = 0xF, /* 4 active links required */
 		.links = tgl_3_in_1_sdca,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-rt711-rt1316-rt714.tplg",
 	},
+	{
+		.link_mask = 0x3, /* rt711 on link 0 and 1 rt1308 on link 1 */
+		.links = tgl_hp,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg",
+	},
 	{
 		.link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */
 		.links = tgl_rvp,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg",
 	},
 	{
 		.link_mask = 0x3, /* rt5682 on link0 & 2xmax98373 on link 1 */
 		.links = tgl_chromebook_base,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-sdw-max98373-rt5682.tplg",
 	},
 	{
 		.link_mask = 0x1, /* this will only enable rt5682 for now */
 		.links = tgl_chromebook_base,
 		.drv_name = "sof_sdw",
-		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-rt5682.tplg",
 	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h
index b07df3059926d97960ed25ac9bf3d072876af02b..a93987ab7f4d7a1e014d816d2d4592c9483cb641 100644
--- a/sound/soc/intel/common/soc-intel-quirks.h
+++ b/sound/soc/intel/common/soc-intel-quirks.h
@@ -11,6 +11,7 @@
 
 #if IS_ENABLED(CONFIG_X86)
 
+#include <linux/dmi.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/iosf_mbi.h>
@@ -38,12 +39,36 @@ SOC_INTEL_IS_CPU(cml, KABYLAKE_L);
 
 static inline bool soc_intel_is_byt_cr(struct platform_device *pdev)
 {
+	/*
+	 * List of systems which:
+	 * 1. Use a non CR version of the Bay Trail SoC
+	 * 2. Contain at least 6 interrupt resources so that the
+	 *    platform_get_resource(pdev, IORESOURCE_IRQ, 5) check below
+	 *    succeeds
+	 * 3. Despite 1. and 2. still have their IPC IRQ at index 0 rather then 5
+	 *
+	 * This needs to be here so that it can be shared between the SST and
+	 * SOF drivers. We rely on the compiler to optimize this out in files
+	 * where soc_intel_is_byt_cr is not used.
+	 */
+	static const struct dmi_system_id force_bytcr_table[] = {
+		{	/* Lenovo Yoga Tablet 2 series */
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+				DMI_MATCH(DMI_PRODUCT_FAMILY, "YOGATablet2"),
+			},
+		},
+		{}
+	};
 	struct device *dev = &pdev->dev;
 	int status = 0;
 
 	if (!soc_intel_is_byt())
 		return false;
 
+	if (dmi_check_system(force_bytcr_table))
+		return true;
+
 	if (iosf_mbi_available()) {
 		u32 bios_status;
 
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index 1c3748f33136ec5848b69ef422daa810855ef159..0fd1e8f62c89f1e4e668a82645cea35f9af416e2 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -5,11 +5,14 @@
 // Intel KeemBay Platform driver.
 //
 
+#include <linux/bitrev.h>
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -37,7 +40,8 @@ static const struct snd_pcm_hardware kmb_pcm_hardware = {
 	.rate_max = 48000,
 	.formats = SNDRV_PCM_FMTBIT_S16_LE |
 		   SNDRV_PCM_FMTBIT_S24_LE |
-		   SNDRV_PCM_FMTBIT_S32_LE,
+		   SNDRV_PCM_FMTBIT_S32_LE |
+		   SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
 	.channels_min = 2,
 	.channels_max = 2,
 	.buffer_bytes_max = BUFFER_BYTES_MAX,
@@ -48,6 +52,50 @@ static const struct snd_pcm_hardware kmb_pcm_hardware = {
 	.fifo_size = 16,
 };
 
+/*
+ * Convert to ADV7511 HDMI hardware format.
+ * ADV7511 HDMI chip need parity bit replaced by block start bit and
+ * with the preamble bits left out.
+ * ALSA IEC958 subframe format:
+ * bit 0-3  = preamble (0x8 = block start)
+ *     4-7  = AUX (=0)
+ *     8-27 = audio data (without AUX if 24bit sample)
+ *     28   = validity
+ *     29   = user data
+ *     30   = channel status
+ *     31   = parity
+ *
+ * ADV7511 IEC958 subframe format:
+ * bit 0-23  = audio data
+ *     24    = validity
+ *     25    = user data
+ *     26    = channel status
+ *     27    = block start
+ *     28-31 = 0
+ * MSB to LSB bit reverse by software as hardware not supporting it.
+ */
+static void hdmi_reformat_iec958(struct snd_pcm_runtime *runtime,
+				 struct kmb_i2s_info *kmb_i2s,
+				 unsigned int tx_ptr)
+{
+	u32(*buf)[2] = (void *)runtime->dma_area;
+	unsigned long temp;
+	u32 i, j, sample;
+
+	for (i = 0; i < kmb_i2s->fifo_th; i++) {
+		j = 0;
+		do {
+			temp = buf[tx_ptr][j];
+			/* Replace parity with block start*/
+			assign_bit(31, &temp, (BIT(3) & temp));
+			sample = bitrev32(temp);
+			buf[tx_ptr][j] = sample << 4;
+			j++;
+		} while (j < 2);
+		tx_ptr++;
+	}
+}
+
 static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
 				  struct snd_pcm_runtime *runtime,
 				  unsigned int tx_ptr, bool *period_elapsed)
@@ -63,6 +111,8 @@ static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
 			writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
 			writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
 		} else {
+			if (kmb_i2s->iec958_fmt)
+				hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr);
 			writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
 			writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
 		}
@@ -233,6 +283,7 @@ static int kmb_pcm_trigger(struct snd_soc_component *component,
 			kmb_i2s->tx_substream = NULL;
 		else
 			kmb_i2s->rx_substream = NULL;
+		kmb_i2s->iec958_fmt = false;
 		break;
 	default:
 		return -EINVAL;
@@ -343,6 +394,53 @@ static const struct snd_soc_component_driver kmb_component = {
 	.pointer	= kmb_pcm_pointer,
 };
 
+static const struct snd_soc_component_driver kmb_component_dma = {
+	.name		= "kmb",
+};
+
+static int kmb_probe(struct snd_soc_dai *cpu_dai)
+{
+	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+
+	if (kmb_i2s->use_pio)
+		return 0;
+
+	snd_soc_dai_init_dma_data(cpu_dai, &kmb_i2s->play_dma_data,
+				  &kmb_i2s->capture_dma_data);
+
+	return 0;
+}
+
+static inline void kmb_i2s_enable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
+{
+	u32 dma_reg;
+
+	dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
+	/* Enable DMA handshake for stream */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_reg |= I2S_DMAEN_TXBLOCK;
+	else
+		dma_reg |= I2S_DMAEN_RXBLOCK;
+
+	writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
+}
+
+static inline void kmb_i2s_disable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
+{
+	u32 dma_reg;
+
+	dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
+	/* Disable DMA handshake for stream */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dma_reg &= ~I2S_DMAEN_TXBLOCK;
+		writel(1, kmb_i2s->i2s_base + I2S_RTXDMA);
+	} else {
+		dma_reg &= ~I2S_DMAEN_RXBLOCK;
+		writel(1, kmb_i2s->i2s_base + I2S_RRXDMA);
+	}
+	writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
+}
+
 static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
 			  struct snd_pcm_substream *substream)
 {
@@ -356,7 +454,11 @@ static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
 	else
 		writel(1, kmb_i2s->i2s_base + IRER);
 
-	kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true);
+	if (kmb_i2s->use_pio)
+		kmb_i2s_irq_trigger(kmb_i2s, substream->stream,
+				    config->chan_nr, true);
+	else
+		kmb_i2s_enable_dma(kmb_i2s, substream->stream);
 
 	if (kmb_i2s->clock_provider)
 		writel(1, kmb_i2s->i2s_base + CER);
@@ -434,7 +536,8 @@ static int kmb_dai_trigger(struct snd_pcm_substream *substream,
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		kmb_i2s->active--;
-		kmb_i2s_stop(kmb_i2s, substream);
+		if (kmb_i2s->use_pio)
+			kmb_i2s_stop(kmb_i2s, substream);
 		break;
 	default:
 		return  -EINVAL;
@@ -485,16 +588,25 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
 		config->data_width = 16;
 		kmb_i2s->ccr = 0x00;
 		kmb_i2s->xfer_resolution = 0x02;
+		kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 		config->data_width = 32;
 		kmb_i2s->ccr = 0x14;
 		kmb_i2s->xfer_resolution = 0x05;
+		kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 		break;
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		kmb_i2s->iec958_fmt = true;
+		fallthrough;
 	case SNDRV_PCM_FORMAT_S32_LE:
 		config->data_width = 32;
 		kmb_i2s->ccr = 0x10;
 		kmb_i2s->xfer_resolution = 0x05;
+		kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 		break;
 	default:
 		dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt");
@@ -572,13 +684,78 @@ static int kmb_dai_prepare(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static int kmb_dai_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+	struct snd_dmaengine_dai_dma_data *dma_data;
+
+	if (kmb_i2s->use_pio)
+		return 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &kmb_i2s->play_dma_data;
+	else
+		dma_data = &kmb_i2s->capture_dma_data;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+	return 0;
+}
+
+static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+	/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
+	if (kmb_i2s->use_pio)
+		kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		writel(0, kmb_i2s->i2s_base + ITER);
+	else
+		writel(0, kmb_i2s->i2s_base + IRER);
+
+	if (kmb_i2s->use_pio)
+		kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
+	else
+		kmb_i2s_disable_dma(kmb_i2s, substream->stream);
+
+	if (!kmb_i2s->active) {
+		writel(0, kmb_i2s->i2s_base + CER);
+		writel(0, kmb_i2s->i2s_base + IER);
+	}
+
+	return 0;
+}
+
 static struct snd_soc_dai_ops kmb_dai_ops = {
+	.startup	= kmb_dai_startup,
 	.trigger	= kmb_dai_trigger,
 	.hw_params	= kmb_dai_hw_params,
+	.hw_free	= kmb_dai_hw_free,
 	.prepare	= kmb_dai_prepare,
 	.set_fmt	= kmb_set_dai_fmt,
 };
 
+static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
+	{
+		.name = "intel_kmb_hdmi_i2s",
+		.playback = {
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min = 48000,
+			.rate_max = 48000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
+		},
+		.ops = &kmb_dai_ops,
+		.probe = kmb_probe,
+	},
+};
+
 static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
 	{
 		.name = "intel_kmb_i2s",
@@ -607,6 +784,7 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
 				    SNDRV_PCM_FMTBIT_S16_LE),
 		},
 		.ops = &kmb_dai_ops,
+		.probe = kmb_probe,
 	},
 };
 
@@ -626,21 +804,25 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
 				    SNDRV_PCM_FMTBIT_S16_LE),
 		},
 		.ops = &kmb_dai_ops,
+		.probe = kmb_probe,
 	},
 };
 
 static const struct of_device_id kmb_plat_of_match[] = {
 	{ .compatible = "intel,keembay-i2s", .data = &intel_kmb_i2s_dai},
+	{ .compatible = "intel,keembay-hdmi-i2s", .data = &intel_kmb_hdmi_dai},
 	{ .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai},
 	{}
 };
 
 static int kmb_plat_dai_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_dai_driver *kmb_i2s_dai;
 	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
 	struct kmb_i2s_info *kmb_i2s;
+	struct resource *res;
 	int ret, irq;
 	u32 comp1_reg;
 
@@ -682,7 +864,7 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
 		return PTR_ERR(kmb_i2s->clk_i2s);
 	}
 
-	kmb_i2s->i2s_base = devm_platform_ioremap_resource(pdev, 0);
+	kmb_i2s->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 	if (IS_ERR(kmb_i2s->i2s_base))
 		return PTR_ERR(kmb_i2s->i2s_base);
 
@@ -692,22 +874,38 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
 
 	kmb_i2s->dev = &pdev->dev;
 
-	irq = platform_get_irq_optional(pdev, 0);
-	if (irq > 0) {
-		ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
-				       pdev->name, kmb_i2s);
-		if (ret < 0) {
-			dev_err(dev, "failed to request irq\n");
-			return ret;
-		}
-	}
-
 	comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1);
 
 	kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2;
 
-	ret = devm_snd_soc_register_component(dev, &kmb_component,
-					      kmb_i2s_dai, 1);
+	kmb_i2s->use_pio = !(of_property_read_bool(np, "dmas"));
+
+	if (kmb_i2s->use_pio) {
+		irq = platform_get_irq_optional(pdev, 0);
+		if (irq > 0) {
+			ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
+					       pdev->name, kmb_i2s);
+			if (ret < 0) {
+				dev_err(dev, "failed to request irq\n");
+				return ret;
+			}
+		}
+		ret = devm_snd_soc_register_component(dev, &kmb_component,
+						      kmb_i2s_dai, 1);
+	} else {
+		kmb_i2s->play_dma_data.addr = res->start + I2S_TXDMA;
+		kmb_i2s->capture_dma_data.addr = res->start + I2S_RXDMA;
+		ret = snd_dmaengine_pcm_register(&pdev->dev,
+						 NULL, 0);
+		if (ret) {
+			dev_err(&pdev->dev, "could not register dmaengine: %d\n",
+				ret);
+			return ret;
+		}
+		ret = devm_snd_soc_register_component(dev, &kmb_component_dma,
+						      kmb_i2s_dai, 1);
+	}
+
 	if (ret) {
 		dev_err(dev, "not able to register dai\n");
 		return ret;
diff --git a/sound/soc/intel/keembay/kmb_platform.h b/sound/soc/intel/keembay/kmb_platform.h
index 0c393e5916b6d06ed8502d065525c044a02ccc45..29be2cd84ddb3577071f897e19d23f1ce0b37f70 100644
--- a/sound/soc/intel/keembay/kmb_platform.h
+++ b/sound/soc/intel/keembay/kmb_platform.h
@@ -12,6 +12,7 @@
 #include <linux/bits.h>
 #include <linux/bitfield.h>
 #include <linux/types.h>
+#include <sound/dmaengine_pcm.h>
 
 /* Register values with reference to KMB databook v1.1 */
 /* common register for all channel */
@@ -103,7 +104,12 @@
 #define DW_I2S_PROVIDER	BIT(3)
 
 #define I2S_RXDMA	0x01C0
+#define I2S_RRXDMA	0x01C4
 #define I2S_TXDMA	0x01C8
+#define I2S_RTXDMA	0x01CC
+#define I2S_DMACR	0x0200
+#define I2S_DMAEN_RXBLOCK	(1 << 16)
+#define I2S_DMAEN_TXBLOCK	(1 << 17)
 
 /*
  * struct i2s_clk_config_data - represent i2s clk configuration data
@@ -131,6 +137,9 @@ struct kmb_i2s_info {
 	u32 xfer_resolution;
 	u32 fifo_th;
 	bool clock_provider;
+	/* data related to DMA transfers b/w i2s and DMAC */
+	struct snd_dmaengine_dai_dma_data play_dma_data;
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
 
 	struct i2s_clk_config_data config;
 	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
@@ -141,6 +150,7 @@ struct kmb_i2s_info {
 	struct snd_pcm_substream *rx_substream;
 	unsigned int tx_ptr;
 	unsigned int rx_ptr;
+	bool iec958_fmt;
 };
 
 #endif /* KMB_PLATFORM_H_ */
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 8b993722f74e7bda319df3a315f49b689bbe1693..5b1a15e3991232cee7f59e64b58886e2ea42054f 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -950,12 +950,8 @@ static int skl_first_init(struct hdac_bus *bus)
 	bus->num_streams = cp_streams + pb_streams;
 
 	/* allow 64bit DMA address if supported by H/W */
-	if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
-		dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
-	} else {
-		dma_set_mask(bus->dev, DMA_BIT_MASK(32));
-		dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
-	}
+	if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64)))
+		dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32));
 
 	/* initialize streams */
 	snd_hdac_ext_stream_init_all
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 0a68f4c3d15a3d9a3cc9d0b43e6db0fba54c856b..52ba0e3a9e954c100d028096f8d24ea49dd02183 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -455,7 +455,7 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
 		.rates = SNDRV_PCM_RATE_8000_48000,
 		.formats = JZ4740_I2S_FMTS,
 	},
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 	.ops = &jz4740_i2s_dai_ops,
 };
 
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index e037826b24517c62facec338533783530b9e4434..c2a5933bfcfc1ad0d2795a6b00d041b272d414f0 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -182,25 +182,6 @@ static int kirkwood_dma_close(struct snd_soc_component *component,
 	return 0;
 }
 
-static int kirkwood_dma_hw_params(struct snd_soc_component *component,
-				  struct snd_pcm_substream *substream,
-				  struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
-
-	return 0;
-}
-
-static int kirkwood_dma_hw_free(struct snd_soc_component *component,
-				struct snd_pcm_substream *substream)
-{
-	snd_pcm_set_runtime_buffer(substream, NULL);
-	return 0;
-}
-
 static int kirkwood_dma_prepare(struct snd_soc_component *component,
 				struct snd_pcm_substream *substream)
 {
@@ -244,82 +225,28 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(
 	return count;
 }
 
-static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
-		int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->area = dma_alloc_coherent(pcm->card->dev, size,
-			&buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-	buf->bytes = size;
-	buf->private_data = NULL;
-
-	return 0;
-}
-
 static int kirkwood_dma_new(struct snd_soc_component *component,
 			    struct snd_soc_pcm_runtime *rtd)
 {
+	size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
 	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
 	int ret;
 
 	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
 	if (ret)
 		return ret;
 
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
-				SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			return ret;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
-				SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			return ret;
-	}
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+				       card->dev, size, size);
 
 	return 0;
 }
 
-static void kirkwood_dma_free_dma_buffers(struct snd_soc_component *component,
-					  struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-
-		dma_free_coherent(pcm->card->dev, buf->bytes,
-				buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
 const struct snd_soc_component_driver kirkwood_soc_component = {
 	.name		= DRV_NAME,
 	.open		= kirkwood_dma_open,
 	.close		= kirkwood_dma_close,
-	.hw_params	= kirkwood_dma_hw_params,
-	.hw_free	= kirkwood_dma_hw_free,
 	.prepare	= kirkwood_dma_prepare,
 	.pointer	= kirkwood_dma_pointer,
 	.pcm_construct	= kirkwood_dma_new,
-	.pcm_destruct	= kirkwood_dma_free_dma_buffers,
 };
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 8d3dcfb6a5802cf86982865a20533951b4979b38..effdb76369e420d6b0137fb681079226d324c745 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -172,7 +172,7 @@ config SND_SOC_MT8192
 config SND_SOC_MT8192_MT6359_RT1015_RT5682
 	tristate "ASoC Audio driver for MT8192 with MT6359 RT1015 RT5682 codec"
 	depends on I2C
-	depends on SND_SOC_MT8192
+	depends on SND_SOC_MT8192 && MTK_PMIC_WRAP
 	select SND_SOC_MT6359
 	select SND_SOC_RT1015
 	select SND_SOC_RT1015P
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index df29641c74aaaa693e50874e05fc178a12a61fcf..d5cffe7a7e154c707ec137cd7203472584494c52 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -655,7 +655,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 
 		},
 		.ops = &mt2701_afe_i2s_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "I2S1",
@@ -679,7 +679,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 				| SNDRV_PCM_FMTBIT_S32_LE)
 			},
 		.ops = &mt2701_afe_i2s_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "I2S2",
@@ -703,7 +703,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 				| SNDRV_PCM_FMTBIT_S32_LE)
 			},
 		.ops = &mt2701_afe_i2s_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "I2S3",
@@ -727,7 +727,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 				| SNDRV_PCM_FMTBIT_S32_LE)
 			},
 		.ops = &mt2701_afe_i2s_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 	{
 		.name = "MRG BT",
@@ -749,7 +749,7 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.ops = &mt2701_btmrg_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	}
 };
 
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
index 3136f0bc7827d789703d798957a711a7d9abb411..51f736f319e421093829a51395dd3f34b7649cd6 100644
--- a/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
@@ -270,8 +270,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 			.formats = MTK_PCM_FORMATS,
 		},
 		.ops = &mtk_dai_pcm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "PCM 2",
@@ -291,8 +291,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 			.formats = MTK_PCM_FORMATS,
 		},
 		.ops = &mtk_dai_pcm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 };
 
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 7e7bda70d12e90eb6c7677b01686585039905947..685f4074b4e0acaae870221014eade2d78bab9fc 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -571,7 +571,7 @@ static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = {
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.ops = &mt8173_afe_i2s_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index cfbd0c65c7a389564ebed1fed50f8dd32413245e..a4d26a6fc84927b79330dc191ce88cf7f85d3000 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -125,12 +125,6 @@ mt8183_da7219_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
 		if (!strcmp(codec_dai->component->name, RT1015_DEV0_NAME) ||
 		    !strcmp(codec_dai->component->name, RT1015_DEV1_NAME)) {
-			ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-			if (ret) {
-				dev_err(rtd->dev, "failed to set bclk ratio\n");
-				return ret;
-			}
-
 			ret = snd_soc_dai_set_pll(codec_dai, 0,
 						  RT1015_PLL_S_BCLK,
 						  rate * 64, rate * 256);
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
index bc3ba3228f0872896f9cddb8a0ace490c533bde5..38ce0e36cdb4b6e46b09adc37b5af68063f75fbe 100644
--- a/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
@@ -270,8 +270,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 			.formats = MTK_PCM_FORMATS,
 		},
 		.ops = &mtk_dai_pcm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "PCM 2",
@@ -291,8 +291,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 			.formats = MTK_PCM_FORMATS,
 		},
 		.ops = &mtk_dai_pcm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 };
 
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index 1ce3eddbee13bd1ed9bfc4d4850adacc833d20a6..271413e719e3052bb7290339b7c4fa8ce98f7456 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -68,12 +68,6 @@ mt8183_mt6358_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
 	int ret, i;
 
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
-		ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-		if (ret < 0) {
-			dev_err(card->dev, "failed to set bclk ratio\n");
-			return ret;
-		}
-
 		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
 				rate * 64, rate * 256);
 		if (ret < 0) {
@@ -123,6 +117,45 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 	return 0;
 }
 
+static int
+mt8183_mt6358_startup(struct snd_pcm_substream *substream)
+{
+	static const unsigned int rates[] = {
+		48000,
+	};
+	static const struct snd_pcm_hw_constraint_list constraints_rates = {
+		.count = ARRAY_SIZE(rates),
+		.list  = rates,
+		.mask = 0,
+	};
+	static const unsigned int channels[] = {
+		2,
+	};
+	static const struct snd_pcm_hw_constraint_list constraints_channels = {
+		.count = ARRAY_SIZE(channels),
+		.list = channels,
+		.mask = 0,
+	};
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+	runtime->hw.channels_max = 2;
+	snd_pcm_hw_constraint_list(runtime, 0,
+				   SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &constraints_channels);
+
+	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+	snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+	return 0;
+}
+
+static const struct snd_soc_ops mt8183_mt6358_ops = {
+	.startup = mt8183_mt6358_startup,
+};
+
 static int
 mt8183_mt6358_ts3a227_max98357_bt_sco_startup(
 	struct snd_pcm_substream *substream)
@@ -362,6 +395,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
 			    SND_SOC_DPCM_TRIGGER_PRE},
 		.dynamic = 1,
 		.dpcm_playback = 1,
+		.ops = &mt8183_mt6358_ops,
 		SND_SOC_DAILINK_REG(playback1),
 	},
 	{
@@ -409,6 +443,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
 			    SND_SOC_DPCM_TRIGGER_PRE},
 		.dynamic = 1,
 		.dpcm_capture = 1,
+		.ops = &mt8183_mt6358_ops,
 		SND_SOC_DAILINK_REG(capture3),
 	},
 	{
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
index e7fec2d75e3d4fe48beffe7b79b6f39cf006c81d..7a1724f5ff4c6c98bc802f9f679d0d5cdd01cfa4 100644
--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
@@ -42,7 +42,7 @@ static const struct snd_pcm_hardware mt8192_afe_hardware = {
 static int mt8192_memif_fs(struct snd_pcm_substream *substream,
 			   unsigned int rate)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_component *component =
 		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
@@ -59,7 +59,7 @@ static int mt8192_get_dai_fs(struct mtk_base_afe *afe,
 
 static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_component *component =
 		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
index 6e94cfdf06fc1fc35a78335ea74b80e192a4c29b..239e3f5b53d3356e4248e29dba2b5f6f9430d6fd 100644
--- a/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
@@ -360,8 +360,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 			.formats = MTK_PCM_FORMATS,
 		},
 		.ops = &mtk_dai_pcm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 	{
 		.name = "PCM 2",
@@ -381,8 +381,8 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 			.formats = MTK_PCM_FORMATS,
 		},
 		.ops = &mtk_dai_pcm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
 	},
 };
 
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
index 8383536b7ae0090beed80e78574cb9fb898b8b2c..f5de1d7696792daf5c38db90de2a16a2f04c809b 100644
--- a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
@@ -738,7 +738,7 @@ static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
 	if (!tdm_priv)
 		return NULL;
 
-	tdm_priv->mclk_multiple = 128;
+	tdm_priv->mclk_multiple = 512;
 	tdm_priv->bck_id = MT8192_I2S4_BCK;
 	tdm_priv->mclk_id = MT8192_I2S4_MCK;
 	tdm_priv->id = MT8192_DAI_TDM;
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index ae2c748eb19c40a490f84880820fc97093f5b895..a606133951b707cecdaaa0b8c7471ce95c8b1df2 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -31,12 +31,15 @@
 #define RT5682_CODEC_DAI	"rt5682-aif1"
 #define RT5682_DEV0_NAME	"rt5682.1-001a"
 
-static struct snd_soc_jack headset_jack;
+struct mt8192_mt6359_priv {
+	struct snd_soc_jack headset_jack;
+	struct snd_soc_jack hdmi_jack;
+};
 
 static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
 				       struct snd_pcm_hw_params *params)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 	struct snd_soc_dai *codec_dai;
@@ -46,12 +49,6 @@ static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
 	int ret, i;
 
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
-		ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
-		if (ret) {
-			dev_err(card->dev, "failed to set bclk ratio\n");
-			return ret;
-		}
-
 		ret = snd_soc_dai_set_pll(codec_dai, 0,
 					  RT1015_PLL_S_BCLK,
 					  params_rate(params) * 64,
@@ -77,7 +74,7 @@ static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
 static int mt8192_rt5682_i2s_hw_params(struct snd_pcm_substream *substream,
 				       struct snd_pcm_hw_params *params)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -311,7 +308,8 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_component *cmpnt_codec =
 		asoc_rtd_to_codec(rtd, 0)->component;
-	struct snd_soc_jack *jack = &headset_jack;
+	struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_jack *jack = &priv->headset_jack;
 	int ret;
 
 	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
@@ -329,14 +327,25 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-	ret = snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+	return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+};
+
+static int mt8192_mt6359_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *cmpnt_codec =
+		asoc_rtd_to_codec(rtd, 0)->component;
+	struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	int ret;
+
+	ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+				    &priv->hdmi_jack, NULL, 0);
 	if (ret) {
-		dev_err(rtd->dev, "Headset Jack set failed: %d\n", ret);
+		dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
 		return ret;
 	}
 
-	return 0;
-};
+	return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+}
 
 static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				      struct snd_pcm_hw_params *params)
@@ -351,14 +360,8 @@ static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 }
 
 static int
-mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
+mt8192_mt6359_cap1_startup(struct snd_pcm_substream *substream)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_component *component =
-		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
-	int ret;
-
 	static const unsigned int channels[] = {
 		1, 2, 4
 	};
@@ -376,13 +379,15 @@ mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
 		.mask = 0,
 	};
 
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 					 SNDRV_PCM_HW_PARAM_CHANNELS,
 					 &constraints_channels);
 	if (ret < 0) {
-		dev_err(afe->dev, "hw_constraint_list channels failed\n");
+		dev_err(rtd->dev, "hw_constraint_list channels failed\n");
 		return ret;
 	}
 
@@ -390,15 +395,15 @@ mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
 					 SNDRV_PCM_HW_PARAM_RATE,
 					 &constraints_rates);
 	if (ret < 0) {
-		dev_err(afe->dev, "hw_constraint_list rate failed\n");
+		dev_err(rtd->dev, "hw_constraint_list rate failed\n");
 		return ret;
 	}
 
 	return 0;
 }
 
-static const struct snd_soc_ops mt8192_mt6359_rt1015_rt5682_capture1_ops = {
-	.startup = mt8192_mt6359_rt1015_rt5682_cap1_startup,
+static const struct snd_soc_ops mt8192_mt6359_capture1_ops = {
+	.startup = mt8192_mt6359_cap1_startup,
 };
 
 static int
@@ -656,7 +661,7 @@ SND_SOC_DAILINK_DEFS(pcm2,
 
 SND_SOC_DAILINK_DEFS(tdm,
 		     DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
-		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
 		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
 
 static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
@@ -759,7 +764,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
 			    SND_SOC_DPCM_TRIGGER_PRE},
 		.dynamic = 1,
 		.dpcm_capture = 1,
-		.ops = &mt8192_mt6359_rt1015_rt5682_capture1_ops,
+		.ops = &mt8192_mt6359_capture1_ops,
 		SND_SOC_DAILINK_REG(capture1),
 	},
 	{
@@ -994,8 +999,14 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
 	{
 		.name = "TDM",
 		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_DSP_A |
+			   SND_SOC_DAIFMT_IB_NF |
+			   SND_SOC_DAIFMT_CBM_CFM,
 		.dpcm_playback = 1,
 		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		.ignore = 1,
+		.init = mt8192_mt6359_hdmi_init,
 		SND_SOC_DAILINK_REG(tdm),
 	},
 };
@@ -1006,6 +1017,7 @@ mt8192_mt6359_rt1015_rt5682_widgets[] = {
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_OUTPUT("TDM Out"),
 };
 
 static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
@@ -1016,6 +1028,8 @@ static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
 	{ "Headphone Jack", NULL, "HPOL" },
 	{ "Headphone Jack", NULL, "HPOR" },
 	{ "IN1P", NULL, "Headset Mic" },
+	/* TDM */
+	{ "TDM Out", NULL, "TDM" },
 };
 
 static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = {
@@ -1089,10 +1103,11 @@ static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682_card = {
 static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card;
-	struct device_node *platform_node;
+	struct device_node *platform_node, *hdmi_codec;
 	int ret, i;
 	struct snd_soc_dai_link *dai_link;
 	const struct of_device_id *match;
+	struct mt8192_mt6359_priv *priv;
 
 	platform_node = of_parse_phandle(pdev->dev.of_node,
 					 "mediatek,platform", 0);
@@ -1108,6 +1123,9 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
 	card = (struct snd_soc_card *)match->data;
 	card->dev = &pdev->dev;
 
+	hdmi_codec = of_parse_phandle(pdev->dev.of_node,
+				      "mediatek,hdmi-codec", 0);
+
 	for_each_card_prelinks(card, i, dai_link) {
 		if (strcmp(dai_link->name, "I2S3") == 0) {
 			if (card == &mt8192_mt6359_rt1015_rt5682_card) {
@@ -1134,10 +1152,20 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
 			}
 		}
 
+		if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
+			dai_link->codecs->of_node = hdmi_codec;
+			dai_link->ignore = 0;
+		}
+
 		if (!dai_link->platforms->name)
 			dai_link->platforms->of_node = platform_node;
 	}
 
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	snd_soc_card_set_drvdata(card, priv);
+
 	ret = mt8192_afe_gpio_init(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "init gpio error %d\n", ret);
diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c
index d91b0d874342fbfa80f8f741f98c7137ecb17de2..2388a2d0b3a6c5206d0521fb17006aa2848c1b85 100644
--- a/sound/soc/meson/aiu-fifo-i2s.c
+++ b/sound/soc/meson/aiu-fifo-i2s.c
@@ -124,7 +124,6 @@ const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = {
 	.trigger	= aiu_fifo_i2s_trigger,
 	.prepare	= aiu_fifo_i2s_prepare,
 	.hw_params	= aiu_fifo_i2s_hw_params,
-	.hw_free	= aiu_fifo_hw_free,
 	.startup	= aiu_fifo_startup,
 	.shutdown	= aiu_fifo_shutdown,
 };
diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c
index 44eb6faacf44d0df3c8630c69c1fe8720ce5b0cb..2fb30f89bf7a2c279bfafe8136bff41051677ddf 100644
--- a/sound/soc/meson/aiu-fifo-spdif.c
+++ b/sound/soc/meson/aiu-fifo-spdif.c
@@ -158,7 +158,6 @@ const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
 	.trigger	= fifo_spdif_trigger,
 	.prepare	= fifo_spdif_prepare,
 	.hw_params	= fifo_spdif_hw_params,
-	.hw_free	= aiu_fifo_hw_free,
 	.startup	= aiu_fifo_startup,
 	.shutdown	= aiu_fifo_shutdown,
 };
diff --git a/sound/soc/meson/aiu-fifo.c b/sound/soc/meson/aiu-fifo.c
index aa88aae8e517dc7c2f566bff3f75aee7e25aaa0e..4ad23267cace58e9b35dc38d6d56b7a8288a1f4b 100644
--- a/sound/soc/meson/aiu-fifo.c
+++ b/sound/soc/meson/aiu-fifo.c
@@ -99,11 +99,6 @@ int aiu_fifo_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_component *component = dai->component;
 	struct aiu_fifo *fifo = dai->playback_dma_data;
 	dma_addr_t end;
-	int ret;
-
-	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-	if (ret < 0)
-		return ret;
 
 	/* Setup the fifo boundaries */
 	end = runtime->dma_addr + runtime->dma_bytes - fifo->fifo_block;
@@ -124,12 +119,6 @@ int aiu_fifo_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-int aiu_fifo_hw_free(struct snd_pcm_substream *substream,
-		     struct snd_soc_dai *dai)
-{
-	return snd_pcm_lib_free_pages(substream);
-}
-
 static irqreturn_t aiu_fifo_isr(int irq, void *dev_id)
 {
 	struct snd_pcm_substream *playback = dev_id;
@@ -187,15 +176,12 @@ void aiu_fifo_shutdown(struct snd_pcm_substream *substream,
 int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd,
 		     struct snd_soc_dai *dai)
 {
-	struct snd_pcm_substream *substream =
-		rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct snd_card *card = rtd->card->snd_card;
 	struct aiu_fifo *fifo = dai->playback_dma_data;
 	size_t size = fifo->pcm->buffer_bytes_max;
 
-	snd_pcm_lib_preallocate_pages(substream,
-				      SNDRV_DMA_TYPE_DEV,
-				      card->dev, size, size);
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+				       card->dev, size, size);
 
 	return 0;
 }
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 5301859a8453c7000641fea3bf0d39c65567b3da..bcde4a96c1688444ebb18c9dd009c8e8db379cb8 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -353,7 +353,7 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
 		.rates = PXA2XX_I2S_RATES,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = &pxa_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver pxa_i2s_component = {
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index 8507ef8f6679b69b2d625efb6dce6099399f41ce..3efa133d1c6410abe461f3c4ca35d47976bd3cdb 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -250,7 +250,7 @@ static struct lpass_variant apq8016_data = {
 	.micmode		= REG_FIELD_ID(0x1000, 4, 7, 4, 0x1000),
 	.micmono		= REG_FIELD_ID(0x1000, 3, 3, 4, 0x1000),
 	.wssrc			= REG_FIELD_ID(0x1000, 2, 2, 4, 0x1000),
-	.bitwidth		= REG_FIELD_ID(0x1000, 0, 0, 4, 0x1000),
+	.bitwidth		= REG_FIELD_ID(0x1000, 0, 1, 4, 0x1000),
 
 	.rdma_dyncclk		= REG_FIELD_ID(0x8400, 12, 12, 2, 0x1000),
 	.rdma_bursten		= REG_FIELD_ID(0x8400, 11, 11, 2, 0x1000),
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 66b834312f330fdd8424d7caca8e93706ecb094a..c642e5f8f28c4c942689059d8ee9a98506621a56 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -286,16 +286,12 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
 				ret);
 
-		if (drvdata->bit_clk_state[id] == LPAIF_BIT_CLK_DISABLE) {
-			ret = clk_enable(drvdata->mi2s_bit_clk[id]);
-			if (ret) {
-				dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
-				clk_disable(drvdata->mi2s_osr_clk[id]);
-				return ret;
-			}
-			drvdata->bit_clk_state[id] = LPAIF_BIT_CLK_ENABLE;
+		ret = clk_enable(drvdata->mi2s_bit_clk[id]);
+		if (ret) {
+			dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
+			clk_disable(drvdata->mi2s_osr_clk[id]);
+			return ret;
 		}
-
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -310,10 +306,9 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 		if (ret)
 			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
 				ret);
-		if (drvdata->bit_clk_state[id] == LPAIF_BIT_CLK_ENABLE) {
-			clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
-			drvdata->bit_clk_state[id] = LPAIF_BIT_CLK_DISABLE;
-		}
+
+		clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
+
 		break;
 	}
 
@@ -480,6 +475,7 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
 }
 
 static struct regmap_config lpass_cpu_regmap_config = {
+	.name = "lpass_cpu",
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -599,7 +595,7 @@ static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
 			return true;
 	}
 
-	for (i = 0; i < v->rdma_channels; ++i) {
+	for (i = 0; i < v->hdmi_rdma_channels; ++i) {
 		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
 			return true;
 		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
@@ -645,7 +641,7 @@ static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
 	if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
 		return true;
 
-	for (i = 0; i < v->rdma_channels; ++i) {
+	for (i = 0; i < v->hdmi_rdma_channels; ++i) {
 		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
 			return true;
 		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
@@ -672,7 +668,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
 	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
 		return true;
 
-	for (i = 0; i < v->rdma_channels; ++i) {
+	for (i = 0; i < v->hdmi_rdma_channels; ++i) {
 		if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
 			return true;
 	}
@@ -680,6 +676,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
 }
 
 static struct regmap_config lpass_hdmi_regmap_config = {
+	.name = "lpass_hdmi",
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -748,7 +745,6 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
 		}
 		if (id == LPASS_DP_RX) {
 			data->hdmi_port_enable = 1;
-			dev_err(dev, "HDMI Port is enabled: %d\n", id);
 		} else {
 			data->mi2s_playback_sd_mode[id] =
 				of_lpass_cpu_parse_sd_lines(dev, node,
@@ -793,11 +789,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
 
 	drvdata->lpaif = devm_ioremap_resource(dev, res);
-	if (IS_ERR((void const __force *)drvdata->lpaif)) {
-		dev_err(dev, "error mapping reg resource: %ld\n",
-				PTR_ERR((void const __force *)drvdata->lpaif));
-		return PTR_ERR((void const __force *)drvdata->lpaif);
-	}
+	if (IS_ERR(drvdata->lpaif))
+		return PTR_ERR(drvdata->lpaif);
 
 	lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
 						variant->wrdma_channels +
@@ -815,14 +808,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif");
 
 		drvdata->hdmiif = devm_ioremap_resource(dev, res);
-		if (IS_ERR((void const __force *)drvdata->hdmiif)) {
-			dev_err(dev, "error mapping reg resource: %ld\n",
-					PTR_ERR((void const __force *)drvdata->hdmiif));
-			return PTR_ERR((void const __force *)drvdata->hdmiif);
-		}
+		if (IS_ERR(drvdata->hdmiif))
+			return PTR_ERR(drvdata->hdmiif);
 
 		lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
-					variant->hdmi_rdma_channels);
+					variant->hdmi_rdma_channels - 1);
 		drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
 					&lpass_hdmi_regmap_config);
 		if (IS_ERR(drvdata->hdmiif_map)) {
@@ -866,7 +856,6 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 				PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
 			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
 		}
-		drvdata->bit_clk_state[dai_id] = LPAIF_BIT_CLK_DISABLE;
 	}
 
 	/* Allocation for i2sctl regmap fields */
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index baf72f124ea9b24603692bad3708821e744dfd87..2eb03ad9b7c7452c449d4d8d0858de50e5975ed5 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -60,9 +60,6 @@
 #define LPAIF_I2SCTL_BITWIDTH_24	1
 #define LPAIF_I2SCTL_BITWIDTH_32	2
 
-#define LPAIF_BIT_CLK_DISABLE		0
-#define LPAIF_BIT_CLK_ENABLE		1
-
 #define LPAIF_I2SCTL_RESET_STATE	0x003C0004
 #define LPAIF_DMACTL_RESET_STATE	0x00200000
 
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index 735c9dac28f2683abdb11b5e51f0d61483253682..8c168d3c589e9ccfddaf2cc84f4fc3455b01d1a8 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -171,7 +171,7 @@ static struct lpass_variant sc7180_data = {
 	.rdma_channels		= 5,
 	.hdmi_rdma_reg_base		= 0x64000,
 	.hdmi_rdma_reg_stride	= 0x1000,
-	.hdmi_rdma_channels		= 3,
+	.hdmi_rdma_channels		= 4,
 	.dmactl_audif_start	= 1,
 	.wrdma_reg_base		= 0x18000,
 	.wrdma_reg_stride	= 0x1000,
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 2d68af0da34d877943946da18d8dda616544dbc4..83b2e08ade0603b9b83deae24f441dd0e02da15f 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -68,7 +68,6 @@ struct lpass_data {
 	unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
 	unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
 	int hdmi_port_enable;
-	int bit_clk_state[LPASS_MAX_MI2S_PORTS];
 
 	/* low-power audio interface (LPAIF) registers */
 	void __iomem *lpaif;
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index daa58b5f941ecd42652f608db3bbb9bab1d04ac3..cad1cd1bfdf0eefd54ab80bfef9f67b8308b5f1e 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -1707,7 +1707,7 @@ int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
 	pkt->hdr.token = hw_block_id;
 	pkt->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST;
 	vote_cfg->hw_block_id = hw_block_id;
-	strlcpy(vote_cfg->client_name, client_name,
+	strscpy(vote_cfg->client_name, client_name,
 			sizeof(vote_cfg->client_name));
 
 	ret = afe_apr_send_pkt(afe, pkt, NULL,
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index c9ac9c1d26c4757619aa044efa2042c5667388cf..9766725c29166e1031bae0ab038d84ea6039f750 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -1233,6 +1233,25 @@ static void q6asm_dai_pcm_free(struct snd_soc_component *component,
 	}
 }
 
+static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
 static const struct snd_soc_component_driver q6asm_fe_dai_component = {
 	.name		= DRV_NAME,
 	.open		= q6asm_dai_open,
@@ -1245,6 +1264,8 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
 	.pcm_construct	= q6asm_dai_pcm_new,
 	.pcm_destruct	= q6asm_dai_pcm_free,
 	.compress_ops	= &q6asm_dai_compress_ops,
+	.dapm_widgets	= q6asm_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
 };
 
 static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index a6618efe22f2b72d1e9a13a18d76bd8e4aa81398..36bf8bd4edd7c1dcae73e5f4b28c9045ead186f6 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -491,7 +491,7 @@ static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
  *
  * @dir: direction of audio stream
  * @ac: audio client instanace
- * @phys: physcial address that needs mapping.
+ * @phys: physical address that needs mapping.
  * @period_sz: audio period size
  * @periods: number of periods
  *
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 53185e26fea1702fc9fc08e88fe7e38a87327d3f..0a6b9433f6acfdaf645efe287537e976d32cc0ce 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -713,24 +713,6 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
 	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA8) };
 
 static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
-	/* Frontend AIF */
-	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0),
-	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
-
 	/* Mixer definitions */
 	SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
 			   hdmi_mixer_controls,
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index eae287d905eb2bbe824f168c9a916fa21977c42a..0740764e7f71f27e293e80b0a3798ab83854f4a4 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -373,7 +373,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 			   I2S_DMACR_RDL(16));
 
 	val = I2S_CKR_TRCM_TXRX;
-	if (dai->driver->symmetric_rates && rtd->dai_link->symmetric_rates)
+	if (dai->driver->symmetric_rate && rtd->dai_link->symmetric_rate)
 		val = I2S_CKR_TRCM_TXONLY;
 
 	regmap_update_bits(i2s->regmap, I2S_CKR,
@@ -471,7 +471,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
 			    SNDRV_PCM_FMTBIT_S32_LE),
 	},
 	.ops = &rockchip_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver rockchip_i2s_component = {
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index e5f732747f711910c21a26a70951d5a3ebc44c93..9295d648624e2b757c22ac98b7f084decc65bf63 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -338,7 +338,7 @@ static struct snd_soc_dai_driver rockchip_pdm_dai = {
 		.formats = ROCKCHIP_PDM_FORMATS,
 	},
 	.ops = &rockchip_pdm_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver rockchip_pdm_component = {
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 4bdc268fd981e68d4146588faf18100a88b5e98a..b043183174b26d443b72821c76323c24050d52c7 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1175,7 +1175,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
 		dai_drv->probe = samsung_i2s_dai_probe;
 		dai_drv->remove = samsung_i2s_dai_remove;
 
-		dai_drv->symmetric_rates = 1;
+		dai_drv->symmetric_rate = 1;
 		dai_drv->ops = &samsung_i2s_dai_ops;
 
 		dai_drv->playback.channels_min = 1;
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 6f50c7b4732606274e91b341867dc1228a84b9c7..bfd76e9cc0cad6306eac0469d59f01acd21bdba0 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -452,7 +452,7 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
 
 #define S3C_PCM_DAI_DECLARE			\
-	.symmetric_rates = 1,					\
+	.symmetric_rate = 1,					\
 	.probe = s3c_pcm_dai_probe,				\
 	.ops = &s3c_pcm_dai_ops,				\
 	.playback = {						\
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 6e670b3e92a002171ba0e83742a544873cad3694..1029d8d9d800af89410d13a88edd37c3bf3d6724 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1320,8 +1320,8 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
 
 	if (rsnd_ssi_is_pin_sharing(io_capture) ||
 	    rsnd_ssi_is_pin_sharing(io_playback)) {
-		/* should have symmetric_rates if pin sharing */
-		drv->symmetric_rates = 1;
+		/* should have symmetric_rate if pin sharing */
+		drv->symmetric_rate = 1;
 	}
 
 	dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
@@ -1472,7 +1472,7 @@ static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
 		uinfo->value.enumerated.items = cfg->max;
 		if (uinfo->value.enumerated.item >= cfg->max)
 			uinfo->value.enumerated.item = cfg->max - 1;
-		strlcpy(uinfo->value.enumerated.name,
+		strscpy(uinfo->value.enumerated.name,
 			cfg->texts[uinfo->value.enumerated.item],
 			sizeof(uinfo->value.enumerated.name));
 	} else {
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
index 6201840f1bc057bf2a209b55320da5903cf2605e..a675c36fc9d9561e8f49e16ecc5507672568fe46 100644
--- a/sound/soc/sh/siu.h
+++ b/sound/soc/sh/siu.h
@@ -169,7 +169,7 @@ static inline u32 siu_read32(u32 __iomem *addr)
 #define SIU_BRGBSEL	(0x108 / sizeof(u32))
 #define SIU_BRRB	(0x10c / sizeof(u32))
 
-extern struct snd_soc_component_driver siu_component;
+extern const struct snd_soc_component_driver siu_component;
 extern struct siu_info *siu_i2s_data;
 
 int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 45c4320976ab9e4f5bdd3383b4792b7db4559777..4785886df4f03872151607409d18c3fe8a53db58 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -543,7 +543,7 @@ static void siu_pcm_free(struct snd_soc_component *component,
 	dev_dbg(pcm->card->dev, "%s\n", __func__);
 }
 
-struct const snd_soc_component_driver siu_component = {
+const struct snd_soc_component_driver siu_component = {
 	.name		= DRV_NAME,
 	.open		= siu_pcm_open,
 	.close		= siu_pcm_close,
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
deleted file mode 100644
index 094a1c89c59dc3911d2b04ddb14cae3738aa1ce8..0000000000000000000000000000000000000000
--- a/sound/soc/sirf/Kconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config SND_SOC_SIRF
-	tristate "SoC Audio for the SiRF SoC chips"
-	depends on ARCH_SIRF || COMPILE_TEST
-	select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_SOC_SIRF_AUDIO
-	tristate "SoC Audio support for SiRF internal audio codec"
-	depends on SND_SOC_SIRF
-	select SND_SOC_SIRF_AUDIO_CODEC
-	select SND_SOC_SIRF_AUDIO_PORT
-
-config SND_SOC_SIRF_AUDIO_PORT
-	select REGMAP_MMIO
-	tristate
-
-config SND_SOC_SIRF_USP
-	tristate "SoC Audio (I2S protocol) for SiRF SoC USP interface"
-	depends on SND_SOC_SIRF
-	select REGMAP_MMIO
-	tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
deleted file mode 100644
index 16ed11965ff9e2a91a0adf87533f5817f52b61d8..0000000000000000000000000000000000000000
--- a/sound/soc/sirf/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-snd-soc-sirf-audio-objs := sirf-audio.o
-snd-soc-sirf-audio-port-objs := sirf-audio-port.o
-snd-soc-sirf-usp-objs := sirf-usp.o
-
-obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o
-obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o
-obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c
deleted file mode 100644
index 8be2f0bc477b11dc1aa72d86d73dc14593094b27..0000000000000000000000000000000000000000
--- a/sound/soc/sirf/sirf-audio-port.c
+++ /dev/null
@@ -1,86 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF Audio port driver
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-struct sirf_audio_port {
-	struct regmap *regmap;
-	struct snd_dmaengine_dai_dma_data playback_dma_data;
-	struct snd_dmaengine_dai_dma_data capture_dma_data;
-};
-
-
-static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
-{
-	struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
-
-	snd_soc_dai_init_dma_data(dai, &port->playback_dma_data,
-			&port->capture_dma_data);
-	return 0;
-}
-
-static struct snd_soc_dai_driver sirf_audio_port_dai = {
-	.probe = sirf_audio_port_dai_probe,
-	.name = "sirf-audio-port",
-	.id = 0,
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-};
-
-static const struct snd_soc_component_driver sirf_audio_port_component = {
-	.name       = "sirf-audio-port",
-};
-
-static int sirf_audio_port_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct sirf_audio_port *port;
-
-	port = devm_kzalloc(&pdev->dev,
-			sizeof(struct sirf_audio_port), GFP_KERNEL);
-	if (!port)
-		return -ENOMEM;
-
-	ret = devm_snd_soc_register_component(&pdev->dev,
-			&sirf_audio_port_component, &sirf_audio_port_dai, 1);
-	if (ret)
-		return ret;
-
-	platform_set_drvdata(pdev, port);
-	return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-}
-
-static const struct of_device_id sirf_audio_port_of_match[] = {
-	{ .compatible = "sirf,audio-port", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match);
-
-static struct platform_driver sirf_audio_port_driver = {
-	.driver = {
-		.name = "sirf-audio-port",
-		.of_match_table = sirf_audio_port_of_match,
-	},
-	.probe = sirf_audio_port_probe,
-};
-
-module_platform_driver(sirf_audio_port_driver);
-
-MODULE_DESCRIPTION("SiRF Audio Port driver");
-MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-audio.c b/sound/soc/sirf/sirf-audio.c
deleted file mode 100644
index c923b6772b22696a4826b472cc4514b3c62ff2a4..0000000000000000000000000000000000000000
--- a/sound/soc/sirf/sirf-audio.c
+++ /dev/null
@@ -1,160 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF audio card driver
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-struct sirf_audio_card {
-	unsigned int            gpio_hp_pa;
-	unsigned int            gpio_spk_pa;
-};
-
-static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w,
-				struct snd_kcontrol *ctrl, int event)
-{
-	struct snd_soc_dapm_context *dapm = w->dapm;
-	struct snd_soc_card *card = dapm->card;
-	struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
-	int on = !SND_SOC_DAPM_EVENT_OFF(event);
-
-	if (gpio_is_valid(sirf_audio_card->gpio_hp_pa))
-		gpio_set_value(sirf_audio_card->gpio_hp_pa, on);
-	return 0;
-}
-
-static int sirf_audio_spk_event(struct snd_soc_dapm_widget *w,
-				struct snd_kcontrol *ctrl, int event)
-{
-	struct snd_soc_dapm_context *dapm = w->dapm;
-	struct snd_soc_card *card = dapm->card;
-	struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
-	int on = !SND_SOC_DAPM_EVENT_OFF(event);
-
-	if (gpio_is_valid(sirf_audio_card->gpio_spk_pa))
-		gpio_set_value(sirf_audio_card->gpio_spk_pa, on);
-
-	return 0;
-}
-static const struct snd_soc_dapm_widget sirf_audio_dapm_widgets[] = {
-	SND_SOC_DAPM_HP("Hp", sirf_audio_hp_event),
-	SND_SOC_DAPM_SPK("Ext Spk", sirf_audio_spk_event),
-	SND_SOC_DAPM_MIC("Ext Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-	{"Hp", NULL, "HPOUTL"},
-	{"Hp", NULL, "HPOUTR"},
-	{"Ext Spk", NULL, "SPKOUT"},
-	{"MICIN1", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "Ext Mic"},
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-SND_SOC_DAILINK_DEFS(sirf,
-	DAILINK_COMP_ARRAY(COMP_EMPTY()),
-	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sirf-audio-codec")),
-	DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-static struct snd_soc_dai_link sirf_audio_dai_link[] = {
-	{
-		.name = "SiRF audio card",
-		.stream_name = "SiRF audio HiFi",
-		SND_SOC_DAILINK_REG(sirf),
-	},
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_sirf_audio_card = {
-	.name = "SiRF audio card",
-	.owner = THIS_MODULE,
-	.dai_link = sirf_audio_dai_link,
-	.num_links = ARRAY_SIZE(sirf_audio_dai_link),
-	.dapm_widgets = sirf_audio_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
-};
-
-static int sirf_audio_probe(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = &snd_soc_sirf_audio_card;
-	struct sirf_audio_card *sirf_audio_card;
-	int ret;
-
-	sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card),
-			GFP_KERNEL);
-	if (sirf_audio_card == NULL)
-		return -ENOMEM;
-
-	sirf_audio_dai_link[0].cpus->of_node =
-		of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
-	sirf_audio_dai_link[0].platforms->of_node =
-		of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
-	sirf_audio_dai_link[0].codecs->of_node =
-		of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0);
-	sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node,
-			"spk-pa-gpios", 0);
-	sirf_audio_card->gpio_hp_pa =  of_get_named_gpio(pdev->dev.of_node,
-			"hp-pa-gpios", 0);
-	if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) {
-		ret = devm_gpio_request_one(&pdev->dev,
-				sirf_audio_card->gpio_spk_pa,
-				GPIOF_OUT_INIT_LOW, "SPA_PA_SD");
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Failed to request GPIO_%d for reset: %d\n",
-				sirf_audio_card->gpio_spk_pa, ret);
-			return ret;
-		}
-	}
-	if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) {
-		ret = devm_gpio_request_one(&pdev->dev,
-				sirf_audio_card->gpio_hp_pa,
-				GPIOF_OUT_INIT_LOW, "HP_PA_SD");
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Failed to request GPIO_%d for reset: %d\n",
-				sirf_audio_card->gpio_hp_pa, ret);
-			return ret;
-		}
-	}
-
-	card->dev = &pdev->dev;
-	snd_soc_card_set_drvdata(card, sirf_audio_card);
-
-	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret)
-		dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
-
-	return ret;
-}
-
-static const struct of_device_id sirf_audio_of_match[] = {
-	{.compatible = "sirf,sirf-audio-card", },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, sirf_audio_of_match);
-
-static struct platform_driver sirf_audio_driver = {
-	.driver = {
-		.name = "sirf-audio-card",
-		.pm = &snd_soc_pm_ops,
-		.of_match_table = sirf_audio_of_match,
-	},
-	.probe = sirf_audio_probe,
-};
-module_platform_driver(sirf_audio_driver);
-
-MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>");
-MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
deleted file mode 100644
index 2af0c6f14ee695b6022448f231b9588b8cd85817..0000000000000000000000000000000000000000
--- a/sound/soc/sirf/sirf-usp.c
+++ /dev/null
@@ -1,435 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SiRF USP in I2S/DSP mode
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/pm_runtime.h>
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "sirf-usp.h"
-
-struct sirf_usp {
-	struct regmap *regmap;
-	struct clk *clk;
-	u32 mode1_reg;
-	u32 mode2_reg;
-	int daifmt_format;
-	struct snd_dmaengine_dai_dma_data playback_dma_data;
-	struct snd_dmaengine_dai_dma_data capture_dma_data;
-};
-
-static void sirf_usp_tx_enable(struct sirf_usp *usp)
-{
-	regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
-		USP_TX_FIFO_RESET, USP_TX_FIFO_RESET);
-	regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
-
-	regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
-		USP_TX_FIFO_START, USP_TX_FIFO_START);
-
-	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-		USP_TX_ENA, USP_TX_ENA);
-}
-
-static void sirf_usp_tx_disable(struct sirf_usp *usp)
-{
-	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-		USP_TX_ENA, ~USP_TX_ENA);
-	/* FIFO stop */
-	regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
-}
-
-static void sirf_usp_rx_enable(struct sirf_usp *usp)
-{
-	regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
-		USP_RX_FIFO_RESET, USP_RX_FIFO_RESET);
-	regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
-
-	regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
-		USP_RX_FIFO_START, USP_RX_FIFO_START);
-
-	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-		USP_RX_ENA, USP_RX_ENA);
-}
-
-static void sirf_usp_rx_disable(struct sirf_usp *usp)
-{
-	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
-		USP_RX_ENA, ~USP_RX_ENA);
-	/* FIFO stop */
-	regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
-}
-
-static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai)
-{
-	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
-	snd_soc_dai_init_dma_data(dai, &usp->playback_dma_data,
-			&usp->capture_dma_data);
-	return 0;
-}
-
-static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
-		unsigned int fmt)
-{
-	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
-	/* set master/slave audio interface */
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		break;
-	default:
-		dev_err(dai->dev, "Only CBM and CFM supported\n");
-		return -EINVAL;
-	}
-
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-	case SND_SOC_DAIFMT_DSP_A:
-		usp->daifmt_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
-		break;
-	default:
-		dev_err(dai->dev, "Only I2S and DSP_A format supported\n");
-		return -EINVAL;
-	}
-
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void sirf_usp_i2s_init(struct sirf_usp *usp)
-{
-	/* Configure RISC mode */
-	regmap_update_bits(usp->regmap, USP_RISC_DSP_MODE,
-		USP_RISC_DSP_SEL, ~USP_RISC_DSP_SEL);
-
-	/*
-	 * Configure DMA IO Length register
-	 * Set no limit, USP can receive data continuously until it is diabled
-	 */
-	regmap_write(usp->regmap, USP_TX_DMA_IO_LEN, 0);
-	regmap_write(usp->regmap, USP_RX_DMA_IO_LEN, 0);
-
-	/* Configure Mode2 register */
-	regmap_write(usp->regmap, USP_MODE2, (1 << USP_RXD_DELAY_LEN_OFFSET) |
-		(0 << USP_TXD_DELAY_LEN_OFFSET) |
-		USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE);
-
-	/* Configure Mode1 register */
-	regmap_write(usp->regmap, USP_MODE1,
-		USP_SYNC_MODE | USP_EN | USP_TXD_ACT_EDGE_FALLING |
-		USP_RFS_ACT_LEVEL_LOGIC1 | USP_TFS_ACT_LEVEL_LOGIC1 |
-		USP_TX_UFLOW_REPEAT_ZERO | USP_CLOCK_MODE_SLAVE);
-
-	/* Configure RX DMA IO Control register */
-	regmap_write(usp->regmap, USP_RX_DMA_IO_CTRL, 0);
-
-	/* Congiure RX FIFO Control register */
-	regmap_write(usp->regmap, USP_RX_FIFO_CTRL,
-		(USP_RX_FIFO_THRESHOLD << USP_RX_FIFO_THD_OFFSET) |
-		(USP_TX_RX_FIFO_WIDTH_DWORD << USP_RX_FIFO_WIDTH_OFFSET));
-
-	/* Congiure RX FIFO Level Check register */
-	regmap_write(usp->regmap, USP_RX_FIFO_LEVEL_CHK,
-		RX_FIFO_SC(0x04) | RX_FIFO_LC(0x0E) | RX_FIFO_HC(0x1B));
-
-	/* Configure TX DMA IO Control register*/
-	regmap_write(usp->regmap, USP_TX_DMA_IO_CTRL, 0);
-
-	/* Configure TX FIFO Control register */
-	regmap_write(usp->regmap, USP_TX_FIFO_CTRL,
-		(USP_TX_FIFO_THRESHOLD << USP_TX_FIFO_THD_OFFSET) |
-		(USP_TX_RX_FIFO_WIDTH_DWORD << USP_TX_FIFO_WIDTH_OFFSET));
-	/* Congiure TX FIFO Level Check register */
-	regmap_write(usp->regmap, USP_TX_FIFO_LEVEL_CHK,
-		TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04));
-}
-
-static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
-		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
-	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-	u32 data_len, frame_len, shifter_len;
-
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		data_len = 16;
-		frame_len = 16;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		data_len = 24;
-		frame_len = 32;
-		break;
-	case SNDRV_PCM_FORMAT_S24_3LE:
-		data_len = 24;
-		frame_len = 24;
-		break;
-	default:
-		dev_err(dai->dev, "Format unsupported\n");
-		return -EINVAL;
-	}
-
-	shifter_len = data_len;
-
-	switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
-			USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG);
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
-			USP_I2S_SYNC_CHG, 0);
-		frame_len = data_len * params_channels(params);
-		data_len = frame_len;
-		break;
-	default:
-		dev_err(dai->dev, "Only support I2S and DSP_A mode\n");
-		return -EINVAL;
-	}
-
-	switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		regmap_update_bits(usp->regmap, USP_MODE1,
-			USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING,
-			USP_RXD_ACT_EDGE_FALLING);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL,
-			USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK
-			| USP_TXC_SHIFTER_LEN_MASK | USP_TXC_SLAVE_CLK_SAMPLE,
-			((data_len - 1) << USP_TXC_DATA_LEN_OFFSET)
-			| ((frame_len - 1) << USP_TXC_FRAME_LEN_OFFSET)
-			| ((shifter_len - 1) << USP_TXC_SHIFTER_LEN_OFFSET)
-			| USP_TXC_SLAVE_CLK_SAMPLE);
-	else
-		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
-			USP_RXC_DATA_LEN_MASK | USP_RXC_FRAME_LEN_MASK
-			| USP_RXC_SHIFTER_LEN_MASK | USP_SINGLE_SYNC_MODE,
-			((data_len - 1) << USP_RXC_DATA_LEN_OFFSET)
-			| ((frame_len - 1) << USP_RXC_FRAME_LEN_OFFSET)
-			| ((shifter_len - 1) << USP_RXC_SHIFTER_LEN_OFFSET)
-			| USP_SINGLE_SYNC_MODE);
-
-	return 0;
-}
-
-static int sirf_usp_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			sirf_usp_tx_enable(usp);
-		else
-			sirf_usp_rx_enable(usp);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			sirf_usp_tx_disable(usp);
-		else
-			sirf_usp_rx_disable(usp);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops sirf_usp_pcm_dai_ops = {
-	.trigger = sirf_usp_pcm_trigger,
-	.set_fmt = sirf_usp_pcm_set_dai_fmt,
-	.hw_params = sirf_usp_pcm_hw_params,
-};
-
-static struct snd_soc_dai_driver sirf_usp_pcm_dai = {
-	.probe = sirf_usp_pcm_dai_probe,
-	.name = "sirf-usp-pcm",
-	.id = 0,
-	.playback = {
-		.stream_name = "SiRF USP PCM Playback",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
-			SNDRV_PCM_FMTBIT_S24_3LE,
-	},
-	.capture = {
-		.stream_name = "SiRF USP PCM Capture",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
-			SNDRV_PCM_FMTBIT_S24_3LE,
-	},
-	.ops = &sirf_usp_pcm_dai_ops,
-};
-
-static int sirf_usp_pcm_runtime_suspend(struct device *dev)
-{
-	struct sirf_usp *usp = dev_get_drvdata(dev);
-
-	clk_disable_unprepare(usp->clk);
-	return 0;
-}
-
-static int sirf_usp_pcm_runtime_resume(struct device *dev)
-{
-	struct sirf_usp *usp = dev_get_drvdata(dev);
-	int ret;
-
-	ret = clk_prepare_enable(usp->clk);
-	if (ret) {
-		dev_err(dev, "clk_enable failed: %d\n", ret);
-		return ret;
-	}
-	sirf_usp_i2s_init(usp);
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int sirf_usp_pcm_suspend(struct device *dev)
-{
-	struct sirf_usp *usp = dev_get_drvdata(dev);
-
-	if (!pm_runtime_status_suspended(dev)) {
-		regmap_read(usp->regmap, USP_MODE1, &usp->mode1_reg);
-		regmap_read(usp->regmap, USP_MODE2, &usp->mode2_reg);
-		sirf_usp_pcm_runtime_suspend(dev);
-	}
-	return 0;
-}
-
-static int sirf_usp_pcm_resume(struct device *dev)
-{
-	struct sirf_usp *usp = dev_get_drvdata(dev);
-	int ret;
-
-	if (!pm_runtime_status_suspended(dev)) {
-		ret = sirf_usp_pcm_runtime_resume(dev);
-		if (ret)
-			return ret;
-		regmap_write(usp->regmap, USP_MODE1, usp->mode1_reg);
-		regmap_write(usp->regmap, USP_MODE2, usp->mode2_reg);
-	}
-	return 0;
-}
-#endif
-
-static const struct snd_soc_component_driver sirf_usp_component = {
-	.name		= "sirf-usp",
-};
-
-static const struct regmap_config sirf_usp_regmap_config = {
-	.reg_bits = 32,
-	.reg_stride = 4,
-	.val_bits = 32,
-	.max_register = USP_RX_FIFO_DATA,
-	.cache_type = REGCACHE_NONE,
-};
-
-static int sirf_usp_pcm_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct sirf_usp *usp;
-	void __iomem *base;
-
-	usp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp),
-			GFP_KERNEL);
-	if (!usp)
-		return -ENOMEM;
-
-	platform_set_drvdata(pdev, usp);
-
-	base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
-	usp->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-					    &sirf_usp_regmap_config);
-	if (IS_ERR(usp->regmap))
-		return PTR_ERR(usp->regmap);
-
-	usp->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(usp->clk)) {
-		dev_err(&pdev->dev, "Get clock failed.\n");
-		return PTR_ERR(usp->clk);
-	}
-
-	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev)) {
-		ret = sirf_usp_pcm_runtime_resume(&pdev->dev);
-		if (ret)
-			return ret;
-	}
-
-	ret = devm_snd_soc_register_component(&pdev->dev, &sirf_usp_component,
-		&sirf_usp_pcm_dai, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
-		return ret;
-	}
-	return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-}
-
-static int sirf_usp_pcm_remove(struct platform_device *pdev)
-{
-	if (!pm_runtime_enabled(&pdev->dev))
-		sirf_usp_pcm_runtime_suspend(&pdev->dev);
-	else
-		pm_runtime_disable(&pdev->dev);
-	return 0;
-}
-
-static const struct of_device_id sirf_usp_pcm_of_match[] = {
-	{ .compatible = "sirf,prima2-usp-pcm", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, sirf_usp_pcm_of_match);
-
-static const struct dev_pm_ops sirf_usp_pcm_pm_ops = {
-	SET_RUNTIME_PM_OPS(sirf_usp_pcm_runtime_suspend,
-		sirf_usp_pcm_runtime_resume, NULL)
-	SET_SYSTEM_SLEEP_PM_OPS(sirf_usp_pcm_suspend, sirf_usp_pcm_resume)
-};
-
-static struct platform_driver sirf_usp_pcm_driver = {
-	.driver = {
-		.name = "sirf-usp-pcm",
-		.of_match_table = sirf_usp_pcm_of_match,
-		.pm = &sirf_usp_pcm_pm_ops,
-	},
-	.probe = sirf_usp_pcm_probe,
-	.remove = sirf_usp_pcm_remove,
-};
-
-module_platform_driver(sirf_usp_pcm_driver);
-
-MODULE_DESCRIPTION("SiRF SoC USP PCM bus driver");
-MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-usp.h b/sound/soc/sirf/sirf-usp.h
deleted file mode 100644
index 08993b5992c41c29116299de75b31d0f915af2e8..0000000000000000000000000000000000000000
--- a/sound/soc/sirf/sirf-usp.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * arch/arm/mach-prima2/include/mach/sirfsoc_usp.h
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#ifndef _SIRF_USP_H
-#define _SIRF_USP_H
-
-/* USP Registers */
-#define USP_MODE1		0x00
-#define USP_MODE2		0x04
-#define USP_TX_FRAME_CTRL	0x08
-#define USP_RX_FRAME_CTRL	0x0C
-#define USP_TX_RX_ENABLE	0x10
-#define USP_INT_ENABLE		0x14
-#define USP_INT_STATUS		0x18
-#define USP_PIN_IO_DATA		0x1C
-#define USP_RISC_DSP_MODE	0x20
-#define USP_AYSNC_PARAM_REG	0x24
-#define USP_IRDA_X_MODE_DIV	0x28
-#define USP_SM_CFG		0x2C
-#define USP_TX_DMA_IO_CTRL	0x100
-#define USP_TX_DMA_IO_LEN	0x104
-#define USP_TX_FIFO_CTRL	0x108
-#define USP_TX_FIFO_LEVEL_CHK	0x10C
-#define USP_TX_FIFO_OP		0x110
-#define USP_TX_FIFO_STATUS	0x114
-#define USP_TX_FIFO_DATA	0x118
-#define USP_RX_DMA_IO_CTRL	0x120
-#define USP_RX_DMA_IO_LEN	0x124
-#define USP_RX_FIFO_CTRL	0x128
-#define USP_RX_FIFO_LEVEL_CHK	0x12C
-#define USP_RX_FIFO_OP		0x130
-#define USP_RX_FIFO_STATUS	0x134
-#define USP_RX_FIFO_DATA	0x138
-
-/* USP MODE register-1 */
-#define USP_SYNC_MODE			0x00000001
-#define USP_CLOCK_MODE_SLAVE		0x00000002
-#define USP_LOOP_BACK_EN		0x00000004
-#define USP_HPSIR_EN			0x00000008
-#define USP_ENDIAN_CTRL_LSBF		0x00000010
-#define USP_EN				0x00000020
-#define USP_RXD_ACT_EDGE_FALLING	0x00000040
-#define USP_TXD_ACT_EDGE_FALLING	0x00000080
-#define USP_RFS_ACT_LEVEL_LOGIC1	0x00000100
-#define USP_TFS_ACT_LEVEL_LOGIC1	0x00000200
-#define USP_SCLK_IDLE_MODE_TOGGLE	0x00000400
-#define USP_SCLK_IDLE_LEVEL_LOGIC1	0x00000800
-#define USP_SCLK_PIN_MODE_IO	0x00001000
-#define USP_RFS_PIN_MODE_IO	0x00002000
-#define USP_TFS_PIN_MODE_IO	0x00004000
-#define USP_RXD_PIN_MODE_IO	0x00008000
-#define USP_TXD_PIN_MODE_IO	0x00010000
-#define USP_SCLK_IO_MODE_INPUT	0x00020000
-#define USP_RFS_IO_MODE_INPUT	0x00040000
-#define USP_TFS_IO_MODE_INPUT	0x00080000
-#define USP_RXD_IO_MODE_INPUT	0x00100000
-#define USP_TXD_IO_MODE_INPUT	0x00200000
-#define USP_IRDA_WIDTH_DIV_MASK	0x3FC00000
-#define USP_IRDA_WIDTH_DIV_OFFSET	0
-#define USP_IRDA_IDLE_LEVEL_HIGH	0x40000000
-#define USP_TX_UFLOW_REPEAT_ZERO	0x80000000
-#define USP_TX_ENDIAN_MODE		0x00000020
-#define USP_RX_ENDIAN_MODE		0x00000020
-
-/* USP Mode Register-2 */
-#define USP_RXD_DELAY_LEN_MASK		0x000000FF
-#define USP_RXD_DELAY_LEN_OFFSET	0
-
-#define USP_TXD_DELAY_LEN_MASK		0x0000FF00
-#define USP_TXD_DELAY_LEN_OFFSET	8
-
-#define USP_ENA_CTRL_MODE		0x00010000
-#define USP_FRAME_CTRL_MODE		0x00020000
-#define USP_TFS_SOURCE_MODE             0x00040000
-#define USP_TFS_MS_MODE                 0x00080000
-#define USP_CLK_DIVISOR_MASK		0x7FE00000
-#define USP_CLK_DIVISOR_OFFSET		21
-
-#define USP_TFS_CLK_SLAVE_MODE		(1<<20)
-#define USP_RFS_CLK_SLAVE_MODE		(1<<19)
-
-#define USP_IRDA_DATA_WIDTH		0x80000000
-
-/* USP Transmit Frame Control Register */
-
-#define USP_TXC_DATA_LEN_MASK		0x000000FF
-#define USP_TXC_DATA_LEN_OFFSET		0
-
-#define USP_TXC_SYNC_LEN_MASK		0x0000FF00
-#define USP_TXC_SYNC_LEN_OFFSET		8
-
-#define USP_TXC_FRAME_LEN_MASK		0x00FF0000
-#define USP_TXC_FRAME_LEN_OFFSET	16
-
-#define USP_TXC_SHIFTER_LEN_MASK	0x1F000000
-#define USP_TXC_SHIFTER_LEN_OFFSET	24
-
-#define USP_TXC_SLAVE_CLK_SAMPLE	0x20000000
-
-#define USP_TXC_CLK_DIVISOR_MASK	0xC0000000
-#define USP_TXC_CLK_DIVISOR_OFFSET	30
-
-/* USP Receive Frame Control Register */
-
-#define USP_RXC_DATA_LEN_MASK		0x000000FF
-#define USP_RXC_DATA_LEN_OFFSET		0
-
-#define USP_RXC_FRAME_LEN_MASK		0x0000FF00
-#define USP_RXC_FRAME_LEN_OFFSET	8
-
-#define USP_RXC_SHIFTER_LEN_MASK	0x001F0000
-#define USP_RXC_SHIFTER_LEN_OFFSET	16
-
-#define USP_START_EDGE_MODE	0x00800000
-#define USP_I2S_SYNC_CHG	0x00200000
-
-#define USP_RXC_CLK_DIVISOR_MASK	0x0F000000
-#define USP_RXC_CLK_DIVISOR_OFFSET	24
-#define USP_SINGLE_SYNC_MODE		0x00400000
-
-/* Tx - RX Enable Register */
-
-#define USP_RX_ENA		0x00000001
-#define USP_TX_ENA		0x00000002
-
-/* USP Interrupt Enable and status Register */
-#define USP_RX_DONE_INT			0x00000001
-#define USP_TX_DONE_INT			0x00000002
-#define USP_RX_OFLOW_INT		0x00000004
-#define USP_TX_UFLOW_INT		0x00000008
-#define USP_RX_IO_DMA_INT		0x00000010
-#define USP_TX_IO_DMA_INT		0x00000020
-#define USP_RXFIFO_FULL_INT		0x00000040
-#define USP_TXFIFO_EMPTY_INT		0x00000080
-#define USP_RXFIFO_THD_INT		0x00000100
-#define USP_TXFIFO_THD_INT		0x00000200
-#define USP_UART_FRM_ERR_INT		0x00000400
-#define USP_RX_TIMEOUT_INT		0x00000800
-#define USP_TX_ALLOUT_INT		0x00001000
-#define USP_RXD_BREAK_INT		0x00008000
-
-/* All possible TX interruots */
-#define USP_TX_INTERRUPT		(USP_TX_DONE_INT|USP_TX_UFLOW_INT|\
-					USP_TX_IO_DMA_INT|\
-					USP_TXFIFO_EMPTY_INT|\
-					USP_TXFIFO_THD_INT)
-/* All possible RX interruots */
-#define USP_RX_INTERRUPT		(USP_RX_DONE_INT|USP_RX_OFLOW_INT|\
-					USP_RX_IO_DMA_INT|\
-					USP_RXFIFO_FULL_INT|\
-					USP_RXFIFO_THD_INT|\
-					USP_RX_TIMEOUT_INT)
-
-#define USP_INT_ALL        0x1FFF
-
-/* USP Pin I/O Data Register */
-
-#define USP_RFS_PIN_VALUE_MASK	0x00000001
-#define USP_TFS_PIN_VALUE_MASK	0x00000002
-#define USP_RXD_PIN_VALUE_MASK	0x00000004
-#define USP_TXD_PIN_VALUE_MASK	0x00000008
-#define USP_SCLK_PIN_VALUE_MASK	0x00000010
-
-/* USP RISC/DSP Mode Register */
-#define USP_RISC_DSP_SEL	0x00000001
-
-/* USP ASYNC PARAMETER Register*/
-
-#define USP_ASYNC_TIMEOUT_MASK	0x0000FFFF
-#define USP_ASYNC_TIMEOUT_OFFSET	0
-#define USP_ASYNC_TIMEOUT(x)	(((x)&USP_ASYNC_TIMEOUT_MASK) \
-				<<USP_ASYNC_TIMEOUT_OFFSET)
-
-#define USP_ASYNC_DIV2_MASK		0x003F0000
-#define USP_ASYNC_DIV2_OFFSET		16
-
-/* USP TX DMA I/O MODE Register */
-#define USP_TX_MODE_IO			0x00000001
-
-/* USP TX DMA I/O Length Register */
-#define USP_TX_DATA_LEN_MASK		0xFFFFFFFF
-#define USP_TX_DATA_LEN_OFFSET		0
-
-/* USP TX FIFO Control Register */
-#define USP_TX_FIFO_WIDTH_MASK		0x00000003
-#define USP_TX_FIFO_WIDTH_OFFSET	0
-
-#define USP_TX_FIFO_THD_MASK		0x000001FC
-#define USP_TX_FIFO_THD_OFFSET		2
-
-/* USP TX FIFO Level Check Register */
-#define USP_TX_FIFO_LEVEL_CHECK_MASK	0x1F
-#define USP_TX_FIFO_SC_OFFSET	0
-#define USP_TX_FIFO_LC_OFFSET	10
-#define USP_TX_FIFO_HC_OFFSET	20
-
-#define TX_FIFO_SC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
-				<< USP_TX_FIFO_SC_OFFSET)
-#define TX_FIFO_LC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
-				<< USP_TX_FIFO_LC_OFFSET)
-#define TX_FIFO_HC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
-				<< USP_TX_FIFO_HC_OFFSET)
-
-/* USP TX FIFO Operation Register */
-#define USP_TX_FIFO_RESET		0x00000001
-#define USP_TX_FIFO_START		0x00000002
-
-/* USP TX FIFO Status Register */
-#define USP_TX_FIFO_LEVEL_MASK		0x0000007F
-#define USP_TX_FIFO_LEVEL_OFFSET	0
-
-#define USP_TX_FIFO_FULL		0x00000080
-#define USP_TX_FIFO_EMPTY		0x00000100
-
-/* USP TX FIFO Data Register */
-#define USP_TX_FIFO_DATA_MASK		0xFFFFFFFF
-#define USP_TX_FIFO_DATA_OFFSET		0
-
-/* USP RX DMA I/O MODE Register */
-#define USP_RX_MODE_IO			0x00000001
-#define USP_RX_DMA_FLUSH		0x00000004
-
-/* USP RX DMA I/O Length Register */
-#define USP_RX_DATA_LEN_MASK		0xFFFFFFFF
-#define USP_RX_DATA_LEN_OFFSET		0
-
-/* USP RX FIFO Control Register */
-#define USP_RX_FIFO_WIDTH_MASK		0x00000003
-#define USP_RX_FIFO_WIDTH_OFFSET	0
-
-#define USP_RX_FIFO_THD_MASK		0x000001FC
-#define USP_RX_FIFO_THD_OFFSET		2
-
-/* USP RX FIFO Level Check Register */
-
-#define USP_RX_FIFO_LEVEL_CHECK_MASK	0x1F
-#define USP_RX_FIFO_SC_OFFSET	0
-#define USP_RX_FIFO_LC_OFFSET	10
-#define USP_RX_FIFO_HC_OFFSET	20
-
-#define RX_FIFO_SC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
-				<< USP_RX_FIFO_SC_OFFSET)
-#define RX_FIFO_LC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
-				<< USP_RX_FIFO_LC_OFFSET)
-#define RX_FIFO_HC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
-				<< USP_RX_FIFO_HC_OFFSET)
-
-/* USP RX FIFO Operation Register */
-#define USP_RX_FIFO_RESET		0x00000001
-#define USP_RX_FIFO_START		0x00000002
-
-/* USP RX FIFO Status Register */
-
-#define USP_RX_FIFO_LEVEL_MASK		0x0000007F
-#define USP_RX_FIFO_LEVEL_OFFSET	0
-
-#define USP_RX_FIFO_FULL		0x00000080
-#define USP_RX_FIFO_EMPTY		0x00000100
-
-/* USP RX FIFO Data Register */
-
-#define USP_RX_FIFO_DATA_MASK		0xFFFFFFFF
-#define USP_RX_FIFO_DATA_OFFSET		0
-
-/*
- * When rx thd irq occur, sender just disable tx empty irq,
- * Remaining data in tx fifo wil also be sent out.
- */
-#define USP_FIFO_SIZE			128
-#define USP_TX_FIFO_THRESHOLD		(USP_FIFO_SIZE/2)
-#define USP_RX_FIFO_THRESHOLD		(USP_FIFO_SIZE/2)
-
-/* FIFO_WIDTH for the USP_TX_FIFO_CTRL and USP_RX_FIFO_CTRL registers */
-#define USP_FIFO_WIDTH_BYTE  0x00
-#define USP_FIFO_WIDTH_WORD  0x01
-#define USP_FIFO_WIDTH_DWORD 0x02
-
-#define USP_ASYNC_DIV2          16
-
-#define USP_PLUGOUT_RETRY_CNT	2
-
-#define USP_TX_RX_FIFO_WIDTH_DWORD    2
-
-#define SIRF_USP_DIV_MCLK	0
-
-#define SIRF_USP_I2S_TFS_SYNC	0
-#define SIRF_USP_I2S_RFS_SYNC	1
-#endif
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 760523382f3c56dbd7f2b6d898309f83a0cb1534..159bf88b9f8cdfe2e496b28a4b2cca9c54492fa4 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <sound/soc.h>
+#include <linux/bitops.h>
 
 #define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
 static inline int _soc_component_ret(struct snd_soc_component *component,
@@ -34,6 +35,18 @@ static inline int _soc_component_ret(struct snd_soc_component *component,
 	return ret;
 }
 
+static inline int soc_component_field_shift(struct snd_soc_component *component,
+					    unsigned int mask)
+{
+	if (!mask) {
+		dev_err(component->dev,	"ASoC: error field mask is zero for %s\n",
+			component->name);
+		return 0;
+	}
+
+	return (ffs(mask) - 1);
+}
+
 /*
  * We might want to check substream by using list.
  * In such case, we can update these macros.
@@ -839,6 +852,47 @@ int snd_soc_component_update_bits_async(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
 
+/**
+ * snd_soc_component_read_field() - Read register field value
+ * @component: Component to read from
+ * @reg: Register to read
+ * @mask: mask of the register field
+ *
+ * Return: read value of register field.
+ */
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
+					  unsigned int reg, unsigned int mask)
+{
+	unsigned int val;
+
+	val = snd_soc_component_read(component, reg);
+
+	val = (val & mask) >> soc_component_field_shift(component, mask);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_read_field);
+
+/**
+ * snd_soc_component_write_field() - write to register field
+ * @component: Component to write to
+ * @reg: Register to write
+ * @mask: mask of the register field to update
+ * @val: value of the field to write
+ *
+ * Return: 1 for change, otherwise 0.
+ */
+int snd_soc_component_write_field(struct snd_soc_component *component,
+				  unsigned int reg, unsigned int mask,
+				  unsigned int val)
+{
+
+	val = (val << soc_component_field_shift(component, mask)) & mask;
+
+	return snd_soc_component_update_bits(component, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_write_field);
+
 /**
  * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed
  * @component: Component for which to wait
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 2b75d0139e478c6f1feaff88601ecb15933c6221..b005f9eadd71919ccc49c8c2eca836250fd8a6fb 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2528,9 +2528,20 @@ static struct snd_soc_dapm_widget *dapm_find_widget(
 {
 	struct snd_soc_dapm_widget *w;
 	struct snd_soc_dapm_widget *fallback = NULL;
+	char prefixed_pin[80];
+	const char *pin_name;
+	const char *prefix = soc_dapm_prefix(dapm);
+
+	if (prefix) {
+		snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s",
+			 prefix, pin);
+		pin_name = prefixed_pin;
+	} else {
+		pin_name = pin;
+	}
 
 	for_each_card_widgets(dapm->card, w) {
-		if (!strcmp(w->name, pin)) {
+		if (!strcmp(w->name, pin_name)) {
 			if (w->dapm == dapm)
 				return w;
 			else
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index ee51dc7fd8937b0d0c886f3b2f19b680db04b5f1..14d85ca1e43572ff8818d4e40150cece22fed997 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -203,6 +203,34 @@ static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
 }
 #endif
 
+/* Set FE's runtime_update state; the state is protected via PCM stream lock
+ * for avoiding the race with trigger callback.
+ * If the state is unset and a trigger is pending while the previous operation,
+ * process the pending trigger action here.
+ */
+static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
+static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
+				     int stream, enum snd_soc_dpcm_update state)
+{
+	struct snd_pcm_substream *substream =
+		snd_soc_dpcm_get_substream(fe, stream);
+
+	snd_pcm_stream_lock_irq(substream);
+	if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
+		dpcm_fe_dai_do_trigger(substream,
+				       fe->dpcm[stream].trigger_pending - 1);
+		fe->dpcm[stream].trigger_pending = 0;
+	}
+	fe->dpcm[stream].runtime_update = state;
+	snd_pcm_stream_unlock_irq(substream);
+}
+
+static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
+				     int stream, enum snd_soc_dpcm_update state)
+{
+	be->dpcm[stream].runtime_update = state;
+}
+
 /**
  * snd_soc_runtime_action() - Increment/Decrement active count for
  * PCM runtime components
@@ -301,59 +329,46 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
 	return 0;
 }
 
+static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
+				   struct snd_pcm_hw_params *params)
+{
+	if (params) {
+		dai->rate	 = params_rate(params);
+		dai->channels	 = params_channels(params);
+		dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
+	} else {
+		dai->rate	 = 0;
+		dai->channels	 = 0;
+		dai->sample_bits = 0;
+	}
+}
+
 static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
 					struct snd_soc_dai *soc_dai)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	int ret;
 
-	if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
-				rtd->dai_link->symmetric_rates)) {
-		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
-				soc_dai->rate);
-
-		ret = snd_pcm_hw_constraint_single(substream->runtime,
-						SNDRV_PCM_HW_PARAM_RATE,
-						soc_dai->rate);
-		if (ret < 0) {
-			dev_err(soc_dai->dev,
-				"ASoC: Unable to apply rate constraint: %d\n",
-				ret);
-			return ret;
-		}
-	}
-
-	if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
-				rtd->dai_link->symmetric_channels)) {
-		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
-				soc_dai->channels);
-
-		ret = snd_pcm_hw_constraint_single(substream->runtime,
-						SNDRV_PCM_HW_PARAM_CHANNELS,
-						soc_dai->channels);
-		if (ret < 0) {
-			dev_err(soc_dai->dev,
-				"ASoC: Unable to apply channel symmetry constraint: %d\n",
-				ret);
-			return ret;
-		}
-	}
-
-	if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
-				rtd->dai_link->symmetric_samplebits)) {
-		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
-				soc_dai->sample_bits);
-
-		ret = snd_pcm_hw_constraint_single(substream->runtime,
-						SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-						soc_dai->sample_bits);
-		if (ret < 0) {
-			dev_err(soc_dai->dev,
-				"ASoC: Unable to apply sample bits symmetry constraint: %d\n",
-				ret);
-			return ret;
-		}
-	}
+#define __soc_pcm_apply_symmetry(name, NAME)				\
+	if (soc_dai->name && (soc_dai->driver->symmetric_##name ||	\
+			      rtd->dai_link->symmetric_##name)) {	\
+		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
+			#name, soc_dai->name);				\
+									\
+		ret = snd_pcm_hw_constraint_single(substream->runtime,	\
+						   SNDRV_PCM_HW_PARAM_##NAME,\
+						   soc_dai->name);	\
+		if (ret < 0) {						\
+			dev_err(soc_dai->dev,				\
+				"ASoC: Unable to apply %s constraint: %d\n",\
+				#name, ret);				\
+			return ret;					\
+		}							\
+	}
+
+	__soc_pcm_apply_symmetry(rate,		RATE);
+	__soc_pcm_apply_symmetry(channels,	CHANNELS);
+	__soc_pcm_apply_symmetry(sample_bits,	SAMPLE_BITS);
 
 	return 0;
 }
@@ -362,61 +377,30 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai d;
 	struct snd_soc_dai *dai;
 	struct snd_soc_dai *cpu_dai;
-	unsigned int rate, channels, sample_bits, symmetry, i;
-
-	rate = params_rate(params);
-	channels = params_channels(params);
-	sample_bits = snd_pcm_format_physical_width(params_format(params));
-
-	/* reject unmatched parameters when applying symmetry */
-	symmetry = rtd->dai_link->symmetric_rates;
-
-	for_each_rtd_cpu_dais(rtd, i, dai)
-		symmetry |= dai->driver->symmetric_rates;
-
-	if (symmetry) {
-		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-			if (cpu_dai->rate && cpu_dai->rate != rate) {
-				dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
-					cpu_dai->rate, rate);
-				return -EINVAL;
-			}
-		}
-	}
-
-	symmetry = rtd->dai_link->symmetric_channels;
+	unsigned int symmetry, i;
 
-	for_each_rtd_dais(rtd, i, dai)
-		symmetry |= dai->driver->symmetric_channels;
-
-	if (symmetry) {
-		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-			if (cpu_dai->channels &&
-			    cpu_dai->channels != channels) {
-				dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
-					cpu_dai->channels, channels);
-				return -EINVAL;
+	soc_pcm_set_dai_params(&d, params);
+
+#define __soc_pcm_params_symmetry(name)					\
+	symmetry = rtd->dai_link->symmetric_##name;			\
+	for_each_rtd_dais(rtd, i, dai)					\
+		symmetry |= dai->driver->symmetric_##name;		\
+									\
+	if (symmetry)							\
+		for_each_rtd_cpu_dais(rtd, i, cpu_dai)			\
+			if (cpu_dai->name && cpu_dai->name != d.name) {	\
+				dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \
+					#name, cpu_dai->name, d.name);	\
+				return -EINVAL;				\
 			}
-		}
-	}
 
-	symmetry = rtd->dai_link->symmetric_samplebits;
-
-	for_each_rtd_dais(rtd, i, dai)
-		symmetry |= dai->driver->symmetric_samplebits;
-
-	if (symmetry) {
-		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-			if (cpu_dai->sample_bits &&
-			    cpu_dai->sample_bits != sample_bits) {
-				dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
-					cpu_dai->sample_bits, sample_bits);
-				return -EINVAL;
-			}
-		}
-	}
+	/* reject unmatched parameters when applying symmetry */
+	__soc_pcm_params_symmetry(rate);
+	__soc_pcm_params_symmetry(channels);
+	__soc_pcm_params_symmetry(sample_bits);
 
 	return 0;
 }
@@ -428,15 +412,15 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
 	struct snd_soc_dai *dai;
 	unsigned int symmetry, i;
 
-	symmetry = link->symmetric_rates ||
+	symmetry = link->symmetric_rate ||
 		link->symmetric_channels ||
-		link->symmetric_samplebits;
+		link->symmetric_sample_bits;
 
 	for_each_rtd_dais(rtd, i, dai)
 		symmetry = symmetry ||
-			dai->driver->symmetric_rates ||
+			dai->driver->symmetric_rate ||
 			dai->driver->symmetric_channels ||
-			dai->driver->symmetric_samplebits;
+			dai->driver->symmetric_sample_bits;
 
 	return symmetry;
 }
@@ -489,6 +473,42 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
 	soc_pcm_set_msb(substream, cpu_bits);
 }
 
+static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
+{
+	hw->rates		= UINT_MAX;
+	hw->rate_min		= 0;
+	hw->rate_max		= UINT_MAX;
+	hw->channels_min	= 0;
+	hw->channels_max	= UINT_MAX;
+	hw->formats		= ULLONG_MAX;
+}
+
+static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
+				   struct snd_soc_pcm_stream *p)
+{
+	hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
+
+	/* setup hw->rate_min/max via hw->rates first */
+	snd_pcm_hw_limit_rates(hw);
+
+	/* update hw->rate_min/max by snd_soc_pcm_stream */
+	hw->rate_min = max(hw->rate_min, p->rate_min);
+	hw->rate_max = min_not_zero(hw->rate_max, p->rate_max);
+}
+
+static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
+				   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)
+{
+	hw->formats &= p->formats;
+}
+
 /**
  * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
  * @rtd: ASoC PCM runtime
@@ -505,14 +525,11 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 	struct snd_soc_dai *cpu_dai;
 	struct snd_soc_pcm_stream *codec_stream;
 	struct snd_soc_pcm_stream *cpu_stream;
-	unsigned int chan_min = 0, chan_max = UINT_MAX;
 	unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
-	unsigned int rate_min = 0, rate_max = UINT_MAX;
-	unsigned int cpu_rate_min = 0, cpu_rate_max = UINT_MAX;
-	unsigned int rates = UINT_MAX, cpu_rates = UINT_MAX;
-	u64 formats = ULLONG_MAX;
 	int i;
 
+	soc_pcm_hw_init(hw);
+
 	/* first calculate min/max only for CPUs in the DAI link */
 	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 
@@ -527,14 +544,12 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 
 		cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
 
-		cpu_chan_min = max(cpu_chan_min, cpu_stream->channels_min);
-		cpu_chan_max = min(cpu_chan_max, cpu_stream->channels_max);
-		cpu_rate_min = max(cpu_rate_min, cpu_stream->rate_min);
-		cpu_rate_max = min_not_zero(cpu_rate_max, cpu_stream->rate_max);
-		formats &= cpu_stream->formats;
-		cpu_rates = snd_pcm_rate_mask_intersect(cpu_stream->rates,
-							cpu_rates);
+		soc_pcm_hw_update_chan(hw, cpu_stream);
+		soc_pcm_hw_update_rate(hw, cpu_stream);
+		soc_pcm_hw_update_format(hw, cpu_stream);
 	}
+	cpu_chan_min = hw->channels_min;
+	cpu_chan_max = hw->channels_max;
 
 	/* second calculate min/max only for CODECs in the DAI link */
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
@@ -550,16 +565,13 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 
 		codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
 
-		chan_min = max(chan_min, codec_stream->channels_min);
-		chan_max = min(chan_max, codec_stream->channels_max);
-		rate_min = max(rate_min, codec_stream->rate_min);
-		rate_max = min_not_zero(rate_max, codec_stream->rate_max);
-		formats &= codec_stream->formats;
-		rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
+		soc_pcm_hw_update_chan(hw, codec_stream);
+		soc_pcm_hw_update_rate(hw, codec_stream);
+		soc_pcm_hw_update_format(hw, codec_stream);
 	}
 
 	/* Verify both a valid CPU DAI and a valid CODEC DAI were found */
-	if (!chan_min || !cpu_chan_min)
+	if (!hw->channels_min)
 		return -EINVAL;
 
 	/*
@@ -568,23 +580,10 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
 	 * channel allocation be fixed up later
 	 */
 	if (rtd->num_codecs > 1) {
-		chan_min = cpu_chan_min;
-		chan_max = cpu_chan_max;
+		hw->channels_min = cpu_chan_min;
+		hw->channels_max = cpu_chan_max;
 	}
 
-	/* finally find a intersection between CODECs and CPUs */
-	hw->channels_min = max(chan_min, cpu_chan_min);
-	hw->channels_max = min(chan_max, cpu_chan_max);
-	hw->formats = formats;
-	hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_rates);
-
-	snd_pcm_hw_limit_rates(hw);
-
-	hw->rate_min = max(hw->rate_min, cpu_rate_min);
-	hw->rate_min = max(hw->rate_min, rate_min);
-	hw->rate_max = min_not_zero(hw->rate_max, cpu_rate_max);
-	hw->rate_max = min_not_zero(hw->rate_max, rate_max);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
@@ -870,11 +869,8 @@ static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
 	for_each_rtd_dais(rtd, i, dai) {
 		int active = snd_soc_dai_stream_active(dai, substream->stream);
 
-		if (snd_soc_dai_active(dai) == 1) {
-			dai->rate = 0;
-			dai->channels = 0;
-			dai->sample_bits = 0;
-		}
+		if (snd_soc_dai_active(dai) == 1)
+			soc_pcm_set_dai_params(dai, NULL);
 
 		if (active == 1)
 			snd_soc_dai_digital_mute(dai, 1, substream->stream);
@@ -971,11 +967,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		if(ret < 0)
 			goto out;
 
-		codec_dai->rate = params_rate(&codec_params);
-		codec_dai->channels = params_channels(&codec_params);
-		codec_dai->sample_bits = snd_pcm_format_physical_width(
-						params_format(&codec_params));
-
+		soc_pcm_set_dai_params(codec_dai, &codec_params);
 		snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
 	}
 
@@ -992,11 +984,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 			goto out;
 
 		/* store the parameters for each DAI */
-		cpu_dai->rate = params_rate(params);
-		cpu_dai->channels = params_channels(params);
-		cpu_dai->sample_bits =
-			snd_pcm_format_physical_width(params_format(params));
-
+		soc_pcm_set_dai_params(cpu_dai, params);
 		snd_soc_dapm_update_dai(substream, params, cpu_dai);
 	}
 
@@ -1335,7 +1323,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
 			stream ? "capture" : "playback",
 			dpcm->be->dai_link->name, fe->dai_link->name);
 		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
-		dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+		dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
 		prune++;
 	}
 
@@ -1371,8 +1359,8 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
 		/* is there a valid BE rtd for this widget */
 		be = dpcm_get_be(card, widget, stream);
 		if (!be) {
-			dev_err(fe->dev, "ASoC: no BE found for %s\n",
-					widget->name);
+			dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
+				widget->name);
 			continue;
 		}
 
@@ -1390,7 +1378,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
 			continue;
 
 		/* new */
-		be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+		dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE);
 		new++;
 	}
 
@@ -1418,8 +1406,7 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
 
 	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
 	for_each_dpcm_be(fe, stream, dpcm)
-		dpcm->be->dpcm[stream].runtime_update =
-						SND_SOC_DPCM_UPDATE_NO;
+		dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO);
 	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
 }
 
@@ -1542,21 +1529,21 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
 static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
 				 struct snd_soc_pcm_stream *stream)
 {
-	runtime->hw.rate_min = stream->rate_min;
-	runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
-	runtime->hw.channels_min = stream->channels_min;
-	runtime->hw.channels_max = stream->channels_max;
+	struct snd_pcm_hardware *hw = &runtime->hw;
+
+	soc_pcm_hw_update_rate(hw, stream);
+	soc_pcm_hw_update_chan(hw, stream);
 	if (runtime->hw.formats)
 		runtime->hw.formats &= stream->formats;
 	else
 		runtime->hw.formats = stream->formats;
-	runtime->hw.rates = stream->rates;
 }
 
 static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
-				      u64 *formats)
+				      struct snd_pcm_runtime *runtime)
 {
 	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+	struct snd_pcm_hardware *hw = &runtime->hw;
 	struct snd_soc_dpcm *dpcm;
 	struct snd_soc_dai *dai;
 	int stream = substream->stream;
@@ -1584,16 +1571,16 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
 
 			codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
 
-			*formats &= codec_stream->formats;
+			soc_pcm_hw_update_format(hw, codec_stream);
 		}
 	}
 }
 
 static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
-				    unsigned int *channels_min,
-				    unsigned int *channels_max)
+				    struct snd_pcm_runtime *runtime)
 {
 	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+	struct snd_pcm_hardware *hw = &runtime->hw;
 	struct snd_soc_dpcm *dpcm;
 	int stream = substream->stream;
 
@@ -1622,10 +1609,7 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
 
 			cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
 
-			*channels_min = max(*channels_min,
-					    cpu_stream->channels_min);
-			*channels_max = min(*channels_max,
-					    cpu_stream->channels_max);
+			soc_pcm_hw_update_chan(hw, cpu_stream);
 		}
 
 		/*
@@ -1635,20 +1619,16 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
 		if (be->num_codecs == 1) {
 			codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
 
-			*channels_min = max(*channels_min,
-					    codec_stream->channels_min);
-			*channels_max = min(*channels_max,
-					    codec_stream->channels_max);
+			soc_pcm_hw_update_chan(hw, codec_stream);
 		}
 	}
 }
 
 static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
-				    unsigned int *rates,
-				    unsigned int *rate_min,
-				    unsigned int *rate_max)
+				    struct snd_pcm_runtime *runtime)
 {
 	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+	struct snd_pcm_hardware *hw = &runtime->hw;
 	struct snd_soc_dpcm *dpcm;
 	int stream = substream->stream;
 
@@ -1676,9 +1656,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
 
 			pcm = snd_soc_dai_get_pcm_stream(dai, stream);
 
-			*rate_min = max(*rate_min, pcm->rate_min);
-			*rate_max = min_not_zero(*rate_max, pcm->rate_max);
-			*rates = snd_pcm_rate_mask_intersect(*rates, pcm->rates);
+			soc_pcm_hw_update_rate(hw, pcm);
 		}
 	}
 }
@@ -1686,10 +1664,13 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
 static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_pcm_hardware *hw = &runtime->hw;
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_dai *cpu_dai;
 	int i;
 
+	soc_pcm_hw_init(hw);
+
 	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 		/*
 		 * Skip CPUs which don't support the current stream
@@ -1703,34 +1684,9 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
 						   substream->stream));
 	}
 
-	dpcm_runtime_merge_format(substream, &runtime->hw.formats);
-	dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
-				&runtime->hw.channels_max);
-	dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
-				&runtime->hw.rate_min, &runtime->hw.rate_max);
-}
-
-static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
-
-/* Set FE's runtime_update state; the state is protected via PCM stream lock
- * for avoiding the race with trigger callback.
- * If the state is unset and a trigger is pending while the previous operation,
- * process the pending trigger action here.
- */
-static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
-				     int stream, enum snd_soc_dpcm_update state)
-{
-	struct snd_pcm_substream *substream =
-		snd_soc_dpcm_get_substream(fe, stream);
-
-	snd_pcm_stream_lock_irq(substream);
-	if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
-		dpcm_fe_dai_do_trigger(substream,
-				       fe->dpcm[stream].trigger_pending - 1);
-		fe->dpcm[stream].trigger_pending = 0;
-	}
-	fe->dpcm[stream].runtime_update = state;
-	snd_pcm_stream_unlock_irq(substream);
+	dpcm_runtime_merge_format(substream, runtime);
+	dpcm_runtime_merge_chan(substream, runtime);
+	dpcm_runtime_merge_rate(substream, runtime);
 }
 
 static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
@@ -1791,7 +1747,6 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
 static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
 {
 	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
-	struct snd_pcm_runtime *runtime = fe_substream->runtime;
 	int stream = fe_substream->stream, ret = 0;
 
 	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
@@ -1814,7 +1769,6 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
 
 	dpcm_set_fe_runtime(fe_substream);
-	snd_pcm_limit_hw_rates(runtime);
 
 	ret = dpcm_apply_symmetry(fe_substream, stream);
 	if (ret < 0)
@@ -2432,7 +2386,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
 		snd_soc_dpcm_get_substream(fe, stream);
 	struct snd_soc_dpcm *dpcm;
 	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
-	int ret;
+	int ret = 0;
 	unsigned long flags;
 
 	dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
@@ -2440,8 +2394,13 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
 
 	/* Only start the BE if the FE is ready */
 	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
-		fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
-		return -EINVAL;
+		fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
+		ret = -EINVAL;
+		dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
+			fe->dai_link->name, fe->dpcm[stream].state);
+		ret = -EINVAL;
+		goto disconnect;
+	}
 
 	/* startup must always be called for new BEs */
 	ret = dpcm_be_dai_startup(fe, stream);
@@ -2502,12 +2461,18 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
 close:
 	dpcm_be_dai_shutdown(fe, stream);
 disconnect:
-	/* disconnect any closed BEs */
+	/* disconnect any pending BEs */
 	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
 	for_each_dpcm_be(fe, stream, dpcm) {
 		struct snd_soc_pcm_runtime *be = dpcm->be;
-		if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
-			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+		/* is this op for this BE ? */
+		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+			continue;
+
+		if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
+			be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW)
+				dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
 	}
 	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
 
@@ -2671,15 +2636,11 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
 	return ret;
 }
 
-/* create a new pcm */
-int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
+				    int *playback, int *capture)
 {
 	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai;
-	struct snd_soc_component *component;
-	struct snd_pcm *pcm;
-	char new_name[64];
-	int ret = 0, playback = 0, capture = 0;
 	int stream;
 	int i;
 
@@ -2695,12 +2656,11 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
 			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
-					playback = 1;
+					*playback = 1;
 					break;
 				}
 			}
-
-			if (!playback) {
+			if (!*playback) {
 				dev_err(rtd->card->dev,
 					"No CPU DAIs support playback for stream %s\n",
 					rtd->dai_link->stream_name);
@@ -2712,12 +2672,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
 			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
-					capture = 1;
+					*capture = 1;
 					break;
 				}
 			}
 
-			if (!capture) {
+			if (!*capture) {
 				dev_err(rtd->card->dev,
 					"No CPU DAIs support capture for stream %s\n",
 					rtd->dai_link->stream_name);
@@ -2744,36 +2704,46 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
 			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
 			    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
-				playback = 1;
+				*playback = 1;
 			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
 			    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
-				capture = 1;
+				*capture = 1;
 		}
 	}
 
 	if (rtd->dai_link->playback_only) {
-		playback = 1;
-		capture = 0;
+		*playback = 1;
+		*capture = 0;
 	}
 
 	if (rtd->dai_link->capture_only) {
-		playback = 0;
-		capture = 1;
+		*playback = 0;
+		*capture = 1;
 	}
 
+	return 0;
+}
+
+static int soc_create_pcm(struct snd_pcm **pcm,
+			  struct snd_soc_pcm_runtime *rtd,
+			  int playback, int capture, int num)
+{
+	char new_name[64];
+	int ret;
+
 	/* create the PCM */
 	if (rtd->dai_link->params) {
 		snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
 			 rtd->dai_link->stream_name);
 
 		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
-					   playback, capture, &pcm);
+					   playback, capture, pcm);
 	} else if (rtd->dai_link->no_pcm) {
 		snprintf(new_name, sizeof(new_name), "(%s)",
 			rtd->dai_link->stream_name);
 
 		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
-				playback, capture, &pcm);
+				playback, capture, pcm);
 	} else {
 		if (rtd->dai_link->dynamic)
 			snprintf(new_name, sizeof(new_name), "%s (*)",
@@ -2785,7 +2755,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 				"multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
 
 		ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
-			capture, &pcm);
+			capture, pcm);
 	}
 	if (ret < 0) {
 		dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
@@ -2794,14 +2764,33 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 	}
 	dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
 
+	return 0;
+}
+
+/* create a new pcm */
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+	struct snd_soc_component *component;
+	struct snd_pcm *pcm;
+	int ret = 0, playback = 0, capture = 0;
+	int i;
+
+	ret = soc_get_playback_capture(rtd, &playback, &capture);
+	if (ret < 0)
+		return ret;
+
+	ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
+	if (ret < 0)
+		return ret;
+
 	/* DAPM dai link stream work */
 	if (rtd->dai_link->params)
 		rtd->close_delayed_work_func = codec2codec_close_delayed_work;
 	else
 		rtd->close_delayed_work_func = snd_soc_close_delayed_work;
 
-	pcm->nonatomic = rtd->dai_link->nonatomic;
 	rtd->pcm = pcm;
+	pcm->nonatomic = rtd->dai_link->nonatomic;
 	pcm->private_data = rtd;
 
 	if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
@@ -2854,8 +2843,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
 	ret = snd_soc_pcm_component_new(rtd);
 	if (ret < 0) {
-		dev_err(rtd->dev, "ASoC: pcm %s constructor failed for dailink %s: %d\n",
-			new_name, rtd->dai_link->name, ret);
+		dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n",
+			rtd->dai_link->name, ret);
 		return ret;
 	}
 
diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..ae3968161509cd1ca15bcacddf9070a30a391ded
--- /dev/null
+++ b/sound/soc/soc-topology-test.c
@@ -0,0 +1,843 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-topology-test.c  --  ALSA SoC Topology Kernel Unit Tests
+ *
+ * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-topology.h>
+#include <kunit/test.h>
+
+/* ===== HELPER FUNCTIONS =================================================== */
+
+/*
+ * snd_soc_component needs device to operate on (primarily for prints), create
+ * fake one, as we don't register with PCI or anything else
+ * device_driver name is used in some of the prints (fmt_single_name) so
+ * we also mock up minimal one
+ */
+static struct device *test_dev;
+
+static struct device_driver test_drv = {
+	.name = "sound-soc-topology-test-driver",
+};
+
+static int snd_soc_tplg_test_init(struct kunit *test)
+{
+	test_dev = root_device_register("sound-soc-topology-test");
+	test_dev = get_device(test_dev);
+	if (!test_dev)
+		return -ENODEV;
+
+	test_dev->driver = &test_drv;
+
+	return 0;
+}
+
+static void snd_soc_tplg_test_exit(struct kunit *test)
+{
+	put_device(test_dev);
+	root_device_unregister(test_dev);
+}
+
+/*
+ * helper struct we use when registering component, as we load topology during
+ * component probe, we need to pass struct kunit somehow to probe function, so
+ * we can report test result
+ */
+struct kunit_soc_component {
+	struct kunit *kunit;
+	int expect; /* what result we expect when loading topology */
+	struct snd_soc_component comp;
+	struct snd_soc_card card;
+	struct firmware fw;
+};
+
+static int d_probe(struct snd_soc_component *component)
+{
+	struct kunit_soc_component *kunit_comp =
+			container_of(component, struct kunit_soc_component, comp);
+	int ret;
+
+	ret = snd_soc_tplg_component_load(component, NULL, &kunit_comp->fw);
+	KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
+			    "Failed topology load");
+
+	return 0;
+}
+
+static void d_remove(struct snd_soc_component *component)
+{
+	struct kunit_soc_component *kunit_comp =
+			container_of(component, struct kunit_soc_component, comp);
+	int ret;
+
+	ret = snd_soc_tplg_component_remove(component);
+	KUNIT_EXPECT_EQ(kunit_comp->kunit, 0, ret);
+}
+
+/*
+ * ASoC minimal boiler plate
+ */
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("sound-soc-topology-test")));
+
+static struct snd_soc_dai_link kunit_dai_links[] = {
+	{
+		.name = "KUNIT Audio Port",
+		.id = 0,
+		.stream_name = "Audio Playback/Capture",
+		.nonatomic = 1,
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(dummy, dummy, platform),
+	},
+};
+
+static const struct snd_soc_component_driver test_component = {
+	.name = "sound-soc-topology-test",
+	.probe = d_probe,
+	.remove = d_remove,
+	.non_legacy_dai_naming = 1,
+};
+
+/* ===== TOPOLOGY TEMPLATES ================================================= */
+
+// Structural representation of topology which can be generated with:
+// $ touch empty
+// $ alsatplg -c empty -o empty.tplg
+// $ xxd -i empty.tplg
+
+struct tplg_tmpl_001 {
+	struct snd_soc_tplg_hdr header;
+	struct snd_soc_tplg_manifest manifest;
+} __packed;
+
+static struct tplg_tmpl_001 tplg_tmpl_empty = {
+	.header = {
+		.magic = cpu_to_le32(SND_SOC_TPLG_MAGIC),
+		.abi = cpu_to_le32(5),
+		.version = 0,
+		.type = cpu_to_le32(SND_SOC_TPLG_TYPE_MANIFEST),
+		.size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr)),
+		.vendor_type = 0,
+		.payload_size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+		.index = 0,
+		.count = cpu_to_le32(1),
+	},
+
+	.manifest = {
+		.size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+		/* rest of fields is 0 */
+	},
+};
+
+// Structural representation of topology containing SectionPCM
+
+struct tplg_tmpl_002 {
+	struct snd_soc_tplg_hdr header;
+	struct snd_soc_tplg_manifest manifest;
+	struct snd_soc_tplg_hdr pcm_header;
+	struct snd_soc_tplg_pcm pcm;
+} __packed;
+
+static struct tplg_tmpl_002 tplg_tmpl_with_pcm = {
+	.header = {
+		.magic = cpu_to_le32(SND_SOC_TPLG_MAGIC),
+		.abi = cpu_to_le32(5),
+		.version = 0,
+		.type = cpu_to_le32(SND_SOC_TPLG_TYPE_MANIFEST),
+		.size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr)),
+		.vendor_type = 0,
+		.payload_size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+		.index = 0,
+		.count = cpu_to_le32(1),
+	},
+	.manifest = {
+		.size = cpu_to_le32(sizeof(struct snd_soc_tplg_manifest)),
+		.pcm_elems = cpu_to_le32(1),
+		/* rest of fields is 0 */
+	},
+	.pcm_header = {
+		.magic = cpu_to_le32(SND_SOC_TPLG_MAGIC),
+		.abi = cpu_to_le32(5),
+		.version = 0,
+		.type = cpu_to_le32(SND_SOC_TPLG_TYPE_PCM),
+		.size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr)),
+		.vendor_type = 0,
+		.payload_size = cpu_to_le32(sizeof(struct snd_soc_tplg_pcm)),
+		.index = 0,
+		.count = cpu_to_le32(1),
+	},
+	.pcm = {
+		.size = cpu_to_le32(sizeof(struct snd_soc_tplg_pcm)),
+		.pcm_name = "KUNIT Audio",
+		.dai_name = "kunit-audio-dai",
+		.pcm_id = 0,
+		.dai_id = 0,
+		.playback = cpu_to_le32(1),
+		.capture = cpu_to_le32(1),
+		.compress = 0,
+		.stream = {
+			[0] = {
+				.channels = cpu_to_le32(2),
+			},
+			[1] = {
+				.channels = cpu_to_le32(2),
+			},
+		},
+		.num_streams = 0,
+		.caps = {
+			[0] = {
+				.name = "kunit-audio-playback",
+				.channels_min = cpu_to_le32(2),
+				.channels_max = cpu_to_le32(2),
+			},
+			[1] = {
+				.name = "kunit-audio-capture",
+				.channels_min = cpu_to_le32(2),
+				.channels_max = cpu_to_le32(2),
+			},
+		},
+		.flag_mask = 0,
+		.flags = 0,
+		.priv = { 0 },
+	},
+};
+
+/* ===== TEST CASES ========================================================= */
+
+// TEST CASE
+// Test passing NULL component as parameter to snd_soc_tplg_component_load
+
+/*
+ * need to override generic probe function with one using NULL when calling
+ * topology load during component initialization, we don't need .remove
+ * handler as load should fail
+ */
+static int d_probe_null_comp(struct snd_soc_component *component)
+{
+	struct kunit_soc_component *kunit_comp =
+			container_of(component, struct kunit_soc_component, comp);
+	int ret;
+
+	/* instead of passing component pointer as first argument, pass NULL here */
+	ret = snd_soc_tplg_component_load(NULL, NULL, &kunit_comp->fw);
+	KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
+			    "Failed topology load");
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver test_component_null_comp = {
+	.name = "sound-soc-topology-test",
+	.probe = d_probe_null_comp,
+	.non_legacy_dai_naming = 1,
+};
+
+static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = -EINVAL; /* expect failure */
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_comp, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test passing NULL ops as parameter to snd_soc_tplg_component_load
+
+/*
+ * NULL ops is default case, we pass empty topology (fw), so we don't have
+ * anything to parse and just do nothing, which results in return 0; from
+ * calling soc_tplg_dapm_complete in soc_tplg_process_headers
+ */
+static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = 0; /* expect success */
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test passing NULL fw as parameter to snd_soc_tplg_component_load
+
+/*
+ * need to override generic probe function with one using NULL pointer to fw
+ * when calling topology load during component initialization, we don't need
+ * .remove handler as load should fail
+ */
+static int d_probe_null_fw(struct snd_soc_component *component)
+{
+	struct kunit_soc_component *kunit_comp =
+			container_of(component, struct kunit_soc_component, comp);
+	int ret;
+
+	/* instead of passing fw pointer as third argument, pass NULL here */
+	ret = snd_soc_tplg_component_load(component, NULL, NULL);
+	KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
+			    "Failed topology load");
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver test_component_null_fw = {
+	.name = "sound-soc-topology-test",
+	.probe = d_probe_null_fw,
+	.non_legacy_dai_naming = 1,
+};
+
+static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = -EINVAL; /* expect failure */
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_fw, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test passing "empty" topology file
+static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	struct tplg_tmpl_001 *data;
+	int size;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = 0; /* expect success */
+
+	size = sizeof(tplg_tmpl_empty);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+
+	kunit_comp->fw.data = (u8 *)data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "magic"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use SND_SOC_TPLG_MAGIC + 1
+static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	struct tplg_tmpl_001 *data;
+	int size;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = -EINVAL; /* expect failure */
+
+	size = sizeof(tplg_tmpl_empty);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+	/*
+	 * override abi
+	 * any value != magic number is wrong
+	 */
+	data->header.magic = cpu_to_le32(SND_SOC_TPLG_MAGIC + 1);
+
+	kunit_comp->fw.data = (u8 *)data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "abi"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use SND_SOC_TPLG_ABI_VERSION + 1
+static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	struct tplg_tmpl_001 *data;
+	int size;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = -EINVAL; /* expect failure */
+
+	size = sizeof(tplg_tmpl_empty);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+	/*
+	 * override abi
+	 * any value != accepted range is wrong
+	 */
+	data->header.abi = cpu_to_le32(SND_SOC_TPLG_ABI_VERSION + 1);
+
+	kunit_comp->fw.data = (u8 *)data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "size"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use sizeof(struct snd_soc_tplg_hdr) + 1
+static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	struct tplg_tmpl_001 *data;
+	int size;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = -EINVAL; /* expect failure */
+
+	size = sizeof(tplg_tmpl_empty);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+	/*
+	 * override size
+	 * any value != struct size is wrong
+	 */
+	data->header.size = cpu_to_le32(sizeof(struct snd_soc_tplg_hdr) + 1);
+
+	kunit_comp->fw.data = (u8 *)data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+}
+
+// TEST CASE
+// Test "empty" topology file, but with bad "payload_size"
+// In theory we could loop through all possible bad values, but it takes too
+// long, so just use the known wrong one
+static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	struct tplg_tmpl_001 *data;
+	int size;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = -EINVAL; /* expect failure */
+
+	size = sizeof(tplg_tmpl_empty);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_empty, sizeof(tplg_tmpl_empty));
+	/*
+	 * override payload size
+	 * there is only explicit check for 0, so check with it, other values
+	 * are handled by just not reading behind EOF
+	 */
+	data->header.payload_size = 0;
+
+	kunit_comp->fw.data = (u8 *)data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	/* cleanup */
+	snd_soc_unregister_component(test_dev);
+
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+}
+
+// TEST CASE
+// Test passing topology file with PCM definition
+static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	u8 *data;
+	int size;
+	int ret;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = 0; /* expect success */
+
+	size = sizeof(tplg_tmpl_with_pcm);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_with_pcm, sizeof(tplg_tmpl_with_pcm));
+
+	kunit_comp->fw.data = data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	snd_soc_unregister_component(test_dev);
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+}
+
+// TEST CASE
+// Test passing topology file with PCM definition
+// with component reload
+static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	u8 *data;
+	int size;
+	int ret;
+	int i;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = 0; /* expect success */
+
+	size = sizeof(tplg_tmpl_with_pcm);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_with_pcm, sizeof(tplg_tmpl_with_pcm));
+
+	kunit_comp->fw.data = data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_register_card(&kunit_comp->card);
+	if (ret != 0 && ret != -EPROBE_DEFER)
+		KUNIT_FAIL(test, "Failed to register card");
+
+	for (i = 0; i < 100; i++) {
+		ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+		KUNIT_EXPECT_EQ(test, 0, ret);
+
+		ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+		KUNIT_EXPECT_EQ(test, 0, ret);
+
+		snd_soc_unregister_component(test_dev);
+	}
+
+	/* cleanup */
+	ret = snd_soc_unregister_card(&kunit_comp->card);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+}
+
+// TEST CASE
+// Test passing topology file with PCM definition
+// with card reload
+static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test)
+{
+	struct kunit_soc_component *kunit_comp;
+	u8 *data;
+	int size;
+	int ret;
+	int i;
+
+	/* prepare */
+	kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
+	kunit_comp->kunit = test;
+	kunit_comp->expect = 0; /* expect success */
+
+	size = sizeof(tplg_tmpl_with_pcm);
+	data = kunit_kzalloc(kunit_comp->kunit, size, GFP_KERNEL);
+	KUNIT_EXPECT_NOT_ERR_OR_NULL(kunit_comp->kunit, data);
+
+	memcpy(data, &tplg_tmpl_with_pcm, sizeof(tplg_tmpl_with_pcm));
+
+	kunit_comp->fw.data = data;
+	kunit_comp->fw.size = size;
+
+	kunit_comp->card.dev = test_dev,
+	kunit_comp->card.name = "kunit-card",
+	kunit_comp->card.owner = THIS_MODULE,
+	kunit_comp->card.dai_link = kunit_dai_links,
+	kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
+	kunit_comp->card.fully_routed = true,
+
+	/* run test */
+	ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+	KUNIT_EXPECT_EQ(test, 0, ret);
+
+	for (i = 0; i < 100; i++) {
+		ret = snd_soc_register_card(&kunit_comp->card);
+		if (ret != 0 && ret != -EPROBE_DEFER)
+			KUNIT_FAIL(test, "Failed to register card");
+
+		ret = snd_soc_unregister_card(&kunit_comp->card);
+		KUNIT_EXPECT_EQ(test, 0, ret);
+	}
+
+	/* cleanup */
+	snd_soc_unregister_component(test_dev);
+}
+
+/* ===== KUNIT MODULE DEFINITIONS =========================================== */
+
+static struct kunit_case snd_soc_tplg_test_cases[] = {
+	KUNIT_CASE(snd_soc_tplg_test_load_with_null_comp),
+	KUNIT_CASE(snd_soc_tplg_test_load_with_null_ops),
+	KUNIT_CASE(snd_soc_tplg_test_load_with_null_fw),
+	KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg),
+	KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_magic),
+	KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_abi),
+	KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_size),
+	KUNIT_CASE(snd_soc_tplg_test_load_empty_tplg_bad_payload_size),
+	KUNIT_CASE(snd_soc_tplg_test_load_pcm_tplg),
+	KUNIT_CASE(snd_soc_tplg_test_load_pcm_tplg_reload_comp),
+	KUNIT_CASE(snd_soc_tplg_test_load_pcm_tplg_reload_card),
+	{}
+};
+
+static struct kunit_suite snd_soc_tplg_test_suite = {
+	.name = "snd_soc_tplg_test",
+	.init = snd_soc_tplg_test_init,
+	.exit = snd_soc_tplg_test_exit,
+	.test_cases = snd_soc_tplg_test_cases,
+};
+
+kunit_test_suites(&snd_soc_tplg_test_suite);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 22e7b4c9115b723f194c931f485bb102cfcc563e..1b0cd33a1348f187a7688400a8bd1c7146880fe2 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1672,7 +1672,7 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
 			  unsigned int flag_mask, unsigned int flags)
 {
 	if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES)
-		dai_drv->symmetric_rates =
+		dai_drv->symmetric_rate =
 			flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0;
 
 	if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS)
@@ -1681,7 +1681,7 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
 			1 : 0;
 
 	if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS)
-		dai_drv->symmetric_samplebits =
+		dai_drv->symmetric_sample_bits =
 			flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ?
 			1 : 0;
 }
@@ -1764,7 +1764,7 @@ static void set_link_flags(struct snd_soc_dai_link *link,
 		unsigned int flag_mask, unsigned int flags)
 {
 	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES)
-		link->symmetric_rates =
+		link->symmetric_rate =
 			flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0;
 
 	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS)
@@ -1773,7 +1773,7 @@ static void set_link_flags(struct snd_soc_dai_link *link,
 			1 : 0;
 
 	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS)
-		link->symmetric_samplebits =
+		link->symmetric_sample_bits =
 			flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ?
 			1 : 0;
 
@@ -2660,8 +2660,14 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
 	struct soc_tplg tplg;
 	int ret;
 
-	/* component needs to exist to keep and reference data while parsing */
-	if (!comp)
+	/*
+	 * check if we have sane parameters:
+	 * comp - needs to exist to keep and reference data while parsing
+	 * comp->dev - used for resource management and prints
+	 * comp->card - used for setting card related parameters
+	 * fw - we need it, as it is the very thing we parse
+	 */
+	if (!comp || !comp->dev || !comp->card || !fw)
 		return -EINVAL;
 
 	/* setup parsing context */
@@ -2669,11 +2675,13 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
 	tplg.fw = fw;
 	tplg.dev = comp->dev;
 	tplg.comp = comp;
-	tplg.ops = ops;
-	tplg.io_ops = ops->io_ops;
-	tplg.io_ops_count = ops->io_ops_count;
-	tplg.bytes_ext_ops = ops->bytes_ext_ops;
-	tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
+	if (ops) {
+		tplg.ops = ops;
+		tplg.io_ops = ops->io_ops;
+		tplg.io_ops_count = ops->io_ops_count;
+		tplg.bytes_ext_ops = ops->bytes_ext_ops;
+		tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
+	}
 
 	ret = soc_tplg_load(&tplg);
 	/* free the created components if fail to load topology */
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index adc7c37145d6407c173c942cd58f61103f0c3bbb..6d8f7d9fd192057ac5b25f245a7c405d30d73928 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -246,6 +246,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
 	if (plat_data->sof_probe_complete)
 		plat_data->sof_probe_complete(sdev->dev);
 
+	sdev->probe_completed = true;
+
 	return 0;
 
 fw_trace_err:
@@ -316,6 +318,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
 	INIT_LIST_HEAD(&sdev->route_list);
 	spin_lock_init(&sdev->ipc_lock);
 	spin_lock_init(&sdev->hw_lock);
+	mutex_init(&sdev->power_state_access);
 
 	if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
 		INIT_WORK(&sdev->probe_work, sof_probe_work);
@@ -339,6 +342,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
 }
 EXPORT_SYMBOL(snd_sof_device_probe);
 
+bool snd_sof_device_probe_completed(struct device *dev)
+{
+	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+
+	return sdev->probe_completed;
+}
+EXPORT_SYMBOL(snd_sof_device_probe_completed);
+
 int snd_sof_device_remove(struct device *dev)
 {
 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
@@ -384,6 +395,14 @@ int snd_sof_device_remove(struct device *dev)
 }
 EXPORT_SYMBOL(snd_sof_device_remove);
 
+int snd_sof_device_shutdown(struct device *dev)
+{
+	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+
+	return snd_sof_shutdown(sdev);
+}
+EXPORT_SYMBOL(snd_sof_device_shutdown);
+
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index 30213a1beaaa28115179c5622c03cfdb011046d2..715a374b33cfb4670474d41d7f7b3e9fee16b4de 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -352,7 +352,7 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
 	char *string;
 	int ret;
 
-	string = kzalloc(count, GFP_KERNEL);
+	string = kzalloc(count+1, GFP_KERNEL);
 	if (!string)
 		return -ENOMEM;
 
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index 789148e5584b39ce3fbc0112ff22484f75ef7df0..30025d3c16b6e925d7c0cd3790d086b2e3bc5be1 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -9,6 +9,7 @@
 
 #include <linux/io.h>
 #include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
 #include "../sof-priv.h"
 #include "hda.h"
 
@@ -19,13 +20,43 @@
 #define sof_hda_ext_ops	NULL
 #endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable)
+{
+	struct hdac_bus *bus = codec->bus;
+	bool oldstate = test_bit(codec->addr, &bus->codec_powered);
+
+	snd_hdac_ext_bus_link_power(codec, enable);
+
+	if (enable == oldstate)
+		return;
+
+	/*
+	 * Both codec driver and controller can hold references to
+	 * display power. To avoid unnecessary power-up/down cycles,
+	 * controller doesn't immediately release its reference.
+	 *
+	 * If the codec driver powers down the link, release
+	 * the controller reference as well.
+	 */
+	if (codec->addr == HDA_IDISP_ADDR && !enable)
+		snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+}
+
+static const struct hdac_bus_ops bus_core_ops = {
+	.command = snd_hdac_bus_send_cmd,
+	.get_response = snd_hdac_bus_get_response,
+	.link_power = sof_hda_bus_link_power,
+};
+#endif
+
 /*
  * This can be used for both with/without hda link support.
  */
 void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev)
 {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-	snd_hdac_ext_bus_init(bus, dev, NULL, sof_hda_ext_ops);
+	snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
 #else /* CONFIG_SND_SOC_SOF_HDA */
 	memset(bus, 0, sizeof(*bus));
 	bus->dev = dev;
diff --git a/sound/soc/sof/intel/hda-compress.c b/sound/soc/sof/intel/hda-compress.c
index 53c08034fa22105c2f06508ada12b4d1c425d669..fe2f3f7d236b10373248ce089a6936d941f79037 100644
--- a/sound/soc/sof/intel/hda-compress.c
+++ b/sound/soc/sof/intel/hda-compress.c
@@ -25,7 +25,7 @@ int hda_probe_compr_assign(struct snd_sof_dev *sdev,
 {
 	struct hdac_ext_stream *stream;
 
-	stream = hda_dsp_stream_get(sdev, cstream->direction);
+	stream = hda_dsp_stream_get(sdev, cstream->direction, 0);
 	if (!stream)
 		return -EBUSY;
 
@@ -82,7 +82,7 @@ int hda_probe_compr_set_params(struct snd_sof_dev *sdev,
 
 	ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
 	if (ret < 0) {
-		dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+		dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
 		return ret;
 	}
 
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 1c5e05b88a90d7a25d21ab2830fc1e80f309254c..5788fe35696057874253b378a8e690c0da3343f4 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -624,7 +624,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
 #endif
 
 	/* power down DSP */
-	ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+	ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
 	if (ret < 0) {
 		dev_err(sdev->dev,
 			"error: failed to power down core during suspend\n");
@@ -732,7 +732,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
 				ret = snd_hdac_ext_bus_link_power_up(hlink);
 				if (ret < 0) {
 					dev_dbg(sdev->dev,
-						"error %x in %s: failed to power up links",
+						"error %d in %s: failed to power up links",
 						ret, __func__);
 					return ret;
 				}
@@ -802,11 +802,15 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
 
 int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
 {
+	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
 	const struct sof_dsp_power_state target_state = {
 		.state = SOF_DSP_PM_D3,
 	};
 	int ret;
 
+	/* cancel any attempt for DSP D0I3 */
+	cancel_delayed_work_sync(&hda->d0i3_work);
+
 	/* stop hda controller and power dsp off */
 	ret = hda_suspend(sdev, true);
 	if (ret < 0)
@@ -930,19 +934,15 @@ void hda_dsp_d0i3_work(struct work_struct *work)
 						      d0i3_work.work);
 	struct hdac_bus *bus = &hdev->hbus.core;
 	struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev);
-	struct sof_dsp_power_state target_state;
+	struct sof_dsp_power_state target_state = {
+		.state = SOF_DSP_PM_D0,
+		.substate = SOF_HDA_DSP_PM_D0I3,
+	};
 	int ret;
 
-	target_state.state = SOF_DSP_PM_D0;
-
 	/* DSP can enter D0I3 iff only D0I3-compatible streams are active */
-	if (snd_sof_dsp_only_d0i3_compatible_stream_active(sdev))
-		target_state.substate = SOF_HDA_DSP_PM_D0I3;
-	else
-		target_state.substate = SOF_HDA_DSP_PM_D0I0;
-
-	/* remain in D0I0 */
-	if (target_state.substate == SOF_HDA_DSP_PM_D0I0)
+	if (!snd_sof_dsp_only_d0i3_compatible_stream_active(sdev))
+		/* remain in D0I0 */
 		return;
 
 	/* This can fail but error cannot be propagated */
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index ed773696b4955b0445f124f91306a1db63a093cf..fc25ee8f68dcb6497cbf3bd5445a482121d72dc8 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -35,7 +35,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
 	struct pci_dev *pci = to_pci_dev(sdev->dev);
 	int ret;
 
-	dsp_stream = hda_dsp_stream_get(sdev, direction);
+	dsp_stream = hda_dsp_stream_get(sdev, direction, 0);
 
 	if (!dsp_stream) {
 		dev_err(sdev->dev, "error: no stream available\n");
@@ -47,7 +47,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
 	/* allocate DMA buffer */
 	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
 	if (ret < 0) {
-		dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret);
+		dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
 		goto error;
 	}
 
@@ -58,13 +58,13 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
 	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
 		ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL);
 		if (ret < 0) {
-			dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret);
+			dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
 			goto error;
 		}
 	} else {
 		ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL);
 		if (ret < 0) {
-			dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+			dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
 			goto error;
 		}
 		hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size);
@@ -93,7 +93,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
 	int i;
 
 	/* step 1: power up corex */
-	ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
+	ret = snd_sof_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
 	if (ret < 0) {
 		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
 			dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@@ -147,8 +147,9 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
 				       chip->ipc_ack_mask,
 				       chip->ipc_ack_mask);
 
-	/* step 5: power down corex */
-	ret = hda_dsp_core_power_down(sdev, chip->host_managed_cores_mask & ~(BIT(0)));
+	/* step 5: power down cores that are no longer needed */
+	ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask &
+					  ~(chip->init_core_mask));
 	if (ret < 0) {
 		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
 			dev_err(sdev->dev,
@@ -183,7 +184,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
 		flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL;
 
 	hda_dsp_dump(sdev, flags);
-	hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+	snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
 
 	return ret;
 }
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 5d35bb18660aefbd4dd8ec512e21d28ec87d6d82..df00db8369c78809c509e6d32e703335b828ed1b 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -111,7 +111,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
 
 	ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params);
 	if (ret < 0) {
-		dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+		dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
 		return ret;
 	}
 
@@ -215,11 +215,25 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
 int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
 		     struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct snd_soc_component *scomp = sdev->component;
 	struct hdac_ext_stream *dsp_stream;
+	struct snd_sof_pcm *spcm;
 	int direction = substream->stream;
+	u32 flags = 0;
+
+	spcm = snd_sof_find_spcm_dai(scomp, rtd);
+	if (!spcm) {
+		dev_err(sdev->dev, "error: can't find PCM with DAI ID %d\n", rtd->dai_link->id);
+		return -EINVAL;
+	}
 
-	dsp_stream = hda_dsp_stream_get(sdev, direction);
+	/* All playback and D0i3 compatible streams are DMI L1 capable */
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK ||
+	    spcm->stream[substream->stream].d0i3_compatible)
+		flags |= SOF_HDA_STREAM_DMI_L1_COMPATIBLE;
 
+	dsp_stream = hda_dsp_stream_get(sdev, direction, flags);
 	if (!dsp_stream) {
 		dev_err(sdev->dev, "error: no stream available\n");
 		return -ENODEV;
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 0e09ede922c7a074bbf78c7f072a07e948e17d77..40a3993ae2cbba0edac108af86d48613fe55a547 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -155,7 +155,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
 
 /* get next unused stream */
 struct hdac_ext_stream *
-hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
+hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags)
 {
 	struct hdac_bus *bus = sof_to_bus(sdev);
 	struct sof_intel_hda_stream *hda_stream;
@@ -183,18 +183,22 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
 	spin_unlock_irq(&bus->reg_lock);
 
 	/* stream found ? */
-	if (!stream)
+	if (!stream) {
 		dev_err(sdev->dev, "error: no free %s streams\n",
 			direction == SNDRV_PCM_STREAM_PLAYBACK ?
 			"playback" : "capture");
+		return stream;
+	}
+
+	hda_stream->flags = flags;
 
 	/*
-	 * Disable DMI Link L1 entry when capture stream is opened.
+	 * Prevent DMI Link L1 entry for streams that don't support it.
 	 * Workaround to address a known issue with host DMA that results
 	 * in xruns during pause/release in capture scenarios.
 	 */
 	if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
-		if (stream && direction == SNDRV_PCM_STREAM_CAPTURE)
+		if (stream && !(flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE))
 			snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
 						HDA_VS_INTEL_EM2,
 						HDA_VS_INTEL_EM2_L1SEN, 0);
@@ -206,37 +210,39 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
 {
 	struct hdac_bus *bus = sof_to_bus(sdev);
+	struct sof_intel_hda_stream *hda_stream;
+	struct hdac_ext_stream *stream;
 	struct hdac_stream *s;
-	bool active_capture_stream = false;
+	bool dmi_l1_enable = true;
 	bool found = false;
 
 	spin_lock_irq(&bus->reg_lock);
 
 	/*
-	 * close stream matching the stream tag
-	 * and check if there are any open capture streams.
+	 * close stream matching the stream tag and check if there are any open streams
+	 * that are DMI L1 incompatible.
 	 */
 	list_for_each_entry(s, &bus->stream_list, list) {
+		stream = stream_to_hdac_ext_stream(s);
+		hda_stream = container_of(stream, struct sof_intel_hda_stream, hda_stream);
+
 		if (!s->opened)
 			continue;
 
 		if (s->direction == direction && s->stream_tag == stream_tag) {
 			s->opened = false;
 			found = true;
-		} else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) {
-			active_capture_stream = true;
+		} else if (!(hda_stream->flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE)) {
+			dmi_l1_enable = false;
 		}
 	}
 
 	spin_unlock_irq(&bus->reg_lock);
 
-	/* Enable DMI L1 entry if there are no capture streams open */
-	if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
-		if (!active_capture_stream)
-			snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
-						HDA_VS_INTEL_EM2,
-						HDA_VS_INTEL_EM2_L1SEN,
-						HDA_VS_INTEL_EM2_L1SEN);
+	/* Enable DMI L1 if permitted */
+	if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1) && dmi_l1_enable)
+		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
+					HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN);
 
 	if (!found) {
 		dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c
index 1eb746d5adeb555876483f4f21a274cf897e3805..29e3da3c63db01ff6b3e948b1154fd531979e9b0 100644
--- a/sound/soc/sof/intel/hda-trace.c
+++ b/sound/soc/sof/intel/hda-trace.c
@@ -32,7 +32,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev)
 
 	ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
 	if (ret < 0)
-		dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+		dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
 
 	return ret;
 }
@@ -42,8 +42,8 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
 	int ret;
 
-	hda->dtrace_stream = hda_dsp_stream_get(sdev,
-						SNDRV_PCM_STREAM_CAPTURE);
+	hda->dtrace_stream = hda_dsp_stream_get(sdev, SNDRV_PCM_STREAM_CAPTURE,
+						SOF_HDA_STREAM_DMI_L1_COMPATIBLE);
 
 	if (!hda->dtrace_stream) {
 		dev_err(sdev->dev,
@@ -59,7 +59,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
 	 */
 	ret = hda_dsp_trace_prepare(sdev);
 	if (ret < 0) {
-		dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret);
+		dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret);
 		hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag);
 		hda->dtrace_stream = NULL;
 		*stream_tag = 0;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 509a9b25642301bd4d8af17c8a11646e3c0bdfc3..0dc3a8c0f5e34a82a4f0879b4b6ae4ba65bbdefb 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -285,11 +285,13 @@ static char *hda_model;
 module_param(hda_model, charp, 0444);
 MODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 static int hda_dmic_num = -1;
 module_param_named(dmic_num, hda_dmic_num, int, 0444);
 MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
+#endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
 module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
 MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
@@ -317,26 +319,6 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
 	{HDA_DSP_ROM_NULL_FW_ENTRY,	"error: null FW entry point"},
 };
 
-static void hda_dsp_get_status_skl(struct snd_sof_dev *sdev)
-{
-	u32 status;
-	int i;
-
-	status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-				  HDA_ADSP_FW_STATUS_SKL);
-
-	for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
-		if (status == hda_dsp_rom_msg[i].code) {
-			dev_err(sdev->dev, "%s - code %8.8x\n",
-				hda_dsp_rom_msg[i].msg, status);
-			return;
-		}
-	}
-
-	/* not for us, must be generic sof message */
-	dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
-}
-
 static void hda_dsp_get_status(struct snd_sof_dev *sdev)
 {
 	u32 status;
@@ -385,36 +367,6 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
 		       stack_words * sizeof(u32));
 }
 
-void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
-{
-	struct sof_ipc_dsp_oops_xtensa xoops;
-	struct sof_ipc_panic_info panic_info;
-	u32 stack[HDA_DSP_STACK_DUMP_SIZE];
-	u32 status, panic;
-
-	/* try APL specific status message types first */
-	hda_dsp_get_status_skl(sdev);
-
-	/* now try generic SOF status messages */
-	status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-				  HDA_ADSP_ERROR_CODE_SKL);
-
-	/*TODO: Check: there is no define in spec, but it is used in the code*/
-	panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-				 HDA_ADSP_ERROR_CODE_SKL + 0x4);
-
-	if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
-		hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
-				      HDA_DSP_STACK_DUMP_SIZE);
-		snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
-				   stack, HDA_DSP_STACK_DUMP_SIZE);
-	} else {
-		dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n",
-			status, panic);
-		hda_dsp_get_status_skl(sdev);
-	}
-}
-
 /* dump the first 8 dwords representing the extended ROM status */
 static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags)
 {
@@ -555,7 +507,7 @@ static int hda_init(struct snd_sof_dev *sdev)
 	return ret;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 
 static int check_nhlt_dmic(struct snd_sof_dev *sdev)
 {
@@ -579,25 +531,76 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
 				   const char *dmic_str)
 {
 	const char *tplg_filename = NULL;
-	char *filename;
-	char *split_ext;
+	char *filename, *tmp;
+	const char *split_ext;
 
-	filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
+	filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
 	if (!filename)
 		return NULL;
 
 	/* this assumes a .tplg extension */
-	split_ext = strsep(&filename, ".");
-	if (split_ext) {
+	tmp = filename;
+	split_ext = strsep(&tmp, ".");
+	if (split_ext)
 		tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
 					       "%s%s%s.tplg",
 					       split_ext, idisp_str, dmic_str);
-		if (!tplg_filename)
-			return NULL;
-	}
+	kfree(filename);
+
 	return tplg_filename;
 }
 
+static int dmic_topology_fixup(struct snd_sof_dev *sdev,
+			       const char **tplg_filename,
+			       const char *idisp_str,
+			       int *dmic_found)
+{
+	const char *default_tplg_filename = *tplg_filename;
+	const char *fixed_tplg_filename;
+	const char *dmic_str;
+	int dmic_num;
+
+	/* first check NHLT for DMICs */
+	dmic_num = check_nhlt_dmic(sdev);
+
+	/* allow for module parameter override */
+	if (hda_dmic_num != -1) {
+		dev_dbg(sdev->dev,
+			"overriding DMICs detected in NHLT tables %d by kernel param %d\n",
+			dmic_num, hda_dmic_num);
+		dmic_num = hda_dmic_num;
+	}
+
+	switch (dmic_num) {
+	case 1:
+		dmic_str = "-1ch";
+		break;
+	case 2:
+		dmic_str = "-2ch";
+		break;
+	case 3:
+		dmic_str = "-3ch";
+		break;
+	case 4:
+		dmic_str = "-4ch";
+		break;
+	default:
+		dmic_num = 0;
+		dmic_str = "";
+		break;
+	}
+
+	fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
+					      idisp_str, dmic_str);
+	if (!fixed_tplg_filename)
+		return -ENOMEM;
+
+	dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
+	*dmic_found = dmic_num;
+	*tplg_filename = fixed_tplg_filename;
+
+	return 0;
+}
 #endif
 
 static int hda_init_caps(struct snd_sof_dev *sdev)
@@ -809,13 +812,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
 	sdev->mailbox_bar = HDA_DSP_BAR;
 
 	/* allow 64bit DMA address if supported by H/W */
-	if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) {
-		dev_dbg(sdev->dev, "DMA mask is 64 bit\n");
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64));
-	} else {
+	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) {
 		dev_dbg(sdev->dev, "DMA mask is 32 bit\n");
-		dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
-		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
+		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
 	}
 
 	/* init streams */
@@ -932,7 +931,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
 
 	/* disable cores */
 	if (chip)
-		hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+		snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
 
 	/* disable DSP */
 	snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
@@ -967,9 +966,9 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
 	struct snd_sof_pdata *pdata = sdev->pdata;
 	const char *tplg_filename;
 	const char *idisp_str;
-	const char *dmic_str;
 	int dmic_num = 0;
 	int codec_num = 0;
+	int ret;
 	int i;
 
 	/* codec detection */
@@ -994,10 +993,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
 		if (!pdata->machine && codec_num <= 2) {
 			hda_mach = snd_soc_acpi_intel_hda_machines;
 
-			/* topology: use the info from hda_machines */
-			pdata->tplg_filename =
-				hda_mach->sof_tplg_filename;
-
 			dev_info(bus->dev, "using HDA machine driver %s now\n",
 				 hda_mach->drv_name);
 
@@ -1006,42 +1001,13 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
 			else
 				idisp_str = "";
 
-			/* first check NHLT for DMICs */
-			dmic_num = check_nhlt_dmic(sdev);
-
-			/* allow for module parameter override */
-			if (hda_dmic_num != -1)
-				dmic_num = hda_dmic_num;
-
-			switch (dmic_num) {
-			case 1:
-				dmic_str = "-1ch";
-				break;
-			case 2:
-				dmic_str = "-2ch";
-				break;
-			case 3:
-				dmic_str = "-3ch";
-				break;
-			case 4:
-				dmic_str = "-4ch";
-				break;
-			default:
-				dmic_num = 0;
-				dmic_str = "";
-				break;
-			}
-
-			tplg_filename = pdata->tplg_filename;
-			tplg_filename = fixup_tplg_name(sdev, tplg_filename,
-							idisp_str, dmic_str);
-			if (!tplg_filename)
-				return -EINVAL;
-
-			dev_info(bus->dev,
-				 "DMICs detected in NHLT tables: %d\n",
-				 dmic_num);
+			/* topology: use the info from hda_machines */
+			tplg_filename = hda_mach->sof_tplg_filename;
+			ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
+			if (ret < 0)
+				return ret;
 
+			hda_mach->mach_params.dmic_num = dmic_num;
 			pdata->machine = hda_mach;
 			pdata->tplg_filename = tplg_filename;
 		}
@@ -1053,7 +1019,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
 			&pdata->machine->mach_params;
 		mach_params->codec_mask = bus->codec_mask;
 		mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
-		mach_params->dmic_num = dmic_num;
 	}
 
 	return 0;
@@ -1075,32 +1040,63 @@ static bool link_slaves_found(struct snd_sof_dev *sdev,
 	struct sdw_intel_slave_id *ids = sdw->ids;
 	int num_slaves = sdw->num_slaves;
 	unsigned int part_id, link_id, unique_id, mfg_id;
-	int i, j;
+	int i, j, k;
 
 	for (i = 0; i < link->num_adr; i++) {
 		u64 adr = link->adr_d[i].adr;
+		int reported_part_count = 0;
 
 		mfg_id = SDW_MFG_ID(adr);
 		part_id = SDW_PART_ID(adr);
 		link_id = SDW_DISCO_LINK_ID(adr);
+
+		for (j = 0; j < num_slaves; j++) {
+			/* find out how many identical parts were reported on that link */
+			if (ids[j].link_id == link_id &&
+			    ids[j].id.part_id == part_id &&
+			    ids[j].id.mfg_id == mfg_id)
+				reported_part_count++;
+		}
+
 		for (j = 0; j < num_slaves; j++) {
+			int expected_part_count = 0;
+
 			if (ids[j].link_id != link_id ||
 			    ids[j].id.part_id != part_id ||
 			    ids[j].id.mfg_id != mfg_id)
 				continue;
-			/*
-			 * we have to check unique id
-			 * if there is more than one
-			 * Slave on the link
-			 */
-			unique_id = SDW_UNIQUE_ID(adr);
-			if (link->num_adr == 1 ||
-			    ids[j].id.unique_id == SDW_IGNORED_UNIQUE_ID ||
-			    ids[j].id.unique_id == unique_id) {
-				dev_dbg(bus->dev,
-					"found %x at link %d\n",
-					part_id, link_id);
-				break;
+
+			/* find out how many identical parts are expected */
+			for (k = 0; k < link->num_adr; k++) {
+				u64 adr2 = link->adr_d[i].adr;
+				unsigned int part_id2, link_id2, mfg_id2;
+
+				mfg_id2 = SDW_MFG_ID(adr2);
+				part_id2 = SDW_PART_ID(adr2);
+				link_id2 = SDW_DISCO_LINK_ID(adr2);
+
+				if (link_id2 == link_id &&
+				    part_id2 == part_id &&
+				    mfg_id2 == mfg_id)
+					expected_part_count++;
+			}
+
+			if (reported_part_count == expected_part_count) {
+				/*
+				 * we have to check unique id
+				 * if there is more than one
+				 * Slave on the link
+				 */
+				unique_id = SDW_UNIQUE_ID(adr);
+				if (reported_part_count == 1 ||
+				    ids[j].id.unique_id == unique_id) {
+					dev_dbg(bus->dev, "found %x at link %d\n",
+						part_id, link_id);
+					break;
+				}
+			} else {
+				dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n",
+					part_id, reported_part_count, expected_part_count, link_id);
 			}
 		}
 		if (j == num_slaves) {
@@ -1117,7 +1113,6 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev)
 {
 	struct snd_sof_pdata *pdata = sdev->pdata;
 	const struct snd_soc_acpi_link_adr *link;
-	struct hdac_bus *bus = sof_to_bus(sdev);
 	struct snd_soc_acpi_mach *mach;
 	struct sof_intel_hda_dev *hdev;
 	u32 link_mask;
@@ -1165,16 +1160,42 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev)
 				break;
 		}
 		if (mach && mach->link_mask) {
-			dev_dbg(bus->dev,
-				"SoundWire machine driver %s topology %s\n",
-				mach->drv_name,
-				mach->sof_tplg_filename);
+			int dmic_num = 0;
+
 			pdata->machine = mach;
 			mach->mach_params.links = mach->links;
 			mach->mach_params.link_mask = mach->link_mask;
 			mach->mach_params.platform = dev_name(sdev->dev);
-			pdata->fw_filename = mach->sof_fw_filename;
+			if (mach->sof_fw_filename)
+				pdata->fw_filename = mach->sof_fw_filename;
+			else
+				pdata->fw_filename = pdata->desc->default_fw_filename;
 			pdata->tplg_filename = mach->sof_tplg_filename;
+
+			/*
+			 * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
+			 * link 2 and 3, thus we only try to enable dmics if all conditions
+			 * are true:
+			 * a) link 2 and 3 are not used by SoundWire
+			 * b) the NHLT table reports the presence of microphones
+			 */
+			if (!(mach->link_mask & GENMASK(3, 2))) {
+				const char *tplg_filename = mach->sof_tplg_filename;
+				int ret;
+
+				ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
+
+				if (ret < 0)
+					return ret;
+
+				pdata->tplg_filename = tplg_filename;
+			}
+			mach->mach_params.dmic_num = dmic_num;
+
+			dev_dbg(sdev->dev,
+				"SoundWire machine driver %s topology %s\n",
+				mach->drv_name,
+				pdata->tplg_filename);
 		} else {
 			dev_info(sdev->dev,
 				 "No SoundWire machine driver found\n");
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index a3b6f3e9121c495813a65724763e7a29c5621e8f..d1c38c37bc9dea1ad1384ee0f5e2987a42f6824c 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -388,7 +388,8 @@
 #define SSP_SET_SFRM_SLAVE	BIT(24)
 #define SSP_SET_SLAVE		(SSP_SET_SCLK_SLAVE | SSP_SET_SFRM_SLAVE)
 
-#define HDA_IDISP_CODEC(x) ((x) & BIT(2))
+#define HDA_IDISP_ADDR		2
+#define HDA_IDISP_CODEC(x) ((x) & BIT(HDA_IDISP_ADDR))
 
 struct sof_intel_dsp_bdl {
 	__le32 addr_l;
@@ -402,6 +403,9 @@ struct sof_intel_dsp_bdl {
 #define SOF_HDA_PLAYBACK		0
 #define SOF_HDA_CAPTURE			1
 
+/* stream flags */
+#define SOF_HDA_STREAM_DMI_L1_COMPATIBLE	1
+
 /*
  * Time in ms for opportunistic D0I3 entry delay.
  * This has been deliberately chosen to be long to avoid race conditions.
@@ -471,6 +475,7 @@ struct sof_intel_hda_stream {
 	struct hdac_ext_stream hda_stream;
 	struct sof_intel_stream stream;
 	int host_reserved; /* reserve host DMA channel */
+	u32 flags;
 };
 
 #define hstream_to_sof_hda_stream(hstream) \
@@ -513,7 +518,6 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev);
 int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
 int hda_dsp_runtime_idle(struct snd_sof_dev *sdev);
 int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
-void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
 void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
 void hda_ipc_dump(struct snd_sof_dev *sdev);
 void hda_ipc_irq_dump(struct snd_sof_dev *sdev);
@@ -562,7 +566,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
 bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
 
 struct hdac_ext_stream *
-	hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);
+	hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
 int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
 			       struct hdac_ext_stream *stream,
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 2252ca38ff4bfc1d5fb1e5784fa2129284a4ecc8..419f05ba192086300f93eb710c795f589374fdbe 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -22,9 +22,10 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
 
 /* Tigerlake ops */
 const struct snd_sof_dsp_ops sof_tgl_ops = {
-	/* probe and remove */
+	/* probe/remove/shutdown */
 	.probe		= hda_dsp_probe,
 	.remove		= hda_dsp_remove,
+	.shutdown	= hda_dsp_remove,
 
 	/* Register IO */
 	.write		= sof_io_write,
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index fc13bb06dbf398e767f7575aa2bcf171034ca299..c2d07b783f60a3e1816071bfd4f561adfec9629c 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -106,6 +106,8 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
 			str2 = "CLK_REQ"; break;
 		case SOF_IPC_PM_CORE_ENABLE:
 			str2 = "CORE_ENABLE"; break;
+		case SOF_IPC_PM_GATE:
+			str2 = "GATE"; break;
 		default:
 			str2 = "unknown type"; break;
 		}
@@ -796,7 +798,7 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
 		return -EINVAL;
 	}
 
-	if (v->abi_version > SOF_ABI_VERSION) {
+	if (SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
 		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
 			dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n");
 		} else {
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index 08a17abb63ff51d69171048aab9261e75ee4fdfc..6efaf766f2ab8d712f897bdaf0990695e3b0acde 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -731,6 +731,8 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
 	if (ret < 0) {
 		dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
 			fw_filename, ret);
+		dev_err(sdev->dev,
+			"you may need to download the firmware from https://github.com/thesofproject/sof-bin/\n");
 		goto err;
 	} else {
 		dev_dbg(sdev->dev, "request_firmware %s successful\n",
@@ -811,7 +813,6 @@ EXPORT_SYMBOL(snd_sof_load_firmware);
 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
 {
 	int ret;
-	int init_core_mask;
 
 	init_waitqueue_head(&sdev->boot_wait);
 
@@ -843,8 +844,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
 		return ret;
 	}
 
-	init_core_mask = ret;
-
 	/*
 	 * now wait for the DSP to boot. There are 3 possible outcomes:
 	 * 1. Boot wait times out indicating FW boot failure.
@@ -874,9 +873,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
 		return ret;
 	}
 
-	/* fw boot is complete. Update the active cores mask */
-	sdev->enabled_cores_mask = init_core_mask;
-
 	return 0;
 }
 EXPORT_SYMBOL(snd_sof_run_firmware);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index 95e748b36903a0084e92769681d50204342449e9..5099ad03df72fd1017d60279a6a3ba9d1119b005 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -37,6 +37,14 @@ static inline int snd_sof_remove(struct snd_sof_dev *sdev)
 	return 0;
 }
 
+static inline int snd_sof_shutdown(struct snd_sof_dev *sdev)
+{
+	if (sof_ops(sdev)->shutdown)
+		return sof_ops(sdev)->shutdown(sdev);
+
+	return 0;
+}
+
 /* control */
 
 /*
@@ -68,19 +76,31 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev)
 static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev,
 					    unsigned int core_mask)
 {
-	if (sof_ops(sdev)->core_power_up)
-		return sof_ops(sdev)->core_power_up(sdev, core_mask);
+	int ret = 0;
 
-	return 0;
+	core_mask &= ~sdev->enabled_cores_mask;
+	if (sof_ops(sdev)->core_power_up && core_mask) {
+		ret = sof_ops(sdev)->core_power_up(sdev, core_mask);
+		if (!ret)
+			sdev->enabled_cores_mask |= core_mask;
+	}
+
+	return ret;
 }
 
 static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev,
 					      unsigned int core_mask)
 {
-	if (sof_ops(sdev)->core_power_down)
-		return sof_ops(sdev)->core_power_down(sdev, core_mask);
+	int ret = 0;
 
-	return 0;
+	core_mask &= sdev->enabled_cores_mask;
+	if (sof_ops(sdev)->core_power_down && core_mask) {
+		ret = sof_ops(sdev)->core_power_down(sdev, core_mask);
+		if (!ret)
+			sdev->enabled_cores_mask &= ~core_mask;
+	}
+
+	return ret;
 }
 
 /* pre/post fw load */
@@ -208,11 +228,16 @@ static inline int
 snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev,
 			    const struct sof_dsp_power_state *target_state)
 {
+	int ret = 0;
+
+	mutex_lock(&sdev->power_state_access);
+
 	if (sof_ops(sdev)->set_power_state)
-		return sof_ops(sdev)->set_power_state(sdev, target_state);
+		ret = sof_ops(sdev)->set_power_state(sdev, target_state);
 
-	/* D0 substate is not supported, do nothing here. */
-	return 0;
+	mutex_unlock(&sdev->power_state_access);
+
+	return ret;
 }
 
 /* debug */
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 0dc39fbcd81de54a01e52814ee230224f28b7b0d..61c3fe17342d98d840e281601d9fc38d491c5581 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -707,7 +707,12 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
 		}
 		break;
 	case SOF_DAI_INTEL_ALH:
-		/* do nothing for ALH dai_link */
+		/*
+		 * Dai could run with different channel count compared with
+		 * front end, so get dai channel count from topology
+		 */
+		channels->min = dai->dai_config->alh.channels;
+		channels->max = dai->dai_config->alh.channels;
 		break;
 	case SOF_DAI_IMX_ESAI:
 		rate->min = dai->dai_config->esai.fsync_rate;
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
index c83fb62559616cddb4f786e98e2c8c8ef333f54f..fd265803f7bc79454ee605c171ef724fea507596 100644
--- a/sound/soc/sof/pm.c
+++ b/sound/soc/sof/pm.c
@@ -256,7 +256,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
 
 	/* reset FW state */
 	sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
-	sdev->enabled_cores_mask = 0;
 
 	return ret;
 }
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 215711ac7450997138d542b952b50db2e3b028d9..fd1f0d8c2853e8cc900f47391238c1a3c0f24904 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -65,6 +65,13 @@ static const struct dmi_system_id community_key_platforms[] = {
 			DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
 		}
 	},
+	{
+		.ident = "Up Extreme",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
+			DMI_MATCH(DMI_BOARD_NAME, "UP-WHL01"),
+		}
+	},
 	{
 		.ident = "Google Chromebooks",
 		.matches = {
@@ -213,7 +220,7 @@ static const struct sof_dev_desc icl_desc = {
 };
 #endif
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) || IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
 static const struct sof_dev_desc tgl_desc = {
 	.machines               = snd_soc_acpi_intel_tgl_machines,
 	.alt_machines		= snd_soc_acpi_intel_tgl_sdw_machines,
@@ -230,7 +237,9 @@ static const struct sof_dev_desc tgl_desc = {
 	.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
 	.ops = &sof_tgl_ops,
 };
+#endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
 static const struct sof_dev_desc tglh_desc = {
 	.machines               = snd_soc_acpi_intel_tgl_machines,
 	.alt_machines		= snd_soc_acpi_intel_tgl_sdw_machines,
@@ -445,13 +454,19 @@ static void sof_pci_remove(struct pci_dev *pci)
 	snd_sof_device_remove(&pci->dev);
 
 	/* follow recommendation in pci-driver.c to increment usage counter */
-	if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
+	if (snd_sof_device_probe_completed(&pci->dev) &&
+	    !(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
 		pm_runtime_get_noresume(&pci->dev);
 
 	/* release pci regions and disable device */
 	pci_release_regions(pci);
 }
 
+static void sof_pci_shutdown(struct pci_dev *pci)
+{
+	snd_sof_device_shutdown(&pci->dev);
+}
+
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
@@ -514,6 +529,8 @@ static const struct pci_device_id sof_pci_ids[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
 	{ PCI_DEVICE(0x8086, 0x7ad0),
 		.driver_data = (unsigned long)&adls_desc},
+	{ PCI_DEVICE(0x8086, 0x51c8),
+		.driver_data = (unsigned long)&tgl_desc},
 #endif
 	{ 0, }
 };
@@ -525,6 +542,7 @@ static struct pci_driver snd_sof_pci_driver = {
 	.id_table = sof_pci_ids,
 	.probe = sof_pci_probe,
 	.remove = sof_pci_remove,
+	.shutdown = sof_pci_shutdown,
 	.driver = {
 		.pm = &sof_pci_pm,
 	},
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 68da8f797403e7624aaee7755ba67cd549839a01..ad0d7ba2708c72f08cbf5388ef4febdc81db7106 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -98,9 +98,10 @@ struct snd_sof_pdata;
  */
 struct snd_sof_dsp_ops {
 
-	/* probe and remove */
+	/* probe/remove/shutdown */
 	int (*probe)(struct snd_sof_dev *sof_dev); /* mandatory */
 	int (*remove)(struct snd_sof_dev *sof_dev); /* optional */
+	int (*shutdown)(struct snd_sof_dev *sof_dev); /* optional */
 
 	/* DSP core boot / reset */
 	int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */
@@ -375,6 +376,8 @@ struct snd_sof_dev {
 
 	/* current DSP power state */
 	struct sof_dsp_power_state dsp_power_state;
+	/* mutex to protect the dsp_power_state access */
+	struct mutex power_state_access;
 
 	/* Intended power target of system suspend */
 	enum sof_system_suspend_state system_suspend_target;
@@ -386,6 +389,7 @@ struct snd_sof_dev {
 
 	/* work queue in case the probe is implemented in two steps */
 	struct work_struct probe_work;
+	bool probe_completed;
 
 	/* DSP HW differentiation */
 	struct snd_sof_pdata *pdata;
@@ -460,6 +464,8 @@ struct snd_sof_dev {
 
 int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data);
 int snd_sof_device_remove(struct device *dev);
+int snd_sof_device_shutdown(struct device *dev);
+bool snd_sof_device_probe_completed(struct device *dev);
 
 int snd_sof_runtime_suspend(struct device *dev);
 int snd_sof_runtime_resume(struct device *dev);
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index b6b32a7a91f876b01db656167eedb25cf96551aa..10f99620eb317dec4236dc29aaf7facbdbb11488 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1073,7 +1073,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
 	scontrol->cmd = SOF_CTRL_CMD_VOLUME;
 
 	/* extract tlv data */
-	if (get_tlv_data(kc->tlv.p, tlv) < 0) {
+	if (!kc->tlv.p || get_tlv_data(kc->tlv.p, tlv) < 0) {
 		dev_err(scomp->dev, "error: invalid TLV data\n");
 		ret = -EINVAL;
 		goto out_free;
@@ -1352,10 +1352,6 @@ static int sof_core_enable(struct snd_sof_dev *sdev, int core)
 			core, ret);
 		goto err;
 	}
-
-	/* update enabled cores mask */
-	sdev->enabled_cores_mask |= BIT(core);
-
 	return ret;
 err:
 	/* power down core if it is host managed and return the original error if this fails too */
@@ -2603,10 +2599,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
 		if (ret < 0)
 			dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
 				pipeline->core);
-
-		/* update enabled cores mask */
-		sdev->enabled_cores_mask &= ~(1 << pipeline->core);
-
 		break;
 	default:
 		break;
@@ -3666,7 +3658,7 @@ static int sof_manifest(struct snd_soc_component *scomp, int index,
 		return -EINVAL;
 	}
 
-	if (abi_version > SOF_ABI_VERSION) {
+	if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
 		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
 			dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
 		} else {
@@ -3740,6 +3732,8 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
 	if (ret < 0) {
 		dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
 			file, ret);
+		dev_err(scomp->dev,
+			"you may need to download the firmware from https://github.com/thesofproject/sof-bin/\n");
 		return ret;
 	}
 
diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c
index f439e5503a3c0d97290c6063ced234d89892cbb8..34b2ce733b5425082b52dc76ef8b0ec71bd0ebf8 100644
--- a/sound/soc/sprd/sprd-mcdt.c
+++ b/sound/soc/sprd/sprd-mcdt.c
@@ -866,23 +866,23 @@ EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_disable);
 struct sprd_mcdt_chan *sprd_mcdt_request_chan(u8 channel,
 					      enum sprd_mcdt_channel_type type)
 {
-	struct sprd_mcdt_chan *temp, *chan = NULL;
+	struct sprd_mcdt_chan *temp;
 
 	mutex_lock(&sprd_mcdt_list_mutex);
 
 	list_for_each_entry(temp, &sprd_mcdt_chan_list, list) {
 		if (temp->type == type && temp->id == channel) {
-			chan = temp;
+			list_del_init(&temp->list);
 			break;
 		}
 	}
 
-	if (chan)
-		list_del(&chan->list);
+	if (list_entry_is_head(temp, &sprd_mcdt_chan_list, list))
+		temp = NULL;
 
 	mutex_unlock(&sprd_mcdt_list_mutex);
 
-	return chan;
+	return temp;
 }
 EXPORT_SYMBOL_GPL(sprd_mcdt_request_chan);
 
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 7c4d63c33f15b33ee71aabb61bf15d17fccd9f65..7d1672cf78cc5e0c350098e7f63ca7cbe7757f63 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -8,6 +8,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/of_irq.h>
@@ -196,6 +197,9 @@ enum i2s_datlen {
 #define STM32_I2S_IS_MASTER(x)		((x)->ms_flg == I2S_MS_MASTER)
 #define STM32_I2S_IS_SLAVE(x)		((x)->ms_flg == I2S_MS_SLAVE)
 
+#define STM32_I2S_NAME_LEN		32
+#define STM32_I2S_RATE_11K		11025
+
 /**
  * struct stm32_i2s_data - private data of I2S
  * @regmap_conf: I2S register map configuration pointer
@@ -206,6 +210,7 @@ enum i2s_datlen {
  * @dma_data_rx: dma configuration data for tx channel
  * @substream: PCM substream data pointer
  * @i2sclk: kernel clock feeding the I2S clock generator
+ * @i2smclk: master clock from I2S mclk provider
  * @pclk: peripheral clock driving bus interface
  * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz
  * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz
@@ -215,6 +220,9 @@ enum i2s_datlen {
  * @irq_lock: prevent race condition with IRQ
  * @mclk_rate: master clock frequency (Hz)
  * @fmt: DAI protocol
+ * @divider: prescaler division ratio
+ * @div: prescaler div field
+ * @odd: prescaler odd field
  * @refcount: keep count of opened streams on I2S
  * @ms_flg: master mode flag.
  */
@@ -227,6 +235,7 @@ struct stm32_i2s_data {
 	struct snd_dmaengine_dai_dma_data dma_data_rx;
 	struct snd_pcm_substream *substream;
 	struct clk *i2sclk;
+	struct clk *i2smclk;
 	struct clk *pclk;
 	struct clk *x8kclk;
 	struct clk *x11kclk;
@@ -236,10 +245,210 @@ struct stm32_i2s_data {
 	spinlock_t irq_lock; /* used to prevent race condition with IRQ */
 	unsigned int mclk_rate;
 	unsigned int fmt;
+	unsigned int divider;
+	unsigned int div;
+	bool odd;
 	int refcount;
 	int ms_flg;
 };
 
+struct stm32_i2smclk_data {
+	struct clk_hw hw;
+	unsigned long freq;
+	struct stm32_i2s_data *i2s_data;
+};
+
+#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw)
+
+static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s,
+				  unsigned long input_rate,
+				  unsigned long output_rate)
+{
+	unsigned int ratio, div, divider = 1;
+	bool odd;
+
+	ratio = DIV_ROUND_CLOSEST(input_rate, output_rate);
+
+	/* Check the parity of the divider */
+	odd = ratio & 0x1;
+
+	/* Compute the div prescaler */
+	div = ratio >> 1;
+
+	/* If div is 0 actual divider is 1 */
+	if (div) {
+		divider = ((2 * div) + odd);
+		dev_dbg(&i2s->pdev->dev, "Divider: 2*%d(div)+%d(odd) = %d\n",
+			div, odd, divider);
+	}
+
+	/* Division by three is not allowed by I2S prescaler */
+	if ((div == 1 && odd) || div > I2S_CGFR_I2SDIV_MAX) {
+		dev_err(&i2s->pdev->dev, "Wrong divider setting\n");
+		return -EINVAL;
+	}
+
+	if (input_rate % divider)
+		dev_dbg(&i2s->pdev->dev,
+			"Rate not accurate. requested (%ld), actual (%ld)\n",
+			output_rate, input_rate / divider);
+
+	i2s->div = div;
+	i2s->odd = odd;
+	i2s->divider = divider;
+
+	return 0;
+}
+
+static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s)
+{
+	u32 cgfr, cgfr_mask;
+
+	cgfr = I2S_CGFR_I2SDIV_SET(i2s->div) | (i2s->odd << I2S_CGFR_ODD_SHIFT);
+	cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD;
+
+	return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+				  cgfr_mask, cgfr);
+}
+
+static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s,
+				      unsigned int rate)
+{
+	struct platform_device *pdev = i2s->pdev;
+	struct clk *parent_clk;
+	int ret;
+
+	if (!(rate % STM32_I2S_RATE_11K))
+		parent_clk = i2s->x11kclk;
+	else
+		parent_clk = i2s->x8kclk;
+
+	ret = clk_set_parent(i2s->i2sclk, parent_clk);
+	if (ret)
+		dev_err(&pdev->dev,
+			"Error %d setting i2sclk parent clock\n", ret);
+
+	return ret;
+}
+
+static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long *prate)
+{
+	struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+	struct stm32_i2s_data *i2s = mclk->i2s_data;
+	int ret;
+
+	ret = stm32_i2s_calc_clk_div(i2s, *prate, rate);
+	if (ret)
+		return ret;
+
+	mclk->freq = *prate / i2s->divider;
+
+	return mclk->freq;
+}
+
+static unsigned long stm32_i2smclk_recalc_rate(struct clk_hw *hw,
+					       unsigned long parent_rate)
+{
+	struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+
+	return mclk->freq;
+}
+
+static int stm32_i2smclk_set_rate(struct clk_hw *hw, unsigned long rate,
+				  unsigned long parent_rate)
+{
+	struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+	struct stm32_i2s_data *i2s = mclk->i2s_data;
+	int ret;
+
+	ret = stm32_i2s_calc_clk_div(i2s, parent_rate, rate);
+	if (ret)
+		return ret;
+
+	ret = stm32_i2s_set_clk_div(i2s);
+	if (ret)
+		return ret;
+
+	mclk->freq = rate;
+
+	return 0;
+}
+
+static int stm32_i2smclk_enable(struct clk_hw *hw)
+{
+	struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+	struct stm32_i2s_data *i2s = mclk->i2s_data;
+
+	dev_dbg(&i2s->pdev->dev, "Enable master clock\n");
+
+	return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+				    I2S_CGFR_MCKOE, I2S_CGFR_MCKOE);
+}
+
+static void stm32_i2smclk_disable(struct clk_hw *hw)
+{
+	struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+	struct stm32_i2s_data *i2s = mclk->i2s_data;
+
+	dev_dbg(&i2s->pdev->dev, "Disable master clock\n");
+
+	regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, 0);
+}
+
+static const struct clk_ops mclk_ops = {
+	.enable = stm32_i2smclk_enable,
+	.disable = stm32_i2smclk_disable,
+	.recalc_rate = stm32_i2smclk_recalc_rate,
+	.round_rate = stm32_i2smclk_round_rate,
+	.set_rate = stm32_i2smclk_set_rate,
+};
+
+static int stm32_i2s_add_mclk_provider(struct stm32_i2s_data *i2s)
+{
+	struct clk_hw *hw;
+	struct stm32_i2smclk_data *mclk;
+	struct device *dev = &i2s->pdev->dev;
+	const char *pname = __clk_get_name(i2s->i2sclk);
+	char *mclk_name, *p, *s = (char *)pname;
+	int ret, i = 0;
+
+	mclk = devm_kzalloc(dev, sizeof(*mclk), GFP_KERNEL);
+	if (!mclk)
+		return -ENOMEM;
+
+	mclk_name = devm_kcalloc(dev, sizeof(char),
+				 STM32_I2S_NAME_LEN, GFP_KERNEL);
+	if (!mclk_name)
+		return -ENOMEM;
+
+	/*
+	 * Forge mclk clock name from parent clock name and suffix.
+	 * String after "_" char is stripped in parent name.
+	 */
+	p = mclk_name;
+	while (*s && *s != '_' && (i < (STM32_I2S_NAME_LEN - 7))) {
+		*p++ = *s++;
+		i++;
+	}
+	strcat(p, "_mclk");
+
+	mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0);
+	mclk->i2s_data = i2s;
+	hw = &mclk->hw;
+
+	dev_dbg(dev, "Register master clock %s\n", mclk_name);
+	ret = devm_clk_hw_register(&i2s->pdev->dev, hw);
+	if (ret) {
+		dev_err(dev, "mclk register fails with error %d\n", ret);
+		return ret;
+	}
+	i2s->i2smclk = hw->clk;
+
+	/* register mclk provider */
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+}
+
 static irqreturn_t stm32_i2s_isr(int irq, void *devid)
 {
 	struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid;
@@ -405,18 +614,46 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
 				int clk_id, unsigned int freq, int dir)
 {
 	struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret = 0;
 
-	dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz\n", freq);
+	dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz. mode: %s, dir: %s\n",
+		freq, STM32_I2S_IS_MASTER(i2s) ? "master" : "slave",
+		dir ? "output" : "input");
 
-	if ((dir == SND_SOC_CLOCK_OUT) && STM32_I2S_IS_MASTER(i2s)) {
-		i2s->mclk_rate = freq;
+	/* MCLK generation is available only in master mode */
+	if (dir == SND_SOC_CLOCK_OUT && STM32_I2S_IS_MASTER(i2s)) {
+		if (!i2s->i2smclk) {
+			dev_dbg(cpu_dai->dev, "No MCLK registered\n");
+			return 0;
+		}
 
-		/* Enable master clock if master mode and mclk-fs are set */
-		return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-					  I2S_CGFR_MCKOE, I2S_CGFR_MCKOE);
+		/* Assume shutdown if requested frequency is 0Hz */
+		if (!freq) {
+			/* Release mclk rate only if rate was actually set */
+			if (i2s->mclk_rate) {
+				clk_rate_exclusive_put(i2s->i2smclk);
+				i2s->mclk_rate = 0;
+			}
+			return regmap_update_bits(i2s->regmap,
+						  STM32_I2S_CGFR_REG,
+						  I2S_CGFR_MCKOE, 0);
+		}
+		/* If master clock is used, set parent clock now */
+		ret = stm32_i2s_set_parent_clock(i2s, freq);
+		if (ret)
+			return ret;
+		ret = clk_set_rate_exclusive(i2s->i2smclk, freq);
+		if (ret) {
+			dev_err(cpu_dai->dev, "Could not set mclk rate\n");
+			return ret;
+		}
+		ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+					 I2S_CGFR_MCKOE, I2S_CGFR_MCKOE);
+		if (!ret)
+			i2s->mclk_rate = freq;
 	}
 
-	return 0;
+	return ret;
 }
 
 static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
@@ -424,11 +661,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
 {
 	struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
 	unsigned long i2s_clock_rate;
-	unsigned int tmp, div, real_div, nb_bits, frame_len;
+	unsigned int nb_bits, frame_len;
 	unsigned int rate = params_rate(params);
+	u32 cgfr;
 	int ret;
-	u32 cgfr, cgfr_mask;
-	bool odd;
 
 	if (!(rate % 11025))
 		clk_set_parent(i2s->i2sclk, i2s->x11kclk);
@@ -449,7 +685,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
 	 *   dsp mode : div = i2s_clk / (nb_bits x ws)
 	 */
 	if (i2s->mclk_rate) {
-		tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, i2s->mclk_rate);
+		ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate,
+					     i2s->mclk_rate);
+		if (ret)
+			return ret;
 	} else {
 		frame_len = 32;
 		if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
@@ -462,34 +701,13 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
 			return ret;
 
 		nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1);
-		tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, (nb_bits * rate));
-	}
-
-	/* Check the parity of the divider */
-	odd = tmp & 0x1;
-
-	/* Compute the div prescaler */
-	div = tmp >> 1;
-
-	cgfr = I2S_CGFR_I2SDIV_SET(div) | (odd << I2S_CGFR_ODD_SHIFT);
-	cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD;
-
-	real_div = ((2 * div) + odd);
-	dev_dbg(cpu_dai->dev, "I2S clk: %ld, SCLK: %d\n",
-		i2s_clock_rate, rate);
-	dev_dbg(cpu_dai->dev, "Divider: 2*%d(div)+%d(odd) = %d\n",
-		div, odd, real_div);
-
-	if (((div == 1) && odd) || (div > I2S_CGFR_I2SDIV_MAX)) {
-		dev_err(cpu_dai->dev, "Wrong divider setting\n");
-		return -EINVAL;
+		ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate,
+					     (nb_bits * rate));
+		if (ret)
+			return ret;
 	}
 
-	if (!div && !odd)
-		dev_warn(cpu_dai->dev, "real divider forced to 1\n");
-
-	ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-				 cgfr_mask, cgfr);
+	ret = stm32_i2s_set_clk_div(i2s);
 	if (ret < 0)
 		return ret;
 
@@ -694,9 +912,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream,
 	struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
 	unsigned long flags;
 
-	regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-			   I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE);
-
 	clk_disable_unprepare(i2s->i2sclk);
 
 	spin_lock_irqsave(&i2s->irq_lock, flags);
@@ -861,6 +1076,13 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
 		return PTR_ERR(i2s->x11kclk);
 	}
 
+	/* Register mclk provider if requested */
+	if (of_find_property(np, "#clock-cells", NULL)) {
+		ret = stm32_i2s_add_mclk_provider(i2s);
+		if (ret < 0)
+			return ret;
+	}
+
 	/* Get irqs */
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -906,16 +1128,16 @@ static int stm32_i2s_probe(struct platform_device *pdev)
 	if (!i2s)
 		return -ENOMEM;
 
-	ret = stm32_i2s_parse_dt(pdev, i2s);
-	if (ret)
-		return ret;
-
 	i2s->pdev = pdev;
 	i2s->ms_flg = I2S_MS_NOT_SET;
 	spin_lock_init(&i2s->lock_fd);
 	spin_lock_init(&i2s->irq_lock);
 	platform_set_drvdata(pdev, i2s);
 
+	ret = stm32_i2s_parse_dt(pdev, i2s);
+	if (ret)
+		return ret;
+
 	ret = stm32_i2s_dais_init(pdev, i2s);
 	if (ret)
 		return ret;
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 4b8ca5be0a29101bb3b40261f4a7501372a2c697..78506c3811dc75e87578fded1c2407f2f1f25886 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1105,7 +1105,7 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
 		.formats = SUN4I_FORMATS,
 	},
 	.ops = &sun4i_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver sun4i_i2s_component = {
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 180442c62be13c21b7c676645a60ce0b90dc53c3..460924fc173fbcc16e592c8410fb7ff77e1aa6fc 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -640,9 +640,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
-		.symmetric_rates	= true,
+		.symmetric_rate		= true,
 		.symmetric_channels	= true,
-		.symmetric_samplebits	= true,
+		.symmetric_sample_bits	= true,
 	},
 	{
 		.name	= "sun8i-codec-aif2",
@@ -665,9 +665,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
-		.symmetric_rates	= true,
+		.symmetric_rate		= true,
 		.symmetric_channels	= true,
-		.symmetric_samplebits	= true,
+		.symmetric_sample_bits	= true,
 	},
 	{
 		.name	= "sun8i-codec-aif3",
@@ -690,9 +690,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
 			.rates		= SUN8I_CODEC_PCM_RATES,
 			.formats	= SUN8I_CODEC_PCM_FORMATS,
 		},
-		.symmetric_rates	= true,
+		.symmetric_rate		= true,
 		.symmetric_channels	= true,
-		.symmetric_samplebits	= true,
+		.symmetric_sample_bits	= true,
 	},
 };
 
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index a62cc87551acf3d19fb4e4f99abd754f79697409..a4e6760944d028cf9295e7ac5e91ecff8ef38fa0 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -9,9 +9,10 @@ config SND_SOC_TEGRA
 	help
 	  Say Y or M here if you want support for SoC audio on Tegra.
 
+if SND_SOC_TEGRA
+
 config SND_SOC_TEGRA20_AC97
 	tristate "Tegra20 AC97 interface"
-	depends on SND_SOC_TEGRA
 	select SND_SOC_AC97_BUS
 	select SND_SOC_TEGRA20_DAS
 	help
@@ -21,7 +22,6 @@ config SND_SOC_TEGRA20_AC97
 
 config SND_SOC_TEGRA20_DAS
 	tristate "Tegra20 DAS module"
-	depends on SND_SOC_TEGRA
 	help
 	  Say Y or M if you want to add support for the Tegra20 DAS module.
 	  You will also need to select the individual machine drivers to
@@ -29,7 +29,6 @@ config SND_SOC_TEGRA20_DAS
 
 config SND_SOC_TEGRA20_I2S
 	tristate "Tegra20 I2S interface"
-	depends on SND_SOC_TEGRA
 	select SND_SOC_TEGRA20_DAS
 	help
 	  Say Y or M if you want to add support for codecs attached to the
@@ -38,7 +37,6 @@ config SND_SOC_TEGRA20_I2S
 
 config SND_SOC_TEGRA20_SPDIF
 	tristate "Tegra20 SPDIF interface"
-	depends on SND_SOC_TEGRA
 	help
 	  Say Y or M if you want to add support for the Tegra20 SPDIF interface.
 	  You will also need to select the individual machine drivers to support
@@ -46,7 +44,6 @@ config SND_SOC_TEGRA20_SPDIF
 
 config SND_SOC_TEGRA30_AHUB
 	tristate "Tegra30 AHUB module"
-	depends on SND_SOC_TEGRA
 	help
 	  Say Y or M if you want to add support for the Tegra30 AHUB module.
 	  You will also need to select the individual machine drivers to
@@ -54,7 +51,6 @@ config SND_SOC_TEGRA30_AHUB
 
 config SND_SOC_TEGRA30_I2S
 	tristate "Tegra30 I2S interface"
-	depends on SND_SOC_TEGRA
 	select SND_SOC_TEGRA30_AHUB
 	help
 	  Say Y or M if you want to add support for codecs attached to the
@@ -63,7 +59,6 @@ config SND_SOC_TEGRA30_I2S
 
 config SND_SOC_TEGRA210_AHUB
 	tristate "Tegra210 AHUB module"
-	depends on SND_SOC_TEGRA
 	help
 	  Config to enable Audio Hub (AHUB) module, which comprises of a
 	  switch called Audio Crossbar (AXBAR) used to configure or modify
@@ -73,7 +68,6 @@ config SND_SOC_TEGRA210_AHUB
 
 config SND_SOC_TEGRA210_DMIC
 	tristate "Tegra210 DMIC module"
-	depends on SND_SOC_TEGRA
 	help
 	  Config to enable the Digital MIC (DMIC) controller which is used
 	  to interface with Pulse Density Modulation (PDM) input devices.
@@ -84,7 +78,6 @@ config SND_SOC_TEGRA210_DMIC
 
 config SND_SOC_TEGRA210_I2S
 	tristate "Tegra210 I2S module"
-	depends on SND_SOC_TEGRA
 	help
 	  Config to enable the Inter-IC Sound (I2S) Controller which
 	  implements full-duplex and bidirectional and single direction
@@ -94,7 +87,6 @@ config SND_SOC_TEGRA210_I2S
 
 config SND_SOC_TEGRA186_DSPK
 	tristate "Tegra186 DSPK module"
-	depends on SND_SOC_TEGRA
 	help
 	  Config to enable the Digital Speaker Controller (DSPK) which
 	  converts the multi-bit Pulse Code Modulation (PCM) audio input to
@@ -107,7 +99,6 @@ config SND_SOC_TEGRA186_DSPK
 
 config SND_SOC_TEGRA210_ADMAIF
 	tristate "Tegra210 ADMAIF module"
-	depends on SND_SOC_TEGRA
 	help
 	  Config to enable ADMAIF which is the interface between ADMA and
 	  Audio Hub (AHUB). Each ADMA channel that sends/receives data to/
@@ -117,9 +108,18 @@ config SND_SOC_TEGRA210_ADMAIF
 	  channel. Buffer size is configurable for each ADMAIIF channel.
 	  Say Y or M if you want to add support for Tegra210 ADMAIF module.
 
+config SND_SOC_TEGRA_AUDIO_GRAPH_CARD
+	tristate "Audio Graph Card based Tegra driver"
+	depends on SND_AUDIO_GRAPH_CARD
+	help
+	  Config to enable Tegra audio machine driver based on generic
+	  audio graph driver. It is a thin driver written to customize
+	  few things for Tegra audio. Most of the code is re-used from
+	  audio graph driver and the same DT bindings are used.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_RT5640
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -127,7 +127,7 @@ config SND_SOC_TEGRA_RT5640
 
 config SND_SOC_TEGRA_WM8753
 	tristate "SoC Audio support for Tegra boards using a WM8753 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_WM8753
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -135,7 +135,7 @@ config SND_SOC_TEGRA_WM8753
 
 config SND_SOC_TEGRA_WM8903
 	tristate "SoC Audio support for Tegra boards using a WM8903 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_WM8903
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -144,7 +144,7 @@ config SND_SOC_TEGRA_WM8903
 
 config SND_SOC_TEGRA_WM9712
 	tristate "SoC Audio support for Tegra boards using a WM9712 codec"
-	depends on SND_SOC_TEGRA && GPIOLIB
+	depends on GPIOLIB
 	select SND_SOC_TEGRA20_AC97
 	select SND_SOC_WM9712
 	help
@@ -153,7 +153,7 @@ config SND_SOC_TEGRA_WM9712
 
 config SND_SOC_TEGRA_TRIMSLICE
 	tristate "SoC Audio support for TrimSlice board"
-	depends on SND_SOC_TEGRA && I2C
+	depends on I2C
 	select SND_SOC_TLV320AIC23_I2C
 	help
 	  Say Y or M here if you want to add support for SoC audio on the
@@ -161,7 +161,7 @@ config SND_SOC_TEGRA_TRIMSLICE
 
 config SND_SOC_TEGRA_ALC5632
 	tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_ALC5632
 	help
 	  Say Y or M here if you want to add support for SoC audio on the
@@ -169,7 +169,7 @@ config SND_SOC_TEGRA_ALC5632
 
 config SND_SOC_TEGRA_MAX98090
 	tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_MAX98090
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -177,7 +177,7 @@ config SND_SOC_TEGRA_MAX98090
 
 config SND_SOC_TEGRA_RT5677
 	tristate "SoC Audio support for Tegra boards using a RT5677 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_RT5677
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -185,9 +185,11 @@ config SND_SOC_TEGRA_RT5677
 
 config SND_SOC_TEGRA_SGTL5000
 	tristate "SoC Audio support for Tegra boards using a SGTL5000 codec"
-	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	depends on I2C && GPIOLIB
 	select SND_SOC_SGTL5000
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
 	  boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or
 	  Colibri T30.
+
+endif
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 60040a06b814fb90ca6940bb8f1b1a215cfbf778..b17dd6eef92ac88d1012b5511e60a3daae31a52d 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -38,6 +38,7 @@ snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 snd-soc-tegra-max98090-objs := tegra_max98090.o
 snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o
+snd-soc-tegra-audio-graph-card-objs := tegra_audio_graph_card.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
 obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
@@ -48,3 +49,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
 obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
 obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
 obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o
+obj-$(CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD) += snd-soc-tegra-audio-graph-card.o
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
index 7d9948fb2ca7444f50a49349b12d4fd3cfefb4eb..8ee9a77bd83d375832de31094be44878093ecfdd 100644
--- a/sound/soc/tegra/tegra186_dspk.c
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -217,7 +217,7 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
 			   SNDRV_PCM_FMTBIT_S32_LE,
 	    },
 	    .ops = &tegra186_dspk_dai_ops,
-	    .symmetric_rates = 1,
+	    .symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 005fc4e645aa58320a9fb1bfbf82fc87a760030a..d7a3d046c8f88939d26031761d03e8f68a851c86 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -260,7 +260,7 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.ops = &tegra20_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver tegra20_i2s_component = {
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
index ead2c99bf72efe55ef25514c95cecb546d56603b..b096478cd2ef0f65eb30239b1e781c0831ec8fad 100644
--- a/sound/soc/tegra/tegra210_dmic.c
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -228,7 +228,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
 				   SNDRV_PCM_FMTBIT_S32_LE,
 		},
 		.ops = &tegra210_dmic_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index ca31ec92e50827b12affa0fd76a63b16a70cc05a..45f31ccb49d89ee2fc195e64e1e89a180c45f862 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -577,7 +577,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
 				SNDRV_PCM_FMTBIT_S32_LE,
 		},
 		.ops = &tegra210_i2s_dai_ops,
-		.symmetric_rates = 1,
+		.symmetric_rate = 1,
 	},
 };
 
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 156e3b9d613c6eabaa8745ed0cfa510e3aaaaf3e..9ef05ca4f6c4db5a385b999ba1d71ce4364f7471 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -45,8 +45,7 @@ static int tegra30_ahub_runtime_suspend(struct device *dev)
 	regcache_cache_only(ahub->regmap_apbif, true);
 	regcache_cache_only(ahub->regmap_ahub, true);
 
-	clk_disable_unprepare(ahub->clk_apbif);
-	clk_disable_unprepare(ahub->clk_d_audio);
+	clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
 
 	return 0;
 }
@@ -66,22 +65,39 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 {
 	int ret;
 
-	ret = clk_prepare_enable(ahub->clk_d_audio);
-	if (ret) {
-		dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
+	ret = reset_control_assert(ahub->reset);
+	if (ret)
 		return ret;
-	}
-	ret = clk_prepare_enable(ahub->clk_apbif);
-	if (ret) {
-		dev_err(dev, "clk_enable apbif failed: %d\n", ret);
-		clk_disable(ahub->clk_d_audio);
+
+	ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
+	if (ret)
 		return ret;
-	}
+
+	usleep_range(10, 100);
+
+	ret = reset_control_deassert(ahub->reset);
+	if (ret)
+		goto disable_clocks;
 
 	regcache_cache_only(ahub->regmap_apbif, false);
 	regcache_cache_only(ahub->regmap_ahub, false);
+	regcache_mark_dirty(ahub->regmap_apbif);
+	regcache_mark_dirty(ahub->regmap_ahub);
+
+	ret = regcache_sync(ahub->regmap_apbif);
+	if (ret)
+		goto disable_clocks;
+
+	ret = regcache_sync(ahub->regmap_ahub);
+	if (ret)
+		goto disable_clocks;
 
 	return 0;
+
+disable_clocks:
+	clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
+
+	return ret;
 }
 
 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
@@ -337,6 +353,8 @@ static const struct {
 	const char *rst_name;
 	u32 mod_list_mask;
 } configlink_mods[] = {
+	{ "d_audio", MOD_LIST_MASK_TEGRA30_OR_LATER },
+	{ "apbif", MOD_LIST_MASK_TEGRA30_OR_LATER },
 	{ "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
 	{ "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
 	{ "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
@@ -526,7 +544,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	/*
 	 * The AHUB hosts a register bus: the "configlink". For this to
 	 * operate correctly, all devices on this bus must be out of reset.
-	 * Ensure that here.
 	 */
 	for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
 		if (!(configlink_mods[i].mod_list_mask &
@@ -542,10 +559,8 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 			return ret;
 		}
 
-		ret = reset_control_deassert(rst);
+		/* just check presence of the reset control in DT */
 		reset_control_put(rst);
-		if (ret)
-			return ret;
 	}
 
 	ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
@@ -557,18 +572,17 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	ahub->soc_data = soc_data;
 	ahub->dev = &pdev->dev;
 
-	ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio");
-	if (IS_ERR(ahub->clk_d_audio)) {
-		dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
-		ret = PTR_ERR(ahub->clk_d_audio);
-		return ret;
-	}
+	ahub->clocks[ahub->nclocks++].id = "apbif";
+	ahub->clocks[ahub->nclocks++].id = "d_audio";
 
-	ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif");
-	if (IS_ERR(ahub->clk_apbif)) {
-		dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
-		ret = PTR_ERR(ahub->clk_apbif);
+	ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
+	if (ret)
 		return ret;
+
+	ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
+	if (IS_ERR(ahub->reset)) {
+		dev_err(&pdev->dev, "Can't get resets: %pe\n", ahub->reset);
+		return PTR_ERR(ahub->reset);
 	}
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 6889c5f23d021fa74d014bc08c6ad4dad28c522d..3b85244f87f19e98b854deb5a6506c30d07ee4de 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -511,8 +511,9 @@ struct tegra30_ahub_soc_data {
 struct tegra30_ahub {
 	const struct tegra30_ahub_soc_data *soc_data;
 	struct device *dev;
-	struct clk *clk_d_audio;
-	struct clk *clk_apbif;
+	struct reset_control *reset;
+	struct clk_bulk_data clocks[2];
+	unsigned int nclocks;
 	resource_size_t apbif_addr;
 	struct regmap *regmap_apbif;
 	struct regmap *regmap_ahub;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index db5a8587bfa4c38b10334ac61c108c44bc5b79dc..6740df541508fd295924a4dac3101c9d16d4a0b6 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -316,7 +316,7 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.ops = &tegra30_i2s_dai_ops,
-	.symmetric_rates = 1,
+	.symmetric_rate = 1,
 };
 
 static const struct snd_soc_component_driver tegra30_i2s_component = {
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
new file mode 100644
index 0000000000000000000000000000000000000000..ddedf18adde188d0dcda0de1ee5ea1d132aa317b
--- /dev/null
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver
+//
+// Copyright (c) 2020-2021 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/graph_card.h>
+#include <sound/pcm_params.h>
+
+#define MAX_PLLA_OUT0_DIV 128
+
+#define simple_to_tegra_priv(simple) \
+		container_of(simple, struct tegra_audio_priv, simple)
+
+enum srate_type {
+	/*
+	 * Sample rates multiple of 8000 Hz and below are supported:
+	 * ( 8000, 16000, 32000, 48000, 96000, 192000 Hz )
+	 */
+	x8_RATE,
+
+	/*
+	 * Sample rates multiple of 11025 Hz and below are supported:
+	 * ( 11025, 22050, 44100, 88200, 176400 Hz )
+	 */
+	x11_RATE,
+
+	NUM_RATE_TYPE,
+};
+
+struct tegra_audio_priv {
+	struct asoc_simple_priv simple;
+	struct clk *clk_plla_out0;
+	struct clk *clk_plla;
+};
+
+/* Tegra audio chip data */
+struct tegra_audio_cdata {
+	unsigned int plla_rates[NUM_RATE_TYPE];
+	unsigned int plla_out0_rates[NUM_RATE_TYPE];
+};
+
+/* Setup PLL clock as per the given sample rate */
+static int tegra_audio_graph_update_pll(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(rtd->card);
+	struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+	struct device *dev = rtd->card->dev;
+	const struct tegra_audio_cdata *data = of_device_get_match_data(dev);
+	unsigned int plla_rate, plla_out0_rate, bclk;
+	unsigned int srate = params_rate(params);
+	int err;
+
+	switch (srate) {
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+	case 176400:
+		plla_out0_rate = data->plla_out0_rates[x11_RATE];
+		plla_rate = data->plla_rates[x11_RATE];
+		break;
+	case 8000:
+	case 16000:
+	case 32000:
+	case 48000:
+	case 96000:
+	case 192000:
+		plla_out0_rate = data->plla_out0_rates[x8_RATE];
+		plla_rate = data->plla_rates[x8_RATE];
+		break;
+	default:
+		dev_err(rtd->card->dev, "Unsupported sample rate %u\n",
+			srate);
+		return -EINVAL;
+	}
+
+	/*
+	 * Below is the clock relation:
+	 *
+	 *	PLLA
+	 *	  |
+	 *	  |--> PLLA_OUT0
+	 *		  |
+	 *		  |---> I2S modules
+	 *		  |
+	 *		  |---> DMIC modules
+	 *		  |
+	 *		  |---> DSPK modules
+	 *
+	 *
+	 * Default PLLA_OUT0 rate might be too high when I/O is running
+	 * at minimum PCM configurations. This may result in incorrect
+	 * clock rates and glitchy audio. The maximum divider is 128
+	 * and any thing higher than that won't work. Thus reduce PLLA_OUT0
+	 * to work for lower configurations.
+	 *
+	 * This problem is seen for I2S only, as DMIC and DSPK minimum
+	 * clock requirements are under allowed divider limits.
+	 */
+	bclk = srate * params_channels(params) * params_width(params);
+	if (div_u64(plla_out0_rate, bclk) > MAX_PLLA_OUT0_DIV)
+		plla_out0_rate >>= 1;
+
+	dev_dbg(rtd->card->dev,
+		"Update clock rates: PLLA(= %u Hz) and PLLA_OUT0(= %u Hz)\n",
+		plla_rate, plla_out0_rate);
+
+	/* Set PLLA rate */
+	err = clk_set_rate(priv->clk_plla, plla_rate);
+	if (err) {
+		dev_err(rtd->card->dev,
+			"Can't set plla rate for %u, err: %d\n",
+			plla_rate, err);
+		return err;
+	}
+
+	/* Set PLLA_OUT0 rate */
+	err = clk_set_rate(priv->clk_plla_out0, plla_out0_rate);
+	if (err) {
+		dev_err(rtd->card->dev,
+			"Can't set plla_out0 rate %u, err: %d\n",
+			plla_out0_rate, err);
+		return err;
+	}
+
+	return err;
+}
+
+static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int err;
+
+	/*
+	 * This gets called for each DAI link (FE or BE) when DPCM is used.
+	 * We may not want to update PLLA rate for each call. So PLLA update
+	 * must be restricted to external I/O links (I2S, DMIC or DSPK) since
+	 * they actually depend on it. I/O modules update their clocks in
+	 * hw_param() of their respective component driver and PLLA rate
+	 * update here helps them to derive appropriate rates.
+	 *
+	 * TODO: When more HW accelerators get added (like sample rate
+	 * converter, volume gain controller etc., which don't really
+	 * depend on PLLA) we need a better way to filter here.
+	 */
+	if (cpu_dai->driver->ops && rtd->dai_link->no_pcm) {
+		err = tegra_audio_graph_update_pll(substream, params);
+		if (err)
+			return err;
+	}
+
+	return asoc_simple_hw_params(substream, params);
+}
+
+static const struct snd_soc_ops tegra_audio_graph_ops = {
+	.startup	= asoc_simple_startup,
+	.shutdown	= asoc_simple_shutdown,
+	.hw_params	= tegra_audio_graph_hw_params,
+};
+
+static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
+{
+	struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(card);
+	struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+
+	priv->clk_plla = devm_clk_get(card->dev, "pll_a");
+	if (IS_ERR(priv->clk_plla)) {
+		dev_err(card->dev, "Can't retrieve clk pll_a\n");
+		return PTR_ERR(priv->clk_plla);
+	}
+
+	priv->clk_plla_out0 = devm_clk_get(card->dev, "plla_out0");
+	if (IS_ERR(priv->clk_plla_out0)) {
+		dev_err(card->dev, "Can't retrieve clk plla_out0\n");
+		return PTR_ERR(priv->clk_plla_out0);
+	}
+
+	return audio_graph_card_probe(card);
+}
+
+static int tegra_audio_graph_probe(struct platform_device *pdev)
+{
+	struct tegra_audio_priv *priv;
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	card = simple_priv_to_card(&priv->simple);
+
+	card->probe = tegra_audio_graph_card_probe;
+
+	/* audio_graph_parse_of() depends on below */
+	card->component_chaining = 1;
+	priv->simple.ops = &tegra_audio_graph_ops;
+	priv->simple.force_dpcm = 1;
+
+	return audio_graph_parse_of(&priv->simple, dev);
+}
+
+static const struct tegra_audio_cdata tegra210_data = {
+	/* PLLA */
+	.plla_rates[x8_RATE] = 368640000,
+	.plla_rates[x11_RATE] = 338688000,
+	/* PLLA_OUT0 */
+	.plla_out0_rates[x8_RATE] = 49152000,
+	.plla_out0_rates[x11_RATE] = 45158400,
+};
+
+static const struct tegra_audio_cdata tegra186_data = {
+	/* PLLA */
+	.plla_rates[x8_RATE] = 245760000,
+	.plla_rates[x11_RATE] = 270950400,
+	/* PLLA_OUT0 */
+	.plla_out0_rates[x8_RATE] = 49152000,
+	.plla_out0_rates[x11_RATE] = 45158400,
+};
+
+static const struct of_device_id graph_of_tegra_match[] = {
+	{ .compatible = "nvidia,tegra210-audio-graph-card",
+	  .data = &tegra210_data },
+	{ .compatible = "nvidia,tegra186-audio-graph-card",
+	  .data = &tegra186_data },
+	{},
+};
+MODULE_DEVICE_TABLE(of, graph_of_tegra_match);
+
+static struct platform_driver tegra_audio_graph_card = {
+	.driver = {
+		.name = "tegra-audio-graph-card",
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = graph_of_tegra_match,
+	},
+	.probe = tegra_audio_graph_probe,
+	.remove = audio_graph_remove,
+};
+module_platform_driver(tegra_audio_graph_card);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Tegra Audio Graph Sound Card");
+MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index b3f36515cbc188aa6ec0c1a938b5cdfdea865bf8..573374b89b100a9ae296a437e27bc5e12a30f4e1 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -255,11 +255,7 @@ static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
 	struct snd_pcm *pcm = rtd->pcm;
 	int ret;
 
-	ret = dma_set_mask(card->dev, DMA_BIT_MASK(32));
-	if (ret < 0)
-		return ret;
-
-	ret = dma_set_coherent_mask(card->dev, DMA_BIT_MASK(32));
+	ret = dma_set_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 6247ec3d3a096c23ec0396ba308ca2d7a1a92558..b94220306d1a88bc52a8a08a303e758a35fdc0af 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -1641,7 +1641,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 		},
 		.ops 		= &davinci_mcasp_dai_ops,
 
-		.symmetric_rates	= 1,
+		.symmetric_rate		= 1,
 	},
 	{
 		.name		= "davinci-mcasp.1",
diff --git a/sound/soc/txx9/Kconfig b/sound/soc/txx9/Kconfig
deleted file mode 100644
index d928edf9f5a909818e9ddc33ace7a2dabdd89de2..0000000000000000000000000000000000000000
--- a/sound/soc/txx9/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-##
-## TXx9 ACLC
-##
-config SND_SOC_TXX9ACLC
-	tristate "SoC Audio for TXx9"
-	depends on HAS_TXX9_ACLC && TXX9_DMAC
-	help
-	  This option enables support for the AC Link Controllers in TXx9 SoC.
-
-config HAS_TXX9_ACLC
-	bool
-
-config SND_SOC_TXX9ACLC_AC97
-	tristate
-	select AC97_BUS
-	select SND_AC97_CODEC
-	select SND_SOC_AC97_BUS
-
-
-##
-## Boards
-##
-config SND_SOC_TXX9ACLC_GENERIC
-	tristate "Generic TXx9 ACLC sound machine"
-	depends on SND_SOC_TXX9ACLC
-	select SND_SOC_TXX9ACLC_AC97
-	select SND_SOC_AC97_CODEC
-	help
-	  This is a generic AC97 sound machine for use in TXx9 based systems.
diff --git a/sound/soc/txx9/Makefile b/sound/soc/txx9/Makefile
deleted file mode 100644
index 37ad833eb329b64f9fc95487cbfc642f59f553bc..0000000000000000000000000000000000000000
--- a/sound/soc/txx9/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Platform
-snd-soc-txx9aclc-objs := txx9aclc.o
-snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o
-
-obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o
-obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o
-
-# Machine
-snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o
-
-obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
deleted file mode 100644
index d9e348444bd0d82fa5ecc1cd266f1e053708d250..0000000000000000000000000000000000000000
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ /dev/null
@@ -1,230 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * TXx9 ACLC AC97 driver
- *
- * Copyright (C) 2009 Atsushi Nemoto
- *
- * Based on RBTX49xx patch from CELF patch archive.
- * (C) Copyright TOSHIBA CORPORATION 2004-2006
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/gfp.h>
-#include <asm/mach-tx39xx/ioremap.h> /* for TXX9_DIRECTMAP_BASE */
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "txx9aclc.h"
-
-#define AC97_DIR	\
-	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
-
-#define AC97_RATES	\
-	SNDRV_PCM_RATE_8000_48000
-
-#ifdef __BIG_ENDIAN
-#define AC97_FMTS	SNDRV_PCM_FMTBIT_S16_BE
-#else
-#define AC97_FMTS	SNDRV_PCM_FMTBIT_S16_LE
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
-
-/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
-static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
-
-static int txx9aclc_regready(struct txx9aclc_plat_drvdata *drvdata)
-{
-	return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
-}
-
-/* AC97 controller reads codec register */
-static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
-					 unsigned short reg)
-{
-	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-	void __iomem *base = drvdata->base;
-	u32 dat;
-
-	if (!(__raw_readl(base + ACINTSTS) & ACINT_CODECRDY(ac97->num)))
-		return 0xffff;
-	reg |= ac97->num << 7;
-	dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
-	__raw_writel(dat, base + ACREGACC);
-	__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-	if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
-		__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-		printk(KERN_ERR "ac97 read timeout (reg %#x)\n", reg);
-		dat = 0xffff;
-		goto done;
-	}
-	dat = __raw_readl(base + ACREGACC);
-	if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
-		printk(KERN_ERR "reg mismatch %x with %x\n",
-			dat, reg);
-		dat = 0xffff;
-		goto done;
-	}
-	dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff;
-done:
-	__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-	return dat;
-}
-
-/* AC97 controller writes to codec register */
-static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-				unsigned short val)
-{
-	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-	void __iomem *base = drvdata->base;
-
-	__raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
-		     (val << ACREGACC_DAT_SHIFT),
-		     base + ACREGACC);
-	__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-	if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
-		printk(KERN_ERR
-			"ac97 write timeout (reg %#x)\n", reg);
-	}
-	__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-}
-
-static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
-{
-	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-	void __iomem *base = drvdata->base;
-	u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
-
-	__raw_writel(ACCTL_ENLINK, base + ACCTLDIS);
-	udelay(1);
-	__raw_writel(ACCTL_ENLINK, base + ACCTLEN);
-	/* wait for primary codec ready status */
-	__raw_writel(ready, base + ACINTEN);
-	if (!wait_event_timeout(ac97_waitq,
-				(__raw_readl(base + ACINTSTS) & ready) == ready,
-				HZ)) {
-		dev_err(&ac97->dev, "primary codec is not ready "
-			"(status %#x)\n",
-			__raw_readl(base + ACINTSTS));
-	}
-	__raw_writel(ACINT_REGACCRDY, base + ACINTSTS);
-	__raw_writel(ready, base + ACINTDIS);
-}
-
-/* AC97 controller operations */
-static struct snd_ac97_bus_ops txx9aclc_ac97_ops = {
-	.read		= txx9aclc_ac97_read,
-	.write		= txx9aclc_ac97_write,
-	.reset		= txx9aclc_ac97_cold_reset,
-};
-
-static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
-{
-	struct txx9aclc_plat_drvdata *drvdata = dev_id;
-	void __iomem *base = drvdata->base;
-
-	__raw_writel(__raw_readl(base + ACINTMSTS), base + ACINTDIS);
-	wake_up(&ac97_waitq);
-	return IRQ_HANDLED;
-}
-
-static int txx9aclc_ac97_probe(struct snd_soc_dai *dai)
-{
-	txx9aclc_drvdata = snd_soc_dai_get_drvdata(dai);
-	return 0;
-}
-
-static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
-{
-	struct txx9aclc_plat_drvdata *drvdata = snd_soc_dai_get_drvdata(dai);
-
-	/* disable AC-link */
-	__raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
-	txx9aclc_drvdata = NULL;
-	return 0;
-}
-
-static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
-	.probe			= txx9aclc_ac97_probe,
-	.remove			= txx9aclc_ac97_remove,
-	.playback = {
-		.rates		= AC97_RATES,
-		.formats	= AC97_FMTS,
-		.channels_min	= 2,
-		.channels_max	= 2,
-	},
-	.capture = {
-		.rates		= AC97_RATES,
-		.formats	= AC97_FMTS,
-		.channels_min	= 2,
-		.channels_max	= 2,
-	},
-};
-
-static const struct snd_soc_component_driver txx9aclc_ac97_component = {
-	.name		= "txx9aclc-ac97",
-};
-
-static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
-{
-	struct txx9aclc_plat_drvdata *drvdata;
-	struct resource *r;
-	int err;
-	int irq;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata)
-		return -ENOMEM;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	drvdata->base = devm_ioremap_resource(&pdev->dev, r);
-	if (IS_ERR(drvdata->base))
-		return PTR_ERR(drvdata->base);
-
-	platform_set_drvdata(pdev, drvdata);
-	drvdata->physbase = r->start;
-	if (sizeof(drvdata->physbase) > sizeof(r->start) &&
-	    r->start >= TXX9_DIRECTMAP_BASE &&
-	    r->start < TXX9_DIRECTMAP_BASE + 0x400000)
-		drvdata->physbase |= 0xf00000000ull;
-	err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
-			       0, dev_name(&pdev->dev), drvdata);
-	if (err < 0)
-		return err;
-
-	err = snd_soc_set_ac97_ops(&txx9aclc_ac97_ops);
-	if (err < 0)
-		return err;
-
-	return devm_snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
-					  &txx9aclc_ac97_dai, 1);
-}
-
-static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
-{
-	snd_soc_set_ac97_ops(NULL);
-	return 0;
-}
-
-static struct platform_driver txx9aclc_ac97_driver = {
-	.probe		= txx9aclc_ac97_dev_probe,
-	.remove		= txx9aclc_ac97_dev_remove,
-	.driver		= {
-		.name	= "txx9aclc-ac97",
-	},
-};
-
-module_platform_driver(txx9aclc_ac97_driver);
-
-MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
-MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:txx9aclc-ac97");
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
deleted file mode 100644
index d6893721ba1d1a8447eec59a6d2f1d34c87fb8d9..0000000000000000000000000000000000000000
--- a/sound/soc/txx9/txx9aclc-generic.c
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic TXx9 ACLC machine driver
- *
- * Copyright (C) 2009 Atsushi Nemoto
- *
- * Based on RBTX49xx patch from CELF patch archive.
- * (C) Copyright TOSHIBA CORPORATION 2004-2006
- *
- * This is a very generic AC97 sound machine driver for boards which
- * have (AC97) audio at ACLC (e.g. RBTX49XX boards).
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "txx9aclc.h"
-
-SND_SOC_DAILINK_DEFS(hifi,
-	DAILINK_COMP_ARRAY(COMP_CPU("txx9aclc-ac97")),
-	DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")),
-	DAILINK_COMP_ARRAY(COMP_PLATFORM("txx9aclc-pcm-audio")));
-
-static struct snd_soc_dai_link txx9aclc_generic_dai = {
-	.name = "AC97",
-	.stream_name = "AC97 HiFi",
-	SND_SOC_DAILINK_REG(hifi),
-};
-
-static struct snd_soc_card txx9aclc_generic_card = {
-	.name		= "Generic TXx9 ACLC Audio",
-	.owner		= THIS_MODULE,
-	.dai_link	= &txx9aclc_generic_dai,
-	.num_links	= 1,
-};
-
-static struct platform_device *soc_pdev;
-
-static int __init txx9aclc_generic_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	soc_pdev = platform_device_alloc("soc-audio", -1);
-	if (!soc_pdev)
-		return -ENOMEM;
-	platform_set_drvdata(soc_pdev, &txx9aclc_generic_card);
-	ret = platform_device_add(soc_pdev);
-	if (ret) {
-		platform_device_put(soc_pdev);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
-{
-	platform_device_unregister(soc_pdev);
-	return 0;
-}
-
-static struct platform_driver txx9aclc_generic_driver = {
-	.remove = __exit_p(txx9aclc_generic_remove),
-	.driver = {
-		.name = "txx9aclc-generic",
-	},
-};
-
-static int __init txx9aclc_generic_init(void)
-{
-	return platform_driver_probe(&txx9aclc_generic_driver,
-				     txx9aclc_generic_probe);
-}
-
-static void __exit txx9aclc_generic_exit(void)
-{
-	platform_driver_unregister(&txx9aclc_generic_driver);
-}
-
-module_init(txx9aclc_generic_init);
-module_exit(txx9aclc_generic_exit);
-
-MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
-MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:txx9aclc-generic");
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
deleted file mode 100644
index 1d2d0d9b57b0e83d3e17239dc03b770e0d8363cd..0000000000000000000000000000000000000000
--- a/sound/soc/txx9/txx9aclc.c
+++ /dev/null
@@ -1,422 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic TXx9 ACLC platform driver
- *
- * Copyright (C) 2009 Atsushi Nemoto
- *
- * Based on RBTX49xx patch from CELF patch archive.
- * (C) Copyright TOSHIBA CORPORATION 2004-2006
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "txx9aclc.h"
-
-#define DRV_NAME "txx9aclc"
-
-static struct txx9aclc_soc_device {
-	struct txx9aclc_dmadata dmadata[2];
-} txx9aclc_soc_device;
-
-/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
-static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
-
-static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
-			     struct txx9aclc_dmadata *dmadata);
-
-static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
-	/*
-	 * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
-	 * needs more works for noncoherent MIPS.
-	 */
-	.info		  = SNDRV_PCM_INFO_INTERLEAVED |
-			    SNDRV_PCM_INFO_BATCH |
-			    SNDRV_PCM_INFO_PAUSE,
-	.period_bytes_min = 1024,
-	.period_bytes_max = 8 * 1024,
-	.periods_min	  = 2,
-	.periods_max	  = 4096,
-	.buffer_bytes_max = 32 * 1024,
-};
-
-static int txx9aclc_pcm_hw_params(struct snd_soc_component *component,
-				  struct snd_pcm_substream *substream,
-				  struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct txx9aclc_dmadata *dmadata = runtime->private_data;
-
-	dev_dbg(component->dev,
-		"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
-		"runtime->min_align %ld\n",
-		(unsigned long)runtime->dma_area,
-		(unsigned long)runtime->dma_addr, runtime->dma_bytes,
-		runtime->min_align);
-	dev_dbg(component->dev,
-		"periods %d period_bytes %d stream %d\n",
-		params_periods(params), params_period_bytes(params),
-		substream->stream);
-
-	dmadata->substream = substream;
-	dmadata->pos = 0;
-	return 0;
-}
-
-static int txx9aclc_pcm_prepare(struct snd_soc_component *component,
-				struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct txx9aclc_dmadata *dmadata = runtime->private_data;
-
-	dmadata->dma_addr = runtime->dma_addr;
-	dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-	dmadata->period_bytes = snd_pcm_lib_period_bytes(substream);
-
-	if (dmadata->buffer_bytes == dmadata->period_bytes) {
-		dmadata->frag_bytes = dmadata->period_bytes >> 1;
-		dmadata->frags = 2;
-	} else {
-		dmadata->frag_bytes = dmadata->period_bytes;
-		dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes;
-	}
-	dmadata->frag_count = 0;
-	dmadata->pos = 0;
-	return 0;
-}
-
-static void txx9aclc_dma_complete(void *arg)
-{
-	struct txx9aclc_dmadata *dmadata = arg;
-	unsigned long flags;
-
-	/* dma completion handler cannot submit new operations */
-	spin_lock_irqsave(&dmadata->dma_lock, flags);
-	if (dmadata->frag_count >= 0) {
-		dmadata->dmacount--;
-		if (!WARN_ON(dmadata->dmacount < 0))
-			queue_work(system_highpri_wq, &dmadata->work);
-	}
-	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-}
-
-static struct dma_async_tx_descriptor *
-txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
-{
-	struct dma_chan *chan = dmadata->dma_chan;
-	struct dma_async_tx_descriptor *desc;
-	struct scatterlist sg;
-
-	sg_init_table(&sg, 1);
-	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)),
-		    dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1));
-	sg_dma_address(&sg) = buf_dma_addr;
-	desc = dmaengine_prep_slave_sg(chan, &sg, 1,
-		dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-		DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
-		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc) {
-		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
-		return NULL;
-	}
-	desc->callback = txx9aclc_dma_complete;
-	desc->callback_param = dmadata;
-	dmaengine_submit(desc);
-	return desc;
-}
-
-#define NR_DMA_CHAIN		2
-
-static void txx9aclc_dma_work(struct work_struct *work)
-{
-	struct txx9aclc_dmadata *dmadata =
-		container_of(work, struct txx9aclc_dmadata, work);
-	struct dma_chan *chan = dmadata->dma_chan;
-	struct dma_async_tx_descriptor *desc;
-	struct snd_pcm_substream *substream = dmadata->substream;
-	u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-		ACCTL_AUDODMA : ACCTL_AUDIDMA;
-	int i;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dmadata->dma_lock, flags);
-	if (dmadata->frag_count < 0) {
-		struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-		void __iomem *base = drvdata->base;
-
-		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-		dmaengine_terminate_all(chan);
-		/* first time */
-		for (i = 0; i < NR_DMA_CHAIN; i++) {
-			desc = txx9aclc_dma_submit(dmadata,
-				dmadata->dma_addr + i * dmadata->frag_bytes);
-			if (!desc)
-				return;
-		}
-		dmadata->dmacount = NR_DMA_CHAIN;
-		dma_async_issue_pending(chan);
-		spin_lock_irqsave(&dmadata->dma_lock, flags);
-		__raw_writel(ctlbit, base + ACCTLEN);
-		dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
-		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-		return;
-	}
-	if (WARN_ON(dmadata->dmacount >= NR_DMA_CHAIN)) {
-		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-		return;
-	}
-	while (dmadata->dmacount < NR_DMA_CHAIN) {
-		dmadata->dmacount++;
-		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-		desc = txx9aclc_dma_submit(dmadata,
-			dmadata->dma_addr +
-			dmadata->frag_count * dmadata->frag_bytes);
-		if (!desc)
-			return;
-		dma_async_issue_pending(chan);
-
-		spin_lock_irqsave(&dmadata->dma_lock, flags);
-		dmadata->frag_count++;
-		dmadata->frag_count %= dmadata->frags;
-		dmadata->pos += dmadata->frag_bytes;
-		dmadata->pos %= dmadata->buffer_bytes;
-		if ((dmadata->frag_count * dmadata->frag_bytes) %
-		    dmadata->period_bytes == 0)
-			snd_pcm_period_elapsed(substream);
-	}
-	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-}
-
-static int txx9aclc_pcm_trigger(struct snd_soc_component *component,
-				struct snd_pcm_substream *substream, int cmd)
-{
-	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-	void __iomem *base = drvdata->base;
-	unsigned long flags;
-	int ret = 0;
-	u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-		ACCTL_AUDODMA : ACCTL_AUDIDMA;
-
-	spin_lock_irqsave(&dmadata->dma_lock, flags);
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		dmadata->frag_count = -1;
-		queue_work(system_highpri_wq, &dmadata->work);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		__raw_writel(ctlbit, base + ACCTLDIS);
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		__raw_writel(ctlbit, base + ACCTLEN);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-	return ret;
-}
-
-static snd_pcm_uframes_t
-txx9aclc_pcm_pointer(struct snd_soc_component *component,
-		     struct snd_pcm_substream *substream)
-{
-	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-
-	return bytes_to_frames(substream->runtime, dmadata->pos);
-}
-
-static int txx9aclc_pcm_open(struct snd_soc_component *component,
-			     struct snd_pcm_substream *substream)
-{
-	struct txx9aclc_soc_device *dev = &txx9aclc_soc_device;
-	struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
-	int ret;
-
-	ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware);
-	if (ret)
-		return ret;
-	/* ensure that buffer size is a multiple of period size */
-	ret = snd_pcm_hw_constraint_integer(substream->runtime,
-					    SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		return ret;
-	substream->runtime->private_data = dmadata;
-	return 0;
-}
-
-static int txx9aclc_pcm_close(struct snd_soc_component *component,
-			      struct snd_pcm_substream *substream)
-{
-	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-	struct dma_chan *chan = dmadata->dma_chan;
-
-	dmadata->frag_count = -1;
-	dmaengine_terminate_all(chan);
-	return 0;
-}
-
-static int txx9aclc_pcm_new(struct snd_soc_component *component,
-			    struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_card *card = rtd->card->snd_card;
-	struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
-	struct snd_pcm *pcm = rtd->pcm;
-	struct platform_device *pdev = to_platform_device(component->dev);
-	struct txx9aclc_soc_device *dev;
-	struct resource *r;
-	int i;
-	int ret;
-
-	/* at this point onwards the AC97 component has probed and this will be valid */
-	dev = snd_soc_dai_get_drvdata(dai);
-
-	dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
-	dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
-	for (i = 0; i < 2; i++) {
-		r = platform_get_resource(pdev, IORESOURCE_DMA, i);
-		if (!r) {
-			ret = -EBUSY;
-			goto exit;
-		}
-		dev->dmadata[i].dma_res = r;
-		ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
-		if (ret)
-			goto exit;
-	}
-
-	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
-		card->dev, 64 * 1024, 4 * 1024 * 1024);
-	return 0;
-
-exit:
-	for (i = 0; i < 2; i++) {
-		if (dev->dmadata[i].dma_chan)
-			dma_release_channel(dev->dmadata[i].dma_chan);
-		dev->dmadata[i].dma_chan = NULL;
-	}
-	return ret;
-}
-
-static bool filter(struct dma_chan *chan, void *param)
-{
-	struct txx9aclc_dmadata *dmadata = param;
-	char *devname;
-	bool found = false;
-
-	devname = kasprintf(GFP_KERNEL, "%s.%d", dmadata->dma_res->name,
-		(int)dmadata->dma_res->start);
-	if (strcmp(dev_name(chan->device->dev), devname) == 0) {
-		chan->private = &dmadata->dma_slave;
-		found = true;
-	}
-	kfree(devname);
-	return found;
-}
-
-static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
-			     struct txx9aclc_dmadata *dmadata)
-{
-	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-	struct txx9dmac_slave *ds = &dmadata->dma_slave;
-	dma_cap_mask_t mask;
-
-	spin_lock_init(&dmadata->dma_lock);
-
-	ds->reg_width = sizeof(u32);
-	if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ds->tx_reg = drvdata->physbase + ACAUDODAT;
-		ds->rx_reg = 0;
-	} else {
-		ds->tx_reg = 0;
-		ds->rx_reg = drvdata->physbase + ACAUDIDAT;
-	}
-
-	/* Try to grab a DMA channel */
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
-	if (!dmadata->dma_chan) {
-		printk(KERN_ERR
-			"DMA channel for %s is not available\n",
-			dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-			"playback" : "capture");
-		return -EBUSY;
-	}
-	INIT_WORK(&dmadata->work, txx9aclc_dma_work);
-	return 0;
-}
-
-static int txx9aclc_pcm_probe(struct snd_soc_component *component)
-{
-	snd_soc_component_set_drvdata(component, &txx9aclc_soc_device);
-	return 0;
-}
-
-static void txx9aclc_pcm_remove(struct snd_soc_component *component)
-{
-	struct txx9aclc_soc_device *dev = snd_soc_component_get_drvdata(component);
-	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
-	void __iomem *base = drvdata->base;
-	int i;
-
-	/* disable all FIFO DMAs */
-	__raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, base + ACCTLDIS);
-	/* dummy R/W to clear pending DMAREQ if any */
-	__raw_writel(__raw_readl(base + ACAUDIDAT), base + ACAUDODAT);
-
-	for (i = 0; i < 2; i++) {
-		struct txx9aclc_dmadata *dmadata = &dev->dmadata[i];
-		struct dma_chan *chan = dmadata->dma_chan;
-
-		if (chan) {
-			dmadata->frag_count = -1;
-			dmaengine_terminate_all(chan);
-			dma_release_channel(chan);
-		}
-		dev->dmadata[i].dma_chan = NULL;
-	}
-}
-
-static const struct snd_soc_component_driver txx9aclc_soc_component = {
-	.name		= DRV_NAME,
-	.probe		= txx9aclc_pcm_probe,
-	.remove		= txx9aclc_pcm_remove,
-	.open		= txx9aclc_pcm_open,
-	.close		= txx9aclc_pcm_close,
-	.hw_params	= txx9aclc_pcm_hw_params,
-	.prepare	= txx9aclc_pcm_prepare,
-	.trigger	= txx9aclc_pcm_trigger,
-	.pointer	= txx9aclc_pcm_pointer,
-	.pcm_construct	= txx9aclc_pcm_new,
-};
-
-static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
-{
-	return devm_snd_soc_register_component(&pdev->dev,
-					&txx9aclc_soc_component, NULL, 0);
-}
-
-static struct platform_driver txx9aclc_pcm_driver = {
-	.driver = {
-			.name = "txx9aclc-pcm-audio",
-	},
-
-	.probe = txx9aclc_soc_platform_probe,
-};
-
-module_platform_driver(txx9aclc_pcm_driver);
-
-MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
-MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
deleted file mode 100644
index 37c691ba56edb216b215440b84ebd7a582ddb38b..0000000000000000000000000000000000000000
--- a/sound/soc/txx9/txx9aclc.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * TXx9 SoC AC Link Controller
- */
-
-#ifndef __TXX9ACLC_H
-#define __TXX9ACLC_H
-
-#include <linux/interrupt.h>
-#include <asm/txx9/dmac.h>
-
-#define ACCTLEN			0x00	/* control enable */
-#define ACCTLDIS		0x04	/* control disable */
-#define   ACCTL_ENLINK		0x00000001	/* enable/disable AC-link */
-#define   ACCTL_AUDODMA		0x00000100	/* AUDODMA enable/disable */
-#define   ACCTL_AUDIDMA		0x00001000	/* AUDIDMA enable/disable */
-#define   ACCTL_AUDOEHLT	0x00010000	/* AUDO error halt
-						   enable/disable */
-#define   ACCTL_AUDIEHLT	0x00100000	/* AUDI error halt
-						   enable/disable */
-#define ACREGACC		0x08	/* codec register access */
-#define   ACREGACC_DAT_SHIFT	0	/* data field */
-#define   ACREGACC_REG_SHIFT	16	/* address field */
-#define   ACREGACC_CODECID_SHIFT	24	/* CODEC ID field */
-#define   ACREGACC_READ		0x80000000	/* CODEC read */
-#define   ACREGACC_WRITE	0x00000000	/* CODEC write */
-#define ACINTSTS		0x10	/* interrupt status */
-#define ACINTMSTS		0x14	/* interrupt masked status */
-#define ACINTEN			0x18	/* interrupt enable */
-#define ACINTDIS		0x1c	/* interrupt disable */
-#define   ACINT_CODECRDY(n)	(0x00000001 << (n))	/* CODECn ready */
-#define   ACINT_REGACCRDY	0x00000010	/* ACREGACC ready */
-#define   ACINT_AUDOERR		0x00000100	/* AUDO underrun error */
-#define   ACINT_AUDIERR		0x00001000	/* AUDI overrun error */
-#define ACDMASTS		0x80	/* DMA request status */
-#define   ACDMA_AUDO		0x00000001	/* AUDODMA pending */
-#define   ACDMA_AUDI		0x00000010	/* AUDIDMA pending */
-#define ACAUDODAT		0xa0	/* audio out data */
-#define ACAUDIDAT		0xb0	/* audio in data */
-#define ACREVID			0xfc	/* revision ID */
-
-struct txx9aclc_dmadata {
-	struct resource *dma_res;
-	struct txx9dmac_slave dma_slave;
-	struct dma_chan *dma_chan;
-	struct work_struct work;
-	spinlock_t dma_lock;
-	int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */
-	struct snd_pcm_substream *substream;
-	unsigned long pos;
-	dma_addr_t dma_addr;
-	unsigned long buffer_bytes;
-	unsigned long period_bytes;
-	unsigned long frag_bytes;
-	int frags;
-	int frag_count;
-	int dmacount;
-};
-
-struct txx9aclc_plat_drvdata {
-	void __iomem *base;
-	u64 physbase;
-};
-
-static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
-	struct snd_soc_dai *dai)
-{
-	return dev_get_drvdata(dai->dev);
-}
-
-#endif /* __TXX9ACLC_H */
diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig
deleted file mode 100644
index a23d4f13ca19e0a95d6a41b9d9bfe7a3908baf45..0000000000000000000000000000000000000000
--- a/sound/soc/zte/Kconfig
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config ZX_SPDIF
-	tristate "ZTE ZX SPDIF Driver Support"
-	depends on ARCH_ZX || COMPILE_TEST
-	depends on COMMON_CLK
-	select SND_SOC_GENERIC_DMAENGINE_PCM
-	help
-	  Say Y or M if you want to add support for codecs attached to the
-	  ZTE ZX SPDIF interface
-
-config ZX_I2S
-	tristate "ZTE ZX I2S Driver Support"
-	depends on ARCH_ZX || COMPILE_TEST
-	depends on COMMON_CLK
-	select SND_SOC_GENERIC_DMAENGINE_PCM
-	help
-	  Say Y or M if you want to add support for codecs attached to the
-	  ZTE ZX I2S interface
-
-config ZX_TDM
-	tristate "ZTE ZX TDM Driver Support"
-	depends on COMMON_CLK
-	select SND_SOC_GENERIC_DMAENGINE_PCM
-	help
-	  Say Y or M if you want to add support for codecs attached to the
-	  ZTE ZX TDM interface
diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile
deleted file mode 100644
index 2f7cdefa42dfd9b3b18f4abaae062ad91524436d..0000000000000000000000000000000000000000
--- a/sound/soc/zte/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ZX_SPDIF)	+= zx-spdif.o
-obj-$(CONFIG_ZX_I2S)	+= zx-i2s.o
-obj-$(CONFIG_ZX_TDM)	+= zx-tdm.o
diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c
deleted file mode 100644
index 1c1a44e08a676d6ec3602b3f90eb0f897bad0e9d..0000000000000000000000000000000000000000
--- a/sound/soc/zte/zx-i2s.c
+++ /dev/null
@@ -1,452 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2015 Linaro
- *
- * Author: Jun Nie <jun.nie@linaro.org>
- */
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-
-#include <sound/core.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/initval.h>
-
-#define ZX_I2S_PROCESS_CTRL	0x04
-#define ZX_I2S_TIMING_CTRL	0x08
-#define	ZX_I2S_FIFO_CTRL	0x0C
-#define	ZX_I2S_FIFO_STATUS	0x10
-#define ZX_I2S_INT_EN		0x14
-#define ZX_I2S_INT_STATUS	0x18
-#define ZX_I2S_DATA		0x1C
-#define ZX_I2S_FRAME_CNTR	0x20
-
-#define I2S_DEAGULT_FIFO_THRES	(0x10)
-#define I2S_MAX_FIFO_THRES	(0x20)
-
-#define ZX_I2S_PROCESS_TX_EN	(1 << 0)
-#define ZX_I2S_PROCESS_TX_DIS	(0 << 0)
-#define ZX_I2S_PROCESS_RX_EN	(1 << 1)
-#define ZX_I2S_PROCESS_RX_DIS	(0 << 1)
-#define ZX_I2S_PROCESS_I2S_EN	(1 << 2)
-#define ZX_I2S_PROCESS_I2S_DIS	(0 << 2)
-
-#define ZX_I2S_TIMING_MAST		(1 << 0)
-#define ZX_I2S_TIMING_SLAVE		(0 << 0)
-#define ZX_I2S_TIMING_MS_MASK		(1 << 0)
-#define ZX_I2S_TIMING_LOOP		(1 << 1)
-#define ZX_I2S_TIMING_NOR		(0 << 1)
-#define ZX_I2S_TIMING_LOOP_MASK		(1 << 1)
-#define ZX_I2S_TIMING_PTNR		(1 << 2)
-#define ZX_I2S_TIMING_NTPR		(0 << 2)
-#define ZX_I2S_TIMING_PHASE_MASK	(1 << 2)
-#define ZX_I2S_TIMING_TDM		(1 << 3)
-#define ZX_I2S_TIMING_I2S		(0 << 3)
-#define ZX_I2S_TIMING_TIMING_MASK	(1 << 3)
-#define ZX_I2S_TIMING_LONG_SYNC		(1 << 4)
-#define ZX_I2S_TIMING_SHORT_SYNC	(0 << 4)
-#define ZX_I2S_TIMING_SYNC_MASK		(1 << 4)
-#define ZX_I2S_TIMING_TEAK_EN		(1 << 5)
-#define ZX_I2S_TIMING_TEAK_DIS		(0 << 5)
-#define ZX_I2S_TIMING_TEAK_MASK		(1 << 5)
-#define ZX_I2S_TIMING_STD_I2S		(0 << 6)
-#define ZX_I2S_TIMING_MSB_JUSTIF	(1 << 6)
-#define ZX_I2S_TIMING_LSB_JUSTIF	(2 << 6)
-#define ZX_I2S_TIMING_ALIGN_MASK	(3 << 6)
-#define ZX_I2S_TIMING_CHN_MASK		(7 << 8)
-#define ZX_I2S_TIMING_CHN(x)		((x - 1) << 8)
-#define ZX_I2S_TIMING_LANE_MASK		(3 << 11)
-#define ZX_I2S_TIMING_LANE(x)		((x - 1) << 11)
-#define ZX_I2S_TIMING_TSCFG_MASK	(7 << 13)
-#define ZX_I2S_TIMING_TSCFG(x)		(x << 13)
-#define ZX_I2S_TIMING_TS_WIDTH_MASK	(0x1f << 16)
-#define ZX_I2S_TIMING_TS_WIDTH(x)	((x - 1) << 16)
-#define ZX_I2S_TIMING_DATA_SIZE_MASK	(0x1f << 21)
-#define ZX_I2S_TIMING_DATA_SIZE(x)	((x - 1) << 21)
-#define ZX_I2S_TIMING_CFG_ERR_MASK	(1 << 31)
-
-#define ZX_I2S_FIFO_CTRL_TX_RST		(1 << 0)
-#define ZX_I2S_FIFO_CTRL_TX_RST_MASK	(1 << 0)
-#define ZX_I2S_FIFO_CTRL_RX_RST		(1 << 1)
-#define ZX_I2S_FIFO_CTRL_RX_RST_MASK	(1 << 1)
-#define ZX_I2S_FIFO_CTRL_TX_DMA_EN	(1 << 4)
-#define ZX_I2S_FIFO_CTRL_TX_DMA_DIS	(0 << 4)
-#define ZX_I2S_FIFO_CTRL_TX_DMA_MASK	(1 << 4)
-#define ZX_I2S_FIFO_CTRL_RX_DMA_EN	(1 << 5)
-#define ZX_I2S_FIFO_CTRL_RX_DMA_DIS	(0 << 5)
-#define ZX_I2S_FIFO_CTRL_RX_DMA_MASK	(1 << 5)
-#define ZX_I2S_FIFO_CTRL_TX_THRES_MASK	(0x1F << 8)
-#define ZX_I2S_FIFO_CTRL_RX_THRES_MASK	(0x1F << 16)
-
-#define CLK_RAT (32 * 4)
-
-struct zx_i2s_info {
-	struct snd_dmaengine_dai_dma_data	dma_playback;
-	struct snd_dmaengine_dai_dma_data	dma_capture;
-	struct clk				*dai_wclk;
-	struct clk				*dai_pclk;
-	void __iomem				*reg_base;
-	int					master;
-	resource_size_t				mapbase;
-};
-
-static void zx_i2s_tx_en(void __iomem *base, bool on)
-{
-	unsigned long val;
-
-	val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL);
-	if (on)
-		val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN;
-	else
-		val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN);
-	writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL);
-}
-
-static void zx_i2s_rx_en(void __iomem *base, bool on)
-{
-	unsigned long val;
-
-	val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL);
-	if (on)
-		val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN;
-	else
-		val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN);
-	writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL);
-}
-
-static void zx_i2s_tx_dma_en(void __iomem *base, bool on)
-{
-	unsigned long val;
-
-	val = readl_relaxed(base + ZX_I2S_FIFO_CTRL);
-	val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8);
-	if (on)
-		val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN;
-	else
-		val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN;
-	writel_relaxed(val, base + ZX_I2S_FIFO_CTRL);
-}
-
-static void zx_i2s_rx_dma_en(void __iomem *base, bool on)
-{
-	unsigned long val;
-
-	val = readl_relaxed(base + ZX_I2S_FIFO_CTRL);
-	val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16);
-	if (on)
-		val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN;
-	else
-		val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN;
-	writel_relaxed(val, base + ZX_I2S_FIFO_CTRL);
-}
-
-#define ZX_I2S_RATES \
-	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-	 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \
-	 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
-
-#define ZX_I2S_FMTBIT \
-	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
-	SNDRV_PCM_FMTBIT_S32_LE)
-
-static int zx_i2s_dai_probe(struct snd_soc_dai *dai)
-{
-	struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-
-	snd_soc_dai_set_drvdata(dai, zx_i2s);
-	zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA;
-	zx_i2s->dma_playback.maxburst = 16;
-	zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA;
-	zx_i2s->dma_capture.maxburst = 16;
-	snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback,
-				  &zx_i2s->dma_capture);
-	return 0;
-}
-
-static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-	struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
-	unsigned long val;
-
-	val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL);
-	val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK |
-			ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK |
-			ZX_I2S_TIMING_MS_MASK);
-
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S);
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF);
-		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF);
-		break;
-	default:
-		dev_err(cpu_dai->dev, "Unknown i2s timing\n");
-		return -EINVAL;
-	}
-
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		/* Codec is master, and I2S is slave. */
-		i2s->master = 0;
-		val |= ZX_I2S_TIMING_SLAVE;
-		break;
-	case SND_SOC_DAIFMT_CBS_CFS:
-		/* Codec is slave, and I2S is master. */
-		i2s->master = 1;
-		val |= ZX_I2S_TIMING_MAST;
-		break;
-	default:
-		dev_err(cpu_dai->dev, "Unknown master/slave format\n");
-		return -EINVAL;
-	}
-
-	writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL);
-	return 0;
-}
-
-static int zx_i2s_hw_params(struct snd_pcm_substream *substream,
-			    struct snd_pcm_hw_params *params,
-			    struct snd_soc_dai *socdai)
-{
-	struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai);
-	struct snd_dmaengine_dai_dma_data *dma_data;
-	unsigned int lane, ch_num, len, ret = 0;
-	unsigned int ts_width = 32;
-	unsigned long val;
-	unsigned long chn_cfg;
-
-	dma_data = snd_soc_dai_get_dma_data(socdai, substream);
-	dma_data->addr_width = ts_width >> 3;
-
-	val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL);
-	val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK |
-		ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK |
-		ZX_I2S_TIMING_TSCFG_MASK);
-
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		len = 16;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		len = 24;
-		break;
-	case SNDRV_PCM_FORMAT_S32_LE:
-		len = 32;
-		break;
-	default:
-		dev_err(socdai->dev, "Unknown data format\n");
-		return -EINVAL;
-	}
-	val |= ZX_I2S_TIMING_TS_WIDTH(ts_width) | ZX_I2S_TIMING_DATA_SIZE(len);
-
-	ch_num = params_channels(params);
-	switch (ch_num) {
-	case 1:
-		lane = 1;
-		chn_cfg = 2;
-		break;
-	case 2:
-	case 4:
-	case 6:
-	case 8:
-		lane = ch_num / 2;
-		chn_cfg = 3;
-		break;
-	default:
-		dev_err(socdai->dev, "Not support channel num %d\n", ch_num);
-		return -EINVAL;
-	}
-	val |= ZX_I2S_TIMING_LANE(lane);
-	val |= ZX_I2S_TIMING_TSCFG(chn_cfg);
-	val |= ZX_I2S_TIMING_CHN(ch_num);
-	writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL);
-
-	if (i2s->master)
-		ret = clk_set_rate(i2s->dai_wclk,
-				params_rate(params) * ch_num * CLK_RAT);
-
-	return ret;
-}
-
-static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-			  struct snd_soc_dai *dai)
-{
-	struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
-	int ret = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		if (capture)
-			zx_i2s_rx_dma_en(zx_i2s->reg_base, true);
-		else
-			zx_i2s_tx_dma_en(zx_i2s->reg_base, true);
-		fallthrough;
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (capture)
-			zx_i2s_rx_en(zx_i2s->reg_base, true);
-		else
-			zx_i2s_tx_en(zx_i2s->reg_base, true);
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-		if (capture)
-			zx_i2s_rx_dma_en(zx_i2s->reg_base, false);
-		else
-			zx_i2s_tx_dma_en(zx_i2s->reg_base, false);
-		fallthrough;
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (capture)
-			zx_i2s_rx_en(zx_i2s->reg_base, false);
-		else
-			zx_i2s_tx_en(zx_i2s->reg_base, false);
-		break;
-
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static int zx_i2s_startup(struct snd_pcm_substream *substream,
-			  struct snd_soc_dai *dai)
-{
-	struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-	int ret;
-
-	ret = clk_prepare_enable(zx_i2s->dai_wclk);
-	if (ret)
-		return ret;
-
-	ret = clk_prepare_enable(zx_i2s->dai_pclk);
-	if (ret) {
-		clk_disable_unprepare(zx_i2s->dai_wclk);
-		return ret;
-	}
-
-	return ret;
-}
-
-static void zx_i2s_shutdown(struct snd_pcm_substream *substream,
-			    struct snd_soc_dai *dai)
-{
-	struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev);
-
-	clk_disable_unprepare(zx_i2s->dai_wclk);
-	clk_disable_unprepare(zx_i2s->dai_pclk);
-}
-
-static const struct snd_soc_dai_ops zx_i2s_dai_ops = {
-	.trigger	= zx_i2s_trigger,
-	.hw_params	= zx_i2s_hw_params,
-	.set_fmt	= zx_i2s_set_fmt,
-	.startup	= zx_i2s_startup,
-	.shutdown	= zx_i2s_shutdown,
-};
-
-static const struct snd_soc_component_driver zx_i2s_component = {
-	.name			= "zx-i2s",
-};
-
-static struct snd_soc_dai_driver zx_i2s_dai = {
-	.name	= "zx-i2s-dai",
-	.id	= 0,
-	.probe	= zx_i2s_dai_probe,
-	.playback   = {
-		.channels_min	= 1,
-		.channels_max	= 8,
-		.rates		= ZX_I2S_RATES,
-		.formats	= ZX_I2S_FMTBIT,
-	},
-	.capture = {
-		.channels_min	= 1,
-		.channels_max	= 2,
-		.rates		= ZX_I2S_RATES,
-		.formats	= ZX_I2S_FMTBIT,
-	},
-	.ops	= &zx_i2s_dai_ops,
-};
-
-static int zx_i2s_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct zx_i2s_info *zx_i2s;
-	int ret;
-
-	zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL);
-	if (!zx_i2s)
-		return -ENOMEM;
-
-	zx_i2s->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
-	if (IS_ERR(zx_i2s->dai_wclk)) {
-		dev_err(&pdev->dev, "Fail to get wclk\n");
-		return PTR_ERR(zx_i2s->dai_wclk);
-	}
-
-	zx_i2s->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
-	if (IS_ERR(zx_i2s->dai_pclk)) {
-		dev_err(&pdev->dev, "Fail to get pclk\n");
-		return PTR_ERR(zx_i2s->dai_pclk);
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	zx_i2s->mapbase = res->start;
-	zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(zx_i2s->reg_base)) {
-		dev_err(&pdev->dev, "ioremap failed!\n");
-		return PTR_ERR(zx_i2s->reg_base);
-	}
-
-	writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
-	platform_set_drvdata(pdev, zx_i2s);
-
-	ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component,
-					      &zx_i2s_dai, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-	if (ret)
-		dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
-
-	return ret;
-}
-
-static const struct of_device_id zx_i2s_dt_ids[] = {
-	{ .compatible = "zte,zx296702-i2s", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, zx_i2s_dt_ids);
-
-static struct platform_driver i2s_driver = {
-	.probe = zx_i2s_probe,
-	.driver = {
-		.name = "zx-i2s",
-		.of_match_table = zx_i2s_dt_ids,
-	},
-};
-
-module_platform_driver(i2s_driver);
-
-MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
-MODULE_DESCRIPTION("ZTE I2S SoC DAI");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/zte/zx-spdif.c b/sound/soc/zte/zx-spdif.c
deleted file mode 100644
index b4168bd532b7498be1429960d645ec3fc84aee87..0000000000000000000000000000000000000000
--- a/sound/soc/zte/zx-spdif.c
+++ /dev/null
@@ -1,363 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2015 Linaro
- *
- * Author: Jun Nie <jun.nie@linaro.org>
- */
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/dmaengine.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <sound/asoundef.h>
-#include <sound/core.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-
-#define ZX_CTRL				0x04
-#define ZX_FIFOCTRL			0x08
-#define ZX_INT_STATUS			0x10
-#define ZX_INT_MASK			0x14
-#define ZX_DATA				0x18
-#define ZX_VALID_BIT			0x1c
-#define ZX_CH_STA_1			0x20
-#define ZX_CH_STA_2			0x24
-#define ZX_CH_STA_3			0x28
-#define ZX_CH_STA_4			0x2c
-#define ZX_CH_STA_5			0x30
-#define ZX_CH_STA_6			0x34
-
-#define ZX_CTRL_MODA_16			(0 << 6)
-#define ZX_CTRL_MODA_18			BIT(6)
-#define ZX_CTRL_MODA_20			(2 << 6)
-#define ZX_CTRL_MODA_24			(3 << 6)
-#define ZX_CTRL_MODA_MASK		(3 << 6)
-
-#define ZX_CTRL_ENB			BIT(4)
-#define ZX_CTRL_DNB			(0 << 4)
-#define ZX_CTRL_ENB_MASK		BIT(4)
-
-#define ZX_CTRL_TX_OPEN			BIT(0)
-#define ZX_CTRL_TX_CLOSE		(0 << 0)
-#define ZX_CTRL_TX_MASK			BIT(0)
-
-#define ZX_CTRL_OPEN			(ZX_CTRL_TX_OPEN | ZX_CTRL_ENB)
-#define ZX_CTRL_CLOSE			(ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB)
-
-#define ZX_CTRL_DOUBLE_TRACK		(0 << 8)
-#define ZX_CTRL_LEFT_TRACK		BIT(8)
-#define ZX_CTRL_RIGHT_TRACK		(2 << 8)
-#define ZX_CTRL_TRACK_MASK		(3 << 8)
-
-#define ZX_FIFOCTRL_TXTH_MASK		(0x1f << 8)
-#define ZX_FIFOCTRL_TXTH(x)		(x << 8)
-#define ZX_FIFOCTRL_TX_DMA_EN		BIT(2)
-#define ZX_FIFOCTRL_TX_DMA_DIS		(0 << 2)
-#define ZX_FIFOCTRL_TX_DMA_EN_MASK	BIT(2)
-#define ZX_FIFOCTRL_TX_FIFO_RST		BIT(0)
-#define ZX_FIFOCTRL_TX_FIFO_RST_MASK	BIT(0)
-
-#define ZX_VALID_DOUBLE_TRACK		(0 << 0)
-#define ZX_VALID_LEFT_TRACK		BIT(1)
-#define ZX_VALID_RIGHT_TRACK		(2 << 0)
-#define ZX_VALID_TRACK_MASK		(3 << 0)
-
-#define ZX_SPDIF_CLK_RAT		(2 * 32)
-
-struct zx_spdif_info {
-	struct snd_dmaengine_dai_dma_data	dma_data;
-	struct clk				*dai_clk;
-	void __iomem				*reg_base;
-	resource_size_t				mapbase;
-};
-
-static int zx_spdif_dai_probe(struct snd_soc_dai *dai)
-{
-	struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-
-	snd_soc_dai_set_drvdata(dai, zx_spdif);
-	zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA;
-	zx_spdif->dma_data.maxburst = 8;
-	snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL);
-	return 0;
-}
-
-static int zx_spdif_chanstats(void __iomem *base, unsigned int rate)
-{
-	u32 cstas1;
-
-	switch (rate) {
-	case 22050:
-		cstas1 = IEC958_AES3_CON_FS_22050;
-		break;
-	case 24000:
-		cstas1 = IEC958_AES3_CON_FS_24000;
-		break;
-	case 32000:
-		cstas1 = IEC958_AES3_CON_FS_32000;
-		break;
-	case 44100:
-		cstas1 = IEC958_AES3_CON_FS_44100;
-		break;
-	case 48000:
-		cstas1 = IEC958_AES3_CON_FS_48000;
-		break;
-	case 88200:
-		cstas1 = IEC958_AES3_CON_FS_88200;
-		break;
-	case 96000:
-		cstas1 = IEC958_AES3_CON_FS_96000;
-		break;
-	case 176400:
-		cstas1 = IEC958_AES3_CON_FS_176400;
-		break;
-	case 192000:
-		cstas1 = IEC958_AES3_CON_FS_192000;
-		break;
-	default:
-		return -EINVAL;
-	}
-	cstas1 = cstas1 << 24;
-	cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT;
-
-	writel_relaxed(cstas1, base + ZX_CH_STA_1);
-	return 0;
-}
-
-static int zx_spdif_hw_params(struct snd_pcm_substream *substream,
-			      struct snd_pcm_hw_params *params,
-			      struct snd_soc_dai *socdai)
-{
-	struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev);
-	struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai);
-	struct snd_dmaengine_dai_dma_data *dma_data =
-		snd_soc_dai_get_dma_data(socdai, substream);
-	u32 val, ch_num, rate;
-	int ret;
-
-	dma_data->addr_width = params_width(params) >> 3;
-
-	val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL);
-	val &= ~ZX_CTRL_MODA_MASK;
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		val |= ZX_CTRL_MODA_16;
-		break;
-
-	case SNDRV_PCM_FORMAT_S18_3LE:
-		val |= ZX_CTRL_MODA_18;
-		break;
-
-	case SNDRV_PCM_FORMAT_S20_3LE:
-		val |= ZX_CTRL_MODA_20;
-		break;
-
-	case SNDRV_PCM_FORMAT_S24_LE:
-		val |= ZX_CTRL_MODA_24;
-		break;
-	default:
-		dev_err(socdai->dev, "Format not support!\n");
-		return -EINVAL;
-	}
-
-	ch_num = params_channels(params);
-	if (ch_num == 2)
-		val |= ZX_CTRL_DOUBLE_TRACK;
-	else
-		val |= ZX_CTRL_LEFT_TRACK;
-	writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL);
-
-	val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT);
-	val &= ~ZX_VALID_TRACK_MASK;
-	if (ch_num == 2)
-		val |= ZX_VALID_DOUBLE_TRACK;
-	else
-		val |= ZX_VALID_RIGHT_TRACK;
-	writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT);
-
-	rate = params_rate(params);
-	ret = zx_spdif_chanstats(zx_spdif->reg_base, rate);
-	if (ret)
-		return ret;
-	return clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT);
-}
-
-static void zx_spdif_cfg_tx(void __iomem *base, int on)
-{
-	u32 val;
-
-	val = readl_relaxed(base + ZX_CTRL);
-	val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK);
-	val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE;
-	writel_relaxed(val, base + ZX_CTRL);
-
-	val = readl_relaxed(base + ZX_FIFOCTRL);
-	val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK;
-	if (on)
-		val |= ZX_FIFOCTRL_TX_DMA_EN;
-	writel_relaxed(val, base + ZX_FIFOCTRL);
-}
-
-static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-			    struct snd_soc_dai *dai)
-{
-	u32 val;
-	struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-	int  ret = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL);
-		val |= ZX_FIFOCTRL_TX_FIFO_RST;
-		writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL);
-		fallthrough;
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		zx_spdif_cfg_tx(zx_spdif->reg_base, true);
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		zx_spdif_cfg_tx(zx_spdif->reg_base, false);
-		break;
-
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static int zx_spdif_startup(struct snd_pcm_substream *substream,
-			    struct snd_soc_dai *dai)
-{
-	struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-
-	return clk_prepare_enable(zx_spdif->dai_clk);
-}
-
-static void zx_spdif_shutdown(struct snd_pcm_substream *substream,
-			      struct snd_soc_dai *dai)
-{
-	struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev);
-
-	clk_disable_unprepare(zx_spdif->dai_clk);
-}
-
-#define ZX_RATES \
-	(SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\
-	SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
-
-#define ZX_FORMAT \
-	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \
-	| SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
-
-static const struct snd_soc_dai_ops zx_spdif_dai_ops = {
-	.trigger	= zx_spdif_trigger,
-	.startup	= zx_spdif_startup,
-	.shutdown	= zx_spdif_shutdown,
-	.hw_params	= zx_spdif_hw_params,
-};
-
-static struct snd_soc_dai_driver zx_spdif_dai = {
-	.name = "spdif",
-	.id = 0,
-	.probe = zx_spdif_dai_probe,
-	.playback = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = ZX_RATES,
-		.formats = ZX_FORMAT,
-	},
-	.ops = &zx_spdif_dai_ops,
-};
-
-static const struct snd_soc_component_driver zx_spdif_component = {
-	.name	= "spdif",
-};
-
-static void zx_spdif_dev_init(void __iomem *base)
-{
-	u32 val;
-
-	writel_relaxed(0, base + ZX_CTRL);
-	writel_relaxed(0, base + ZX_INT_MASK);
-	writel_relaxed(0xf, base + ZX_INT_STATUS);
-	writel_relaxed(0x1, base + ZX_FIFOCTRL);
-
-	val = readl_relaxed(base + ZX_FIFOCTRL);
-	val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK);
-	val |= ZX_FIFOCTRL_TXTH(8);
-	writel_relaxed(val, base + ZX_FIFOCTRL);
-}
-
-static int zx_spdif_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct zx_spdif_info *zx_spdif;
-	int ret;
-
-	zx_spdif = devm_kzalloc(&pdev->dev, sizeof(*zx_spdif), GFP_KERNEL);
-	if (!zx_spdif)
-		return -ENOMEM;
-
-	zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx");
-	if (IS_ERR(zx_spdif->dai_clk)) {
-		dev_err(&pdev->dev, "Fail to get clk\n");
-		return PTR_ERR(zx_spdif->dai_clk);
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	zx_spdif->mapbase = res->start;
-	zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(zx_spdif->reg_base)) {
-		return PTR_ERR(zx_spdif->reg_base);
-	}
-
-	zx_spdif_dev_init(zx_spdif->reg_base);
-	platform_set_drvdata(pdev, zx_spdif);
-
-	ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component,
-					 &zx_spdif_dai, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-	if (ret)
-		dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
-
-	return ret;
-}
-
-static const struct of_device_id zx_spdif_dt_ids[] = {
-	{ .compatible = "zte,zx296702-spdif", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, zx_spdif_dt_ids);
-
-static struct platform_driver spdif_driver = {
-	.probe = zx_spdif_probe,
-	.driver = {
-		.name = "zx-spdif",
-		.of_match_table = zx_spdif_dt_ids,
-	},
-};
-
-module_platform_driver(spdif_driver);
-
-MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
-MODULE_DESCRIPTION("ZTE SPDIF SoC DAI");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c
deleted file mode 100644
index 4f787185d6300ed23fde5a12127f1bac91ef66a6..0000000000000000000000000000000000000000
--- a/sound/soc/zte/zx-tdm.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ZTE's TDM driver
- *
- * Copyright (C) 2017 ZTE Ltd
- *
- * Author: Baoyou Xie <baoyou.xie@linaro.org>
- */
-
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-
-#define	REG_TIMING_CTRL		0x04
-#define	REG_TX_FIFO_CTRL	0x0C
-#define	REG_RX_FIFO_CTRL	0x10
-#define REG_INT_EN		0x1C
-#define REG_INT_STATUS		0x20
-#define REG_DATABUF		0x24
-#define REG_TS_MASK0		0x44
-#define REG_PROCESS_CTRL	0x54
-
-#define FIFO_CTRL_TX_RST	BIT(0)
-#define FIFO_CTRL_RX_RST	BIT(0)
-#define DEAGULT_FIFO_THRES	GENMASK(4, 2)
-
-#define FIFO_CTRL_TX_DMA_EN	BIT(1)
-#define FIFO_CTRL_RX_DMA_EN	BIT(1)
-
-#define TX_FIFO_RST_MASK	BIT(0)
-#define RX_FIFO_RST_MASK	BIT(0)
-
-#define FIFOCTRL_TX_FIFO_RST	BIT(0)
-#define FIFOCTRL_RX_FIFO_RST	BIT(0)
-
-#define TXTH_MASK		GENMASK(5, 2)
-#define RXTH_MASK		GENMASK(5, 2)
-
-#define FIFOCTRL_THRESHOLD(x)	((x) << 2)
-
-#define TIMING_MS_MASK		BIT(1)
-/*
- * 00: 8 clk cycles every timeslot
- * 01: 16 clk cycles every timeslot
- * 10: 32 clk cycles every timeslot
- */
-#define TIMING_SYNC_WIDTH_MASK	GENMASK(6, 5)
-#define TIMING_WIDTH_SHIFT      5
-#define TIMING_DEFAULT_WIDTH    0
-#define TIMING_TS_WIDTH(x)	((x) << TIMING_WIDTH_SHIFT)
-#define TIMING_WIDTH_FACTOR     8
-
-#define TIMING_MASTER_MODE	BIT(21)
-#define TIMING_LSB_FIRST	BIT(20)
-#define TIMING_TS_NUM(x)	(((x) - 1) << 7)
-#define TIMING_CLK_SEL_MASK	GENMASK(2, 0)
-#define TIMING_CLK_SEL_DEF	BIT(2)
-
-#define PROCESS_TX_EN		BIT(0)
-#define PROCESS_RX_EN		BIT(1)
-#define PROCESS_TDM_EN		BIT(2)
-#define PROCESS_DISABLE_ALL	0
-
-#define INT_DISABLE_ALL		0
-#define INT_STATUS_MASK		GENMASK(6, 0)
-
-struct zx_tdm_info {
-	struct snd_dmaengine_dai_dma_data	dma_playback;
-	struct snd_dmaengine_dai_dma_data	dma_capture;
-	resource_size_t				phy_addr;
-	void __iomem				*regbase;
-	struct clk				*dai_wclk;
-	struct clk				*dai_pclk;
-	int					master;
-	struct device				*dev;
-};
-
-static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg)
-{
-	return readl_relaxed(tdm->regbase + reg);
-}
-
-static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val)
-{
-	writel_relaxed(val, tdm->regbase + reg);
-}
-
-static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on)
-{
-	unsigned long val;
-
-	val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
-	if (on)
-		val |= PROCESS_TX_EN | PROCESS_TDM_EN;
-	else
-		val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN);
-	zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
-}
-
-static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on)
-{
-	unsigned long val;
-
-	val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
-	if (on)
-		val |= PROCESS_RX_EN | PROCESS_TDM_EN;
-	else
-		val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN);
-	zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
-}
-
-static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on)
-{
-	unsigned long val;
-
-	val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
-	val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES;
-	if (on)
-		val |= FIFO_CTRL_TX_DMA_EN;
-	else
-		val &= ~FIFO_CTRL_TX_DMA_EN;
-	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
-}
-
-static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
-{
-	unsigned long val;
-
-	val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
-	val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES;
-	if (on)
-		val |= FIFO_CTRL_RX_DMA_EN;
-	else
-		val &= ~FIFO_CTRL_RX_DMA_EN;
-	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
-}
-
-#define ZX_TDM_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
-
-#define ZX_TDM_FMTBIT \
-	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_MU_LAW | \
-	SNDRV_PCM_FMTBIT_A_LAW)
-
-static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
-{
-	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-
-	snd_soc_dai_set_drvdata(dai, zx_tdm);
-	zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF;
-	zx_tdm->dma_playback.maxburst = 16;
-	zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF;
-	zx_tdm->dma_capture.maxburst = 16;
-	snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback,
-				  &zx_tdm->dma_capture);
-	return 0;
-}
-
-static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-	struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai);
-	unsigned long val;
-
-	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
-	val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK);
-	val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT;
-
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		tdm->master = 1;
-		val |= TIMING_MASTER_MODE;
-		break;
-	case SND_SOC_DAIFMT_CBS_CFS:
-		tdm->master = 0;
-		val &= ~TIMING_MASTER_MODE;
-		break;
-	default:
-		dev_err(cpu_dai->dev, "Unknown master/slave format\n");
-		return -EINVAL;
-	}
-
-
-	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
-
-	return 0;
-}
-
-static int zx_tdm_hw_params(struct snd_pcm_substream *substream,
-			    struct snd_pcm_hw_params *params,
-			    struct snd_soc_dai *socdai)
-{
-	struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai);
-	struct snd_dmaengine_dai_dma_data *dma_data;
-	unsigned int ts_width = TIMING_DEFAULT_WIDTH;
-	unsigned int ch_num = 32;
-	unsigned int mask = 0;
-	unsigned int ret = 0;
-	unsigned long val;
-
-	dma_data = snd_soc_dai_get_dma_data(socdai, substream);
-	dma_data->addr_width = ch_num >> 3;
-
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_MU_LAW:
-	case SNDRV_PCM_FORMAT_A_LAW:
-	case SNDRV_PCM_FORMAT_S16_LE:
-		ts_width = 1;
-		break;
-	default:
-		dev_err(socdai->dev, "Unknown data format\n");
-		return -EINVAL;
-	}
-
-	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
-	val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1);
-	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
-	zx_tdm_writel(tdm, REG_TS_MASK0, mask);
-
-	if (tdm->master)
-		ret = clk_set_rate(tdm->dai_wclk,
-			params_rate(params) * TIMING_WIDTH_FACTOR * ch_num);
-
-	return ret;
-}
-
-static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
-			  struct snd_soc_dai *dai)
-{
-	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
-	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-	unsigned int val;
-	int ret = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		if (capture) {
-			val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL);
-			val |= FIFOCTRL_RX_FIFO_RST;
-			zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val);
-
-			zx_tdm_rx_dma_en(zx_tdm, true);
-		} else {
-			val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL);
-			val |= FIFOCTRL_TX_FIFO_RST;
-			zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val);
-
-			zx_tdm_tx_dma_en(zx_tdm, true);
-		}
-		break;
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (capture)
-			zx_tdm_rx_en(zx_tdm, true);
-		else
-			zx_tdm_tx_en(zx_tdm, true);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		if (capture)
-			zx_tdm_rx_dma_en(zx_tdm, false);
-		else
-			zx_tdm_tx_dma_en(zx_tdm, false);
-		break;
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (capture)
-			zx_tdm_rx_en(zx_tdm, false);
-		else
-			zx_tdm_tx_en(zx_tdm, false);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static int zx_tdm_startup(struct snd_pcm_substream *substream,
-			  struct snd_soc_dai *dai)
-{
-	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-	int ret;
-
-	ret = clk_prepare_enable(zx_tdm->dai_wclk);
-	if (ret)
-		return ret;
-
-	ret = clk_prepare_enable(zx_tdm->dai_pclk);
-	if (ret) {
-		clk_disable_unprepare(zx_tdm->dai_wclk);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void zx_tdm_shutdown(struct snd_pcm_substream *substream,
-			    struct snd_soc_dai *dai)
-{
-	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
-
-	clk_disable_unprepare(zx_tdm->dai_pclk);
-	clk_disable_unprepare(zx_tdm->dai_wclk);
-}
-
-static const struct snd_soc_dai_ops zx_tdm_dai_ops = {
-	.trigger	= zx_tdm_trigger,
-	.hw_params	= zx_tdm_hw_params,
-	.set_fmt	= zx_tdm_set_fmt,
-	.startup	= zx_tdm_startup,
-	.shutdown	= zx_tdm_shutdown,
-};
-
-static const struct snd_soc_component_driver zx_tdm_component = {
-	.name			= "zx-tdm",
-};
-
-static void zx_tdm_init_state(struct zx_tdm_info *tdm)
-{
-	unsigned int val;
-
-	zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL);
-
-	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
-	val |= TIMING_LSB_FIRST;
-	val &= ~TIMING_CLK_SEL_MASK;
-	val |= TIMING_CLK_SEL_DEF;
-	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
-
-	zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL);
-	/*
-	 * write INT_STATUS register to clear it.
-	 */
-	zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK);
-	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST);
-	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST);
-
-	val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
-	val &= ~(RXTH_MASK | RX_FIFO_RST_MASK);
-	val |= FIFOCTRL_THRESHOLD(8);
-	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
-
-	val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
-	val &= ~(TXTH_MASK | TX_FIFO_RST_MASK);
-	val |= FIFOCTRL_THRESHOLD(8);
-	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
-}
-
-static struct snd_soc_dai_driver zx_tdm_dai = {
-	.name	= "zx-tdm-dai",
-	.id	= 0,
-	.probe	= zx_tdm_dai_probe,
-	.playback   = {
-		.channels_min	= 1,
-		.channels_max	= 4,
-		.rates		= ZX_TDM_RATES,
-		.formats	= ZX_TDM_FMTBIT,
-	},
-	.capture = {
-		.channels_min	= 1,
-		.channels_max	= 4,
-		.rates		= ZX_TDM_RATES,
-		.formats	= ZX_TDM_FMTBIT,
-	},
-	.ops	= &zx_tdm_dai_ops,
-};
-
-static int zx_tdm_probe(struct platform_device *pdev)
-{
-	struct of_phandle_args out_args;
-	unsigned int dma_reg_offset;
-	struct zx_tdm_info *zx_tdm;
-	unsigned int dma_mask;
-	struct resource *res;
-	struct regmap *regmap_sysctrl;
-	int ret;
-
-	zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
-	if (!zx_tdm)
-		return -ENOMEM;
-
-	zx_tdm->dev = &pdev->dev;
-
-	zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
-	if (IS_ERR(zx_tdm->dai_wclk)) {
-		dev_err(&pdev->dev, "Fail to get wclk\n");
-		return PTR_ERR(zx_tdm->dai_wclk);
-	}
-
-	zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
-	if (IS_ERR(zx_tdm->dai_pclk)) {
-		dev_err(&pdev->dev, "Fail to get pclk\n");
-		return PTR_ERR(zx_tdm->dai_pclk);
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	zx_tdm->phy_addr = res->start;
-	zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(zx_tdm->regbase))
-		return PTR_ERR(zx_tdm->regbase);
-
-	ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
-				"zte,tdm-dma-sysctrl", 2, 0, &out_args);
-	if (ret) {
-		dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
-		return ret;
-	}
-
-	dma_reg_offset = out_args.args[0];
-	dma_mask = out_args.args[1];
-	regmap_sysctrl = syscon_node_to_regmap(out_args.np);
-	if (IS_ERR(regmap_sysctrl)) {
-		of_node_put(out_args.np);
-		return PTR_ERR(regmap_sysctrl);
-	}
-
-	regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask);
-	of_node_put(out_args.np);
-
-	zx_tdm_init_state(zx_tdm);
-	platform_set_drvdata(pdev, zx_tdm);
-
-	ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
-						&zx_tdm_dai, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-	if (ret)
-		dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
-
-	return ret;
-}
-
-static const struct of_device_id zx_tdm_dt_ids[] = {
-	{ .compatible = "zte,zx296718-tdm", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids);
-
-static struct platform_driver tdm_driver = {
-	.probe = zx_tdm_probe,
-	.driver = {
-		.name = "zx-tdm",
-		.of_match_table = zx_tdm_dt_ids,
-	},
-};
-module_platform_driver(tdm_driver);
-
-MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
-MODULE_DESCRIPTION("ZTE TDM DAI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c
index 010976d9ceb25fbc5b09552783dbc0a3c0e00451..cd4a0bc6d278fd4d82d6895bc622fcfeff2ae12a 100644
--- a/sound/usb/bcd2000/bcd2000.c
+++ b/sound/usb/bcd2000/bcd2000.c
@@ -300,7 +300,7 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k)
 	if (ret < 0)
 		return ret;
 
-	strlcpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
+	strscpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
 
 	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
 	rmidi->private_data = bcd2k;
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 3b6bb2cbe886b36e3dc3fcb6190823efd0351e5d..4981753652a7fe5274373efe62e8f44c27f796ee 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -804,7 +804,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
 	}
 
 	cdev->pcm->private_data = cdev;
-	strlcpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
+	strscpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
 
 	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
 	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 2af3b7eb0a88c5618f962fe60dfcce2e6bcd6000..e03481caf7f62dba91962450df32b090a626d386 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -477,9 +477,9 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
 	usb_string(usb_dev, usb_dev->descriptor.iProduct,
 		   cdev->product_name, CAIAQ_USB_STR_LEN);
 
-	strlcpy(card->driver, MODNAME, sizeof(card->driver));
-	strlcpy(card->shortname, cdev->product_name, sizeof(card->shortname));
-	strlcpy(card->mixername, cdev->product_name, sizeof(card->mixername));
+	strscpy(card->driver, MODNAME, sizeof(card->driver));
+	strscpy(card->shortname, cdev->product_name, sizeof(card->shortname));
+	strscpy(card->mixername, cdev->product_name, sizeof(card->mixername));
 
 	/* if the id was not passed as module option, fill it with a shortened
 	 * version of the product string which does not contain any
diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c
index 512fbb3ee604903c115fab14a130e8adf32bef35..c656d0162432149526f0b531de48094bb4e155c7 100644
--- a/sound/usb/caiaq/midi.c
+++ b/sound/usb/caiaq/midi.c
@@ -125,7 +125,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
 	if (ret < 0)
 		return ret;
 
-	strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name));
+	strscpy(rmidi->name, device->product_name, sizeof(rmidi->name));
 
 	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
 	rmidi->private_data = device;
diff --git a/sound/usb/card.c b/sound/usb/card.c
index e08fbf8e3ee0f66027d6989e26c846edc4d563fb..85ed8507e41a21d10008dd72dc7c6a957f84e68e 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -472,7 +472,7 @@ static void usb_audio_make_shortname(struct usb_device *dev,
 	else if (quirk && quirk->product_name)
 		s = quirk->product_name;
 	if (s && *s) {
-		strlcpy(card->shortname, s, sizeof(card->shortname));
+		strscpy(card->shortname, s, sizeof(card->shortname));
 		return;
 	}
 
@@ -504,7 +504,7 @@ static void usb_audio_make_longname(struct usb_device *dev,
 	if (preset && preset->profile_name)
 		s = preset->profile_name;
 	if (s && *s) {
-		strlcpy(card->longname, s, sizeof(card->longname));
+		strscpy(card->longname, s, sizeof(card->longname));
 		return;
 	}
 
@@ -512,18 +512,17 @@ static void usb_audio_make_longname(struct usb_device *dev,
 		s = preset->vendor_name;
 	else if (quirk && quirk->vendor_name)
 		s = quirk->vendor_name;
+	*card->longname = 0;
 	if (s && *s) {
-		len = strlcpy(card->longname, s, sizeof(card->longname));
+		strscpy(card->longname, s, sizeof(card->longname));
 	} else {
 		/* retrieve the vendor and device strings as longname */
 		if (dev->descriptor.iManufacturer)
-			len = usb_string(dev, dev->descriptor.iManufacturer,
-					 card->longname, sizeof(card->longname));
-		else
-			len = 0;
+			usb_string(dev, dev->descriptor.iManufacturer,
+				   card->longname, sizeof(card->longname));
 		/* we don't really care if there isn't any vendor string */
 	}
-	if (len > 0) {
+	if (*card->longname) {
 		strim(card->longname);
 		if (*card->longname)
 			strlcat(card->longname, " ", sizeof(card->longname));
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 37091b11761434a5ccfb6b40e3906ea184d9a52b..a741e7da83a2963528482f6b14d1675e6ce59e23 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -71,7 +71,7 @@ struct snd_usb_endpoint {
 	unsigned char altsetting;	/* corresponding alternate setting */
 	unsigned char ep_idx;		/* endpoint array index */
 
-	unsigned long flags;	/* running bit flags */
+	atomic_t state;		/* running state */
 
 	void (*prepare_data_urb) (struct snd_usb_substream *subs,
 				  struct urb *urb);
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index dc68ed65e47877a31b6fcb1144246337f5a5213d..8243652d5604a3629644c0526c8e4db9e35376d1 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -298,6 +298,11 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
 	if (selector) {
 		int ret, i, cur;
 
+		if (selector->bNrInPins == 1) {
+			ret = 1;
+			goto find_source;
+		}
+
 		/* the entity ID we are looking for is a selector.
 		 * find out what it currently selects */
 		ret = uac_clock_selector_get_val(chip, selector->bClockID);
@@ -314,6 +319,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
 			return -EINVAL;
 		}
 
+	find_source:
 		cur = ret;
 		ret = __uac_clock_find_source(chip, fmt,
 					      selector->baCSourceID[ret - 1],
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 8e568823c99246ff66d88be10bf0d692e4bad95b..102d53515a76f78e634668d59cca5504de873740 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -21,8 +21,11 @@
 #include "clock.h"
 #include "quirks.h"
 
-#define EP_FLAG_RUNNING		1
-#define EP_FLAG_STOPPING	2
+enum {
+	EP_STATE_STOPPED,
+	EP_STATE_RUNNING,
+	EP_STATE_STOPPING,
+};
 
 /* interface refcounting */
 struct snd_usb_iface_ref {
@@ -115,6 +118,16 @@ static const char *usb_error_string(int err)
 	}
 }
 
+static inline bool ep_state_running(struct snd_usb_endpoint *ep)
+{
+	return atomic_read(&ep->state) == EP_STATE_RUNNING;
+}
+
+static inline bool ep_state_update(struct snd_usb_endpoint *ep, int old, int new)
+{
+	return atomic_cmpxchg(&ep->state, old, new) == old;
+}
+
 /**
  * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type
  *
@@ -393,7 +406,7 @@ next_packet_fifo_dequeue(struct snd_usb_endpoint *ep)
  */
 static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
 {
-	while (test_bit(EP_FLAG_RUNNING, &ep->flags)) {
+	while (ep_state_running(ep)) {
 
 		unsigned long flags;
 		struct snd_usb_packet_info *packet;
@@ -454,13 +467,13 @@ static void snd_complete_urb(struct urb *urb)
 	if (unlikely(atomic_read(&ep->chip->shutdown)))
 		goto exit_clear;
 
-	if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+	if (unlikely(!ep_state_running(ep)))
 		goto exit_clear;
 
 	if (usb_pipeout(ep->pipe)) {
 		retire_outbound_urb(ep, ctx);
 		/* can be stopped during retire callback */
-		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+		if (unlikely(!ep_state_running(ep)))
 			goto exit_clear;
 
 		if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
@@ -474,12 +487,12 @@ static void snd_complete_urb(struct urb *urb)
 
 		prepare_outbound_urb(ep, ctx);
 		/* can be stopped during prepare callback */
-		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+		if (unlikely(!ep_state_running(ep)))
 			goto exit_clear;
 	} else {
 		retire_inbound_urb(ep, ctx);
 		/* can be stopped during retire callback */
-		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+		if (unlikely(!ep_state_running(ep)))
 			goto exit_clear;
 
 		prepare_inbound_urb(ep, ctx);
@@ -835,7 +848,7 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
 	unsigned long end_time = jiffies + msecs_to_jiffies(1000);
 	int alive;
 
-	if (!test_bit(EP_FLAG_STOPPING, &ep->flags))
+	if (atomic_read(&ep->state) != EP_STATE_STOPPING)
 		return 0;
 
 	do {
@@ -850,10 +863,11 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
 		usb_audio_err(ep->chip,
 			"timeout: still %d active urbs on EP #%x\n",
 			alive, ep->ep_num);
-	clear_bit(EP_FLAG_STOPPING, &ep->flags);
 
-	ep->sync_sink = NULL;
-	snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
+	if (ep_state_update(ep, EP_STATE_STOPPING, EP_STATE_STOPPED)) {
+		ep->sync_sink = NULL;
+		snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
+	}
 
 	return 0;
 }
@@ -868,26 +882,20 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
 }
 
 /*
- * Stop and unlink active urbs.
+ * Stop active urbs
  *
- * This function checks and clears EP_FLAG_RUNNING state.
- * When @wait_sync is set, it waits until all pending URBs are killed.
+ * This function moves the EP to STOPPING state if it's being RUNNING.
  */
-static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
-				bool wait_sync)
+static int stop_urbs(struct snd_usb_endpoint *ep, bool force)
 {
 	unsigned int i;
 
-	if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */
-		return -EBADFD;
-
-	if (atomic_read(&ep->running))
+	if (!force && atomic_read(&ep->running))
 		return -EBUSY;
 
-	if (!test_and_clear_bit(EP_FLAG_RUNNING, &ep->flags))
-		goto out;
+	if (!ep_state_update(ep, EP_STATE_RUNNING, EP_STATE_STOPPING))
+		return 0;
 
-	set_bit(EP_FLAG_STOPPING, &ep->flags);
 	INIT_LIST_HEAD(&ep->ready_playback_urbs);
 	ep->next_packet_head = 0;
 	ep->next_packet_queued = 0;
@@ -901,24 +909,25 @@ static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
 		}
 	}
 
- out:
-	if (wait_sync)
-		return wait_clear_urbs(ep);
 	return 0;
 }
 
 /*
  * release an endpoint's urbs
  */
-static void release_urbs(struct snd_usb_endpoint *ep, int force)
+static int release_urbs(struct snd_usb_endpoint *ep, bool force)
 {
-	int i;
+	int i, err;
 
 	/* route incoming urbs to nirvana */
 	snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
 
-	/* stop urbs */
-	stop_and_unlink_urbs(ep, force, true);
+	/* stop and unlink urbs */
+	err = stop_urbs(ep, force);
+	if (err)
+		return err;
+
+	wait_clear_urbs(ep);
 
 	for (i = 0; i < ep->nurbs; i++)
 		release_urb_ctx(&ep->urb[i]);
@@ -928,6 +937,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)
 
 	ep->syncbuf = NULL;
 	ep->nurbs = 0;
+	return 0;
 }
 
 /*
@@ -1118,7 +1128,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
 	return 0;
 
 out_of_memory:
-	release_urbs(ep, 0);
+	release_urbs(ep, false);
 	return -ENOMEM;
 }
 
@@ -1162,7 +1172,7 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep)
 	return 0;
 
 out_of_memory:
-	release_urbs(ep, 0);
+	release_urbs(ep, false);
 	return -ENOMEM;
 }
 
@@ -1180,7 +1190,9 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
 	int err;
 
 	/* release old buffers, if any */
-	release_urbs(ep, 0);
+	err = release_urbs(ep, false);
+	if (err < 0)
+		return err;
 
 	ep->datainterval = fmt->datainterval;
 	ep->maxpacksize = fmt->maxpacksize;
@@ -1360,7 +1372,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
 	 * from that context.
 	 */
 
-	set_bit(EP_FLAG_RUNNING, &ep->flags);
+	if (!ep_state_update(ep, EP_STATE_STOPPED, EP_STATE_RUNNING))
+		goto __error;
 
 	if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
 		for (i = 0; i < ep->nurbs; i++) {
@@ -1433,7 +1446,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
 		WRITE_ONCE(ep->sync_source->sync_sink, NULL);
 
 	if (!atomic_dec_return(&ep->running))
-		stop_and_unlink_urbs(ep, false, false);
+		stop_urbs(ep, false);
 }
 
 /**
@@ -1446,12 +1459,12 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
  */
 void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
 {
-	release_urbs(ep, 1);
+	release_urbs(ep, true);
 }
 
 /**
  * snd_usb_endpoint_free_all: Free the resources of an snd_usb_endpoint
- * @card: The chip
+ * @chip: The chip
  *
  * This free all endpoints and those resources
  */
diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c
index b2d9623e99347906778a8b81cf90483551fb9c2a..c2824188d1420099eceff105fe3a425d690d01de 100644
--- a/sound/usb/hiface/chip.c
+++ b/sound/usb/hiface/chip.c
@@ -80,12 +80,12 @@ static int hiface_chip_create(struct usb_interface *intf,
 		return ret;
 	}
 
-	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+	strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
 
 	if (quirk && quirk->device_name)
-		strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname));
+		strscpy(card->shortname, quirk->device_name, sizeof(card->shortname));
 	else
-		strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
+		strscpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
 
 	strlcat(card->longname, card->shortname, sizeof(card->longname));
 	len = strlcat(card->longname, " at ", sizeof(card->longname));
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
index d942179ca0957a3d3e12f2599f3a2af1b83da21b..71f17f02f34188586f7475e7c71c44af20d6ef32 100644
--- a/sound/usb/hiface/pcm.c
+++ b/sound/usb/hiface/pcm.c
@@ -594,7 +594,7 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
 	pcm->private_data = rt;
 	pcm->private_free = hiface_pcm_free;
 
-	strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
+	strscpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
 				       NULL, 0, 0);
diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
index 521cc846d9d9fec8246e38f22fb01fd0030d2fe0..11a85e66aa96de6992cf08909d80947a38ab0141 100644
--- a/sound/usb/implicit.c
+++ b/sound/usb/implicit.c
@@ -73,6 +73,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
 	/* No quirk for playback but with capture quirk (see below) */
 	IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130),	/* BOSS BR-80 */
 	IMPLICIT_FB_SKIP_DEV(0x0582, 0x0171),   /* BOSS RC-505 */
+	IMPLICIT_FB_SKIP_DEV(0x0582, 0x0185),	/* BOSS GP-10 */
 	IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189),	/* BOSS GT-100v2 */
 	IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d6),	/* BOSS GT-1 */
 	IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8),	/* BOSS Katana */
@@ -86,6 +87,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
 static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
 	IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */
 	IMPLICIT_FB_FIXED_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */
+	IMPLICIT_FB_FIXED_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */
 	IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */
 	IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */
 	IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */
@@ -302,7 +304,8 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
 	/* Pioneer devices with vendor spec class */
 	if (attr == USB_ENDPOINT_SYNC_ASYNC &&
 	    alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
-	    USB_ID_VENDOR(chip->usb_id) == 0x2b73 /* Pioneer */) {
+	    (USB_ID_VENDOR(chip->usb_id) == 0x2b73 || /* Pioneer */
+	     USB_ID_VENDOR(chip->usb_id) == 0x08e4    /* Pioneer */)) {
 		if (skip_pioneer_sync_ep(chip, fmt, alts))
 			return 1;
 	}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 12b15ed59eaa11ae7767a9b566b32abf033355a5..b1c78db0d4700e8e0a12127b6f548723ae10b7f1 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -115,11 +115,14 @@ find_map(const struct usbmix_name_map *p, int unitid, int control)
 static int
 check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
 {
+	int len;
+
 	if (!p || !p->name)
 		return 0;
 
 	buflen--;
-	return strlcpy(buf, p->name, buflen);
+	len = strscpy(buf, p->name, buflen);
+	return len < 0 ? buflen : len;
 }
 
 /* ignore the error value if ignore_ctl_error flag is set */
@@ -151,12 +154,15 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,
 				      int index, char *buf, int buflen)
 {
 	const struct usbmix_selector_map *p;
+	int len;
 
 	if (!state->selector_map)
 		return 0;
 	for (p = state->selector_map; p->id; p++) {
-		if (p->id == unitid && index < p->count)
-			return strlcpy(buf, p->names[index], buflen);
+		if (p->id == unitid && index < p->count) {
+			len = strscpy(buf, p->names[index], buflen);
+			return len < 0 ? buflen : len;
+		}
 	}
 	return 0;
 }
@@ -254,7 +260,7 @@ static int get_relative_value(struct usb_mixer_elem_info *cval, int val)
 	if (val < cval->min)
 		return 0;
 	else if (val >= cval->max)
-		return (cval->max - cval->min + cval->res - 1) / cval->res;
+		return DIV_ROUND_UP(cval->max - cval->min, cval->res);
 	else
 		return (val - cval->min) / cval->res;
 }
@@ -1232,7 +1238,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
 				  (cval->control << 8) | minchn,
 				  &cval->res) < 0) {
 			cval->res = 1;
-		} else {
+		} else if (cval->head.mixer->protocol == UAC_VERSION_1) {
 			int last_valid_res = cval->res;
 
 			while (cval->res > 1) {
@@ -1338,7 +1344,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
 		}
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max =
-			(cval->max - cval->min + cval->res - 1) / cval->res;
+			DIV_ROUND_UP(cval->max - cval->min, cval->res);
 	}
 	return 0;
 }
@@ -1556,7 +1562,7 @@ static void check_no_speaker_on_headset(struct snd_kcontrol *kctl,
 	if (!found)
 		return;
 
-	strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name));
+	strscpy(kctl->id.name, "Headphone", sizeof(kctl->id.name));
 }
 
 static const struct usb_feature_control_info *get_feature_control_info(int control)
@@ -1691,7 +1697,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
 		break;
 	default:
 		if (!len)
-			strlcpy(kctl->id.name, audio_feature_info[control-1].name,
+			strscpy(kctl->id.name, audio_feature_info[control-1].name,
 				sizeof(kctl->id.name));
 		break;
 	}
@@ -1770,7 +1776,7 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer,
 	int name_len = get_term_name(mixer->chip, term, name, name_size, 0);
 
 	if (name_len == 0)
-		strlcpy(name, "Unknown", name_size);
+		strscpy(name, "Unknown", name_size);
 
 	/*
 	 *  sound/core/ctljack.c has a convention of naming jack controls
@@ -2490,7 +2496,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
 		if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {
 			/* nothing */ ;
 		} else if (info->name) {
-			strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
+			strscpy(kctl->id.name, info->name, sizeof(kctl->id.name));
 		} else {
 			if (extension_unit)
 				nameid = uac_extension_unit_iExtension(desc, state->mixer->protocol);
@@ -2503,7 +2509,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
 							       kctl->id.name,
 							       sizeof(kctl->id.name));
 			if (!len)
-				strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+				strscpy(kctl->id.name, name, sizeof(kctl->id.name));
 		}
 		append_ctl_name(kctl, " ");
 		append_ctl_name(kctl, valinfo->suffix);
@@ -2743,7 +2749,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
 				    kctl->id.name, sizeof(kctl->id.name), 0);
 		/* ... or use the fixed string "USB" as the last resort */
 		if (!len)
-			strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
+			strscpy(kctl->id.name, "USB", sizeof(kctl->id.name));
 
 		/* and add the proper suffix */
 		if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index df036a359f2fc528861278321e9699ca1acecad0..08873d2afe4d6606f97043f445c31219fc2f4fe3 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -2603,141 +2603,251 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
 }
 
 /*
- * Pioneer DJ DJM-250MK2 and maybe other DJM models
+ * Pioneer DJ DJM Mixers
  *
- * For playback, no duplicate mapping should be set.
- * There are three mixer stereo channels (CH1, CH2, AUX)
- * and three stereo sources (Playback 1-2, Playback 3-4, Playback 5-6).
- * Each channel should be mapped just once to one source.
- * If mapped multiple times, only one source will play on given channel
- * (sources are not mixed together).
+ * These devices generally have options for soft-switching the playback and
+ * capture sources in addition to the recording level. Although different
+ * devices have different configurations, there seems to be canonical values
+ * for specific capture/playback types:  See the definitions of these below.
  *
- * For recording, duplicate mapping is OK. We will get the same signal multiple times.
- *
- * Channels 7-8 are in both directions fixed to FX SEND / FX RETURN.
- *
- * See also notes in the quirks-table.h file.
+ * The wValue is masked with the stereo channel number. e.g. Setting Ch2 to
+ * capture phono would be 0x0203. Capture, playback and capture level have
+ * different wIndexes.
  */
 
-struct snd_pioneer_djm_option {
-	const u16 wIndex;
-	const u16 wValue;
+// Capture types
+#define SND_DJM_CAP_LINE	0x00
+#define SND_DJM_CAP_CDLINE	0x01
+#define SND_DJM_CAP_DIGITAL	0x02
+#define SND_DJM_CAP_PHONO	0x03
+#define SND_DJM_CAP_PFADER	0x06
+#define SND_DJM_CAP_XFADERA	0x07
+#define SND_DJM_CAP_XFADERB	0x08
+#define SND_DJM_CAP_MIC		0x09
+#define SND_DJM_CAP_AUX		0x0d
+#define SND_DJM_CAP_RECOUT	0x0a
+#define SND_DJM_CAP_NONE	0x0f
+#define SND_DJM_CAP_CH1PFADER	0x11
+#define SND_DJM_CAP_CH2PFADER	0x12
+#define SND_DJM_CAP_CH3PFADER	0x13
+#define SND_DJM_CAP_CH4PFADER	0x14
+
+// Playback types
+#define SND_DJM_PB_CH1		0x00
+#define SND_DJM_PB_CH2		0x01
+#define SND_DJM_PB_AUX		0x04
+
+#define SND_DJM_WINDEX_CAP	0x8002
+#define SND_DJM_WINDEX_CAPLVL	0x8003
+#define SND_DJM_WINDEX_PB	0x8016
+
+// kcontrol->private_value layout
+#define SND_DJM_VALUE_MASK	0x0000ffff
+#define SND_DJM_GROUP_MASK	0x00ff0000
+#define SND_DJM_DEVICE_MASK	0xff000000
+#define SND_DJM_GROUP_SHIFT	16
+#define SND_DJM_DEVICE_SHIFT	24
+
+// device table index
+#define SND_DJM_250MK2_IDX	0x0
+#define SND_DJM_750_IDX		0x1
+#define SND_DJM_900NXS2_IDX	0x2
+
+
+#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
+	.name = _name, \
+	.options = snd_djm_opts_##suffix, \
+	.noptions = ARRAY_SIZE(snd_djm_opts_##suffix), \
+	.default_value = _default_value, \
+	.wIndex = _windex }
+
+#define SND_DJM_DEVICE(suffix) { \
+	.controls = snd_djm_ctls_##suffix, \
+	.ncontrols = ARRAY_SIZE(snd_djm_ctls_##suffix) }
+
+
+struct snd_djm_device {
 	const char *name;
+	const struct snd_djm_ctl *controls;
+	size_t ncontrols;
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_level[] = {
-	{ .name =  "-5 dB",                  .wValue = 0x0300, .wIndex = 0x8003 },
-	{ .name = "-10 dB",                  .wValue = 0x0200, .wIndex = 0x8003 },
-	{ .name = "-15 dB",                  .wValue = 0x0100, .wIndex = 0x8003 },
-	{ .name = "-19 dB",                  .wValue = 0x0000, .wIndex = 0x8003 }
+struct snd_djm_ctl {
+	const char *name;
+	const u16 *options;
+	size_t noptions;
+	u16 default_value;
+	u16 wIndex;
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch12[] = {
-	{ .name =  "CH1 Control Tone PHONO", .wValue = 0x0103, .wIndex = 0x8002 },
-	{ .name =  "CH1 Control Tone LINE",  .wValue = 0x0100, .wIndex = 0x8002 },
-	{ .name =  "Post CH1 Fader",         .wValue = 0x0106, .wIndex = 0x8002 },
-	{ .name =  "Cross Fader A",          .wValue = 0x0107, .wIndex = 0x8002 },
-	{ .name =  "Cross Fader B",          .wValue = 0x0108, .wIndex = 0x8002 },
-	{ .name =  "MIC",                    .wValue = 0x0109, .wIndex = 0x8002 },
-	{ .name =  "AUX",                    .wValue = 0x010d, .wIndex = 0x8002 },
-	{ .name =  "REC OUT",                .wValue = 0x010a, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_caplevel(u16 wvalue)
+{
+	switch (wvalue) {
+	case 0x0000:	return "-19dB";
+	case 0x0100:	return "-15dB";
+	case 0x0200:	return "-10dB";
+	case 0x0300:	return "-5dB";
+	default:	return NULL;
+	}
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch34[] = {
-	{ .name =  "CH2 Control Tone PHONO", .wValue = 0x0203, .wIndex = 0x8002 },
-	{ .name =  "CH2 Control Tone LINE",  .wValue = 0x0200, .wIndex = 0x8002 },
-	{ .name =  "Post CH2 Fader",         .wValue = 0x0206, .wIndex = 0x8002 },
-	{ .name =  "Cross Fader A",          .wValue = 0x0207, .wIndex = 0x8002 },
-	{ .name =  "Cross Fader B",          .wValue = 0x0208, .wIndex = 0x8002 },
-	{ .name =  "MIC",                    .wValue = 0x0209, .wIndex = 0x8002 },
-	{ .name =  "AUX",                    .wValue = 0x020d, .wIndex = 0x8002 },
-	{ .name =  "REC OUT",                .wValue = 0x020a, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_cap(u16 wvalue)
+{
+	switch (wvalue & 0x00ff) {
+	case SND_DJM_CAP_LINE:		return "Control Tone LINE";
+	case SND_DJM_CAP_CDLINE:	return "Control Tone CD/LINE";
+	case SND_DJM_CAP_DIGITAL:	return "Control Tone DIGITAL";
+	case SND_DJM_CAP_PHONO:		return "Control Tone PHONO";
+	case SND_DJM_CAP_PFADER:	return "Post Fader";
+	case SND_DJM_CAP_XFADERA:	return "Cross Fader A";
+	case SND_DJM_CAP_XFADERB:	return "Cross Fader B";
+	case SND_DJM_CAP_MIC:		return "Mic";
+	case SND_DJM_CAP_RECOUT:	return "Rec Out";
+	case SND_DJM_CAP_AUX:		return "Aux";
+	case SND_DJM_CAP_NONE:		return "None";
+	case SND_DJM_CAP_CH1PFADER:	return "Post Fader Ch1";
+	case SND_DJM_CAP_CH2PFADER:	return "Post Fader Ch2";
+	case SND_DJM_CAP_CH3PFADER:	return "Post Fader Ch3";
+	case SND_DJM_CAP_CH4PFADER:	return "Post Fader Ch4";
+	default:			return NULL;
+	}
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch56[] = {
-	{ .name =  "REC OUT",                .wValue = 0x030a, .wIndex = 0x8002 },
-	{ .name =  "Post CH1 Fader",         .wValue = 0x0311, .wIndex = 0x8002 },
-	{ .name =  "Post CH2 Fader",         .wValue = 0x0312, .wIndex = 0x8002 },
-	{ .name =  "Cross Fader A",          .wValue = 0x0307, .wIndex = 0x8002 },
-	{ .name =  "Cross Fader B",          .wValue = 0x0308, .wIndex = 0x8002 },
-	{ .name =  "MIC",                    .wValue = 0x0309, .wIndex = 0x8002 },
-	{ .name =  "AUX",                    .wValue = 0x030d, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_pb(u16 wvalue)
+{
+	switch (wvalue & 0x00ff) {
+	case SND_DJM_PB_CH1:	return "Ch1";
+	case SND_DJM_PB_CH2:	return "Ch2";
+	case SND_DJM_PB_AUX:	return "Aux";
+	default:		return NULL;
+	}
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_12[] = {
-	{ .name =  "CH1",                    .wValue = 0x0100, .wIndex = 0x8016 },
-	{ .name =  "CH2",                    .wValue = 0x0101, .wIndex = 0x8016 },
-	{ .name =  "AUX",                    .wValue = 0x0104, .wIndex = 0x8016 }
+static const char *snd_djm_get_label(u16 wvalue, u16 windex)
+{
+	switch (windex) {
+	case SND_DJM_WINDEX_CAPLVL:	return snd_djm_get_label_caplevel(wvalue);
+	case SND_DJM_WINDEX_CAP:	return snd_djm_get_label_cap(wvalue);
+	case SND_DJM_WINDEX_PB:		return snd_djm_get_label_pb(wvalue);
+	default:			return NULL;
+	}
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_34[] = {
-	{ .name =  "CH1",                    .wValue = 0x0200, .wIndex = 0x8016 },
-	{ .name =  "CH2",                    .wValue = 0x0201, .wIndex = 0x8016 },
-	{ .name =  "AUX",                    .wValue = 0x0204, .wIndex = 0x8016 }
+
+// DJM-250MK2
+static const u16 snd_djm_opts_cap_level[] = {
+	0x0000, 0x0100, 0x0200, 0x0300 };
+
+static const u16 snd_djm_opts_250mk2_cap1[] = {
+	0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a };
+
+static const u16 snd_djm_opts_250mk2_cap2[] = {
+	0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a };
+
+static const u16 snd_djm_opts_250mk2_cap3[] = {
+	0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d };
+
+static const u16 snd_djm_opts_250mk2_pb1[] = { 0x0100, 0x0101, 0x0104 };
+static const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 };
+static const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 };
+
+static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = {
+	SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+	SND_DJM_CTL("Ch1 Input",   250mk2_cap1, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch2 Input",   250mk2_cap2, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch3 Input",   250mk2_cap3, 0, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch1 Output",   250mk2_pb1, 0, SND_DJM_WINDEX_PB),
+	SND_DJM_CTL("Ch2 Output",   250mk2_pb2, 1, SND_DJM_WINDEX_PB),
+	SND_DJM_CTL("Ch3 Output",   250mk2_pb3, 2, SND_DJM_WINDEX_PB)
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_56[] = {
-	{ .name =  "CH1",                    .wValue = 0x0300, .wIndex = 0x8016 },
-	{ .name =  "CH2",                    .wValue = 0x0301, .wIndex = 0x8016 },
-	{ .name =  "AUX",                    .wValue = 0x0304, .wIndex = 0x8016 }
+
+// DJM-750
+static const u16 snd_djm_opts_750_cap1[] = {
+	0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f };
+static const u16 snd_djm_opts_750_cap2[] = {
+	0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f };
+static const u16 snd_djm_opts_750_cap3[] = {
+	0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f };
+static const u16 snd_djm_opts_750_cap4[] = {
+	0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f };
+
+static const struct snd_djm_ctl snd_djm_ctls_750[] = {
+	SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+	SND_DJM_CTL("Ch1 Input",   750_cap1, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch2 Input",   750_cap2, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch3 Input",   750_cap3, 0, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch4 Input",   750_cap4, 0, SND_DJM_WINDEX_CAP)
 };
 
-struct snd_pioneer_djm_option_group {
-	const char *name;
-	const struct snd_pioneer_djm_option *options;
-	const size_t count;
-	const u16 default_value;
+
+// DJM-900NXS2
+static const u16 snd_djm_opts_900nxs2_cap1[] = {
+	0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a };
+static const u16 snd_djm_opts_900nxs2_cap2[] = {
+	0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a };
+static const u16 snd_djm_opts_900nxs2_cap3[] = {
+	0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a };
+static const u16 snd_djm_opts_900nxs2_cap4[] = {
+	0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a };
+static const u16 snd_djm_opts_900nxs2_cap5[] = {
+	0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 };
+
+static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = {
+	SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+	SND_DJM_CTL("Ch1 Input",   900nxs2_cap1, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch2 Input",   900nxs2_cap2, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch3 Input",   900nxs2_cap3, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch4 Input",   900nxs2_cap4, 2, SND_DJM_WINDEX_CAP),
+	SND_DJM_CTL("Ch5 Input",   900nxs2_cap5, 3, SND_DJM_WINDEX_CAP)
 };
 
-#define snd_pioneer_djm_option_group_item(_name, suffix, _default_value) { \
-	.name = _name, \
-	.options = snd_pioneer_djm_options_##suffix, \
-	.count = ARRAY_SIZE(snd_pioneer_djm_options_##suffix), \
-	.default_value = _default_value }
-
-static const struct snd_pioneer_djm_option_group snd_pioneer_djm_option_groups[] = {
-	snd_pioneer_djm_option_group_item("Master Capture Level Capture Switch", capture_level, 0),
-	snd_pioneer_djm_option_group_item("Capture 1-2 Capture Switch",          capture_ch12,  2),
-	snd_pioneer_djm_option_group_item("Capture 3-4 Capture Switch",          capture_ch34,  2),
-	snd_pioneer_djm_option_group_item("Capture 5-6 Capture Switch",          capture_ch56,  0),
-	snd_pioneer_djm_option_group_item("Playback 1-2 Playback Switch",        playback_12,   0),
-	snd_pioneer_djm_option_group_item("Playback 3-4 Playback Switch",        playback_34,   1),
-	snd_pioneer_djm_option_group_item("Playback 5-6 Playback Switch",        playback_56,   2)
+
+static const struct snd_djm_device snd_djm_devices[] = {
+	SND_DJM_DEVICE(250mk2),
+	SND_DJM_DEVICE(750),
+	SND_DJM_DEVICE(900nxs2)
 };
 
-// layout of the kcontrol->private_value:
-#define SND_PIONEER_DJM_VALUE_MASK 0x0000ffff
-#define SND_PIONEER_DJM_GROUP_MASK 0xffff0000
-#define SND_PIONEER_DJM_GROUP_SHIFT 16
 
-static int snd_pioneer_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info)
+static int snd_djm_controls_info(struct snd_kcontrol *kctl,
+				struct snd_ctl_elem_info *info)
 {
-	u16 group_index = kctl->private_value >> SND_PIONEER_DJM_GROUP_SHIFT;
-	size_t count;
+	unsigned long private_value = kctl->private_value;
+	u8 device_idx = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+	u8 ctl_idx = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
+	const struct snd_djm_device *device = &snd_djm_devices[device_idx];
 	const char *name;
-	const struct snd_pioneer_djm_option_group *group;
+	const struct snd_djm_ctl *ctl;
+	size_t noptions;
 
-	if (group_index >= ARRAY_SIZE(snd_pioneer_djm_option_groups))
+	if (ctl_idx >= device->ncontrols)
 		return -EINVAL;
 
-	group = &snd_pioneer_djm_option_groups[group_index];
-	count = group->count;
-	if (info->value.enumerated.item >= count)
-		info->value.enumerated.item = count - 1;
-	name = group->options[info->value.enumerated.item].name;
-	strlcpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
+	ctl = &device->controls[ctl_idx];
+	noptions = ctl->noptions;
+	if (info->value.enumerated.item >= noptions)
+		info->value.enumerated.item = noptions - 1;
+
+	name = snd_djm_get_label(ctl->options[info->value.enumerated.item],
+				ctl->wIndex);
+	if (!name)
+		return -EINVAL;
+
+	strscpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
 	info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	info->count = 1;
-	info->value.enumerated.items = count;
+	info->value.enumerated.items = noptions;
 	return 0;
 }
 
-static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u16 group, u16 value)
+static int snd_djm_controls_update(struct usb_mixer_interface *mixer,
+				u8 device_idx, u8 group, u16 value)
 {
 	int err;
+	const struct snd_djm_device *device = &snd_djm_devices[device_idx];
 
-	if (group >= ARRAY_SIZE(snd_pioneer_djm_option_groups)
-			|| value >= snd_pioneer_djm_option_groups[group].count)
+	if ((group >= device->ncontrols) || value >= device->controls[group].noptions)
 		return -EINVAL;
 
 	err = snd_usb_lock_shutdown(mixer->chip);
@@ -2748,63 +2858,76 @@ static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u1
 		mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0),
 		USB_REQ_SET_FEATURE,
 		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		snd_pioneer_djm_option_groups[group].options[value].wValue,
-		snd_pioneer_djm_option_groups[group].options[value].wIndex,
+		device->controls[group].options[value],
+		device->controls[group].wIndex,
 		NULL, 0);
 
 	snd_usb_unlock_shutdown(mixer->chip);
 	return err;
 }
 
-static int snd_pioneer_djm_controls_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
+static int snd_djm_controls_get(struct snd_kcontrol *kctl,
+				struct snd_ctl_elem_value *elem)
 {
-	elem->value.enumerated.item[0] = kctl->private_value & SND_PIONEER_DJM_VALUE_MASK;
+	elem->value.enumerated.item[0] = kctl->private_value & SND_DJM_VALUE_MASK;
 	return 0;
 }
 
-static int snd_pioneer_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
+static int snd_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
 {
 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
 	struct usb_mixer_interface *mixer = list->mixer;
 	unsigned long private_value = kctl->private_value;
-	u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
+
+	u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+	u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
 	u16 value = elem->value.enumerated.item[0];
 
-	kctl->private_value = (group << SND_PIONEER_DJM_GROUP_SHIFT) | value;
+	kctl->private_value = ((device << SND_DJM_DEVICE_SHIFT) |
+			      (group << SND_DJM_GROUP_SHIFT) |
+			      value);
 
-	return snd_pioneer_djm_controls_update(mixer, group, value);
+	return snd_djm_controls_update(mixer, device, group, value);
 }
 
-static int snd_pioneer_djm_controls_resume(struct usb_mixer_elem_list *list)
+static int snd_djm_controls_resume(struct usb_mixer_elem_list *list)
 {
 	unsigned long private_value = list->kctl->private_value;
-	u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
-	u16 value = (private_value & SND_PIONEER_DJM_VALUE_MASK);
+	u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+	u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
+	u16 value = (private_value & SND_DJM_VALUE_MASK);
 
-	return snd_pioneer_djm_controls_update(list->mixer, group, value);
+	return snd_djm_controls_update(list->mixer, device, group, value);
 }
 
-static int snd_pioneer_djm_controls_create(struct usb_mixer_interface *mixer)
+static int snd_djm_controls_create(struct usb_mixer_interface *mixer,
+		const u8 device_idx)
 {
 	int err, i;
-	const struct snd_pioneer_djm_option_group *group;
+	u16 value;
+
+	const struct snd_djm_device *device = &snd_djm_devices[device_idx];
+
 	struct snd_kcontrol_new knew = {
 		.iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 		.index = 0,
-		.info = snd_pioneer_djm_controls_info,
-		.get  = snd_pioneer_djm_controls_get,
-		.put  = snd_pioneer_djm_controls_put
+		.info = snd_djm_controls_info,
+		.get  = snd_djm_controls_get,
+		.put  = snd_djm_controls_put
 	};
 
-	for (i = 0; i < ARRAY_SIZE(snd_pioneer_djm_option_groups); i++) {
-		group = &snd_pioneer_djm_option_groups[i];
-		knew.name = group->name;
-		knew.private_value = (i << SND_PIONEER_DJM_GROUP_SHIFT) | group->default_value;
-		err = snd_pioneer_djm_controls_update(mixer, i, group->default_value);
+	for (i = 0; i < device->ncontrols; i++) {
+		value = device->controls[i].default_value;
+		knew.name = device->controls[i].name;
+		knew.private_value = (
+			(device_idx << SND_DJM_DEVICE_SHIFT) |
+			(i << SND_DJM_GROUP_SHIFT) |
+			value);
+		err = snd_djm_controls_update(mixer, device_idx, i, value);
 		if (err)
 			return err;
-		err = add_single_ctl_with_resume(mixer, 0, snd_pioneer_djm_controls_resume,
+		err = add_single_ctl_with_resume(mixer, 0, snd_djm_controls_resume,
 						 &knew, NULL);
 		if (err)
 			return err;
@@ -2917,7 +3040,13 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 		err = snd_bbfpro_controls_create(mixer);
 		break;
 	case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
-		err = snd_pioneer_djm_controls_create(mixer);
+		err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
+		break;
+	case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */
+		err = snd_djm_controls_create(mixer, SND_DJM_750_IDX);
+		break;
+	case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
+		err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX);
 		break;
 	}
 
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
index 49fcd25054439a05244afd30db79282353b4a943..691b95466d0fcba5262eae4f827cb554e5bd5bdd 100644
--- a/sound/usb/mixer_scarlett.c
+++ b/sound/usb/mixer_scarlett.c
@@ -569,7 +569,7 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
 	}
 	kctl->private_free = snd_usb_mixer_elem_free;
 
-	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+	strscpy(kctl->id.name, name, sizeof(kctl->id.name));
 
 	err = snd_usb_mixer_add_control(&elem->head, kctl);
 	if (err < 0)
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 4bbec56c7df343bbd78f226ffecd7ac8ef5bbb10..560c2ade829d08b0c501a963e35a1b4e47692fb0 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -961,7 +961,7 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer,
 	}
 	kctl->private_free = snd_usb_mixer_elem_free;
 
-	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+	strscpy(kctl->id.name, name, sizeof(kctl->id.name));
 
 	err = snd_usb_mixer_add_control(&elem->head, kctl);
 	if (err < 0)
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
index bd63a9ce6a707e25bf2e5357af0f75d5506da038..b7b6f3834ed5e1de4a1b3f897c01bd1117cdbf10 100644
--- a/sound/usb/mixer_us16x08.c
+++ b/sound/usb/mixer_us16x08.c
@@ -1076,7 +1076,7 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
 	else
 		kctl->private_free = snd_usb_mixer_elem_free;
 
-	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+	strscpy(kctl->id.name, name, sizeof(kctl->id.name));
 
 	err = snd_usb_mixer_add_control(&elem->head, kctl);
 	if (err < 0)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 078bb4c94033498e7ddcc938aa31eb1a5a471e2e..bf5a0f3c1fadeb9b24084e7420e5783b39ec1914 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -270,10 +270,7 @@ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream)
 {
 	struct snd_usb_substream *subs = substream->runtime->private_data;
 
-	if (!snd_usb_lock_shutdown(subs->stream->chip)) {
-		sync_pending_stops(subs);
-		snd_usb_unlock_shutdown(subs->stream->chip);
-	}
+	sync_pending_stops(subs);
 	return 0;
 }
 
@@ -1558,7 +1555,7 @@ void snd_usb_preallocate_buffer(struct snd_usb_substream *subs)
 {
 	struct snd_pcm *pcm = subs->stream->pcm;
 	struct snd_pcm_substream *s = pcm->streams[subs->direction].substream;
-	struct device *dev = subs->dev->bus->controller;
+	struct device *dev = subs->dev->bus->sysdev;
 
 	if (snd_usb_use_vmalloc)
 		snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_VMALLOC,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c8a4bdf18207c915486b0ebcdaa9f9405f8ebe44..1165a5ac60f22f2b897a20ad4c2a81f91fd28b86 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3757,6 +3757,123 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
 		}
 	}
 },
+{
+	/*
+	 * Pioneer DJ DJM-750
+	 * 8 channels playback & 8 channels capture @ 44.1/48/96kHz S24LE
+	 */
+	USB_DEVICE_VENDOR_SPEC(0x08e4, 0x017f),
+	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+					.channels = 8,
+					.iface = 0,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.endpoint = 0x05,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC|
+					    USB_ENDPOINT_SYNC_ASYNC,
+					.rates = SNDRV_PCM_RATE_44100|
+						SNDRV_PCM_RATE_48000|
+						SNDRV_PCM_RATE_96000,
+					.rate_min = 44100,
+					.rate_max = 96000,
+					.nr_rates = 3,
+					.rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+				}
+			},
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+					.channels = 8,
+					.iface = 0,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.endpoint = 0x86,
+					.ep_idx = 1,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC|
+						USB_ENDPOINT_SYNC_ASYNC|
+						USB_ENDPOINT_USAGE_IMPLICIT_FB,
+					.rates = SNDRV_PCM_RATE_44100|
+						SNDRV_PCM_RATE_48000|
+						SNDRV_PCM_RATE_96000,
+					.rate_min = 44100,
+					.rate_max = 96000,
+					.nr_rates = 3,
+					.rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
+	/*
+	 * Pioneer DJ DJM-450
+	 * PCM is 8 channels out @ 48 fixed (endpoint 0x01)
+	 * and 8 channels in @ 48 fixed (endpoint 0x82).
+	 */
+	USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0013),
+	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+					.channels = 8, // outputs
+					.iface = 0,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.endpoint = 0x01,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC|
+						USB_ENDPOINT_SYNC_ASYNC,
+					.rates = SNDRV_PCM_RATE_48000,
+					.rate_min = 48000,
+					.rate_max = 48000,
+					.nr_rates = 1,
+					.rate_table = (unsigned int[]) { 48000 }
+					}
+			},
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+					.channels = 8, // inputs
+					.iface = 0,
+					.altsetting = 1,
+					.altset_idx = 1,
+					.endpoint = 0x82,
+					.ep_idx = 1,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC|
+						USB_ENDPOINT_SYNC_ASYNC|
+						USB_ENDPOINT_USAGE_IMPLICIT_FB,
+					.rates = SNDRV_PCM_RATE_48000,
+					.rate_min = 48000,
+					.rate_max = 48000,
+					.nr_rates = 1,
+					.rate_table = (unsigned int[]) { 48000 }
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 
 #undef USB_DEVICE_VENDOR_SPEC
 #undef USB_AUDIO_DEVICE
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e196e364cef19401c5557bc5bf6a05d5843e3206..9ba4682ebc482b1a1ef610b9b7615a95d7717de1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1470,6 +1470,23 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,
 	subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
 }
 
+static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs,
+					u16 windex)
+{
+	unsigned int cur_rate = subs->data_endpoint->cur_rate;
+	u8 sr[3];
+	// Convert to little endian
+	sr[0] = cur_rate & 0xff;
+	sr[1] = (cur_rate >> 8) & 0xff;
+	sr[2] = (cur_rate >> 16) & 0xff;
+	usb_set_interface(subs->dev, 0, 1);
+	// we should derive windex from fmt-sync_ep but it's not set
+	snd_usb_ctl_msg(subs->stream->chip->dev,
+		usb_rcvctrlpipe(subs->stream->chip->dev, 0),
+		0x01, 0x22, 0x0100, windex, &sr, 0x0003);
+	return 0;
+}
+
 void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
 			      const struct audioformat *fmt)
 {
@@ -1483,6 +1500,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
 	case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
 		subs->stream_offset_adj = 2;
 		break;
+	case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */
+		pioneer_djm_set_format_quirk(subs, 0x0082);
+		break;
 	}
 }
 
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index 9f9fcd2749f224d8ec09e8fae677991f60cc0c9f..1d66c3a4fb107e6e65bd6e8452226f4b65b50708 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -1770,8 +1770,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 	card_ctx->irq = irq;
 
 	/* only 32bit addressable */
-	dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
-	dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
 
 	init_channel_allocations();
 
@@ -1790,7 +1789,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 		/* setup private data which can be retrieved when required */
 		pcm->private_data = ctx;
 		pcm->info_flags = 0;
-		strlcpy(pcm->name, card->shortname, strlen(card->shortname));
+		strscpy(pcm->name, card->shortname, strlen(card->shortname));
 		/* setup the ops for playabck */
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops);
 
diff --git a/sound/xen/xen_snd_front_cfg.c b/sound/xen/xen_snd_front_cfg.c
index eda077c8087a87304f9b3d9a80bc21ee7fd13efd..63b0398c327656b543cca5962bb8991ee8b287cd 100644
--- a/sound/xen/xen_snd_front_cfg.c
+++ b/sound/xen/xen_snd_front_cfg.c
@@ -398,7 +398,7 @@ static int cfg_device(struct xen_snd_front_info *front_info,
 
 	str = xenbus_read(XBT_NIL, device_path, XENSND_FIELD_DEVICE_NAME, NULL);
 	if (!IS_ERR(str)) {
-		strlcpy(pcm_instance->name, str, sizeof(pcm_instance->name));
+		strscpy(pcm_instance->name, str, sizeof(pcm_instance->name));
 		kfree(str);
 	}