Merge remote-tracking branch 'asoc/for-7.4' into asoc-next
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1372.yaml b/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
index 9a7ff50..532550d 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
+++ b/Documentation/devicetree/bindings/sound/adi,adau1372.yaml
@@ -52,11 +52,11 @@
         #address-cells = <1>;
         #size-cells = <0>;
         audio-codec@3c {
-                compatible = "adi,adau1372";
-                reg = <0x3c>;
-                #sound-dai-cells = <0>;
-                clock-names = "mclk";
-                clocks = <&adau1372z_xtal>;
+            compatible = "adi,adau1372";
+            reg = <0x3c>;
+            #sound-dai-cells = <0>;
+            clock-names = "mclk";
+            clocks = <&adau1372z_xtal>;
         };
     };
 
diff --git a/Documentation/devicetree/bindings/sound/adi,adau7118.yaml b/Documentation/devicetree/bindings/sound/adi,adau7118.yaml
index 11f59c2..8272cda 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau7118.yaml
+++ b/Documentation/devicetree/bindings/sound/adi,adau7118.yaml
@@ -68,20 +68,20 @@
         #address-cells = <1>;
         #size-cells = <0>;
         adau7118_codec: audio-codec@14 {
-                compatible = "adi,adau7118";
-                reg = <0x14>;
-                #sound-dai-cells = <0>;
-                iovdd-supply = <&supply>;
-                dvdd-supply = <&supply>;
-                adi,pdm-clk-map = <1 1 0 0>;
-                adi,decimation-ratio = <16>;
+            compatible = "adi,adau7118";
+            reg = <0x14>;
+            #sound-dai-cells = <0>;
+            iovdd-supply = <&supply>;
+            dvdd-supply = <&supply>;
+            adi,pdm-clk-map = <1 1 0 0>;
+            adi,decimation-ratio = <16>;
         };
     };
 
     /* example with hw standalone mode */
     adau7118_codec_hw: adau7118-codec-hw {
-            compatible = "adi,adau7118";
-            #sound-dai-cells = <0>;
-            iovdd-supply = <&supply>;
-            dvdd-supply = <&supply>;
+        compatible = "adi,adau7118";
+        #sound-dai-cells = <0>;
+        iovdd-supply = <&supply>;
+        dvdd-supply = <&supply>;
     };
diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
index 6fdf605..2be3b34 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
@@ -94,20 +94,20 @@
         audio-routing = "I2S ENCODER I2S IN", "I2S FIFO Playback";
 
         dai-link-0 {
-               sound-dai = <&i2s_fifo>;
+            sound-dai = <&i2s_fifo>;
         };
 
         dai-link-1 {
-                sound-dai = <&i2s_encoder>;
-                dai-format = "i2s";
-                mclk-fs = <256>;
+            sound-dai = <&i2s_encoder>;
+            dai-format = "i2s";
+            mclk-fs = <256>;
 
-                codec-0 {
-                        sound-dai = <&codec0>;
-                };
+            codec-0 {
+                sound-dai = <&codec0>;
+            };
 
-                codec-1 {
-                        sound-dai = <&codec1>;
-                };
+            codec-1 {
+                sound-dai = <&codec1>;
+            };
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml
index d412531..2e81947 100644
--- a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4619.yaml
@@ -54,9 +54,9 @@
 
             #sound-dai-cells = <0>;
             port {
-                 ak4619_endpoint: endpoint {
-                       remote-endpoint = <&rsnd_endpoint>;
-                  };
+                ak4619_endpoint: endpoint {
+                    remote-endpoint = <&rsnd_endpoint>;
+                };
             };
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml
index 70f6c62..1ba8098 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l45.yaml
@@ -53,6 +53,24 @@
     maximum: 3
     default: 2
 
+  cirrus,sync-lsw-txid:
+    description:
+      Transmitter ID to use for long software (LSW) data packets
+      on the SYNC bus.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 7
+    default: 0
+
+  cirrus,sync-sw-txid:
+    description:
+      Transmitter ID to use for short software (SW) data packets
+      on the SYNC bus.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 7
+    default: 0
+
 patternProperties:
   "^cirrus,gpio-ctrl[1-3]$":
     description:
@@ -135,25 +153,27 @@
         #address-cells = <1>;
         #size-cells = <0>;
 
-        cs35l45: cs35l45@2 {
-          #sound-dai-cells = <1>;
-          compatible = "cirrus,cs35l45";
-          reg = <2>;
-          spi-max-frequency = <5000000>;
-          vdd-a-supply = <&dummy_vreg>;
-          vdd-batt-supply = <&dummy_vreg>;
-          reset-gpios = <&gpio 110 0>;
-          cirrus,asp-sdout-hiz-ctrl = <(CS35L45_ASP_TX_HIZ_UNUSED |
-                                        CS35L45_ASP_TX_HIZ_DISABLED)>;
-          cirrus,gpio-ctrl1 {
-             gpio-ctrl = <0x2>;
-          };
-          cirrus,gpio-ctrl2 {
-             gpio-ctrl = <0x2>;
-          };
-          cirrus,gpio-ctrl3 {
-             gpio-ctrl = <0x1>;
-             gpio-dir = <0x1>;
-          };
+        cs35l45: audio-codec@2 {
+            #sound-dai-cells = <1>;
+            compatible = "cirrus,cs35l45";
+            reg = <2>;
+            spi-max-frequency = <5000000>;
+            vdd-a-supply = <&dummy_vreg>;
+            vdd-batt-supply = <&dummy_vreg>;
+            reset-gpios = <&gpio 110 0>;
+            cirrus,asp-sdout-hiz-ctrl = <(CS35L45_ASP_TX_HIZ_UNUSED |
+                                          CS35L45_ASP_TX_HIZ_DISABLED)>;
+            cirrus,sync-lsw-txid = <0x1>;
+            cirrus,sync-sw-txid = <0x1>;
+            cirrus,gpio-ctrl1 {
+                gpio-ctrl = <0x2>;
+            };
+            cirrus,gpio-ctrl2 {
+                gpio-ctrl = <0x2>;
+            };
+            cirrus,gpio-ctrl3 {
+                gpio-ctrl = <0x1>;
+                gpio-dir = <0x1>;
+            };
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml
index 336e117..6110629 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs4270.yaml
@@ -49,11 +49,11 @@
 examples:
   - |
     i2c {
-      #address-cells = <1>;
-      #size-cells = <0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
 
-      codec@48 {
-          compatible = "cirrus,cs4270";
-          reg = <0x48>;
-      };
+        codec@48 {
+            compatible = "cirrus,cs4270";
+            reg = <0x48>;
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml
index af599d8..ab4c7d2 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml
@@ -199,28 +199,28 @@
   - |
     #include <dt-bindings/sound/cs42l42.h>
     i2c {
-      #address-cells = <1>;
-      #size-cells = <0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
 
-      cs42l42: cs42l42@48 {
-          compatible = "cirrus,cs42l42";
-          reg = <0x48>;
-          VA-supply = <&dummy_vreg>;
-          VP-supply = <&dummy_vreg>;
-          VCP-supply = <&dummy_vreg>;
-          VD_FILT-supply = <&dummy_vreg>;
-          VL-supply = <&dummy_vreg>;
+        audio-codec@48 {
+            compatible = "cirrus,cs42l42";
+            reg = <0x48>;
+            VA-supply = <&dummy_vreg>;
+            VP-supply = <&dummy_vreg>;
+            VCP-supply = <&dummy_vreg>;
+            VD_FILT-supply = <&dummy_vreg>;
+            VL-supply = <&dummy_vreg>;
 
-          reset-gpios = <&axi_gpio_0 1 0>;
-          interrupt-parent = <&gpio0>;
-          interrupts = <55 8>;
+            reset-gpios = <&axi_gpio_0 1 0>;
+            interrupt-parent = <&gpio0>;
+            interrupts = <55 8>;
 
-          cirrus,ts-inv = <CS42L42_TS_INV_DIS>;
-          cirrus,ts-dbnc-rise = <CS42L42_TS_DBNCE_1000>;
-          cirrus,ts-dbnc-fall = <CS42L42_TS_DBNCE_0>;
-          cirrus,btn-det-init-dbnce = <100>;
-          cirrus,btn-det-event-dbnce = <10>;
-          cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>;
-          cirrus,hs-bias-ramp-rate = <CS42L42_HSBIAS_RAMP_SLOW>;
-      };
+            cirrus,ts-inv = <CS42L42_TS_INV_DIS>;
+            cirrus,ts-dbnc-rise = <CS42L42_TS_DBNCE_1000>;
+            cirrus,ts-dbnc-fall = <CS42L42_TS_DBNCE_0>;
+            cirrus,btn-det-init-dbnce = <100>;
+            cirrus,btn-det-event-dbnce = <10>;
+            cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>;
+            cirrus,hs-bias-ramp-rate = <CS42L42_HSBIAS_RAMP_SLOW>;
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml
index 7f8338e..94062c1 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml
@@ -43,14 +43,14 @@
     #include <dt-bindings/gpio/gpio.h>
     #include <dt-bindings/interrupt-controller/irq.h>
     i2c {
-      #address-cells = <1>;
-      #size-cells = <0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
 
-      jack_codec: codec@4b {
-          compatible = "cirrus,cs42l84";
-          reg = <0x4b>;
-          reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>;
-          interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>;
-          #sound-dai-cells = <0>;
-      };
+        jack_codec: codec@4b {
+            compatible = "cirrus,cs42l84";
+            reg = <0x4b>;
+            reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>;
+            interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>;
+            #sound-dai-cells = <0>;
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
index a1ae548..b5cdc7e 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
@@ -75,37 +75,37 @@
 examples:
   - |
     i2c {
-      #address-cells = <1>;
-      #size-cells = <0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
 
-      codec@48 {
-          compatible = "cirrus,cs42888";
-          reg = <0x48>;
-          clocks = <&codec_mclk 0>;
-          clock-names = "mclk";
-          VA-supply = <&reg_audio>;
-          VD-supply = <&reg_audio>;
-          VLS-supply = <&reg_audio>;
-          VLC-supply = <&reg_audio>;
-          reset-gpios = <&gpio 1>;
-      };
+        codec@48 {
+            compatible = "cirrus,cs42888";
+            reg = <0x48>;
+            clocks = <&codec_mclk 0>;
+            clock-names = "mclk";
+            VA-supply = <&reg_audio>;
+            VD-supply = <&reg_audio>;
+            VLS-supply = <&reg_audio>;
+            VLC-supply = <&reg_audio>;
+            reset-gpios = <&gpio 1>;
+        };
     };
 
     spi {
-      #address-cells = <1>;
-      #size-cells = <0>;
-      cs-gpios = <&gpio 8 0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        cs-gpios = <&gpio 8 0>;
 
-      codec@0 {
-          compatible = "cirrus,cs42888";
-          reg = <0>;
-          spi-max-frequency = <6000000>;
-          clocks = <&codec_mclk 0>;
-          clock-names = "mclk";
-          VA-supply = <&reg_audio>;
-          VD-supply = <&reg_audio>;
-          VLS-supply = <&reg_audio>;
-          VLC-supply = <&reg_audio>;
-          reset-gpios = <&gpio 1>;
-      };
+        codec@0 {
+            compatible = "cirrus,cs42888";
+            reg = <0>;
+            spi-max-frequency = <6000000>;
+            clocks = <&codec_mclk 0>;
+            clock-names = "mclk";
+            VA-supply = <&reg_audio>;
+            VD-supply = <&reg_audio>;
+            VLS-supply = <&reg_audio>;
+            VLC-supply = <&reg_audio>;
+            reset-gpios = <&gpio 1>;
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
deleted file mode 100644
index 963e100..0000000
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-* Texas Instruments SoC audio setups with TLV320AIC3X Codec
-
-Required properties:
-- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
-- ti,model : The user-visible name of this sound complex.
-- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
-- ti,mcasp-controller : The phandle of the McASP controller
-- ti,audio-routing : A list of the connections between audio components.
-  Each entry is a pair of strings, the first being the connection's sink,
-  the second being the connection's source. Valid names for sources and
-  sinks are the codec's pins, and the jacks on the board:
-
-Optional properties:
-- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec.
-- clocks : Reference to the master clock
-- clock-names : The clock should be named "mclk"
-- Either codec-clock-rate or the codec-clock reference has to be defined. If
-  the both are defined the driver attempts to set referenced clock to the
-  defined rate and takes the rate from the clock reference.
-
-  Board connectors:
-
-  * Headphone Jack
-  * Line Out
-  * Mic Jack
-  * Line In
-
-
-Example:
-
-sound {
-	compatible = "ti,da830-evm-audio";
-	ti,model = "DA830 EVM";
-	ti,audio-codec = <&tlv320aic3x>;
-	ti,mcasp-controller = <&mcasp1>;
-	ti,codec-clock-rate = <12000000>;
-	ti,audio-routing =
-		"Headphone Jack",       "HPLOUT",
-		"Headphone Jack",       "HPROUT",
-		"Line Out",             "LLOUT",
-		"Line Out",             "RLOUT",
-		"MIC3L",                "Mic Bias 2V",
-		"MIC3R",                "Mic Bias 2V",
-		"Mic Bias 2V",          "Mic Jack",
-		"LINE1L",               "Line In",
-		"LINE2L",               "Line In",
-		"LINE1R",               "Line In",
-		"LINE2R",               "Line In";
-};
diff --git a/Documentation/devicetree/bindings/sound/dialog,da7219.yaml b/Documentation/devicetree/bindings/sound/dialog,da7219.yaml
index 19137ab..852f27e 100644
--- a/Documentation/devicetree/bindings/sound/dialog,da7219.yaml
+++ b/Documentation/devicetree/bindings/sound/dialog,da7219.yaml
@@ -195,44 +195,44 @@
   - |
     #include <dt-bindings/interrupt-controller/irq.h>
     i2c {
-      #address-cells = <1>;
-      #size-cells = <0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
 
-      codec: da7219@1a {
-          compatible = "dlg,da7219";
-          reg = <0x1a>;
+        codec: audio-codec@1a {
+            compatible = "dlg,da7219";
+            reg = <0x1a>;
 
-          interrupt-parent = <&gpio6>;
-          interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+            interrupt-parent = <&gpio6>;
+            interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
 
-          VDD-supply = <&vdd_reg>;
-          VDDMIC-supply = <&vddmic_reg>;
-          VDDIO-supply = <&vddio_reg>;
+            VDD-supply = <&vdd_reg>;
+            VDDMIC-supply = <&vddmic_reg>;
+            VDDIO-supply = <&vddio_reg>;
 
-          #clock-cells = <1>;
-          clock-output-names = "da7219-dai-wclk", "da7219-dai-bclk";
+            #clock-cells = <1>;
+            clock-output-names = "da7219-dai-wclk", "da7219-dai-bclk";
 
-          clocks = <&clks 201>;
-          clock-names = "mclk";
+            clocks = <&clks 201>;
+            clock-names = "mclk";
 
-          dlg,micbias-lvl = <2600>;
-          dlg,mic-amp-in-sel = "diff";
+            dlg,micbias-lvl = <2600>;
+            dlg,mic-amp-in-sel = "diff";
 
-          da7219_aad {
-              dlg,btn-cfg = <50>;
-              dlg,mic-det-thr = <500>;
-              dlg,jack-ins-deb = <20>;
-              dlg,jack-ins-det-pty = "low";
-              dlg,jack-det-rate = "32_64";
-              dlg,jack-rem-deb = <1>;
+            da7219_aad {
+                dlg,btn-cfg = <50>;
+                dlg,mic-det-thr = <500>;
+                dlg,jack-ins-deb = <20>;
+                dlg,jack-ins-det-pty = "low";
+                dlg,jack-det-rate = "32_64";
+                dlg,jack-rem-deb = <1>;
 
-              dlg,a-d-btn-thr = <0xa>;
-              dlg,d-b-btn-thr = <0x16>;
-              dlg,b-c-btn-thr = <0x21>;
-              dlg,c-mic-btn-thr = <0x3E>;
+                dlg,a-d-btn-thr = <0xa>;
+                dlg,d-b-btn-thr = <0x16>;
+                dlg,b-c-btn-thr = <0x21>;
+                dlg,c-mic-btn-thr = <0x3E>;
 
-              dlg,btn-avg = <4>;
-              dlg,adc-1bit-rpt = <1>;
-          };
-      };
+                dlg,btn-avg = <4>;
+                dlg,adc-1bit-rpt = <1>;
+            };
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml b/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml
index 4da7353..17c938a 100644
--- a/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml
+++ b/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml
@@ -63,7 +63,7 @@
       a. Register initialization settings
       b. DSP effect parameters
       c. Multi-scene sound effect configurations(optional)
-      It's gernerated by FourSemi's tuning tool.
+      It's generated by FourSemi's tuning tool.
 
 required:
   - compatible
diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
index 608defc..cd69bad 100644
--- a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
@@ -186,5 +186,5 @@
             asrc_endpoint: endpoint {
                 remote-endpoint = <&fe00_ep>;
             };
-       };
+        };
     };
diff --git a/Documentation/devicetree/bindings/sound/fsl,sai.yaml b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
index ba65b3f3..eb0b9d8 100644
--- a/Documentation/devicetree/bindings/sound/fsl,sai.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
@@ -260,13 +260,13 @@
                 playback-only;
 
                 sai1_endpoint0: endpoint {
-                   dai-tdm-slot-num = <8>;
-                   dai-tdm-slot-width = <32>;
-                   dai-tdm-slot-width-map = <32 8 32>;
-                   dai-format = "dsp_a";
-                   bitclock-master;
-                   frame-master;
-                   remote-endpoint = <&mcodec01_ep>;
+                    dai-tdm-slot-num = <8>;
+                    dai-tdm-slot-width = <32>;
+                    dai-tdm-slot-width-map = <32 8 32>;
+                    dai-format = "dsp_a";
+                    bitclock-master;
+                    frame-master;
+                    remote-endpoint = <&mcodec01_ep>;
                 };
             };
 
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
index 950e3ea..27636466 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
@@ -105,10 +105,10 @@
             format = "i2s";
             fsl,mclk-equal-bclk;
             cpu {
-                 sound-dai = <&sai1>;
+                sound-dai = <&sai1>;
             };
             codec {
-                 sound-dai = <&ak4458_1>, <&ak4458_2>;
+                sound-dai = <&ak4458_1>, <&ak4458_2>;
             };
         };
         fe-dai-link {
diff --git a/Documentation/devicetree/bindings/sound/imx-audmux.yaml b/Documentation/devicetree/bindings/sound/imx-audmux.yaml
index dab45c3..501af1a 100644
--- a/Documentation/devicetree/bindings/sound/imx-audmux.yaml
+++ b/Documentation/devicetree/bindings/sound/imx-audmux.yaml
@@ -101,10 +101,10 @@
         mux-ssi1 {
             fsl,audmux-port = <0>;
             fsl,port-config = <
-                IMX_AUDMUX_V2_PTCR_SYN		0
-                IMX_AUDMUX_V2_PTCR_TFSEL(2)	0
-                IMX_AUDMUX_V2_PTCR_TCSEL(2)	0
-                IMX_AUDMUX_V2_PTCR_TFSDIR	0
+                IMX_AUDMUX_V2_PTCR_SYN      0
+                IMX_AUDMUX_V2_PTCR_TFSEL(2) 0
+                IMX_AUDMUX_V2_PTCR_TCSEL(2) 0
+                IMX_AUDMUX_V2_PTCR_TFSDIR   0
                 IMX_AUDMUX_V2_PTCR_TCLKDIR      IMX_AUDMUX_V2_PDCR_RXDSEL(2)
               >;
         };
diff --git a/Documentation/devicetree/bindings/sound/invensense,ics43432.yaml b/Documentation/devicetree/bindings/sound/invensense,ics43432.yaml
index 7bd9848..054f803 100644
--- a/Documentation/devicetree/bindings/sound/invensense,ics43432.yaml
+++ b/Documentation/devicetree/bindings/sound/invensense,ics43432.yaml
@@ -42,10 +42,10 @@
         compatible = "invensense,ics43432";
 
         port {
-          endpoint {
-            remote-endpoint = <&i2s1_endpoint>;
-            dai-format = "i2s";
-          };
+            endpoint {
+                remote-endpoint = <&i2s1_endpoint>;
+                dai-format = "i2s";
+            };
         };
 
     };
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
index dc7f4af..69ea611 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
@@ -79,7 +79,7 @@
             sound-dai = <&i2s>;
         };
         codec {
-             sound-dai = <&es8323>;
+            sound-dai = <&es8323>;
         };
     };
 
@@ -104,6 +104,6 @@
         };
 
         codec {
-             sound-dai = <&es8388>;
+            sound-dai = <&es8388>;
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml
index d8993b5..4c66160 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8173-afe-pcm.yaml
@@ -84,15 +84,15 @@
                  <&topckgen CLK_TOP_I2S2_M_SEL>,
                  <&topckgen CLK_TOP_I2S3_M_SEL>,
                  <&topckgen CLK_TOP_I2S3_B_SEL>;
-         clock-names = "infra_sys_audio_clk",
-                       "top_pdn_audio",
-                       "top_pdn_aud_intbus",
-                       "bck0",
-                       "bck1",
-                       "i2s0_m",
-                       "i2s1_m",
-                       "i2s2_m",
-                       "i2s3_m",
-                       "i2s3_b";
-          memory-region = <&afe_dma_mem>;
+        clock-names = "infra_sys_audio_clk",
+                      "top_pdn_audio",
+                      "top_pdn_aud_intbus",
+                      "bck0",
+                      "bck1",
+                      "i2s0_m",
+                      "i2s1_m",
+                      "i2s2_m",
+                      "i2s3_m",
+                      "i2s3_b";
+        memory-region = <&afe_dma_mem>;
     };
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8183-audio.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8183-audio.yaml
index 031b0fa..261247c 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt8183-audio.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8183-audio.yaml
@@ -182,47 +182,47 @@
                  <&topckgen CLK_TOP_APLL12_DIV4>,
                  <&topckgen CLK_TOP_APLL12_DIVB>,
                  <&clk26m>;
-      clock-names = "aud_afe_clk",
-                    "aud_dac_clk",
-                    "aud_dac_predis_clk",
-                    "aud_adc_clk",
-                    "aud_adc_adda6_clk",
-                    "aud_apll22m_clk",
-                    "aud_apll24m_clk",
-                    "aud_apll1_tuner_clk",
-                    "aud_apll2_tuner_clk",
-                    "aud_i2s1_bclk_sw",
-                    "aud_i2s2_bclk_sw",
-                    "aud_i2s3_bclk_sw",
-                    "aud_i2s4_bclk_sw",
-                    "aud_tdm_clk",
-                    "aud_tml_clk",
-                    "aud_infra_clk",
-                    "mtkaif_26m_clk",
-                    "top_mux_audio",
-                    "top_mux_aud_intbus",
-                    "top_syspll_d2_d4",
-                    "top_mux_aud_1",
-                    "top_apll1_ck",
-                    "top_mux_aud_2",
-                    "top_apll2_ck",
-                    "top_mux_aud_eng1",
-                    "top_apll1_d8",
-                    "top_mux_aud_eng2",
-                    "top_apll2_d8",
-                    "top_i2s0_m_sel",
-                    "top_i2s1_m_sel",
-                    "top_i2s2_m_sel",
-                    "top_i2s3_m_sel",
-                    "top_i2s4_m_sel",
-                    "top_i2s5_m_sel",
-                    "top_apll12_div0",
-                    "top_apll12_div1",
-                    "top_apll12_div2",
-                    "top_apll12_div3",
-                    "top_apll12_div4",
-                    "top_apll12_divb",
-                    "top_clk26m_clk";
+        clock-names = "aud_afe_clk",
+                      "aud_dac_clk",
+                      "aud_dac_predis_clk",
+                      "aud_adc_clk",
+                      "aud_adc_adda6_clk",
+                      "aud_apll22m_clk",
+                      "aud_apll24m_clk",
+                      "aud_apll1_tuner_clk",
+                      "aud_apll2_tuner_clk",
+                      "aud_i2s1_bclk_sw",
+                      "aud_i2s2_bclk_sw",
+                      "aud_i2s3_bclk_sw",
+                      "aud_i2s4_bclk_sw",
+                      "aud_tdm_clk",
+                      "aud_tml_clk",
+                      "aud_infra_clk",
+                      "mtkaif_26m_clk",
+                      "top_mux_audio",
+                      "top_mux_aud_intbus",
+                      "top_syspll_d2_d4",
+                      "top_mux_aud_1",
+                      "top_apll1_ck",
+                      "top_mux_aud_2",
+                      "top_apll2_ck",
+                      "top_mux_aud_eng1",
+                      "top_apll1_d8",
+                      "top_mux_aud_eng2",
+                      "top_apll2_d8",
+                      "top_i2s0_m_sel",
+                      "top_i2s1_m_sel",
+                      "top_i2s2_m_sel",
+                      "top_i2s3_m_sel",
+                      "top_i2s4_m_sel",
+                      "top_i2s5_m_sel",
+                      "top_apll12_div0",
+                      "top_apll12_div1",
+                      "top_apll12_div2",
+                      "top_apll12_div3",
+                      "top_apll12_div4",
+                      "top_apll12_divb",
+                      "top_clk26m_clk";
     };
 
 ...
diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml
index 037f214..d5b3588 100644
--- a/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml
@@ -167,30 +167,30 @@
                 "HDMI1", "TX";
 
         hs-playback-dai-link {
-                link-name = "I2S0";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&da7219>;
-                };
+            link-name = "I2S0";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&da7219>;
+            };
         };
 
         hs-capture-dai-link {
-                link-name = "I2S1";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&da7219>;
-                };
+            link-name = "I2S1";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&da7219>;
+            };
         };
 
         spk-dp-playback-dai-link {
-                link-name = "I2S3";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&anx_bridge_dp>, <&max98357a>;
-                };
+            link-name = "I2S3";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&anx_bridge_dp>, <&max98357a>;
+            };
         };
     };
 
diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
index ed93f18..7f55357 100644
--- a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
@@ -171,30 +171,30 @@
                 "HDMI1", "TX";
 
         hs-playback-dai-link {
-                link-name = "I2S0";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&rt5682s 0>;
-                };
+            link-name = "I2S0";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&rt5682s 0>;
+            };
         };
 
         hs-capture-dai-link {
-                link-name = "I2S1";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&rt5682s 0>;
-                };
+            link-name = "I2S1";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&rt5682s 0>;
+            };
         };
 
         spk-hdmi-playback-dai-link {
-                link-name = "I2S3";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&it6505dptx>, <&rt1019p>;
-                };
+            link-name = "I2S3";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&it6505dptx>, <&rt1019p>;
+            };
         };
     };
 
diff --git a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
index c4e68f3..841aab0 100644
--- a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
@@ -165,38 +165,38 @@
                 "Speakers", "Speaker";
 
         spk-playback-dai-link {
-                link-name = "I2S3";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&rt1015p>;
-                };
+            link-name = "I2S3";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&rt1015p>;
+            };
         };
 
         hs-playback-dai-link {
-                link-name = "I2S8";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&rt5682 0>;
-                };
+            link-name = "I2S8";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&rt5682 0>;
+            };
         };
 
         hs-capture-dai-link {
-                link-name = "I2S9";
-                dai-format = "i2s";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&rt5682 0>;
-                };
+            link-name = "I2S9";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&rt5682 0>;
+            };
         };
 
         displayport-dai-link {
-                link-name = "TDM";
-                dai-format = "dsp_a";
-                codec {
-                        sound-dai = <&anx_bridge_dp>;
-                };
+            link-name = "TDM";
+            dai-format = "dsp_a";
+            codec {
+                sound-dai = <&anx_bridge_dp>;
+            };
         };
     };
 
diff --git a/Documentation/devicetree/bindings/sound/mt8195-mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8195-mt6359.yaml
index 356e1fee..c6bd286 100644
--- a/Documentation/devicetree/bindings/sound/mt8195-mt6359.yaml
+++ b/Documentation/devicetree/bindings/sound/mt8195-mt6359.yaml
@@ -156,46 +156,46 @@
                 "Ext Spk", "Speaker";
 
         mm-dai-link {
-                link-name = "ETDM1_IN_BE";
-                mediatek,clk-provider = "cpu";
+            link-name = "ETDM1_IN_BE";
+            mediatek,clk-provider = "cpu";
         };
 
         hs-playback-dai-link {
-                link-name = "ETDM1_OUT_BE";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&headset_codec>;
-                };
+            link-name = "ETDM1_OUT_BE";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&headset_codec>;
+            };
         };
 
         hs-capture-dai-link {
-                link-name = "ETDM2_IN_BE";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&headset_codec>;
-                };
+            link-name = "ETDM2_IN_BE";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&headset_codec>;
+            };
         };
 
         spk-playback-dai-link {
-                link-name = "ETDM2_OUT_BE";
-                mediatek,clk-provider = "cpu";
-                codec {
-                        sound-dai = <&spk_amplifier>;
-                };
+            link-name = "ETDM2_OUT_BE";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&spk_amplifier>;
+            };
         };
 
         hdmi-dai-link {
-                link-name = "ETDM3_OUT_BE";
-                codec {
-                        sound-dai = <&hdmi_tx>;
-                };
+            link-name = "ETDM3_OUT_BE";
+            codec {
+                sound-dai = <&hdmi_tx>;
+            };
         };
 
         displayport-dai-link {
-                link-name = "DPTX_BE";
-                codec {
-                        sound-dai = <&dp_tx>;
-                };
+            link-name = "DPTX_BE";
+            codec {
+                sound-dai = <&dp_tx>;
+            };
         };
     };
 
diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8360.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8360.yaml
new file mode 100644
index 0000000..3edab94
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8360.yaml
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nuvoton,nau8360.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton NAU83G60 Stereo Class-D Amplifier with DSP
+
+description:
+  Stereo Class-D Amplifier with DSP and I/V-sense.
+  This device supports I2C.
+
+maintainers:
+  - Neo Chang <YLCHANG2@nuvoton.com>
+
+properties:
+  compatible:
+    enum:
+      - nuvoton,nau8360
+
+  reg:
+    description: The I2C address is determined by the hardware pins.
+    enum: [0x1a, 0x1b, 0x4a, 0x4b]
+
+  "#sound-dai-cells":
+    const: 0
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: mclk
+
+  firmware-name:
+    description:
+      List of DSP core firmware filenames. Both Left and Right DSP firmware
+      must be provided and loaded. In PBTL mode, the Left DSP must use the
+      same binary file as the Right DSP.
+    items:
+      - description: Left DSP core firmware filename.
+      - description: Right DSP core firmware filename.
+
+  nuvoton,pbtl-enable:
+    type: boolean
+    description: NAU83G60 supports PBTL mode for mono output.
+
+  nuvoton,dac-cur-enable:
+    type: boolean
+    description:
+      Adjust DAC output current to match speaker impedance and prevent
+      hardware damage. +3.2dB when present, 0dB by default.
+
+  nuvoton,dsp-rx-slot-mapping:
+    description:
+      Configures the TDM slot routing for DSP RX functions.
+      Each integer assigns a specific DSP internal function to a TDM slot.
+      The indices of the array correspond to the following hardware functions
+        (0) DACL
+        (1) DACR
+        (2) ANCL
+        (3) ANCR
+      Assigned slots must be unique, except 255 which disables the function.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 4
+    maxItems: 4
+    items:
+      enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 255 ]
+
+  nuvoton,dsp-tx-slot-mapping:
+    description:
+      Configures the TDM slot routing for DSP TX functions.
+      Each integer assigns a specific DSP internal function to a TDM slot.
+      The indices of the array correspond to the following hardware functions
+        (0) AECL (Acoustic echo cancellation left)
+        (1) AECR (Acoustic echo cancellation right)
+        (2) ISNSL (Current sense left)
+        (3) ISNSR (Current sense right)
+        (4) VSNSL (Voltage sense left)
+        (5) VSNSR (Voltage sense right)
+        (6) TJ (Junction temperature)
+        (7) VBAT (Battery voltage)
+      Assigned slots must be unique, except 255 which disables the function.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 8
+    maxItems: 8
+    items:
+      enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 255 ]
+
+required:
+  - compatible
+  - reg
+  - firmware-name
+
+allOf:
+  - $ref: dai-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        codec@1a {
+            compatible = "nuvoton,nau8360";
+            reg = <0x1a>;
+            #sound-dai-cells = <0>;
+            firmware-name = "NAU83G60.kcs.bin.l", "NAU83G60.kcs.bin.r";
+            nuvoton,dac-cur-enable;
+            nuvoton,pbtl-enable;
+            nuvoton,dsp-rx-slot-mapping = <0 1 2 3>;
+            nuvoton,dsp-tx-slot-mapping = <0 1 2 3 4 5 6 7>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
index 4878c42..7858713 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
@@ -75,11 +75,11 @@
         #size-cells = <0>;
 
         dai@10 {
-           reg = <PRIMARY_MI2S_RX>;
-           clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT
-                              LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
-                    <&q6prmcc LPASS_CLK_ID_MCLK_1
-                              LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
-           clock-names = "bclk", "mclk";
+            reg = <PRIMARY_MI2S_RX>;
+            clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT
+                               LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                     <&q6prmcc LPASS_CLK_ID_MCLK_1
+                               LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+            clock-names = "bclk", "mclk";
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
index e8a2acb..d3516fb 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
@@ -432,14 +432,14 @@
                       "ssi.1", "ssi.0";
 
         rcar_sound,dvc {
-               dvc0: dvc-0 {
-                    dmas = <&audma0 0xbc>;
-                    dma-names = "tx";
-               };
-               dvc1: dvc-1 {
-                    dmas = <&audma0 0xbe>;
-                    dma-names = "tx";
-               };
+            dvc0: dvc-0 {
+                dmas = <&audma0 0xbc>;
+                dma-names = "tx";
+            };
+            dvc1: dvc-1 {
+                dmas = <&audma0 0xbe>;
+                dma-names = "tx";
+            };
         };
 
         rcar_sound,mix {
diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
index 1394f78..d696fb3 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
@@ -95,20 +95,20 @@
     ssi0: ssi@10049c00 {
         compatible = "renesas,r9a07g044-ssi",
                      "renesas,rz-ssi";
-            reg = <0x10049c00 0x400>;
-            interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
-                         <GIC_SPI 328 IRQ_TYPE_EDGE_RISING>;
-            interrupt-names = "int_req", "dma_rx", "dma_tx";
-            clocks = <&cpg CPG_MOD R9A07G044_SSI0_PCLK2>,
-                     <&cpg CPG_MOD R9A07G044_SSI0_PCLK_SFR>,
-                     <&audio_clk1>,
-                     <&audio_clk2>;
-            clock-names = "ssi", "ssi_sfr", "audio_clk1", "audio_clk2";
-            power-domains = <&cpg>;
-            resets = <&cpg R9A07G044_SSI0_RST_M2_REG>;
-            dmas = <&dmac 0x2655>,
-                   <&dmac 0x2656>;
-            dma-names = "tx", "rx";
-            #sound-dai-cells = <0>;
+        reg = <0x10049c00 0x400>;
+        interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
+                     <GIC_SPI 328 IRQ_TYPE_EDGE_RISING>;
+        interrupt-names = "int_req", "dma_rx", "dma_tx";
+        clocks = <&cpg CPG_MOD R9A07G044_SSI0_PCLK2>,
+                 <&cpg CPG_MOD R9A07G044_SSI0_PCLK_SFR>,
+                 <&audio_clk1>,
+                 <&audio_clk2>;
+        clock-names = "ssi", "ssi_sfr", "audio_clk1", "audio_clk2";
+        power-domains = <&cpg>;
+        resets = <&cpg R9A07G044_SSI0_RST_M2_REG>;
+        dmas = <&dmac 0x2655>,
+               <&dmac 0x2656>;
+        dma-names = "tx", "rx";
+        #sound-dai-cells = <0>;
     };
diff --git a/Documentation/devicetree/bindings/sound/ti,da830-evm-audio.yaml b/Documentation/devicetree/bindings/sound/ti,da830-evm-audio.yaml
new file mode 100644
index 0000000..b4a1cf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,da830-evm-audio.yaml
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,da830-evm-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments SoC audio setups with TLV320AIC3X Codec
+
+maintainers:
+  - Eduard Bostina <egbostina@gmail.com>
+
+properties:
+  compatible:
+    const: ti,da830-evm-audio
+
+  ti,model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: The user-visible name of this sound complex.
+
+  ti,audio-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of the TLV320AIC3x audio codec
+
+  ti,mcasp-controller:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of the McASP controller
+
+  ti,audio-routing:
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    description:
+      A list of the connections between audio components. Each entry is a
+      pair of strings, the first being the connection's sink, the second
+      being the connection's source. Valid names for sources and sinks
+      are the codec's pins, and the jacks on the board (Headphone Jack,
+      Line Out, Mic Jack, Line In).
+
+  ti,codec-clock-rate:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: The Codec Clock rate (in Hz) applied to the Codec.
+
+  clocks:
+    maxItems: 1
+    description: Reference to the master clock
+
+  clock-names:
+    const: mclk
+
+required:
+  - compatible
+  - ti,model
+  - ti,audio-codec
+  - ti,mcasp-controller
+  - ti,audio-routing
+
+anyOf:
+  - required:
+      - ti,codec-clock-rate
+  - required:
+      - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    sound {
+        compatible = "ti,da830-evm-audio";
+        ti,model = "DA830 EVM";
+        ti,audio-codec = <&tlv320aic3x>;
+        ti,mcasp-controller = <&mcasp1>;
+        ti,codec-clock-rate = <12000000>;
+        ti,audio-routing =
+            "Headphone Jack",       "HPLOUT",
+            "Headphone Jack",       "HPROUT",
+            "Line Out",             "LLOUT",
+            "Line Out",             "RLOUT",
+            "MIC3L",                "Mic Bias 2V",
+            "MIC3R",                "Mic Bias 2V",
+            "Mic Bias 2V",          "Mic Jack",
+            "LINE1L",               "Line In",
+            "LINE2L",               "Line In",
+            "LINE1R",               "Line In",
+            "LINE2R",               "Line In";
+    };
diff --git a/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml
index c2c2835..f2ab274 100644
--- a/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml
@@ -45,13 +45,13 @@
         #address-cells = <1>;
         #size-cells = <0>;
         tas5805m: tas5805m@2c {
-                reg = <0x2c>;
-                compatible = "ti,tas5805m";
+            reg = <0x2c>;
+            compatible = "ti,tas5805m";
 
-                pvdd-supply = <&audiopwr>;
-                pdn-gpios = <&tlmm 160 0>;
+            pvdd-supply = <&audiopwr>;
+            pdn-gpios = <&tlmm 160 0>;
 
-                ti,dsp-config-name = "mono_pbtl_48khz";
+            ti,dsp-config-name = "mono_pbtl_48khz";
         };
     };
 ...
diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml
index 1029906..3bdaab1 100644
--- a/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml
@@ -121,6 +121,6 @@
             AVDD-supply = <&regulator>;
             IOVDD-supply = <&regulator>;
             DVDD-supply = <&regulator>;
-       };
+        };
     };
 
diff --git a/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml b/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml
index a42bf9b..5634b60 100644
--- a/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml
@@ -50,6 +50,6 @@
             reg = <0x60>;
             Vdd-supply = <&vmmc2>;
             power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>;
-       };
+        };
     };
 
diff --git a/MAINTAINERS b/MAINTAINERS
index c241444..20d67cc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -30182,9 +30182,12 @@
 
 SENARYTECH AUDIO CODEC DRIVER
 M:	bo liu <bo.liu@senarytech.com>
+M:	qianghua.wang <qianghua.wang@senarytech.com>
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:	sound/hda/codecs/senarytech.c
+F:	sound/soc/codecs/sn624x*
+F:	sound/soc/sdw_utils/soc_sdw_senary*
 
 ZTE DINGHAI ETHERNET DRIVER
 M:	Junyang Han <han.junyang@zte.com.cn>
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index bb93b24..0401528 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -3505,7 +3505,7 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, "FW_CS_DSP");
  *
  * As cs_dsp_chunk_write only writes data when a whole DSP word is ready to
  * be written out it is possible that some data will remain in the cache, this
- * function will pad that data with zeros upto a whole DSP word and write out.
+ * function will pad that data with zeros up to a whole DSP word and write out.
  *
  * Return: Zero for success, a negative number on error.
  */
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index bd8c3a0..68faec5 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -219,12 +219,14 @@ static inline int simple_util_parse_aux_devs(struct simple_util_priv *priv, char
 int simple_util_init_jack(struct snd_soc_card *card,
 			       struct simple_util_jack *sjack,
 			       int is_hp, char *prefix, char *pin);
+void simple_util_remove_jack(struct simple_util_jack *sjack);
 int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix);
 int simple_util_init_priv(struct simple_util_priv *priv,
 			       struct link_info *li);
 void simple_util_remove(struct platform_device *pdev);
 
 int graph_util_card_probe(struct snd_soc_card *card);
+int graph_util_card_remove(struct snd_soc_card *card);
 int graph_util_is_ports0(struct device_node *port);
 int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
 			 struct snd_soc_dai_link_component *dlc, int *is_single_link);
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index ba3ae56..7e64e049 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -213,7 +213,8 @@ int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai,
 		unsigned int *rx_num, unsigned int *rx_slot);
 
 int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai);
-
+int snd_soc_dai_add_controls(struct snd_soc_dai *dai,
+			     const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
 			  struct snd_pcm_substream *substream,
 			  struct snd_pcm_hw_params *params);
@@ -277,7 +278,11 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
 				   struct snd_compr_stream *cstream,
 				   struct snd_compr_metadata *metadata);
 
-const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai);
+int snd_soc_dai_matches_args(const struct snd_soc_dai *dai,
+			     const struct of_phandle_args *args2);
+int snd_soc_dai_matches_dlc(struct snd_soc_dai *dai,
+			    const struct snd_soc_dai_link_component *dlc);
+const char *snd_soc_dai_name(const struct snd_soc_dai *dai);
 
 struct snd_soc_dai_ops {
 	/* DAI driver callbacks */
@@ -489,69 +494,51 @@ struct snd_soc_dai {
 	void *priv;
 };
 
+const struct snd_soc_pcm_stream *
+snd_soc_dai_pcm_stream_get_i(const struct snd_soc_dai *dai, int stream);
 static inline const struct snd_soc_pcm_stream *
-snd_soc_dai_get_pcm_stream(const struct snd_soc_dai *dai, int stream)
+snd_soc_dai_pcm_stream_get_s(const struct snd_soc_dai *dai, struct snd_pcm_substream *substream)
 {
-	return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-		&dai->driver->playback : &dai->driver->capture;
+	return snd_soc_dai_pcm_stream_get_i(dai, substream->stream);
 }
+#define snd_soc_dai_pcm_stream_get(dai, x) _Generic((x),		\
+	int :				snd_soc_dai_pcm_stream_get_i,	\
+	struct snd_pcm_substream * :	snd_soc_dai_pcm_stream_get_s)(dai, x)
 
-#define snd_soc_dai_get_widget_playback(dai)	snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_PLAYBACK)
-#define snd_soc_dai_get_widget_capture(dai)	snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_CAPTURE)
-static inline
-struct snd_soc_dapm_widget *snd_soc_dai_get_widget(struct snd_soc_dai *dai, int stream)
-{
-	return dai->stream[stream].widget;
-}
+#define snd_soc_dai_stream_widget_get_playback(dai)	snd_soc_dai_stream_widget_get(dai, SNDRV_PCM_STREAM_PLAYBACK)
+#define snd_soc_dai_stream_widget_get_capture(dai)	snd_soc_dai_stream_widget_get(dai, SNDRV_PCM_STREAM_CAPTURE)
+struct snd_soc_dapm_widget *snd_soc_dai_stream_widget_get(struct snd_soc_dai *dai, int stream);
 
-#define snd_soc_dai_set_widget_playback(dai, widget)	snd_soc_dai_set_widget(dai, SNDRV_PCM_STREAM_PLAYBACK, widget)
-#define snd_soc_dai_set_widget_capture(dai,  widget)	snd_soc_dai_set_widget(dai, SNDRV_PCM_STREAM_CAPTURE,  widget)
-static inline
-void snd_soc_dai_set_widget(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget *widget)
-{
-	dai->stream[stream].widget = widget;
-}
+#define snd_soc_dai_stream_widget_set_playback(dai, widget)	snd_soc_dai_stream_widget_set(dai, SNDRV_PCM_STREAM_PLAYBACK, widget)
+#define snd_soc_dai_stream_widget_set_capture(dai,  widget)	snd_soc_dai_stream_widget_set(dai, SNDRV_PCM_STREAM_CAPTURE,  widget)
+void snd_soc_dai_stream_widget_set(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget *widget);
 
-#define snd_soc_dai_dma_data_get_playback(dai)	snd_soc_dai_dma_data_get(dai, SNDRV_PCM_STREAM_PLAYBACK)
-#define snd_soc_dai_dma_data_get_capture(dai)	snd_soc_dai_dma_data_get(dai, SNDRV_PCM_STREAM_CAPTURE)
-#define snd_soc_dai_get_dma_data(dai, ss)	snd_soc_dai_dma_data_get(dai, ss->stream)
-static inline void *snd_soc_dai_dma_data_get(const struct snd_soc_dai *dai, int stream)
+#define snd_soc_dai_stream_dma_data_get_playback(dai)	snd_soc_dai_stream_dma_data_get(dai, SNDRV_PCM_STREAM_PLAYBACK)
+#define snd_soc_dai_stream_dma_data_get_capture(dai)	snd_soc_dai_stream_dma_data_get(dai, SNDRV_PCM_STREAM_CAPTURE)
+void *snd_soc_dai_stream_dma_data_get_i(const struct snd_soc_dai *dai, int stream);
+static inline void *snd_soc_dai_stream_dma_data_get_s(const struct snd_soc_dai *dai, struct snd_pcm_substream *substream)
 {
-	return dai->stream[stream].dma_data;
+	return snd_soc_dai_stream_dma_data_get_i(dai, substream->stream);
 }
+#define snd_soc_dai_stream_dma_data_get(dai, x) _Generic((x),			\
+	int :				snd_soc_dai_stream_dma_data_get_i,	\
+	struct snd_pcm_substream * :	snd_soc_dai_stream_dma_data_get_s)(dai, x)
 
-#define snd_soc_dai_dma_data_set_playback(dai, data)	snd_soc_dai_dma_data_set(dai, SNDRV_PCM_STREAM_PLAYBACK, data)
-#define snd_soc_dai_dma_data_set_capture(dai,  data)	snd_soc_dai_dma_data_set(dai, SNDRV_PCM_STREAM_CAPTURE,  data)
-#define snd_soc_dai_set_dma_data(dai, ss, data)		snd_soc_dai_dma_data_set(dai, ss->stream, data)
-static inline void snd_soc_dai_dma_data_set(struct snd_soc_dai *dai, int stream, void *data)
+#define snd_soc_dai_stream_dma_data_set_playback(dai, data)	snd_soc_dai_stream_dma_data_set(dai, SNDRV_PCM_STREAM_PLAYBACK, data)
+#define snd_soc_dai_stream_dma_data_set_capture(dai,  data)	snd_soc_dai_stream_dma_data_set(dai, SNDRV_PCM_STREAM_CAPTURE,  data)
+void snd_soc_dai_stream_dma_data_set_i(struct snd_soc_dai *dai, int stream, void *data);
+static inline void snd_soc_dai_stream_dma_data_set_s(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, void *data)
 {
-	dai->stream[stream].dma_data = data;
+	snd_soc_dai_stream_dma_data_set_i(dai, substream->stream, data);
 }
+#define snd_soc_dai_stream_dma_data_set(dai, x, data) _Generic((x),		\
+	int :				snd_soc_dai_stream_dma_data_set_i,	\
+	struct snd_pcm_substream * :	snd_soc_dai_stream_dma_data_set_s)(dai, x, data)
 
-static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, void *playback, void *capture)
-{
-	snd_soc_dai_dma_data_set_playback(dai, playback);
-	snd_soc_dai_dma_data_set_capture(dai,  capture);
-}
+unsigned int snd_soc_dai_stream_tdm_mask_get(const struct snd_soc_dai *dai, int stream);
+void snd_soc_dai_stream_tdm_mask_set(struct snd_soc_dai *dai, int stream, unsigned int tdm_mask);
 
-static inline unsigned int snd_soc_dai_tdm_mask_get(const struct snd_soc_dai *dai,
-						    int stream)
-{
-	return dai->stream[stream].tdm_mask;
-}
-
-static inline void snd_soc_dai_tdm_mask_set(struct snd_soc_dai *dai, int stream,
-					    unsigned int tdm_mask)
-{
-	dai->stream[stream].tdm_mask = tdm_mask;
-}
-
-static inline unsigned int snd_soc_dai_stream_active(const struct snd_soc_dai *dai,
-						     int stream)
-{
-	/* see snd_soc_dai_action() for setup */
-	return dai->stream[stream].active;
-}
+unsigned int snd_soc_dai_stream_active(const struct snd_soc_dai *dai, int stream);
 
 static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
 		void *data)
@@ -564,45 +551,36 @@ static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
 	return dev_get_drvdata(dai->dev);
 }
 
-/**
- * snd_soc_dai_set_stream() - Configures a DAI for stream operation
- * @dai: DAI
- * @stream: STREAM (opaque structure depending on DAI type)
- * @direction: Stream direction(Playback/Capture)
- * Some subsystems, such as SoundWire, don't have a notion of direction and we reuse
- * the ASoC stream direction to configure sink/source ports.
- * Playback maps to source ports and Capture for sink ports.
- *
- * This should be invoked with NULL to clear the stream set previously.
- * Returns 0 on success, a negative error code otherwise.
- */
-static inline int snd_soc_dai_set_stream(struct snd_soc_dai *dai,
-					 void *stream, int direction)
-{
-	if (dai->driver->ops->set_stream)
-		return dai->driver->ops->set_stream(dai, stream, direction);
-	else
-		return -ENOTSUPP;
-}
+int snd_soc_dai_set_stream(struct snd_soc_dai *dai, void *stream, int direction);
+void *snd_soc_dai_get_stream(struct snd_soc_dai *dai, int direction);
 
-/**
- * snd_soc_dai_get_stream() - Retrieves stream from DAI
- * @dai: DAI
- * @direction: Stream direction(Playback/Capture)
- *
- * This routine only retrieves that was previously configured
- * with snd_soc_dai_get_stream()
- *
- * Returns pointer to stream or an ERR_PTR value, e.g.
- * ERR_PTR(-ENOTSUPP) if callback is not supported;
- */
-static inline void *snd_soc_dai_get_stream(struct snd_soc_dai *dai,
-					   int direction)
+struct snd_soc_dai *snd_soc_dai_register(struct snd_soc_component *component,
+					 struct snd_soc_dai_driver *dai_drv,
+					 bool legacy_dai_naming);
+void snd_soc_dai_unregister(struct snd_soc_dai *dai);
+
+/* REMOVE ME */
+#define snd_soc_dai_get_pcm_stream			snd_soc_dai_pcm_stream_get
+#define snd_soc_dai_get_widget_playback(dai)		snd_soc_dai_stream_widget_get(dai, SNDRV_PCM_STREAM_PLAYBACK)
+#define snd_soc_dai_get_widget_capture(dai)		snd_soc_dai_stream_widget_get(dai, SNDRV_PCM_STREAM_CAPTURE)
+#define snd_soc_dai_get_widget				snd_soc_dai_stream_widget_get
+#define snd_soc_dai_set_widget_playback(dai, widget)	snd_soc_dai_stream_widget_set(dai, SNDRV_PCM_STREAM_PLAYBACK, widget)
+#define snd_soc_dai_set_widget_capture(dai,  widget)	snd_soc_dai_stream_widget_set(dai, SNDRV_PCM_STREAM_CAPTURE,  widget)
+#define snd_soc_dai_set_widget				snd_soc_dai_stream_widget_set
+#define snd_soc_dai_dma_data_get_playback(dai)		snd_soc_dai_stream_dma_data_get(dai, SNDRV_PCM_STREAM_PLAYBACK)
+#define snd_soc_dai_dma_data_get_capture(dai)		snd_soc_dai_stream_dma_data_get(dai, SNDRV_PCM_STREAM_CAPTURE)
+#define snd_soc_dai_get_dma_data			snd_soc_dai_stream_dma_data_get
+#define snd_soc_dai_dma_data_get			snd_soc_dai_stream_dma_data_get
+#define snd_soc_dai_dma_data_set_playback(dai, data)	snd_soc_dai_stream_dma_data_set(dai, SNDRV_PCM_STREAM_PLAYBACK, data)
+#define snd_soc_dai_dma_data_set_capture(dai,  data)	snd_soc_dai_stream_dma_data_set(dai, SNDRV_PCM_STREAM_CAPTURE,  data)
+#define snd_soc_dai_set_dma_data			snd_soc_dai_stream_dma_data_set
+#define snd_soc_dai_dma_data_set			snd_soc_dai_stream_dma_data_set
+#define snd_soc_dai_tdm_mask_get			snd_soc_dai_stream_tdm_mask_get
+#define snd_soc_dai_tdm_mask_set			snd_soc_dai_stream_tdm_mask_set
+static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, void *playback, void *capture)
 {
-	if (dai->driver->ops->get_stream)
-		return dai->driver->ops->get_stream(dai, direction);
-	else
-		return ERR_PTR(-ENOTSUPP);
+	snd_soc_dai_stream_dma_data_set_playback(dai, playback);
+	snd_soc_dai_stream_dma_data_set_capture(dai,  capture);
 }
 
 #endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 5afc34b..553bb7e 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -555,8 +555,6 @@ int snd_soc_add_component_controls(struct snd_soc_component *component,
 	const struct snd_kcontrol_new *controls, unsigned int num_controls);
 int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
 	const struct snd_kcontrol_new *controls, int num_controls);
-int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
-	const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
@@ -1389,19 +1387,12 @@ void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platform
 struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
 					      const struct of_phandle_args *args);
 struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_args);
-struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
-					 struct snd_soc_dai_driver *dai_drv,
-					 bool legacy_dai_naming);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
 
 struct snd_soc_dai *snd_soc_find_dai(
 	const struct snd_soc_dai_link_component *dlc);
 struct snd_soc_dai *snd_soc_find_dai_with_mutex(
 	const struct snd_soc_dai_link_component *dlc);
 
-void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
-			    struct snd_pcm_hw_params *params);
-
 #include <sound/soc-dai.h>
 
 static inline
@@ -1551,4 +1542,11 @@ static inline void _snd_soc_dpcm_mutex_assert_held_r(struct snd_soc_pcm_runtime
 #include <sound/soc-card.h>
 #include <sound/soc-jack.h>
 
+/*
+ * REMOVE ME
+ */
+#define snd_soc_add_dai_controls			snd_soc_dai_add_controls
+#define snd_soc_register_dai				snd_soc_dai_register
+#define snd_soc_unregister_dai				snd_soc_dai_unregister
+
 #endif
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 9fbb69b..4184664 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -292,4 +292,24 @@ int asoc_sdw_es9356_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai
 int asoc_sdw_es9356_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
 int asoc_sdw_es9356_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
 
+/* Senary SN624x SDCA */
+int asoc_sdw_senary_sdca_jack_init(struct snd_soc_card *card,
+				   struct snd_soc_dai_link *dai_links,
+				   struct asoc_sdw_codec_info *info,
+				   bool playback);
+int asoc_sdw_senary_sdca_jack_exit(struct snd_soc_card *card,
+				   struct snd_soc_dai_link *dai_link);
+int asoc_sdw_senary_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd,
+				       struct snd_soc_dai *dai);
+int asoc_sdw_senary_amp_init(struct snd_soc_card *card,
+			     struct snd_soc_dai_link *dai_links,
+			     struct asoc_sdw_codec_info *info,
+			     bool playback);
+int asoc_sdw_senary_amp_exit(struct snd_soc_card *card,
+			     struct snd_soc_dai_link *dai_link);
+int asoc_sdw_senary_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd,
+				      struct snd_soc_dai *dai);
+int asoc_sdw_senary_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd,
+				  struct snd_soc_dai *dai);
+
 #endif
diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h
index e845687..de087f4 100644
--- a/include/sound/tas2781-dsp.h
+++ b/include/sound/tas2781-dsp.h
@@ -56,6 +56,10 @@ enum tasdevice_dsp_dev_idx {
 	TASDEVICE_DSP_TAS_2781_QUAD,
 	TASDEVICE_DSP_TAS_5825_MONO,
 	TASDEVICE_DSP_TAS_5825_DUAL,
+	TASDEVICE_DSP_TAS_2573_MONO,
+	TASDEVICE_DSP_TAS_2573_DUAL,
+	TASDEVICE_DSP_TAS_2573_21,
+	TASDEVICE_DSP_TAS_2573_QUAD,
 	TASDEVICE_DSP_TAS_MAX_DEVICE
 };
 
diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h
index 3930cc4..17e4e97 100644
--- a/sound/soc/amd/acp/soc_amd_sdw_common.h
+++ b/sound/soc/amd/acp/soc_amd_sdw_common.h
@@ -23,6 +23,19 @@
 #define ACP71_PCI_REV			0x71
 #define ACP72_PCI_REV			0x72
 
+/**
+ * struct amd_pdm_pdata - platform data passed via mach->pdata to machine driver
+ * @pdm_sel: active PDM controller (ACP7X_PDM_DMIC0 or ACP7X_PDM_DMIC1),
+ *           non-zero when a PDM controller was identified via ACPI _DSD
+ *
+ * Carries the PDM controller selection for ACP7.B/7.F platforms, derived
+ * from the acp-audio-ep-port ACPI _DSD property and passed via mach->pdata
+ * to the machine driver.
+ */
+struct amd_pdm_pdata {
+	unsigned int pdm_sel;
+};
+
 #define SOC_JACK_JDSRC(quirk)		((quirk) & GENMASK(3, 0))
 #define ASOC_SDW_FOUR_SPK		BIT(4)
 #define ASOC_SDW_ACP_DMIC		BIT(5)
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index 7306e04..e4b73ae 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -47,7 +47,7 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
  * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC
  *
  * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to
- * check if any overrun occured.
+ * check if any overrun occurred.
  */
 static void atmel_pcm_dma_irq(u32 ssc_sr,
 	struct snd_pcm_substream *substream)
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 4925e03..7848e15 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -27,7 +27,7 @@ struct ringbuf_regs {
 	unsigned wraddr;
 	unsigned baseaddr;
 	unsigned endaddr;
-	unsigned fmark;   /* freemark for play, fullmark for caputure */
+	unsigned fmark;   /* freemark for play, fullmark for capture */
 	unsigned period_bytes;
 	unsigned buf_size;
 };
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index b4f5b24..7596227 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -1136,11 +1136,15 @@ static int pm860x_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 pm860x_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_I2S;
+
 static const struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
 	.mute_stream	= pm860x_mute_stream,
 	.hw_params	= pm860x_pcm_hw_params,
 	.set_fmt	= pm860x_pcm_set_dai_fmt,
 	.set_sysclk	= pm860x_set_dai_sysclk,
+	.auto_selectable_formats	= &pm860x_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1149,6 +1153,8 @@ static const struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
 	.hw_params	= pm860x_i2s_hw_params,
 	.set_fmt	= pm860x_i2s_set_dai_fmt,
 	.set_sysclk	= pm860x_set_dai_sysclk,
+	.auto_selectable_formats	= &pm860x_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8e251e1..f883815 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -173,6 +173,7 @@
 	imply SND_SOC_MT6660
 	imply SND_SOC_NAU8315
 	imply SND_SOC_NAU8325
+	imply SND_SOC_NAU8360
 	imply SND_SOC_NAU8540
 	imply SND_SOC_NAU8810
 	imply SND_SOC_NAU8821
@@ -255,6 +256,7 @@
 	imply SND_SOC_SIMPLE_MUX
 	imply SND_SOC_SMA1303
 	imply SND_SOC_SMA1307
+	imply SND_SOC_SN624X_SDCA_SDW
 	imply SND_SOC_SPDIF
 	imply SND_SOC_SRC4XXX_I2C
 	imply SND_SOC_SSM2305
@@ -2097,6 +2099,18 @@
 	  If you are using a system with an SMA1307 amplifier connected
 	  via I2C, enable this option.
 
+config SND_SOC_SN624X_SDCA_SDW
+	tristate "Senary SN624x SDCA Codec - SDW"
+	depends on SND_SOC_SDCA
+	depends on SOUNDWIRE
+	select REGMAP_SOUNDWIRE
+	select REGMAP_SOUNDWIRE_MBQ
+	help
+	  Enable support for Senary SN624x SDCA SoundWire codecs.
+	  These multi-function devices provide headset jack, speaker
+	  amplifier, and digital microphone endpoints on the SoundWire
+	  bus.
+
 config SND_SOC_SPDIF
 	tristate "S/PDIF CODEC"
 
@@ -2901,6 +2915,16 @@
 	tristate
 	depends on I2C
 
+config SND_SOC_NAU8360
+	tristate "Nuvoton Technology Corporation NAU83G60 Stereo Smart Amplifier"
+	depends on I2C
+	select FW_LOADER
+	help
+	  The NAU83G60 is a stereo 30W+30W smart amplifier with integrated
+	  low-latency Advanced Audio DSP running the KCS (Klippel Controlled
+	  Sound) speaker control algorithm. KCS provides mechanical and
+	  thermal speaker protection with voltage and current sensing.
+
 config SND_SOC_NTPFW
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3d122ac..9287a60 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -198,6 +198,7 @@
 snd-soc-mt6660-y := mt6660.o
 snd-soc-nau8315-y := nau8315.o
 snd-soc-nau8325-y := nau8325.o
+snd-soc-nau8360-y := nau8360.o nau8360-dsp.o
 snd-soc-nau8540-y := nau8540.o
 snd-soc-nau8810-y := nau8810.o
 snd-soc-nau8821-y := nau8821.o
@@ -301,6 +302,7 @@
 snd-soc-si476x-y := si476x.o
 snd-soc-sma1303-y := sma1303.o
 snd-soc-sma1307-y := sma1307.o
+snd-soc-sn624x-sdca-y := sn624x-sdca-sdw.o
 snd-soc-spdif-tx-y := spdif_transmitter.o
 snd-soc-spdif-rx-y := spdif_receiver.o
 snd-soc-src4xxx-y := src4xxx.o
@@ -637,6 +639,7 @@
 obj-$(CONFIG_SND_SOC_MT6660)	+= snd-soc-mt6660.o
 obj-$(CONFIG_SND_SOC_NAU8315)   += snd-soc-nau8315.o
 obj-$(CONFIG_SND_SOC_NAU8325)   += snd-soc-nau8325.o
+obj-$(CONFIG_SND_SOC_NAU8360)   += snd-soc-nau8360.o
 obj-$(CONFIG_SND_SOC_NAU8540)   += snd-soc-nau8540.o
 obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8821)   += snd-soc-nau8821.o
@@ -742,6 +745,7 @@
 obj-$(CONFIG_SND_SOC_SI476X)	+= snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SMA1303)	+= snd-soc-sma1303.o
 obj-$(CONFIG_SND_SOC_SMA1307)	+= snd-soc-sma1307.o
+obj-$(CONFIG_SND_SOC_SN624X_SDCA_SDW)    += snd-soc-sn624x-sdca.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif-rx.o snd-soc-spdif-tx.o
 obj-$(CONFIG_SND_SOC_SRC4XXX)	+= snd-soc-src4xxx.o
 obj-$(CONFIG_SND_SOC_SRC4XXX_I2C)	+= snd-soc-src4xxx-i2c.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index e1a0e35..fc20488 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1950,9 +1950,22 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 ab8500_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_GATED	|
+	SND_SOC_POSSIBLE_DAIFMT_CONT	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops ab8500_codec_ops = {
 	.set_fmt = ab8500_codec_set_dai_fmt,
 	.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+	.auto_selectable_formats = &ab8500_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver ab8500_codec_dai[] = {
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
index cc174ec3..0830d7d 100644
--- a/sound/soc/codecs/adau1372.c
+++ b/sound/soc/codecs/adau1372.c
@@ -881,12 +881,24 @@ static const struct snd_soc_component_driver adau1372_driver = {
 	.endianness = 1,
 };
 
+static const u64 adau1372_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops adau1372_dai_ops = {
 	.set_fmt = adau1372_set_dai_fmt,
 	.set_tdm_slot = adau1372_set_tdm_slot,
 	.set_tristate = adau1372_set_tristate,
 	.hw_params = adau1372_hw_params,
 	.startup = adau1372_startup,
+	.auto_selectable_formats = &adau1372_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 5dd961b..aa7d3a4 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1196,10 +1196,22 @@ static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 adau1373_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops adau1373_dai_ops = {
 	.hw_params	= adau1373_hw_params,
 	.set_sysclk	= adau1373_set_dai_sysclk,
 	.set_fmt	= adau1373_set_dai_fmt,
+	.auto_selectable_formats	= &adau1373_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define ADAU1373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 329ab01..4afbf46 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -4,7 +4,7 @@
  *
  * Copyright 2011 Analog Devices Inc.
  * Author: Lars-Peter Clausen <lars@metafoo.de>
- *	based on an inital version by Cliff Cai <cliff.cai@analog.com>
+ *	based on an initial version by Cliff Cai <cliff.cai@analog.com>
  */
 
 #include <linux/module.h>
@@ -627,11 +627,22 @@ static int adau1701_startup(struct snd_pcm_substream *substream,
 #define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 adau1701_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops adau1701_dai_ops = {
 	.set_fmt	= adau1701_set_dai_fmt,
 	.hw_params	= adau1701_hw_params,
 	.mute_stream	= adau1701_mute_stream,
 	.startup	= adau1701_startup,
+	.auto_selectable_formats	= &adau1701_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -688,7 +699,7 @@ static int adau1701_probe(struct snd_soc_component *component)
 	 */
 	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
 
-	/* initalize with pre-configured pll mode settings */
+	/* initialize with pre-configured pll mode settings */
 	ret = adau1701_reset(component, adau1701->pll_clkdiv, 0);
 	if (ret < 0)
 		goto exit_regulators_disable;
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 26d7eb4..45ac226 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -776,6 +776,17 @@ static int adau17x1_startup(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 adau17x1_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 const struct snd_soc_dai_ops adau17x1_dai_ops = {
 	.hw_params	= adau17x1_hw_params,
 	.set_sysclk	= adau17x1_set_dai_sysclk,
@@ -783,6 +794,8 @@ const struct snd_soc_dai_ops adau17x1_dai_ops = {
 	.set_pll	= adau17x1_set_dai_pll,
 	.set_tdm_slot	= adau17x1_set_dai_tdm_slot,
 	.startup	= adau17x1_startup,
+	.auto_selectable_formats	= &adau17x1_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
 
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index b42f35b..b9d9853 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -741,6 +741,17 @@ static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
 		ADAU1977_SAI_OVERTEMP_DRV_HIZ, val);
 }
 
+static const u64 adau1977_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops adau1977_dai_ops = {
 	.startup	= adau1977_startup,
 	.hw_params	= adau1977_hw_params,
@@ -748,6 +759,8 @@ static const struct snd_soc_dai_ops adau1977_dai_ops = {
 	.set_fmt	= adau1977_set_dai_fmt,
 	.set_tdm_slot	= adau1977_set_tdm_slot,
 	.set_tristate	= adau1977_set_tristate,
+	.auto_selectable_formats	= &adau1977_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver adau1977_dai = {
diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c
index 5ddea63..9749299 100644
--- a/sound/soc/codecs/adau7118.c
+++ b/sound/soc/codecs/adau7118.c
@@ -418,12 +418,24 @@ static int adau7118_component_probe(struct snd_soc_component *component)
 	return ret;
 }
 
+static const u64 adau7118_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops adau7118_ops = {
 	.hw_params = adau7118_hw_params,
 	.set_channel_map = adau7118_set_channel_map,
 	.set_fmt = adau7118_set_fmt,
 	.set_tdm_slot = adau7118_set_tdm_slot,
 	.set_tristate = adau7118_set_tristate,
+	.auto_selectable_formats = &adau7118_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver adau7118_dai = {
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 6ea7cb7..5ebc3af 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -147,9 +147,16 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 ak4101_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ak4101_dai_ops = {
 	.hw_params = ak4104_hw_params,
 	.set_fmt = ak4104_set_dai_fmt,
+	.auto_selectable_formats = &ak4101_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver ak4104_dai = {
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index 03dadba..2b96b82 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -236,9 +236,16 @@ static int ak4118_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+/* NOTE: Common formats only are auto detected */
+static const u64 ak4118_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ak4118_dai_ops = {
 	.hw_params = ak4118_hw_params,
 	.set_fmt   = ak4118_set_dai_fmt,
+	.auto_selectable_formats	= &ak4118_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ak4118_dai = {
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index f81cd8c..a74be99 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -591,12 +591,21 @@ static int ak4458_startup(struct snd_pcm_substream *substream,
 					  &ak4458_rate_constraints);
 }
 
+static const u64 ak4458_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_PDM;
+
 static const struct snd_soc_dai_ops ak4458_dai_ops = {
 	.startup        = ak4458_startup,
 	.hw_params	= ak4458_hw_params,
 	.set_fmt	= ak4458_set_dai_fmt,
 	.mute_stream	= ak4458_set_dai_mute,
 	.set_tdm_slot	= ak4458_set_tdm_slot,
+	.auto_selectable_formats	= &ak4458_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 3755567..6cabad4 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -346,11 +346,17 @@ static int ak4535_set_bias_level(struct snd_soc_component *component,
 		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
+static const u64 ak4535_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ak4535_dai_ops = {
 	.hw_params	= ak4535_hw_params,
 	.set_fmt	= ak4535_set_dai_fmt,
 	.mute_stream	= ak4535_mute,
 	.set_sysclk	= ak4535_set_dai_sysclk,
+	.auto_selectable_formats	= &ak4535_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/ak4619.c b/sound/soc/codecs/ak4619.c
index d9c9f6b..5252b30 100644
--- a/sound/soc/codecs/ak4619.c
+++ b/sound/soc/codecs/ak4619.c
@@ -799,7 +799,26 @@ static const struct snd_soc_dai_ops ak4619_dai_ops = {
 	.num_auto_selectable_formats	= ARRAY_SIZE(ak4619_dai_formats),
 };
 
+static int ak4619_suspend(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+
+	regcache_cache_only(regmap, true);
+	regcache_mark_dirty(regmap);
+	return 0;
+}
+
+static int ak4619_resume(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+
+	regcache_cache_only(regmap, false);
+	return regcache_sync(regmap);
+}
+
 static const struct snd_soc_component_driver soc_component_dev_ak4619 = {
+	.suspend		= ak4619_suspend,
+	.resume			= ak4619_resume,
 	.set_bias_level		= ak4619_set_bias_level,
 	.controls		= ak4619_snd_controls,
 	.num_controls		= ARRAY_SIZE(ak4619_snd_controls),
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 08ec203..cd92a1b 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -493,12 +493,18 @@ static int ak4642_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 ak4642_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ak4642_dai_ops = {
 	.startup	= ak4642_dai_startup,
 	.shutdown	= ak4642_dai_shutdown,
 	.set_sysclk	= ak4642_dai_set_sysclk,
 	.set_fmt	= ak4642_dai_set_fmt,
 	.hw_params	= ak4642_dai_hw_params,
+	.auto_selectable_formats	= &ak4642_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ak4642_dai = {
@@ -607,14 +613,13 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev)
 	struct device_node *np = dev->of_node;
 	struct clk *clk;
 	const char *clk_name = np->name;
-	const char *parent_clk_name = NULL;
+	const char *parent_clk_name;
 	u32 rate;
 
 	if (of_property_read_u32(np, "clock-frequency", &rate))
 		return NULL;
 
-	if (of_property_read_bool(np, "clocks"))
-		parent_clk_name = of_clk_get_parent_name(np, 0);
+	parent_clk_name = of_clk_get_parent_name(np, 0);
 
 	of_property_read_string(np, "clock-output-names", &clk_name);
 
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index aac54e9..1d804f0 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -582,10 +582,17 @@ static int ak4671_set_bias_level(struct snd_soc_component *component,
 
 #define AK4671_FORMATS		SNDRV_PCM_FMTBIT_S16_LE
 
+static const u64 ak4671_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 static const struct snd_soc_dai_ops ak4671_dai_ops = {
 	.hw_params	= ak4671_hw_params,
 	.set_sysclk	= ak4671_set_dai_sysclk,
 	.set_fmt	= ak4671_set_dai_fmt,
+	.auto_selectable_formats	= &ak4671_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ak4671_dai = {
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index 6525d50..933ca90 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -128,10 +128,16 @@ static int ak5386_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 ak5386_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ak5386_dai_ops = {
 	.set_fmt	= ak5386_set_dai_fmt,
 	.hw_params	= ak5386_hw_params,
 	.hw_free	= ak5386_hw_free,
+	.auto_selectable_formats	= &ak5386_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ak5386_dai = {
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 691db65..0c9cdf9a 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -285,12 +285,19 @@ static int ak5558_startup(struct snd_pcm_substream *substream,
 					  &ak5558_rate_constraints);
 }
 
+static const u64 ak5558_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops ak5558_dai_ops = {
 	.startup        = ak5558_startup,
 	.hw_params	= ak5558_hw_params,
 
 	.set_fmt	= ak5558_set_dai_fmt,
 	.set_tdm_slot   = ak5558_set_tdm_slot,
+	.auto_selectable_formats	= &ak5558_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ak5558_dai = {
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index f5a666c..96bb1d5 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -822,12 +822,23 @@ static int alc5623_set_bias_level(struct snd_soc_component *component,
 			| SNDRV_PCM_FMTBIT_S24_LE \
 			| SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 alc5623_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops alc5623_dai_ops = {
 		.hw_params = alc5623_pcm_hw_params,
 		.mute_stream = alc5623_mute,
 		.set_fmt = alc5623_set_dai_fmt,
 		.set_sysclk = alc5623_set_dai_sysclk,
 		.set_pll = alc5623_set_dai_pll,
+		.auto_selectable_formats = &alc5623_selectable_formats,
+		.num_auto_selectable_formats = 1,
 		.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 2fd3dd7..a5e95f3 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1003,12 +1003,25 @@ static int alc5632_set_bias_level(struct snd_soc_component *component,
 			| SNDRV_PCM_FMTBIT_S24_LE \
 			| SNDRV_PCM_FMTBIT_S32_LE)
 
+
+static const u64 alc5632_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops alc5632_dai_ops = {
 		.hw_params = alc5632_pcm_hw_params,
 		.mute_stream = alc5632_mute,
 		.set_fmt = alc5632_set_dai_fmt,
 		.set_sysclk = alc5632_set_dai_sysclk,
 		.set_pll = alc5632_set_dai_pll,
+		.auto_selectable_formats = &alc5632_selectable_formats,
+		.num_auto_selectable_formats = 1,
 		.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
index 819d080..6587d46 100644
--- a/sound/soc/codecs/arizona-jack.c
+++ b/sound/soc/codecs/arizona-jack.c
@@ -699,6 +699,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_priv *info)
 	snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE,
 			    SND_JACK_LINEOUT | SND_JACK_HEADPHONE);
 
+	pm_runtime_put_autosuspend(arizona->dev);
 	info->hpdet_active = false;
 }
 
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 4411165..7c296c5 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -2016,6 +2016,27 @@ static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
+static const u64 arizona_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/*
+	 * 2nd priority
+	 *
+	 * _DSP_B / _LEFT_J can't be clock consumer (= arizona_set_fmt()).
+	 */
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+};
+
 const struct snd_soc_dai_ops arizona_dai_ops = {
 	.startup = arizona_startup,
 	.set_fmt = arizona_set_fmt,
@@ -2023,6 +2044,8 @@ const struct snd_soc_dai_ops arizona_dai_ops = {
 	.hw_params = arizona_hw_params,
 	.set_sysclk = arizona_dai_set_sysclk,
 	.set_tristate = arizona_set_tristate,
+	.auto_selectable_formats = arizona_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(arizona_selectable_formats),
 };
 EXPORT_SYMBOL_GPL(arizona_dai_ops);
 
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index fc41e15..0262900 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -1244,11 +1244,24 @@ static int cpcap_hifi_set_mute(struct snd_soc_dai *dai, int mute, int direction)
 	return regmap_update_bits(cpcap->regmap, reg, mask, val);
 }
 
+static const u64 cpcap_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cpcap_dai_hifi_ops = {
 	.hw_params	= cpcap_hifi_hw_params,
 	.set_sysclk	= cpcap_hifi_set_dai_sysclk,
 	.set_fmt	= cpcap_hifi_set_dai_fmt,
 	.mute_stream	= cpcap_hifi_set_mute,
+	.auto_selectable_formats	= &cpcap_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1406,6 +1419,8 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
 	.set_sysclk	= cpcap_voice_set_dai_sysclk,
 	.set_fmt	= cpcap_voice_set_dai_fmt,
 	.mute_stream	= cpcap_voice_set_mute,
+	.auto_selectable_formats	= &cpcap_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index e217da1..b8c19f1 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -578,7 +578,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			| CS35L33_X_LOC);
 	}
 
-	/* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/
+	/* disconnect {vp,vbst}_mon routes: enable later if set in tx_mask*/
 	snd_soc_dapm_del_routes(dapm, cs35l33_vp_vbst_mon_route,
 		ARRAY_SIZE(cs35l33_vp_vbst_mon_route));
 
@@ -663,12 +663,18 @@ static int cs35l33_component_set_sysclk(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 cs35l33_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 static const struct snd_soc_dai_ops cs35l33_ops = {
 	.startup = cs35l33_pcm_startup,
 	.set_tristate = cs35l33_set_tristate,
 	.set_fmt = cs35l33_set_dai_fmt,
 	.hw_params = cs35l33_pcm_hw_params,
 	.set_tdm_slot = cs35l33_set_tdm_slot,
+	.auto_selectable_formats = &cs35l33_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver cs35l33_dai = {
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 3f265bd..a72be62 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -297,7 +297,7 @@ static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				CS35L34_X_STATE | CS35L34_X_LOC,
 				CS35L34_X_STATE | CS35L34_X_LOC);
 
-	/* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/
+	/* disconnect {vp,vbst}_mon routes: enable later if set in tx_mask*/
 	while (slot >= 0) {
 		/* configure VMON_TX_LOC */
 		if (slot_num == 0)
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index b2439ec..302d838 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -657,17 +657,24 @@ static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 cs35l35_selectable_formats_i2s = SND_SOC_POSSIBLE_DAIFMT_I2S;
+static const u64 cs35l35_selectable_formats_pdm = SND_SOC_POSSIBLE_DAIFMT_PDM;
+
 static const struct snd_soc_dai_ops cs35l35_ops = {
 	.startup = cs35l35_pcm_startup,
 	.set_fmt = cs35l35_set_dai_fmt,
 	.hw_params = cs35l35_hw_params,
 	.set_sysclk = cs35l35_dai_set_sysclk,
+	.auto_selectable_formats = &cs35l35_selectable_formats_i2s,
+	.num_auto_selectable_formats = 1,
 };
 
 static const struct snd_soc_dai_ops cs35l35_pdm_ops = {
 	.startup = cs35l35_pdm_startup,
 	.set_fmt = cs35l35_set_dai_fmt,
 	.hw_params = cs35l35_hw_params,
+	.auto_selectable_formats	= &cs35l35_selectable_formats_pdm,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver cs35l35_dai[] = {
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index 8964532..170588b 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -947,10 +947,22 @@ static const struct cs35l36_pll_config *cs35l36_get_clk_config(
 	return NULL;
 }
 
+static const u64 cs35l36_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_GATED	|
+	SND_SOC_POSSIBLE_DAIFMT_CONT	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs35l36_ops = {
 	.set_fmt = cs35l36_set_dai_fmt,
 	.hw_params = cs35l36_pcm_hw_params,
 	.set_sysclk = cs35l36_dai_set_sysclk,
+	.auto_selectable_formats = &cs35l36_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define CS35L36_RATES (		    \
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index b2a0767..d286025 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -953,11 +953,21 @@ static void cs35l41_component_remove(struct snd_soc_component *component)
 	wm_adsp2_component_remove(&cs35l41->dsp, component);
 }
 
+static const u64 cs35l41_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs35l41_ops = {
 	.set_fmt = cs35l41_set_dai_fmt,
 	.hw_params = cs35l41_pcm_hw_params,
 	.set_sysclk = cs35l41_dai_set_sysclk,
 	.set_channel_map = cs35l41_set_channel_map,
+	.auto_selectable_formats = &cs35l41_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define CS35L41_RATES (		    \
diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c
index 764dbaa..57982b8 100644
--- a/sound/soc/codecs/cs35l45-tables.c
+++ b/sound/soc/codecs/cs35l45-tables.c
@@ -51,6 +51,8 @@ static const struct reg_default cs35l45_defaults[] = {
 	{ CS35L45_WKI2C_CTL,			0x00000030 },
 	{ CS35L45_REFCLK_INPUT,			0x00000510 },
 	{ CS35L45_GLOBAL_SAMPLE_RATE,		0x00000003 },
+	{ CS35L45_SYNC_TX_RX_ENABLES,		0x00000200 },
+	{ CS35L45_SYNC_SW_TX_ID,		0x00000000 },
 	{ CS35L45_ASP_ENABLES1,			0x00000000 },
 	{ CS35L45_ASP_CONTROL1,			0x00000028 },
 	{ CS35L45_ASP_CONTROL2,			0x18180200 },
@@ -134,6 +136,8 @@ static bool cs35l45_readable_reg(struct device *dev, unsigned int reg)
 	case CS35L45_PWRMGT_STS:
 	case CS35L45_REFCLK_INPUT:
 	case CS35L45_GLOBAL_SAMPLE_RATE:
+	case CS35L45_SYNC_TX_RX_ENABLES:
+	case CS35L45_SYNC_SW_TX_ID:
 	case CS35L45_ASP_ENABLES1:
 	case CS35L45_ASP_CONTROL1:
 	case CS35L45_ASP_CONTROL2:
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index a032bb2..0ab7682 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -6,6 +6,7 @@
 //
 // Author: James Schulman <james.schulman@cirrus.com>
 
+#include <linux/bitfield.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
@@ -195,6 +196,46 @@ static int cs35l45_activate_ctl(struct snd_soc_component *component,
 	return 0;
 }
 
+static int cs35l45_sync_en_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct cs35l45_private *cs35l45 =
+			snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = cs35l45->sync_en;
+
+	return 0;
+}
+
+static int cs35l45_sync_en_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct cs35l45_private *cs35l45 =
+			snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+			snd_soc_component_to_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	if ((bool)ucontrol->value.integer.value[0] == cs35l45->sync_en) {
+		snd_soc_dapm_mutex_unlock(dapm);
+		return 0;
+	}
+
+	if ((bool)ucontrol->value.integer.value[0])
+		regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES2, CS35L45_SYNC_EN_MASK);
+	else
+		regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES2, CS35L45_SYNC_EN_MASK);
+
+	cs35l45->sync_en = (bool)ucontrol->value.integer.value[0];
+
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return 1;
+}
+
 static int cs35l45_amplifier_mode_get(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
@@ -591,6 +632,18 @@ static SOC_ENUM_SINGLE_DECL(amplifier_mode_enum, SND_SOC_NOPM, 0,
 static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 1000, 300, 0);
 static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true);
 
+static const struct snd_kcontrol_new cs35l45_sync_controls[] = {
+	SOC_SINGLE_BOOL_EXT("SYNC Switch", 0, cs35l45_sync_en_get, cs35l45_sync_en_put),
+	SOC_SINGLE("SYNC LSW RX Switch", CS35L45_SYNC_TX_RX_ENABLES,
+			CS35L45_SYNC_LSW_RX_EN_SHIFT, 1, 0),
+	SOC_SINGLE("SYNC LSW TX Switch", CS35L45_SYNC_TX_RX_ENABLES,
+			CS35L45_SYNC_LSW_TX_EN_SHIFT, 1, 0),
+	SOC_SINGLE("SYNC SW RX Switch", CS35L45_SYNC_TX_RX_ENABLES,
+			CS35L45_SYNC_SW_RX_EN_SHIFT, 1, 0),
+	SOC_SINGLE("SYNC SW TX Switch", CS35L45_SYNC_TX_RX_ENABLES,
+			CS35L45_SYNC_SW_TX_EN_SHIFT, 1, 0),
+};
+
 static const struct snd_kcontrol_new cs35l45_controls[] = {
 	SOC_ENUM_EXT("Amplifier Mode", amplifier_mode_enum,
 		     cs35l45_amplifier_mode_get, cs35l45_amplifier_mode_put),
@@ -846,12 +899,22 @@ static int cs35l45_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 	return 0;
 }
 
+static const u64 cs35l45_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs35l45_asp_dai_ops = {
 	.set_fmt = cs35l45_asp_set_fmt,
 	.hw_params = cs35l45_asp_hw_params,
 	.set_tdm_slot = cs35l45_asp_set_tdm_slot,
 	.set_sysclk = cs35l45_asp_set_sysclk,
 	.mute_stream = cs35l45_mute_stream,
+	.auto_selectable_formats	= &cs35l45_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver cs35l45_dai[] = {
@@ -880,6 +943,19 @@ static struct snd_soc_dai_driver cs35l45_dai[] = {
 static int cs35l45_component_probe(struct snd_soc_component *component)
 {
 	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_add_component_controls(component, cs35l45_controls,
+					     ARRAY_SIZE(cs35l45_controls));
+	if (ret < 0)
+		return ret;
+
+	if (cs35l45->sync_pin_set) {
+		ret = snd_soc_add_component_controls(component, cs35l45_sync_controls,
+						     ARRAY_SIZE(cs35l45_sync_controls));
+		if (ret < 0)
+			return ret;
+	}
 
 	return wm_adsp2_component_probe(&cs35l45->dsp, component);
 }
@@ -901,9 +977,6 @@ static const struct snd_soc_component_driver cs35l45_component = {
 	.dapm_routes = cs35l45_dapm_routes,
 	.num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes),
 
-	.controls = cs35l45_controls,
-	.num_controls = ARRAY_SIZE(cs35l45_controls),
-
 	.name = "cs35l45",
 
 	.endianness = 1,
@@ -1064,6 +1137,19 @@ static int cs35l45_sys_resume(struct device *dev)
 	return 0;
 }
 
+static void cs35l45_apply_sync_property_config(struct cs35l45_private *cs35l45)
+{
+	unsigned int val;
+
+	if (device_property_read_u32(cs35l45->dev, "cirrus,sync-lsw-txid", &val) == 0)
+		regmap_update_bits(cs35l45->regmap, CS35L45_SYNC_SW_TX_ID,
+				   CS35L45_SYNC_LSW_TXID_MASK, val << CS35L45_SYNC_LSW_TXID_SHIFT);
+
+	if (device_property_read_u32(cs35l45->dev, "cirrus,sync-sw-txid", &val) == 0)
+		regmap_update_bits(cs35l45->regmap, CS35L45_SYNC_SW_TX_ID,
+				   CS35L45_SYNC_SW_TXID_MASK, val);
+}
+
 static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
 {
 	struct device_node *node = cs35l45->dev->of_node;
@@ -1110,10 +1196,15 @@ static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
 					   val << CS35L45_GPIO_POL_SHIFT);
 
 		ret = of_property_read_u32(child, "gpio-ctrl", &val);
-		if (!ret)
+		if (!ret) {
+			if ((i == 0) && (val == CS35L45_GP1_CTRL_MDSYNC)) {
+				cs35l45->sync_pin_set = true;
+				cs35l45_apply_sync_property_config(cs35l45);
+			}
 			regmap_update_bits(cs35l45->regmap, pad_regs[i],
 					   CS35L45_GPIO_CTRL_MASK,
 					   val << CS35L45_GPIO_CTRL_SHIFT);
+		}
 
 		ret = of_property_read_u32(child, "gpio-invert", &val);
 		if (!ret) {
diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h
index 7a790d2..f8a4713 100644
--- a/sound/soc/codecs/cs35l45.h
+++ b/sound/soc/codecs/cs35l45.h
@@ -35,6 +35,8 @@
 #define CS35L45_PWRMGT_STS			0x0000290C
 #define CS35L45_REFCLK_INPUT			0x00002C04
 #define CS35L45_GLOBAL_SAMPLE_RATE		0x00002C0C
+#define CS35L45_SYNC_TX_RX_ENABLES		0x00003400
+#define CS35L45_SYNC_SW_TX_ID			0x00003408
 #define CS35L45_BOOST_CCM_CFG			0x00003808
 #define CS35L45_BOOST_DCM_CFG			0x0000380C
 #define CS35L45_BOOST_OV_CFG			0x0000382C
@@ -183,6 +185,8 @@
 #define CS35L45_ASP_EN_SHIFT			27
 #define CS35L45_AMP_DRE_EN_SHIFT		20
 #define CS35L45_AMP_DRE_EN_MASK		BIT(20)
+#define CS35L45_SYNC_EN_SHIFT			8
+#define CS35L45_SYNC_EN_MASK			BIT(8)
 #define CS35L45_MEM_RDY_SHIFT			1
 #define CS35L45_MEM_RDY_MASK			BIT(1)
 
@@ -220,6 +224,22 @@
 #define CS35L45_44P100_KHZ			0x0B
 #define CS35L45_88P200_KHZ			0x0C
 
+/* SYNC_TX_RX_ENABLES */
+#define CS35L45_SYNC_LSW_RX_EN_SHIFT		19
+#define CS35L45_SYNC_LSW_RX_EN_MASK		BIT(19)
+#define CS35L45_SYNC_LSW_TX_EN_SHIFT		18
+#define CS35L45_SYNC_LSW_TX_EN_MASK		BIT(18)
+#define CS35L45_SYNC_SW_RX_EN_SHIFT		17
+#define CS35L45_SYNC_SW_RX_EN_MASK		BIT(17)
+#define CS35L45_SYNC_SW_TX_EN_SHIFT		16
+#define CS35L45_SYNC_SW_TX_EN_MASK		BIT(16)
+
+/* SYNC_SW_TX_ID */
+#define CS35L45_SYNC_LSW_TXID_SHIFT		8
+#define CS35L45_SYNC_LSW_TXID_MASK		GENMASK(10, 8)
+#define CS35L45_SYNC_SW_TXID_SHIFT		0
+#define CS35L45_SYNC_SW_TXID_MASK		GENMASK(2, 0)
+
 /* ASP_ENABLES_1 */
 #define CS35L45_ASP_RX2_EN_SHIFT		17
 #define CS35L45_ASP_RX1_EN_SHIFT		16
@@ -320,6 +340,7 @@
 #define CS35L45_GPIO_CTRL_MASK			GENMASK(22, 20)
 #define CS35L45_GPIO_INVERT_SHIFT		19
 #define CS35L45_GPIO_INVERT_MASK		BIT(19)
+#define CS35L45_GP1_CTRL_MDSYNC		0x2
 
 /* CS35L45_IRQ1_EINT_1 */
 #define CS35L45_BST_UVP_ERR_SHIFT		7
@@ -493,6 +514,8 @@ struct cs35l45_private {
 	struct regulator *vdd_a;
 	bool initialized;
 	bool sysclk_set;
+	bool sync_en;
+	bool sync_pin_set;
 	u8 slot_width;
 	u8 slot_count;
 	int amplifier_mode;
diff --git a/sound/soc/codecs/cs35l56-shared-test.c b/sound/soc/codecs/cs35l56-shared-test.c
index 4f52c8a..34bb3d4 100644
--- a/sound/soc/codecs/cs35l56-shared-test.c
+++ b/sound/soc/codecs/cs35l56-shared-test.c
@@ -29,6 +29,7 @@ struct cs35l56_shared_test_priv {
 	struct faux_device *gpio_dev;
 	struct cs35l56_shared_test_mock_gpio *gpio_priv;
 	struct regmap *registers;
+	const struct regmap_config *regmap_config;
 	unsigned int reg_offset;
 	struct cs35l56_base *cs35l56_base;
 	u8 applied_pad_pull_state[CS35L56_MAX_GPIO];
@@ -614,6 +615,55 @@ static void cs35l56_shared_test_get_speaker_id_from_host_gpio(struct kunit *test
 	KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), param->spkid);
 }
 
+static void cs35l56_shared_test_sorted_regmap_defaults(struct kunit *test)
+{
+	struct cs35l56_shared_test_priv *priv = test->priv;
+	const struct reg_default *defaults;
+	int i;
+
+	KUNIT_ASSERT_NOT_NULL(test, priv->regmap_config);
+	defaults = priv->regmap_config->reg_defaults;
+	KUNIT_ASSERT_NOT_NULL(test, defaults);
+	KUNIT_ASSERT_NE(test, priv->regmap_config->num_reg_defaults, 0);
+
+	for (i = 1; i < priv->regmap_config->num_reg_defaults; i++)
+		KUNIT_EXPECT_LT(test, defaults[i - 1].reg, defaults[i].reg);
+}
+
+static void cs35l56_shared_test_regmap_defaults_not_volatile(struct kunit *test)
+{
+	struct cs35l56_shared_test_priv *priv = test->priv;
+	struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
+	const struct regmap_config *config = priv->regmap_config;
+	int i;
+
+	KUNIT_ASSERT_NOT_NULL(test, config);
+	KUNIT_ASSERT_NOT_NULL(test, config->volatile_reg);
+
+	for (i = 0; i < config->num_reg_defaults; i++) {
+		KUNIT_EXPECT_FALSE(test,
+				   config->volatile_reg(cs35l56_base->dev,
+							config->reg_defaults[i].reg));
+	}
+}
+
+static void cs35l56_shared_test_regmap_defaults_readable(struct kunit *test)
+{
+	struct cs35l56_shared_test_priv *priv = test->priv;
+	struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
+	const struct regmap_config *config = priv->regmap_config;
+	int i;
+
+	KUNIT_ASSERT_NOT_NULL(test, config);
+	KUNIT_ASSERT_NOT_NULL(test, config->readable_reg);
+
+	for (i = 0; i < config->num_reg_defaults; i++) {
+		KUNIT_EXPECT_TRUE(test,
+				  config->readable_reg(cs35l56_base->dev,
+						       config->reg_defaults[i].reg));
+	}
+}
+
 static int cs35l56_shared_test_case_regmap_init(struct kunit *test,
 						const struct regmap_config *regmap_config)
 {
@@ -645,6 +695,8 @@ static int cs35l56_shared_test_case_regmap_init(struct kunit *test,
 			kunit_add_action_or_reset(test, regmap_exit_wrapper,
 						  cs35l56_base->regmap));
 
+	priv->regmap_config = regmap_config;
+
 	return 0;
 }
 
@@ -862,6 +914,10 @@ static struct kunit_case cs35l56_shared_test_cases[] = {
 			      cs35l56_shared_test_host_gpio_spkid_gen_params,
 			      { KUNIT_SPEED_SLOW }),
 
+	KUNIT_CASE(cs35l56_shared_test_sorted_regmap_defaults),
+	KUNIT_CASE(cs35l56_shared_test_regmap_defaults_not_volatile),
+	KUNIT_CASE(cs35l56_shared_test_regmap_defaults_readable),
+
 	{ }
 };
 
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 35d2106..74129fc 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -613,12 +613,22 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 cs35l56_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs35l56_ops = {
 	.probe = cs35l56_asp_dai_probe,
 	.set_fmt = cs35l56_asp_dai_set_fmt,
 	.set_tdm_slot = cs35l56_asp_dai_set_tdm_slot,
 	.hw_params = cs35l56_asp_dai_hw_params,
 	.set_sysclk = cs35l56_asp_dai_set_sysclk,
+	.auto_selectable_formats = &cs35l56_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static void cs35l56_sdw_dai_shutdown(struct snd_pcm_substream *substream,
diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c
index 6763671..698aa59 100644
--- a/sound/soc/codecs/cs40l50-codec.c
+++ b/sound/soc/codecs/cs40l50-codec.c
@@ -233,10 +233,19 @@ static int cs40l50_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int rati
 	return 0;
 }
 
+static const u64 cs40l50_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs40l50_dai_ops = {
 	.set_fmt = cs40l50_set_dai_fmt,
 	.set_bclk_ratio = cs40l50_set_dai_bclk_ratio,
 	.hw_params = cs40l50_hw_params,
+	.auto_selectable_formats = &cs40l50_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver cs40l50_dai[] = {
diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c
index a889fbd..a6ead1e 100644
--- a/sound/soc/codecs/cs4234.c
+++ b/sound/soc/codecs/cs4234.c
@@ -560,11 +560,20 @@ static int cs4234_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask
 	return 0;
 }
 
+static const u64 cs4234_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops cs4234_dai_ops = {
 	.set_fmt	= cs4234_dai_set_fmt,
 	.hw_params	= cs4234_dai_hw_params,
 	.startup	= cs4234_dai_startup,
 	.set_tdm_slot	= cs4234_dai_set_tdm_slot,
+	.auto_selectable_formats	= &cs4234_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver cs4234_dai[] = {
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 0b7d682..97e32e6 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -495,11 +495,23 @@ static int cs4265_set_bias_level(struct snd_soc_component *component,
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \
 			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
 
+/*
+ * NOTE
+ *
+ * auto_select doesn't include _RIGHT_J, because capture can't use it
+ * (= cs4265_pcm_hw_params()). It can be selected via Card directly if needed.
+ */
+static const u64 cs4265_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops cs4265_ops = {
 	.hw_params	= cs4265_pcm_hw_params,
 	.mute_stream	= cs4265_mute,
 	.set_fmt	= cs4265_set_fmt,
 	.set_sysclk	= cs4265_set_sysclk,
+	.auto_selectable_formats	= &cs4265_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 47b2f90..aa3bbb9 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -456,11 +456,17 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
 		snd_soc_get_volsw, cs4270_soc_put_mute),
 };
 
+static const u64 cs4270_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops cs4270_dai_ops = {
 	.hw_params	= cs4270_hw_params,
 	.set_sysclk	= cs4270_set_dai_sysclk,
 	.set_fmt	= cs4270_set_dai_fmt,
 	.mute_stream	= cs4270_dai_mute,
+	.auto_selectable_formats	= &cs4270_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index d8cdd37..398d8c2 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -455,11 +455,17 @@ static const struct snd_kcontrol_new cs4271_snd_controls[] = {
 		7, 1, 1),
 };
 
+static const u64 cs4271_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops cs4271_dai_ops = {
 	.hw_params	= cs4271_hw_params,
 	.set_sysclk	= cs4271_set_dai_sysclk,
 	.set_fmt	= cs4271_set_dai_fmt,
 	.mute_stream	= cs4271_mute_stream,
+	.auto_selectable_formats	= &cs4271_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver cs4271_dai = {
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index fadf688..b5d69d55 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -1122,6 +1122,13 @@ EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, "SND_SOC_CS42L42_CORE");
 			 SNDRV_PCM_FMTBIT_S24_LE |\
 			 SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 cs42l42_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs42l42_ops = {
 	.startup	= cs42l42_dai_startup,
 	.hw_params	= cs42l42_pcm_hw_params,
@@ -1129,6 +1136,8 @@ static const struct snd_soc_dai_ops cs42l42_ops = {
 	.set_sysclk	= cs42l42_set_sysclk,
 	.set_bclk_ratio	= cs42l42_set_bclk_ratio,
 	.mute_stream	= cs42l42_mute_stream,
+	.auto_selectable_formats	= &cs42l42_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 struct snd_soc_dai_driver cs42l42_dai = {
@@ -1673,7 +1682,7 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
 	if (cs42l42->suspended || !cs42l42->init_done)
 		return IRQ_NONE;
 
-	/* Read sticky registers to clear interurpt */
+	/* Read sticky registers to clear interrupt */
 	for (i = 0; i < ARRAY_SIZE(stickies); i++) {
 		regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
 				&(stickies[i]));
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 1b817e1..b6238f8 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -671,6 +671,16 @@ static int cs42l43_dai_remove(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 cs42l43_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs42l43_asp_ops = {
 	.probe		= cs42l43_dai_probe,
 	.remove		= cs42l43_dai_remove,
@@ -678,6 +688,8 @@ static const struct snd_soc_dai_ops cs42l43_asp_ops = {
 	.hw_params	= cs42l43_asp_hw_params,
 	.set_fmt	= cs42l43_asp_set_fmt,
 	.set_tdm_slot	= cs42l43_asp_set_tdm_slot,
+	.auto_selectable_formats	= &cs42l43_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 0519aff..4b964c7 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -533,11 +533,18 @@ static int cs42l51_of_xlate_dai_id(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 cs42l51_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops cs42l51_dai_ops = {
 	.hw_params      = cs42l51_hw_params,
 	.set_sysclk     = cs42l51_set_dai_sysclk,
 	.set_fmt        = cs42l51_set_dai_fmt,
 	.mute_stream    = cs42l51_dai_mute,
+	.auto_selectable_formats	= &cs42l51_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 9d6bcfb..5f03355 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -883,11 +883,24 @@ static int cs42l52_set_bias_level(struct snd_soc_component *component,
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
 
+static const u64 cs42l52_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs42l52_ops = {
 	.hw_params	= cs42l52_pcm_hw_params,
 	.mute_stream	= cs42l52_mute,
 	.set_fmt	= cs42l52_set_fmt,
 	.set_sysclk	= cs42l52_set_sysclk,
+	.auto_selectable_formats	= &cs42l52_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1000,7 +1013,7 @@ static void cs42l52_init_beep(struct snd_soc_component *component)
 	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	cs42l52->beep = devm_input_allocate_device(component->dev);
+	cs42l52->beep = input_allocate_device();
 	if (!cs42l52->beep) {
 		dev_err(component->dev, "Failed to allocate beep device\n");
 		return;
@@ -1021,8 +1034,10 @@ static void cs42l52_init_beep(struct snd_soc_component *component)
 
 	ret = input_register_device(cs42l52->beep);
 	if (ret != 0) {
+		input_free_device(cs42l52->beep);
 		cs42l52->beep = NULL;
 		dev_err(component->dev, "Failed to register beep device\n");
+		return;
 	}
 
 	ret = device_create_file(component->dev, &dev_attr_beep);
@@ -1038,7 +1053,10 @@ static void cs42l52_free_beep(struct snd_soc_component *component)
 
 	device_remove_file(component->dev, &dev_attr_beep);
 	cancel_work_sync(&cs42l52->beep_work);
-	cs42l52->beep = NULL;
+	if (cs42l52->beep) {
+		input_unregister_device(cs42l52->beep);
+		cs42l52->beep = NULL;
+	}
 
 	snd_soc_component_update_bits(component, CS42L52_BEEP_TONE_CTL,
 			    CS42L52_BEEP_EN_MASK, 0);
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index 4d9a22a..ad45e8f 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -960,11 +960,19 @@ static int cs42l56_set_bias_level(struct snd_soc_component *component,
 			SNDRV_PCM_FMTBIT_S32_LE)
 
 
+static const u64 cs42l56_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops cs42l56_ops = {
 	.hw_params	= cs42l56_pcm_hw_params,
 	.mute_stream	= cs42l56_mute,
 	.set_fmt	= cs42l56_set_dai_fmt,
 	.set_sysclk	= cs42l56_set_sysclk,
+	.auto_selectable_formats	= &cs42l56_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1077,7 +1085,7 @@ static void cs42l56_init_beep(struct snd_soc_component *component)
 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	cs42l56->beep = devm_input_allocate_device(component->dev);
+	cs42l56->beep = input_allocate_device();
 	if (!cs42l56->beep) {
 		dev_err(component->dev, "Failed to allocate beep device\n");
 		return;
@@ -1098,8 +1106,10 @@ static void cs42l56_init_beep(struct snd_soc_component *component)
 
 	ret = input_register_device(cs42l56->beep);
 	if (ret != 0) {
+		input_free_device(cs42l56->beep);
 		cs42l56->beep = NULL;
 		dev_err(component->dev, "Failed to register beep device\n");
+		return;
 	}
 
 	ret = device_create_file(component->dev, &dev_attr_beep);
@@ -1115,7 +1125,10 @@ static void cs42l56_free_beep(struct snd_soc_component *component)
 
 	device_remove_file(component->dev, &dev_attr_beep);
 	cancel_work_sync(&cs42l56->beep_work);
-	cs42l56->beep = NULL;
+	if (cs42l56->beep) {
+		input_unregister_device(cs42l56->beep);
+		cs42l56->beep = NULL;
+	}
 
 	snd_soc_component_update_bits(component, CS42L56_BEEP_TONE_CFG,
 			    CS42L56_BEEP_EN_MASK, 0);
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 6ddc654..72c4213 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -761,7 +761,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
 	{"ASPOUTL", "ASP-IP Volume", "ASPL Output Mixer"},
 	{"ASPOUTR", "ASP-IP Volume", "ASPR Output Mixer"},
 
-	/* Auxillary Capture */
+	/* Auxiliary Capture */
 	{"XSPL Output Mixer", NULL, "Input Left Capture"},
 	{"XSPR Output Mixer", NULL, "Input Right Capture"},
 
@@ -1126,7 +1126,7 @@ static int cs42l73_set_bias_level(struct snd_soc_component *component,
 			mdelay(cs42l73->shutdwn_delay);
 			cs42l73->shutdwn_delay = 0;
 		} else {
-			mdelay(15); /* Min amount of time requred to power
+			mdelay(15); /* Min amount of time required to power
 				     * down.
 				     */
 		}
@@ -1163,12 +1163,19 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,
 #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 cs42l73_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops cs42l73_ops = {
 	.startup = cs42l73_pcm_startup,
 	.hw_params = cs42l73_pcm_hw_params,
 	.set_fmt = cs42l73_set_dai_fmt,
 	.set_sysclk = cs42l73_set_sysclk,
 	.set_tristate = cs42l73_set_tristate,
+	.auto_selectable_formats = &cs42l73_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver cs42l73_dai[] = {
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
index a545730..7701559 100644
--- a/sound/soc/codecs/cs42l84.c
+++ b/sound/soc/codecs/cs42l84.c
@@ -662,11 +662,17 @@ static int cs42l84_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 	return 0;
 }
 
+static const u64 cs42l84_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs42l84_ops = {
 	.hw_params	= cs42l84_pcm_hw_params,
 	.set_fmt	= cs42l84_set_dai_fmt,
 	.set_sysclk	= cs42l84_set_sysclk,
 	.mute_stream	= cs42l84_mute_stream,
+	.auto_selectable_formats	= &cs42l84_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define CS42L84_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index 5b68954..fb9f4af 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -393,12 +393,20 @@ static int cs42xx8_mute(struct snd_soc_dai *dai, int mute, int direction)
 	return 0;
 }
 
+static const u64 cs42xx8_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
 	.set_fmt	= cs42xx8_set_dai_fmt,
 	.set_sysclk	= cs42xx8_set_dai_sysclk,
 	.hw_params	= cs42xx8_hw_params,
 	.hw_free	= cs42xx8_hw_free,
 	.mute_stream	= cs42xx8_mute,
+	.auto_selectable_formats	= &cs42xx8_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index 48d88da..7bbb2e8 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -1609,12 +1609,24 @@ static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
+static const u64 cs43130_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs43130_pcm_ops = {
 	.startup	= cs43130_pcm_startup,
 	.hw_params	= cs43130_hw_params,
 	.hw_free	= cs43130_hw_free,
 	.set_sysclk	= cs43130_set_sysclk,
 	.set_fmt	= cs43130_pcm_set_fmt,
+	.auto_selectable_formats	= &cs43130_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops cs43130_dop_ops = {
@@ -1623,6 +1635,8 @@ static const struct snd_soc_dai_ops cs43130_dop_ops = {
 	.hw_free	= cs43130_hw_free,
 	.set_sysclk	= cs43130_set_sysclk,
 	.set_fmt	= cs43130_pcm_set_fmt,
+	.auto_selectable_formats	= &cs43130_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops cs43130_dsd_ops = {
diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c
index a44e6b3..74544c5 100644
--- a/sound/soc/codecs/cs4341.c
+++ b/sound/soc/codecs/cs4341.c
@@ -171,10 +171,18 @@ static const struct snd_kcontrol_new cs4341_controls[] = {
 	SOC_SINGLE("Popguard Transient Switch", CS4341_REG_MODE2, 1, 1, 0),
 };
 
+static const u64 cs4341_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops cs4341_dai_ops = {
 	.set_fmt	= cs4341_set_fmt,
 	.hw_params	= cs4341_hw_params,
 	.mute_stream	= cs4341_mute,
+	.auto_selectable_formats	= &cs4341_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 9a7f701..2832095 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -228,10 +228,22 @@ static const struct snd_soc_dapm_route cs4349_routes[] = {
 
 #define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000
 
+/*
+ * NOTE
+ *
+ * auto_select doesn't include _RIGHT_J, because 32bit width can't use it
+ * (= cs4349_pcm_hw_params()). It can be selected via Card directly if needed.
+ */
+static const u64 cs4349_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops cs4349_dai_ops = {
 	.hw_params	= cs4349_pcm_hw_params,
 	.set_fmt	= cs4349_set_dai_fmt,
 	.mute_stream	= cs4349_mute,
+	.auto_selectable_formats	= &cs4349_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c
index a996777..c11fc1a 100644
--- a/sound/soc/codecs/cs48l32.c
+++ b/sound/soc/codecs/cs48l32.c
@@ -2361,6 +2361,27 @@ static int cs48l32_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
+static const u64 cs48l32_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/*
+	 * 2nd priority
+	 *
+	 * _DSP_B / _LEFT_J can't be clock consumer (= cs48l32_set_fmt()).
+	 */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+};
+
 static const struct snd_soc_dai_ops cs48l32_dai_ops = {
 	.probe = &cs48l32_asp_dai_probe,
 	.startup = &cs48l32_startup,
@@ -2368,6 +2389,8 @@ static const struct snd_soc_dai_ops cs48l32_dai_ops = {
 	.set_tdm_slot = &cs48l32_set_tdm_slot,
 	.hw_params = &cs48l32_hw_params,
 	.set_sysclk = &cs48l32_dai_set_sysclk,
+	.auto_selectable_formats = cs48l32_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(cs48l32_selectable_formats),
 };
 
 static int cs48l32_sysclk_ev(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
index 2c7e331..e0ea246 100644
--- a/sound/soc/codecs/cs530x.c
+++ b/sound/soc/codecs/cs530x.c
@@ -945,10 +945,19 @@ static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				  val << CS530X_ASP_TDM_SLOT_SHIFT);
 }
 
+static const u64 cs530x_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs530x_dai_ops = {
 	.set_fmt = cs530x_set_fmt,
 	.hw_params = cs530x_hw_params,
 	.set_tdm_slot = cs530x_set_tdm_slot,
+	.auto_selectable_formats        = &cs530x_selectable_formats,
+	.num_auto_selectable_formats    = 1,
 };
 
 static const struct snd_soc_dai_driver cs530x_dai = {
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 511453b..c9c682a 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -833,6 +833,12 @@ static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 #define CS53L30_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 cs53l30_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops cs53l30_ops = {
 	.hw_params = cs53l30_pcm_hw_params,
 	.set_fmt = cs53l30_set_dai_fmt,
@@ -840,6 +846,8 @@ static const struct snd_soc_dai_ops cs53l30_ops = {
 	.set_tristate = cs53l30_set_tristate,
 	.set_tdm_slot = cs53l30_set_dai_tdm_slot,
 	.mute_stream = cs53l30_mute_stream,
+	.auto_selectable_formats        = &cs53l30_selectable_formats,
+	.num_auto_selectable_formats    = 1,
 };
 
 static struct snd_soc_dai_driver cs53l30_dai = {
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 0dea84c..d3c7a93 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -200,7 +200,7 @@ static int cx20442_write(struct snd_soc_component *component, unsigned int reg,
  * Line discpline related code
  *
  * Any of the callback functions below can be used in two ways:
- * 1) registerd by a machine driver as one of line discipline operations,
+ * 1) registered by a machine driver as one of line discipline operations,
  * 2) called from a machine's provided line discipline callback function
  *    in case when extra machine specific code must be run as well.
  */
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index d02ab74..5b9e952 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -1521,6 +1521,16 @@ static const struct snd_soc_component_driver soc_codec_driver_cx2072x = {
 	.endianness = 1,
 };
 
+
+static const u64 cx2072x_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 /*
  * DAI ops
  */
@@ -1529,6 +1539,8 @@ static const struct snd_soc_dai_ops cx2072x_dai_ops = {
 	.set_fmt = cx2072x_set_dai_fmt,
 	.hw_params = cx2072x_hw_params,
 	.set_bclk_ratio = cx2072x_set_dai_bclk_ratio,
+	.auto_selectable_formats        = &cx2072x_selectable_formats,
+	.num_auto_selectable_formats    = 1,
 };
 
 static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai)
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 4df1a25..40d75993 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1030,6 +1030,11 @@ static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	return -EINVAL;
 }
 
+static const u64 da7210_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 /* DAI operations */
 static const struct snd_soc_dai_ops da7210_dai_ops = {
 	.hw_params	= da7210_hw_params,
@@ -1037,6 +1042,8 @@ static const struct snd_soc_dai_ops da7210_dai_ops = {
 	.set_sysclk	= da7210_set_dai_sysclk,
 	.set_pll	= da7210_set_dai_pll,
 	.mute_stream	= da7210_mute,
+	.auto_selectable_formats        = &da7210_selectable_formats,
+	.num_auto_selectable_formats    = 1,
 	.no_capture_mute = 1,
 };
 
@@ -1151,7 +1158,7 @@ static int da7210_probe(struct snd_soc_component *component)
 	snd_soc_component_write(component, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
 					      DA7210_PLL_BYP);
 
-	/* Diable PLL and bypass it */
+	/* Disable PLL and bypass it */
 	snd_soc_component_write(component, DA7210_PLL, DA7210_PLL_FS_48000);
 
 	/* Activate all enabled subsystem */
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 93bd045..361daf1 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -2166,12 +2166,24 @@ static int da7218_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 da7218_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops da7218_dai_ops = {
 	.hw_params	= da7218_hw_params,
 	.set_sysclk	= da7218_set_dai_sysclk,
 	.set_pll	= da7218_set_dai_pll,
 	.set_fmt	= da7218_set_dai_fmt,
 	.set_tdm_slot	= da7218_set_dai_tdm_slot,
+	.auto_selectable_formats        = &da7218_selectable_formats,
+	.num_auto_selectable_formats    = 1,
 };
 
 #define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f6d371e..673285c 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1643,12 +1643,24 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 da7219_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops da7219_dai_ops = {
 	.hw_params	= da7219_hw_params,
 	.set_sysclk	= da7219_set_dai_sysclk,
 	.set_pll	= da7219_set_dai_pll,
 	.set_fmt	= da7219_set_dai_fmt,
 	.set_tdm_slot	= da7219_set_dai_tdm_slot,
+	.auto_selectable_formats        = &da7219_selectable_formats,
+	.num_auto_selectable_formats    = 1,
 };
 
 #define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 12d1ac9..c9b6172 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1188,10 +1188,27 @@ static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 #define	DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 da732x_selectable_formats[] = {
+	/* Hi Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* Low Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops da732x_dai_ops = {
 	.hw_params	= da732x_hw_params,
 	.set_fmt	= da732x_set_dai_fmt,
 	.set_sysclk	= da732x_set_dai_sysclk,
+	.auto_selectable_formats	= da732x_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(da732x_selectable_formats),
 };
 
 static struct snd_soc_dai_driver da732x_dai[] = {
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index a88c135..faff153 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1317,6 +1317,12 @@ static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	return -EINVAL;
 }
 
+static const u64 da9055_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 /* DAI operations */
 static const struct snd_soc_dai_ops da9055_dai_ops = {
 	.hw_params	= da9055_hw_params,
@@ -1324,6 +1330,8 @@ static const struct snd_soc_dai_ops da9055_dai_ops = {
 	.set_sysclk	= da9055_set_dai_sysclk,
 	.set_pll	= da9055_set_dai_pll,
 	.mute_stream	= da9055_mute,
+	.auto_selectable_formats	= &da9055_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
index 441df15..e3e6142 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -130,10 +130,16 @@ static int es7134_component_probe(struct snd_soc_component *c)
 	return 0;
 }
 
+static const u64 es7134_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops es7134_dai_ops = {
 	.set_fmt	= es7134_set_fmt,
 	.hw_params	= es7134_hw_params,
 	.set_sysclk	= es7134_set_sysclk,
+	.auto_selectable_formats	= &es7134_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver es7134_dai = {
diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c
index 339553c..a0bd538 100644
--- a/sound/soc/codecs/es7241.c
+++ b/sound/soc/codecs/es7241.c
@@ -152,10 +152,17 @@ static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 }
 
+static const u64 es7241_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops es7241_dai_ops = {
 	.set_fmt	= es7241_set_fmt,
 	.hw_params	= es7241_hw_params,
 	.set_sysclk	= es7241_set_sysclk,
+	.auto_selectable_formats	= &es7241_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver es7241_dai = {
diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c
index 6fe3ae4..e46b85f 100644
--- a/sound/soc/codecs/es8311.c
+++ b/sound/soc/codecs/es8311.c
@@ -800,12 +800,29 @@ static int es8311_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 es8311_selectable_formats[] = {
+	/* Hi Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* Low Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops es8311_dai_ops = {
 	.startup = es8311_startup,
 	.hw_params = es8311_hw_params,
 	.mute_stream = es8311_mute,
 	.set_sysclk = es8311_set_sysclk,
 	.set_fmt = es8311_set_dai_fmt,
+	.auto_selectable_formats = es8311_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(es8311_selectable_formats),
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 24ec8b2..5939947 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -566,12 +566,21 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute, int direction)
 #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 es8316_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops es8316_ops = {
 	.startup = es8316_pcm_startup,
 	.hw_params = es8316_pcm_hw_params,
 	.set_fmt = es8316_set_dai_fmt,
 	.set_sysclk = es8316_set_dai_sysclk,
 	.mute_stream = es8316_mute,
+	.auto_selectable_formats = &es8316_selectable_formats,
+	.num_auto_selectable_formats = 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c
index b926340..12fcfe0 100644
--- a/sound/soc/codecs/es8323.c
+++ b/sound/soc/codecs/es8323.c
@@ -622,12 +622,25 @@ static int es8323_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 					     mute ? ES8323_DACCONTROL3_DACMUTE : 0);
 }
 
+static const u64 es8323_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops es8323_ops = {
 	.startup	= es8323_pcm_startup,
 	.hw_params	= es8323_pcm_hw_params,
 	.set_fmt	= es8323_set_dai_fmt,
 	.set_sysclk	= es8323_set_dai_sysclk,
 	.mute_stream	= es8323_mute_stream,
+	.auto_selectable_formats	= &es8323_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define ES8323_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index b6eadc2..a95b3b8 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -33,11 +33,16 @@ struct es8326_priv {
 	 * while enabling or disabling or during an irq.
 	 */
 	struct mutex lock;
+	struct mutex hpf_lock;
 	u8 jack_pol;
 	u8 interrupt_src;
 	u8 interrupt_clk;
 	u8 hpl_vol;
 	u8 hpr_vol;
+	u8 hpfl;
+	u8 hpfr;
+	u32 hpf_freq;
+	u32 capture_rate;
 	bool jd_inverted;
 	unsigned int sysclk;
 
@@ -47,6 +52,48 @@ struct es8326_priv {
 	int jack_remove_retry;
 };
 
+static const u32 hpf_table[10][10] = {
+	{1020, 754, 624, 559, 527, 511, 502, 498, 497, 496},
+	{754, 495, 368, 306, 274, 259, 251, 247, 246, 244},
+	{624, 368, 243, 182, 151, 136, 128, 124, 123, 121},
+	{559, 306, 182, 120, 90, 75, 68, 63, 62, 60},
+	{527, 274, 151, 90, 60, 45, 38, 33, 32, 31},
+	{511, 259, 136, 75, 45, 30, 23, 19, 18, 17},
+	{502, 251, 128, 68, 38, 23, 16, 13, 11, 11},
+	{498, 247, 124, 63, 33, 19, 13, 10, 8, 8},
+	{497, 246, 123, 62, 32, 18, 11, 8, 8, 0},
+	{496, 244, 121, 60, 31, 17, 11, 8, 0, 0}
+};
+
+static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2)
+{
+	int best_row = -1, best_col = -1;
+	u32 min_diff = U32_MAX;
+	u32 f, diff;
+	int i, j;
+
+	if (target_hz > 1020)
+		return false;
+
+	for (i = 0; i < 10; i++) {
+		for (j = i; j < 10; j++) {
+			f = hpf_table[i][j];
+
+			diff = (target_hz > f) ? (target_hz - f) : (f - target_hz);
+			if (diff < min_diff) {
+				min_diff = diff;
+				best_row = i;
+				best_col = j;
+			}
+		}
+	}
+
+	*hpf1 = best_col + ES8326_HPF_OFFSET;
+	*hpf2 = best_row + ES8326_HPF_OFFSET;
+
+	return true;
+}
+
 static int es8326_crosstalk1_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
@@ -189,6 +236,48 @@ static int es8326_hprvol_set(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int es8326_hpf_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = es8326->hpf_freq;
+	return 0;
+}
+
+static int es8326_hpf_set(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	u32 freq;
+	bool hpf;
+
+	if ((ucontrol->value.integer.value[0] > 1020) || (ucontrol->value.integer.value[0] < 0))
+		return -EBUSY;
+
+	if (es8326->hpf_freq == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (es8326->capture_rate) {
+		guard(mutex)(&es8326->hpf_lock);
+		freq = (ucontrol->value.integer.value[0] * 48000) / es8326->capture_rate;
+
+		hpf = find_best_hpf_freq(freq, &es8326->hpfl, &es8326->hpfr);
+		if (!hpf)
+			return -EBUSY;
+
+		regmap_update_bits(es8326->regmap, ES8326_ADC_HPFS1, 0x0f, es8326->hpfl);
+		regmap_update_bits(es8326->regmap, ES8326_ADC_HPFS2, 0x0f, es8326->hpfr);
+	} else {
+		dev_dbg_ratelimited(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n");
+	}
+	es8326->hpf_freq = ucontrol->value.integer.value[0];
+
+	return 1;
+}
+
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
@@ -269,6 +358,8 @@ static const struct snd_kcontrol_new es8326_snd_controls[] = {
 	SOC_ENUM("ALC Capture Winsize", alc_winsize),
 	SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
 			0, 0x0f, 0, drc_target_tlv),
+	SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0,
+				es8326_hpf_get, es8326_hpf_set),
 
 	SOC_SINGLE_EXT("CROSSTALK1", SND_SOC_NOPM, 0, 31, 0,
 			es8326_crosstalk1_get, es8326_crosstalk1_set),
@@ -353,8 +444,6 @@ static bool es8326_writeable_register(struct device *dev, unsigned int reg)
 	case ES8326_BIAS_SW2:
 	case ES8326_BIAS_SW3:
 	case ES8326_BIAS_SW4:
-	case ES8326_ADC_HPFS1:
-	case ES8326_ADC_HPFS2:
 		return false;
 	default:
 		return true;
@@ -558,6 +647,8 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
 	u8 srate = 0;
 	int coeff, array;
+	u32 freq;
+	bool hpf;
 
 	if (es8326->version == 0) {
 		coeff_div =  coeff_div_v0;
@@ -612,6 +703,28 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
 		dev_warn(component->dev, "Clock coefficients do not match");
 	}
 
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		es8326->capture_rate = params_rate(params);
+		freq = (es8326->hpf_freq * 48000) / params_rate(params);
+		hpf = find_best_hpf_freq(freq, &es8326->hpfl, &es8326->hpfr);
+		if (!hpf) {
+			dev_err(component->dev, "The HPF frequency is invalid\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int es8326_pcm_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		es8326->capture_rate = 0;
+
 	return 0;
 }
 
@@ -636,6 +749,8 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
 				regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
 				regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x30);
 			}
+			regmap_update_bits(es8326->regmap, ES8326_ADC_HPFS1, 0x0f, 0x04);
+			regmap_update_bits(es8326->regmap, ES8326_ADC_HPFS2, 0x0f, 0x04);
 		}
 	} else {
 		if (!es8326->calibrated) {
@@ -705,7 +820,8 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x58);
+		regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x13);
 		regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00);
 		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
 		if (es8326->version > ES8326_VERSION_B) {
@@ -726,11 +842,21 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
 #define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 es8326_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops es8326_ops = {
 	.hw_params = es8326_pcm_hw_params,
+	.hw_free = es8326_pcm_hw_free,
 	.set_fmt = es8326_set_dai_fmt,
 	.set_sysclk = es8326_set_dai_sysclk,
 	.mute_stream = es8326_mute,
+	.auto_selectable_formats = &es8326_selectable_formats,
+	.num_auto_selectable_formats = 1,
 	.no_capture_mute = 0,
 };
 
@@ -781,6 +907,8 @@ static void es8326_capture_pop_handler(struct work_struct *work)
 	struct es8326_priv *es8326 =
 		container_of(work, struct es8326_priv, capture_pop_work.work);
 
+	regmap_update_bits(es8326->regmap, ES8326_ADC_HPFS1, 0x0f, es8326->hpfl);
+	regmap_update_bits(es8326->regmap, ES8326_ADC_HPFS2, 0x0f, es8326->hpfr);
 	regmap_update_bits(es8326->regmap,  ES8326_ADC_MUTE,
 					0x0F, 0x00);
 }
@@ -865,7 +993,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
 	struct es8326_priv *es8326 =
 		container_of(work, struct es8326_priv, jack_detect_work.work);
 	struct snd_soc_component *comp = es8326->component;
-	unsigned int iface;
+	unsigned int iface, pga_status;
 
 	guard(mutex)(&es8326->lock);
 	iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
@@ -961,12 +1089,19 @@ static void es8326_jack_detect_handler(struct work_struct *work)
 			dev_dbg(comp->dev, "Headset detected\n");
 			snd_soc_jack_report(es8326->jack,
 					SND_JACK_HEADSET, SND_JACK_HEADSET);
-			regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
-					0x08, 0x08);
-			regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
-			regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
-			regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
-					0x08, 0x00);
+			pga_status = snd_soc_component_read(comp, ES8326_PGA_PDN);
+
+			if ((pga_status & 0x08) >> 3) {
+				regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
+				regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
+			} else {
+				regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+						0x08, 0x08);
+				regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
+				regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
+				regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+						0x08, 0x00);
+			}
 			usleep_range(10000, 15000);
 		}
 	}
@@ -1130,18 +1265,28 @@ static int es8326_resume(struct snd_soc_component *component)
 {
 	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
+	int ret;
 
 	regcache_cache_only(es8326->regmap, false);
 	regcache_cache_bypass(es8326->regmap, true);
-	regmap_read(es8326->regmap, ES8326_CLK_RESAMPLE, &reg);
+	ret = regmap_read(es8326->regmap, ES8326_CLK_RESAMPLE, &reg);
 	regcache_cache_bypass(es8326->regmap, false);
-	/* reset internal clock state */
-	if (reg == 0x05)
-		regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
-	else
-		es8326_init(component);
+	if (ret)
+		return ret;
 
-	regcache_sync(es8326->regmap);
+	/* reset internal clock state */
+	if (reg == 0x05) {
+		ret = regmap_write(es8326->regmap, ES8326_CLK_CTL,
+				   ES8326_CLK_ON);
+		if (ret)
+			return ret;
+	} else {
+		es8326_init(component);
+	}
+
+	ret = regcache_sync(es8326->regmap);
+	if (ret)
+		return ret;
 
 	es8326_irq(es8326->irq, es8326);
 	return 0;
@@ -1202,6 +1347,7 @@ static int es8326_probe(struct snd_soc_component *component)
 	}
 	dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
 
+	es8326->hpf_freq = ES8326_HPF_DEFAULT;
 	es8326_init(component);
 	return 0;
 }
@@ -1288,6 +1434,7 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
 	i2c_set_clientdata(i2c, es8326);
 	es8326->i2c = i2c;
 	mutex_init(&es8326->lock);
+	mutex_init(&es8326->hpf_lock);
 	es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
 	if (IS_ERR(es8326->regmap)) {
 		ret = PTR_ERR(es8326->regmap);
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
index 1c5b3ec..c78d528 100644
--- a/sound/soc/codecs/es8326.h
+++ b/sound/soc/codecs/es8326.h
@@ -149,6 +149,10 @@
 #define ES8326_ADC_SRC_DMIC_SDIN3 6
 #define ES8326_ADC_SRC_DMIC_SDIN3_INV 7
 
+/* HPF Settings */
+#define ES8326_HPF_DEFAULT            8
+#define ES8326_HPF_OFFSET             4
+
 #define ES8326_ADC_AMIC	((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \
 		| (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT))
 #define ES8326_ADC_DMIC	((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index aaa6646..7d52b5d 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -727,12 +727,19 @@ static int es8328_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 es8328_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops es8328_dai_ops = {
 	.startup	= es8328_startup,
 	.hw_params	= es8328_hw_params,
 	.mute_stream	= es8328_mute,
 	.set_sysclk	= es8328_set_sysclk,
 	.set_fmt	= es8328_set_dai_fmt,
+	.auto_selectable_formats	= &es8328_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/es8375.c b/sound/soc/codecs/es8375.c
index e8747bc..80707d2 100644
--- a/sound/soc/codecs/es8375.c
+++ b/sound/soc/codecs/es8375.c
@@ -494,11 +494,23 @@ static int es8375_mute(struct snd_soc_dai *dai, int mute, int stream)
 #define es8375_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 es8375_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops es8375_ops = {
 	.hw_params = es8375_hw_params,
 	.mute_stream = es8375_mute,
 	.set_sysclk = es8375_set_sysclk,
 	.set_fmt = es8375_set_dai_fmt,
+	.auto_selectable_formats = &es8375_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver es8375_dai = {
@@ -577,20 +589,24 @@ static int es8375_resume(struct snd_soc_component *component)
 {
 	struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
+	int ret;
 
 	regcache_cache_only(es8375->regmap, false);
 	regcache_cache_bypass(es8375->regmap, true);
-	regmap_read(es8375->regmap, ES8375_CLK_MGR2, &reg);
+	ret = regmap_read(es8375->regmap, ES8375_CLK_MGR2, &reg);
 	regcache_cache_bypass(es8375->regmap, false);
+	if (ret)
+		return ret;
 
-	if (reg == 0x00)
+	if (reg == 0x00) {
 		es8375_init(component);
-	else
-		es8375_set_bias_level(component, SND_SOC_BIAS_ON);
+	} else {
+		ret = es8375_set_bias_level(component, SND_SOC_BIAS_ON);
+		if (ret)
+			return ret;
+	}
 
-	regcache_sync(es8375->regmap);
-
-	return 0;
+	return regcache_sync(es8375->regmap);
 }
 
 static int es8375_codec_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 2ea0c40..fe341fe 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -910,6 +910,13 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
 #define es8389_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 es8389_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops es8389_ops = {
 	.hw_params = es8389_pcm_hw_params,
 	.hw_free = es8389_pcm_hw_free,
@@ -917,6 +924,8 @@ static const struct snd_soc_dai_ops es8389_ops = {
 	.set_sysclk = es8389_set_dai_sysclk,
 	.set_tdm_slot = es8389_set_tdm_slot,
 	.mute_stream = es8389_mute,
+	.auto_selectable_formats = &es8389_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver es8389_dai = {
@@ -1032,20 +1041,28 @@ static int es8389_resume(struct snd_soc_component *component)
 {
 	struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
 	unsigned int regv;
+	int ret;
 
 	regcache_cache_only(es8389->regmap, false);
 	regcache_cache_bypass(es8389->regmap, true);
-	regmap_read(es8389->regmap, ES8389_RESET, &regv);
+	ret = regmap_read(es8389->regmap, ES8389_RESET, &regv);
+	if (ret)
+		goto disable_bypass;
 
-	if (regv == 0xff)
+	if (regv == 0xff) {
 		es8389_init(component);
-	else
-		es8389_set_bias_level(component, SND_SOC_BIAS_ON);
+	} else {
+		ret = es8389_set_bias_level(component, SND_SOC_BIAS_ON);
+		if (ret)
+			goto disable_bypass;
+	}
 
+disable_bypass:
 	regcache_cache_bypass(es8389->regmap, false);
-	regcache_sync(es8389->regmap);
+	if (ret)
+		return ret;
 
-	return 0;
+	return regcache_sync(es8389->regmap);
 }
 
 static int es8389_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c
index 510cbee..316f3fe 100644
--- a/sound/soc/codecs/fs210x.c
+++ b/sound/soc/codecs/fs210x.c
@@ -610,8 +610,9 @@ static int fs210x_init_chip(struct fs210x_priv *fs210x)
 	if (!ret) {
 		regcache_cache_only(fs210x->regmap, false);
 		regcache_mark_dirty(fs210x->regmap);
-		regcache_sync(fs210x->regmap);
-		fs210x->is_inited = true;
+		ret = regcache_sync(fs210x->regmap);
+		if (!ret)
+			fs210x->is_inited = true;
 	}
 
 	return ret;
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index 237b0b0..0846591 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -85,12 +85,11 @@ static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_compo
 	struct snd_soc_dai_driver *drvs = NULL;
 	struct snd_soc_dapm_context *dapm;
 	struct hda_pcm *pcm;
-	int ret, pcm_count = 0;
+	int ret, pcm_count;
 
-	if (list_empty(&codec->pcm_list_head))
+	pcm_count = list_count_nodes(&codec->pcm_list_head);
+	if (!pcm_count)
 		return -EINVAL;
-	list_for_each_entry(pcm, &codec->pcm_list_head, list)
-		pcm_count++;
 
 	ret = hda_codec_create_dais(codec, pcm_count, &drvs);
 	if (ret < 0)
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 1c06fdb..7414be0 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -520,7 +520,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 	/*
 	 * hdac_device core already sets the state to active and calls
 	 * get_noresume. So enable runtime and set the device to suspend.
-	 * pm_runtime_enable is also called during codec registeration
+	 * pm_runtime_enable is also called during codec registration
 	 */
 	pm_runtime_put(&hdev->dev);
 	pm_runtime_suspend(&hdev->dev);
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index d9e6fa6..b3f677e7 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1753,7 +1753,7 @@ static int hdmi_codec_resume(struct device *dev)
 	/*
 	 * As the ELD notify callback request is not entertained while the
 	 * device is in suspend state. Need to manually check detection of
-	 * all pins here. pin capablity change is not support, so use the
+	 * all pins here. pin capability change is not support, so use the
 	 * already set pin caps.
 	 *
 	 * NOTE: this is safe to call even if the codec doesn't actually resume.
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index fdd19f8e..aaf03f2 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -309,9 +309,21 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
 			   SNDRV_PCM_FMTBIT_S24_LE  | \
 			   SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 rk3036_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rk3036_codec_dai_ops = {
 	.set_fmt	= rk3036_codec_dai_set_fmt,
 	.hw_params	= rk3036_codec_dai_hw_params,
+	.auto_selectable_formats	= &rk3036_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index fa1c23d..7e8dde7 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1011,10 +1011,17 @@ static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 #define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 isabelle_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_PDM;
+
 static const struct snd_soc_dai_ops isabelle_hs_dai_ops = {
 	.hw_params	= isabelle_hw_params,
 	.set_fmt	= isabelle_set_dai_fmt,
 	.mute_stream	= isabelle_hs_mute,
+	.auto_selectable_formats	= &isabelle_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1022,6 +1029,8 @@ static const struct snd_soc_dai_ops isabelle_hf_dai_ops = {
 	.hw_params	= isabelle_hw_params,
 	.set_fmt	= isabelle_set_dai_fmt,
 	.mute_stream	= isabelle_hf_mute,
+	.auto_selectable_formats	= &isabelle_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1029,12 +1038,16 @@ static const struct snd_soc_dai_ops isabelle_line_dai_ops = {
 	.hw_params	= isabelle_hw_params,
 	.set_fmt	= isabelle_set_dai_fmt,
 	.mute_stream	= isabelle_line_mute,
+	.auto_selectable_formats	= &isabelle_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
 static const struct snd_soc_dai_ops isabelle_ul_dai_ops = {
 	.hw_params	= isabelle_hw_params,
 	.set_fmt	= isabelle_set_dai_fmt,
+	.auto_selectable_formats	= &isabelle_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 /* ISABELLE dai structure */
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 6e2e292..991555b 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1283,11 +1283,18 @@ static int lm49453_set_bias_level(struct snd_soc_component *component,
 #define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 lm49453_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops lm49453_headset_dai_ops = {
 	.hw_params	= lm49453_hw_params,
 	.set_sysclk	= lm49453_set_dai_sysclk,
 	.set_fmt	= lm49453_set_dai_fmt,
 	.mute_stream	= lm49453_hp_mute,
+	.auto_selectable_formats	= &lm49453_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1296,6 +1303,8 @@ static const struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
 	.set_sysclk	= lm49453_set_dai_sysclk,
 	.set_fmt	= lm49453_set_dai_fmt,
 	.mute_stream	= lm49453_ls_mute,
+	.auto_selectable_formats	= &lm49453_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1304,6 +1313,8 @@ static const struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
 	.set_sysclk	= lm49453_set_dai_sysclk,
 	.set_fmt	= lm49453_set_dai_fmt,
 	.mute_stream	= lm49453_ha_mute,
+	.auto_selectable_formats	= &lm49453_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1312,6 +1323,8 @@ static const struct snd_soc_dai_ops lm49453_ep_dai_ops = {
 	.set_sysclk	= lm49453_set_dai_sysclk,
 	.set_fmt	= lm49453_set_dai_fmt,
 	.mute_stream	= lm49453_ep_mute,
+	.auto_selectable_formats	= &lm49453_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1320,6 +1333,8 @@ static const struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
 	.set_sysclk	= lm49453_set_dai_sysclk,
 	.set_fmt	= lm49453_set_dai_fmt,
 	.mute_stream	= lm49453_lo_mute,
+	.auto_selectable_formats	= &lm49453_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 282a6aaa..c41eb8d 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -1673,7 +1673,7 @@ static const struct regmap_config rx_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 32, /* 8 but with 32 bit read/write */
 	.reg_stride = 4,
-	.cache_type = REGCACHE_FLAT,
+	.cache_type = REGCACHE_MAPLE,
 	.max_register = RX_MAX_OFFSET,
 	.writeable_reg = rx_is_writeable_register,
 	.volatile_reg = rx_is_volatile_register,
@@ -3732,8 +3732,8 @@ static int rx_macro_register_mclk_output(struct rx_macro *rx)
 	struct device *dev = rx->dev;
 	const char *parent_clk_name = NULL;
 	const char *clk_name = "lpass-rx-mclk";
+	struct clk_init_data init = {};
 	struct clk_hw *hw;
-	struct clk_init_data init;
 	int ret;
 
 	if (rx->npl)
@@ -3852,6 +3852,8 @@ static int rx_macro_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+	regcache_sort_defaults(reg_defaults, def_count);
+
 	struct regmap_config *reg_config __free(kfree) = kmemdup(&rx_regmap_config,
 								 sizeof(*reg_config),
 								 GFP_KERNEL);
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index a8e83eb..6deaaab 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -602,7 +602,7 @@ static const struct regmap_config tx_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 32,
 	.reg_stride = 4,
-	.cache_type = REGCACHE_FLAT,
+	.cache_type = REGCACHE_MAPLE,
 	.max_register = TX_MAX_OFFSET,
 	.reg_defaults = tx_defaults,
 	.num_reg_defaults = ARRAY_SIZE(tx_defaults),
@@ -2210,8 +2210,8 @@ static int tx_macro_register_mclk_output(struct tx_macro *tx)
 	struct device *dev = tx->dev;
 	const char *parent_clk_name = NULL;
 	const char *clk_name = "lpass-tx-mclk";
+	struct clk_init_data init = {};
 	struct clk_hw *hw;
-	struct clk_init_data init;
 	int ret;
 
 	if (tx->npl)
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index dbc5795..03d6434 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -454,7 +454,7 @@ static const struct regmap_config va_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
 	.reg_stride = 4,
-	.cache_type = REGCACHE_FLAT,
+	.cache_type = REGCACHE_MAPLE,
 	.reg_defaults = va_defaults,
 	.num_reg_defaults = ARRAY_SIZE(va_defaults),
 	.max_register = VA_MAX_OFFSET,
@@ -1414,7 +1414,7 @@ static int va_macro_register_fsgen_output(struct va_macro *va)
 	struct device_node *np = dev->of_node;
 	const char *parent_clk_name;
 	const char *clk_name = "fsgen";
-	struct clk_init_data init;
+	struct clk_init_data init = {};
 	int ret;
 
 	if (va->has_npl_clk)
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index cfd2ac0..42423666 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -1109,7 +1109,7 @@ static const struct regmap_config wsa_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 32, /* 8 but with 32 bit read/write */
 	.reg_stride = 4,
-	.cache_type = REGCACHE_FLAT,
+	.cache_type = REGCACHE_MAPLE,
 	/* .reg_defaults and .num_reg_defaults set in probe() */
 	.max_register = WSA_MAX_OFFSET,
 	.writeable_reg = wsa_is_writeable_register,
@@ -1129,27 +1129,35 @@ static const struct regmap_config wsa_regmap_config = {
 int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode)
 {
 	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	unsigned int comp1_ctl3, comp1_ctl7;
+	u8 comp_val, boost_val;
 
 	wsa->spkr_mode = mode;
 
-	switch (mode) {
-	case WSA_MACRO_SPKR_MODE_1:
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00);
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00);
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00);
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00);
-		snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44);
-		snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44);
-		break;
-	default:
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80);
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80);
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01);
-		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01);
-		snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58);
-		snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58);
-		break;
+	/* Compander1 CTL3/CTL7 moved on v2.5+ silicon. */
+	if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5) {
+		comp1_ctl3 = CDC_2_5_WSA_COMPANDER1_CTL3;
+		comp1_ctl7 = CDC_2_5_WSA_COMPANDER1_CTL7;
+	} else {
+		comp1_ctl3 = CDC_WSA_COMPANDER1_CTL3;
+		comp1_ctl7 = CDC_WSA_COMPANDER1_CTL7;
 	}
+
+	if (mode == WSA_MACRO_SPKR_MODE_1) {
+		comp_val = 0x00;
+		boost_val = 0x44;
+	} else {
+		comp_val = 0x80;
+		boost_val = 0x58;
+	}
+
+	snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, comp_val);
+	snd_soc_component_update_bits(component, comp1_ctl3, 0x80, comp_val);
+	snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, comp_val ? 0x01 : 0x00);
+	snd_soc_component_update_bits(component, comp1_ctl7, 0x01, comp_val ? 0x01 : 0x00);
+	snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, boost_val);
+	snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, boost_val);
+
 	return 0;
 }
 EXPORT_SYMBOL(wsa_macro_set_spkr_mode);
@@ -2638,10 +2646,10 @@ static const struct clk_ops swclk_gate_ops = {
 
 static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
 {
+	struct clk_init_data init = {};
 	struct device *dev = wsa->dev;
 	const char *parent_clk_name;
 	struct clk_hw *hw;
-	struct clk_init_data init;
 	int ret;
 
 	if (wsa->npl)
@@ -2755,6 +2763,8 @@ static int wsa_macro_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+	regcache_sort_defaults(reg_defaults, def_count);
+
 	struct regmap_config *reg_config __free(kfree) = kmemdup(&wsa_regmap_config,
 								 sizeof(*reg_config),
 								 GFP_KERNEL);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index df438ba..1dd7881 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1342,11 +1342,21 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
 #define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
 #define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 max98088_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max98088_dai1_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai1_set_fmt,
        .hw_params = max98088_dai1_hw_params,
        .mute_stream = max98088_dai1_mute,
+       .auto_selectable_formats = &max98088_selectable_formats,
+       .num_auto_selectable_formats = 1,
        .no_capture_mute = 1,
 };
 
@@ -1355,6 +1365,8 @@ static const struct snd_soc_dai_ops max98088_dai2_ops = {
        .set_fmt = max98088_dai2_set_fmt,
        .hw_params = max98088_dai2_hw_params,
        .mute_stream = max98088_dai2_mute,
+       .auto_selectable_formats = &max98088_selectable_formats,
+       .num_auto_selectable_formats = 1,
        .no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 64dc442..c31f3d3 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2382,6 +2382,29 @@ static int max98090_set_jack(struct snd_soc_component *component,
 #define MAX98090_RATES SNDRV_PCM_RATE_8000_96000
 #define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 max98090_selectable_formats[] = {
+	/*
+	 * Non RIGHT_J formats doesn't have 24bit support.
+	 * priority is RIGHT_J > I2S/LEFT_J/DSP_A
+	 * see
+	 *	max98090_dai_startup()
+	 */
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+};
+
 static const struct snd_soc_dai_ops max98090_dai_ops = {
 	.startup = max98090_dai_startup,
 	.set_sysclk = max98090_dai_set_sysclk,
@@ -2390,6 +2413,8 @@ static const struct snd_soc_dai_ops max98090_dai_ops = {
 	.hw_params = max98090_dai_hw_params,
 	.mute_stream = max98090_dai_mute,
 	.trigger = max98090_dai_trigger,
+	.auto_selectable_formats = max98090_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(max98090_selectable_formats),
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index d934360..a64a5ba 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -1413,22 +1413,36 @@ static int max98095_set_bias_level(struct snd_soc_component *component,
 #define MAX98095_RATES SNDRV_PCM_RATE_8000_96000
 #define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 max98095_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max98095_dai1_ops = {
 	.set_sysclk = max98095_dai_set_sysclk,
 	.set_fmt = max98095_dai1_set_fmt,
 	.hw_params = max98095_dai1_hw_params,
+	.auto_selectable_formats = &max98095_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static const struct snd_soc_dai_ops max98095_dai2_ops = {
 	.set_sysclk = max98095_dai_set_sysclk,
 	.set_fmt = max98095_dai2_set_fmt,
 	.hw_params = max98095_dai2_hw_params,
+	.auto_selectable_formats = &max98095_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static const struct snd_soc_dai_ops max98095_dai3_ops = {
 	.set_sysclk = max98095_dai_set_sysclk,
 	.set_fmt = max98095_dai3_set_fmt,
 	.hw_params = max98095_dai3_hw_params,
+	.auto_selectable_formats = &max98095_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver max98095_dai[] = {
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index c8d4c68..b62bd98 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -322,9 +322,16 @@ static const struct snd_soc_dapm_route max98371_audio_map[] = {
 #define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
 		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
+static const u64 max98371_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops max98371_dai_ops = {
 	.set_fmt = max98371_dai_set_fmt,
 	.hw_params = max98371_dai_hw_params,
+	.auto_selectable_formats = &max98371_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver max98371_dai[] = {
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index cbd7ebf..4e52282a 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -398,10 +398,20 @@ static int max98373_dai_tdm_slot(struct snd_soc_dai *dai,
 #define MAX98373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 max98373_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops max98373_dai_ops = {
 	.set_fmt = max98373_dai_set_fmt,
 	.hw_params = max98373_dai_hw_params,
 	.set_tdm_slot = max98373_dai_tdm_slot,
+	.auto_selectable_formats = &max98373_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static bool max98373_readable_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
index d97dab4..a653e0a 100644
--- a/sound/soc/codecs/max98388.c
+++ b/sound/soc/codecs/max98388.c
@@ -776,10 +776,20 @@ static int max98388_dai_tdm_slot(struct snd_soc_dai *dai,
 #define MAX98388_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 max98388_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops max98388_dai_ops = {
 	.set_fmt = max98388_dai_set_fmt,
 	.hw_params = max98388_dai_hw_params,
 	.set_tdm_slot = max98388_dai_tdm_slot,
+	.auto_selectable_formats = &max98388_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static bool max98388_readable_register(struct device *dev,
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 2295fc0..b87cca2a 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -462,11 +462,21 @@ static int max98390_dai_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 max98390_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops max98390_dai_ops = {
 	.set_sysclk = max98390_dai_set_sysclk,
 	.set_fmt = max98390_dai_set_fmt,
 	.hw_params = max98390_dai_hw_params,
 	.set_tdm_slot = max98390_dai_tdm_slot,
+	.auto_selectable_formats = &max98390_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static int max98390_dac_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index e5a2fe8..935319f 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -790,10 +790,22 @@ static int max98396_dai_tdm_slot(struct snd_soc_dai *dai,
 #define MAX98396_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 max98396_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max98396_dai_ops = {
 	.set_fmt = max98396_dai_set_fmt,
 	.hw_params = max98396_dai_hw_params,
 	.set_tdm_slot = max98396_dai_tdm_slot,
+	.auto_selectable_formats = &max98396_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static int max98396_dac_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 9bd6a61..c229b73 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -254,10 +254,21 @@ static int max9850_set_bias_level(struct snd_soc_component *component,
 #define MAX9850_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 max9850_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max9850_dai_ops = {
 	.hw_params	= max9850_hw_params,
 	.set_sysclk	= max9850_set_dai_sysclk,
 	.set_fmt	= max9850_set_dai_fmt,
+	.auto_selectable_formats	= &max9850_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver max9850_dai = {
diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c
index 4fb9850..57759d8 100644
--- a/sound/soc/codecs/max98520.c
+++ b/sound/soc/codecs/max98520.c
@@ -326,10 +326,20 @@ static int max98520_dai_tdm_slot(struct snd_soc_dai *dai,
 #define MAX98520_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 max98520_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops max98520_dai_ops = {
 	.set_fmt = max98520_dai_set_fmt,
 	.hw_params = max98520_dai_hw_params,
 	.set_tdm_slot = max98520_dai_tdm_slot,
+	.auto_selectable_formats = &max98520_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static int max98520_dac_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 20e288e..35265c250 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -459,9 +459,32 @@ static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 }
 
+static const u64 max9860_selectable_formats[] = {
+	/*
+	 * DSP_A/B has some limitations.
+	 * priority is I2S/LEFT_J > DSP_A/B
+	 * see
+	 *	max9860_hw_params()
+	 */
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops max9860_dai_ops = {
 	.hw_params = max9860_hw_params,
 	.set_fmt = max9860_set_fmt,
+	.auto_selectable_formats = max9860_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(max9860_selectable_formats),
 };
 
 static struct snd_soc_dai_driver max9860_dai = {
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 07a53ec..f2214e3 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -522,12 +522,22 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
+static const u64 max9867_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max9867_dai_ops = {
 	.set_sysclk	= max9867_set_dai_sysclk,
 	.set_fmt	= max9867_dai_set_fmt,
 	.mute_stream	= max9867_mute,
 	.startup	= max9867_startup,
 	.hw_params	= max9867_dai_hw_params,
+	.auto_selectable_formats	= &max9867_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index 4302ab1..fe43ef9 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -484,10 +484,18 @@ static int max98925_dai_set_sysclk(struct snd_soc_dai *dai,
 #define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 max98925_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max98925_dai_ops = {
 	.set_sysclk = max98925_dai_set_sysclk,
 	.set_fmt = max98925_dai_set_fmt,
 	.hw_params = max98925_dai_hw_params,
+	.auto_selectable_formats = &max98925_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver max98925_dai[] = {
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 51a30c1..5b590a1 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -448,9 +448,17 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
 #define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 max98926_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops max98926_dai_ops = {
 	.set_fmt = max98926_dai_set_fmt,
 	.hw_params = max98926_dai_hw_params,
+	.auto_selectable_formats = &max98926_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver max98926_dai[] = {
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 524300d..285c9d1 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -463,11 +463,21 @@ static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 max98927_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops max98927_dai_ops = {
 	.set_sysclk = max98927_dai_set_sysclk,
 	.set_fmt = max98927_dai_set_fmt,
 	.hw_params = max98927_dai_hw_params,
 	.set_tdm_slot = max98927_dai_tdm_slot,
+	.auto_selectable_formats = &max98927_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static int max98927_dac_event(struct snd_soc_dapm_widget *w,
@@ -662,7 +672,7 @@ static int max98927_probe(struct snd_soc_component *component)
 		     0x80);
 	regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
 		     0x1);
-	/* Set inital volume (+13dB) */
+	/* Set initial volume (+13dB) */
 	regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38);
 	regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05);
 	/* Enable DC blocker */
@@ -860,7 +870,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
 	/* voltage/current slot configuration */
 	max98927_slot_config(i2c, max98927);
 
-	/* codec registeration */
+	/* codec registration */
 	ret = devm_snd_soc_register_component(&i2c->dev,
 		&soc_component_dev_max98927,
 		max98927_dai, ARRAY_SIZE(max98927_dai));
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 086ac97..a6231a1 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -637,11 +637,21 @@ static void mc13783_remove(struct snd_soc_component *component)
 #define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 mc13783_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops mc13783_ops_dac = {
 	.hw_params	= mc13783_pcm_hw_params_dac,
 	.set_fmt	= mc13783_set_fmt_async,
 	.set_sysclk	= mc13783_set_sysclk_dac,
 	.set_tdm_slot	= mc13783_set_tdm_slot_dac,
+	.auto_selectable_formats	= &mc13783_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops mc13783_ops_codec = {
@@ -649,6 +659,8 @@ static const struct snd_soc_dai_ops mc13783_ops_codec = {
 	.set_fmt	= mc13783_set_fmt_async,
 	.set_sysclk	= mc13783_set_sysclk_codec,
 	.set_tdm_slot	= mc13783_set_tdm_slot_codec,
+	.auto_selectable_formats	= &mc13783_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 /*
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 7209b47..a94a3f9 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -492,11 +492,17 @@ static int ml26124_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 ml26124_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops ml26124_dai_ops = {
 	.hw_params	= ml26124_hw_params,
 	.mute_stream	= ml26124_mute,
 	.set_fmt	= ml26124_set_dai_fmt,
 	.set_sysclk	= ml26124_set_dai_sysclk,
+	.auto_selectable_formats	= &ml26124_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c
index b15bdb1..c51eae60 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -82,7 +82,7 @@ static void mt6359_reset_capture_gpio(struct mt6359_priv *priv)
 			   0x3 << 0, 0x0);
 }
 
-/* use only when doing mtkaif calibraiton at the boot time */
+/* use only when doing mtkaif calibration at the boot time */
 static void mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
 {
 	regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
@@ -90,7 +90,7 @@ static void mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
 			   (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
 }
 
-/* use only when doing mtkaif calibraiton at the boot time */
+/* use only when doing mtkaif calibration at the boot time */
 static void mt6359_set_clksq(struct mt6359_priv *priv, bool enable)
 {
 	/* Enable/disable CLKSQ 26MHz */
@@ -99,7 +99,7 @@ static void mt6359_set_clksq(struct mt6359_priv *priv, bool enable)
 			   (enable ? 1 : 0) << RG_CLKSQ_EN_SFT);
 }
 
-/* use only when doing mtkaif calibraiton at the boot time */
+/* use only when doing mtkaif calibration at the boot time */
 static void mt6359_set_aud_global_bias(struct mt6359_priv *priv, bool enable)
 {
 	regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13,
@@ -107,7 +107,7 @@ static void mt6359_set_aud_global_bias(struct mt6359_priv *priv, bool enable)
 			   (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA32_SFT);
 }
 
-/* use only when doing mtkaif calibraiton at the boot time */
+/* use only when doing mtkaif calibration at the boot time */
 static void mt6359_set_topck(struct mt6359_priv *priv, bool enable)
 {
 	regmap_update_bits(priv->regmap, MT6359_AUD_TOP_CKPDN_CON0,
diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c
index 236d94c..2c95ed0 100644
--- a/sound/soc/codecs/nau8325.c
+++ b/sound/soc/codecs/nau8325.c
@@ -628,10 +628,21 @@ static const struct snd_soc_component_driver nau8325_component_driver = {
 	.num_dapm_routes = ARRAY_SIZE(nau8325_dapm_routes),
 };
 
+static const u64 nau8325_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops nau8325_dai_ops = {
 	.startup = nau8325_dai_startup,
 	.hw_params = nau8325_hw_params,
 	.set_fmt = nau8325_set_fmt,
+	.auto_selectable_formats = &nau8325_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define NAU8325_RATES SNDRV_PCM_RATE_8000_96000
diff --git a/sound/soc/codecs/nau8360-dsp.c b/sound/soc/codecs/nau8360-dsp.c
new file mode 100644
index 0000000..65ffec8
--- /dev/null
+++ b/sound/soc/codecs/nau8360-dsp.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// The NAU83G60 Stereo Class-D Amplifier with DSP and I/V-sense driver.
+//
+// Copyright (C) 2026 Nuvoton Technology Corp.
+// Author: David Lin <ctlin0@nuvoton.com>
+//         Seven Lee <wtli@nuvoton.com>
+//         John Hsu <kchsu0@nuvoton.com>
+//         Neo Chang <ylchang2@nuvoton.com>
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
+#include <sound/soc.h>
+
+#include "nau8360-dsp.h"
+#include "nau8360.h"
+
+#define NAU8360_DSP_IDLE_RETRY 10
+static const unsigned short nau8360_dsp_addr[NAU8360_DSP_FW_NUM] = {
+	NAU8360_RF000_DSP_COMM, NAU8360_RF002_DSP_COMM };
+
+static int nau8360_dsp_chan_kcs_setup(struct snd_soc_component *cp,
+	const char *fw_name, int dsp_addr);
+
+#define NAU_DSP_CMD(_id, _msg, _setup, _reply) \
+	[_id] = { \
+		.cmd_id = _id, \
+		.msg_param = _msg, \
+		.setup_data = _setup, \
+		.reply_data = _reply, \
+	}
+
+#define NAU_DSP_CMD_ID(_id) \
+	[_id] = { \
+		.cmd_id = _id, \
+	}
+
+/*
+ * Preamble Fragment Masks:
+ * FIELD           | BITS   | SHIFT | MASK | DETAILS
+ * ----------------|--------|-------|------|---------------------------------
+ * length high     | [31:24]| 24    | 0xff | Upper 8 bits of total length (LEN[9:2])
+ * cmd_id          | [23:18]| 18    | 0x3f | Command identifier (6 bits)
+ * length low      | [17:16]| 16    | 0x03 | Lower 2 bits of total length (LEN[1:0])
+ * preamble magic  | [15:0] | 0     |0xffff| Preamble signature (0xB2A1)
+ */
+#define NAU8360_HOST_LEN_HIGH_MASK	GENMASK(31, 24)
+#define NAU8360_HOST_CMD_ID_MASK	GENMASK(23, 18)
+#define NAU8360_HOST_LEN_LOW_MASK	GENMASK(17, 16)
+#define NAU8360_HOST_PREAMBLE_MASK	GENMASK(15, 0)
+
+/*
+ * Payload Fragment Masks:
+ * FIELD           | BITS   | SHIFT | MASK | DETAILS
+ * ----------------|--------|-------|------|---------------------------------
+ * param_size      | [31:16]| 16    |0xffff| Size of parameter data (16 bits)
+ * param_offset    | [15:0] | 0     |0xffff| Starting offset (16 bits)
+ */
+#define NAU8360_HOST_PARAM_SIZE_MASK	GENMASK(31, 16)
+#define NAU8360_HOST_PARAM_OFFSET_MASK	GENMASK(15, 0)
+
+/*
+ * Trailing Fragment Masks:
+ * FIELD           | BITS   | SHIFT | MASK | DETAILS
+ * ----------------|--------|-------|------|---------------------------------
+ * length high     | [15:14]| 14    | 0x03 | Upper 2 bits of total length
+ * padding         | [13:12]| 12    | 0x03 | Padding bytes count
+ * length low      | [7:0]  | 0     | 0xff | Lower 8 bits of total length
+ * Note: Reassembled length = (length_high << 8) | length_low (Total 10 bits)
+ */
+#define NAU8360_TRAIL_LEN_LOW_MASK	GENMASK(7, 0)
+#define NAU8360_TRAIL_PAD_MASK		GENMASK(13, 12)
+#define NAU8360_TRAIL_LEN_HIGH_MASK	GENMASK(15, 14)
+
+/*
+ * Reply Preamble Masks:
+ * FIELD           | BITS   | SHIFT | MASK | DETAILS
+ * ----------------|--------|-------|------|---------------------------------
+ * length high     | [31:24]| 24    | 0xff | Upper 8 bits of total length
+ * reply_id        | [23:18]| 18    | 0x3f | Reply identifier (6 bits)
+ * length low      | [17:16]| 16    | 0x03 | Lower 2 bits of total length
+ * Note: Reassembled length = (length_high << 2) | length_low (Total 10 bits)
+ */
+#define NAU8360_REPLY_LEN_HIGH_MASK	GENMASK(31, 24)
+#define NAU8360_REPLY_ID_MASK		GENMASK(23, 18)
+#define NAU8360_REPLY_LEN_LOW_MASK	GENMASK(17, 16)
+
+static const struct nau8360_cmd_info nau8360_dsp_cmd_table[] = {
+	/* { cmd_id, msg_param, setup_data, reply_data} */
+	NAU_DSP_CMD(NAU8360_DSP_CMD_GET_COUNTER,      0, 0, 1),
+	NAU_DSP_CMD(NAU8360_DSP_CMD_GET_FRAME_STATUS, 0, 0, 1),
+	NAU_DSP_CMD(NAU8360_DSP_CMD_GET_REVISION,     0, 0, 1),
+	NAU_DSP_CMD(NAU8360_DSP_CMD_GET_KCS_RSLTS,    1, 0, 1),
+	NAU_DSP_CMD(NAU8360_DSP_CMD_GET_KCS_SETUP,    1, 0, 1),
+	NAU_DSP_CMD(NAU8360_DSP_CMD_SET_KCS_SETUP,    1, 1, 0),
+	NAU_DSP_CMD_ID(NAU8360_DSP_CMD_CLK_STOP),
+	NAU_DSP_CMD_ID(NAU8360_DSP_CMD_CLK_RESTART),
+};
+
+static const char *const dsp_cmd_table[] = {
+	[NAU8360_DSP_CMD_GET_COUNTER] = "GET_COUNTER",
+	[NAU8360_DSP_CMD_GET_FRAME_STATUS] = "GET_FRAME_STATUS",
+	[NAU8360_DSP_CMD_GET_REVISION] = "GET_REVISION",
+	[NAU8360_DSP_CMD_GET_KCS_RSLTS] = "GET_KCS_RSLTS",
+	[NAU8360_DSP_CMD_GET_KCS_SETUP] = "GET_KCS_SETUP",
+	[NAU8360_DSP_CMD_SET_KCS_SETUP] = "SET_KCS_SETUP",
+	[NAU8360_DSP_CMD_CLK_STOP] = "CLK_STOP",
+	[NAU8360_DSP_CMD_CLK_RESTART] = "CLK_RESTART",
+};
+
+static int nau8360_dsp_idle(struct snd_soc_component *cp, unsigned short dsp_addr)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	unsigned int idle_pattern, timeout = NAU8360_DSP_IDLE_RETRY * USEC_PER_MSEC;
+	int ret = 0;
+
+	ret = regmap_read_poll_timeout(nau8360->regmap, dsp_addr, idle_pattern,
+		idle_pattern == NAU8360_DSP_COMM_IDLE_WORD, USEC_PER_MSEC, timeout);
+	if (ret)
+		dev_err(nau8360->dev, "Timeout waiting for DSP idle state: %d", ret);
+
+	return ret;
+}
+
+/**
+ * nau8360_pack_preamble - Pack DSP preamble fragment
+ * @cmd_id: Command ID for the DSP message
+ * @frag_len: Total length of the message fragments
+ *
+ * Return: 32-bit packed payload in Little Endian format.
+ */
+static inline u32 nau8360_pack_preamble(u8 cmd_id, u16 frag_len)
+{
+	return FIELD_PREP(NAU8360_HOST_PREAMBLE_MASK, NAU8360_DSP_COMM_PREAMBLE) |
+		FIELD_PREP(NAU8360_HOST_CMD_ID_MASK, cmd_id) |
+		FIELD_PREP(NAU8360_HOST_LEN_LOW_MASK, frag_len) |
+		FIELD_PREP(NAU8360_HOST_LEN_HIGH_MASK, frag_len >> 2);
+}
+
+/**
+ * nau8360_pack_param - Pack DSP parameter fragment
+ * @param_offset: Starting offset of the parameter data
+ * @param_size: Size of the parameter data in bytes
+ *
+ * Return: 32-bit packed payload in Little Endian format.
+ */
+static inline u32 nau8360_pack_param(u16 param_offset, u16 param_size)
+{
+	return FIELD_PREP(NAU8360_HOST_PARAM_OFFSET_MASK, param_offset) |
+		FIELD_PREP(NAU8360_HOST_PARAM_SIZE_MASK, param_size);
+}
+
+/**
+ * nau8360_pack_trailing - Pack DSP trailing fragment
+ * @frag_cnt: Current fragment count
+ * @padding: Number of padding bytes added to the final data fragment
+ *
+ * Return: 32-bit packed payload in Little Endian format.
+ */
+static inline u32 nau8360_pack_trailing(u16 frag_cnt, u8 padding)
+{
+	return FIELD_PREP(NAU8360_TRAIL_LEN_LOW_MASK, frag_cnt) |
+		FIELD_PREP(NAU8360_TRAIL_PAD_MASK, padding) |
+		FIELD_PREP(NAU8360_TRAIL_LEN_HIGH_MASK, frag_cnt >> 8);
+}
+
+static void nau8360_send_data_payload(struct snd_soc_component *cp,
+	unsigned short dsp_addr, const void *param_data, int param_size,
+	int *frag_cnt, int *padding)
+{
+	const u8 *data = (const u8 *)param_data;
+	u32 payload = 0;
+	int i, data_size = 0;
+
+	for (i = 0; i < param_size; i++) {
+		payload |= data[i] << (data_size * 8);
+		data_size++;
+
+		if (data_size == NAU8360_DSP_DATA_BYTE) {
+			snd_soc_component_write(cp, dsp_addr, payload);
+			data_size = 0;
+			payload = 0;
+			(*frag_cnt)++;
+		}
+	}
+
+	if (data_size > 0) {
+		*padding = NAU8360_DSP_DATA_BYTE - data_size;
+		snd_soc_component_write(cp, dsp_addr, payload);
+		(*frag_cnt)++;
+	}
+}
+
+static int nau8360_message_to_dsp(struct snd_soc_component *cp,
+	const struct nau8360_cmd_info *cmd_info, int frag_len, int param_offset,
+	int param_size, void *param_data, unsigned short dsp_addr)
+{
+	unsigned int payload;
+	int ret, padding = 0, frag_cnt = 0;
+
+	ret = nau8360_dsp_idle(cp, dsp_addr);
+	if (ret)
+		return ret;
+
+	/* sending preamble fragment */
+	payload = nau8360_pack_preamble(cmd_info->cmd_id, frag_len);
+	snd_soc_component_write(cp, dsp_addr, payload);
+
+	if (!cmd_info->msg_param)
+		return 0;
+
+	/* sending payload + padding */
+	payload = nau8360_pack_param(param_offset, param_size);
+	snd_soc_component_write(cp, dsp_addr, payload);
+	frag_cnt++;
+
+	if (cmd_info->setup_data)
+		nau8360_send_data_payload(cp, dsp_addr, param_data, param_size,
+			&frag_cnt, &padding);
+
+	/* sending trailing fragment */
+	frag_cnt++;
+	payload = nau8360_pack_trailing(frag_cnt, padding);
+	snd_soc_component_write(cp, dsp_addr, payload);
+
+	if (frag_cnt != frag_len) {
+		dev_err(cp->dev, "message error (CMD_ID 0x%x, LEN 0x%x) !!!",
+			cmd_info->cmd_id, frag_cnt);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int nau8360_dsp_replied(struct nau8360 *nau8360, int *length,
+	unsigned short dsp_addr)
+{
+	unsigned int reply_preamble;
+	int ret, reply_id;
+
+	ret = regmap_read_poll_timeout(nau8360->regmap, dsp_addr, reply_preamble,
+		(reply_preamble & 0xffff) == NAU8360_DSP_COMM_PREAMBLE,
+		USEC_PER_MSEC, NAU8360_DSP_IDLE_RETRY * USEC_PER_MSEC);
+	if (ret) {
+		dev_err(nau8360->dev, "timeout for reply preamble: %d", ret);
+		return ret;
+	}
+
+	*length = FIELD_GET(NAU8360_REPLY_LEN_LOW_MASK, reply_preamble);
+	*length |= FIELD_GET(NAU8360_REPLY_LEN_HIGH_MASK, reply_preamble) << 2;
+	reply_id = FIELD_GET(NAU8360_REPLY_ID_MASK, reply_preamble);
+
+	return (reply_id != NAU8360_DSP_REPLY_OK) ? -reply_id : 0;
+}
+
+static int nau8360_validate_trailing(struct snd_soc_component *cp,
+	unsigned short dsp_addr, int frag_len, int pad_len_exp)
+{
+	int ret, len_pos, pad_len;
+	unsigned int payload;
+	struct device *dev = cp->dev;
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+
+	/* reading trailing fragment */
+	ret = regmap_read(nau8360->regmap, dsp_addr, &payload);
+	if (ret) {
+		dev_err(dev, "failed to read trailing fragment");
+		return ret;
+	}
+
+	len_pos = FIELD_GET(NAU8360_TRAIL_LEN_LOW_MASK, payload);
+	len_pos |= FIELD_GET(NAU8360_TRAIL_LEN_HIGH_MASK, payload) << 8;
+
+	if (len_pos != frag_len) {
+		dev_err(dev, "LEN_POST %02X, expect %02X", len_pos, frag_len);
+		return -EPROTO;
+	}
+
+	pad_len = FIELD_GET(NAU8360_TRAIL_PAD_MASK, payload);
+	if (pad_len != pad_len_exp) {
+		dev_err(dev, "PAD_LEN %02X, expect %02X", pad_len, pad_len_exp);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int nau8360_read_data_payload(struct snd_soc_component *cp,
+	unsigned short dsp_addr, int frag_len, bool msg_param,
+	void *data, int data_size, int *data_count)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct device *dev = cp->dev;
+	unsigned int payload;
+	u32 *data_buf = data;
+	int i, j, ret;
+
+	*data_count = (msg_param) ? data_size : 0;
+	for (i = 0; i < frag_len - 1; i++) {
+		ret = regmap_read(nau8360->regmap, dsp_addr, &payload);
+		if (ret) {
+			dev_err(dev, "failed to read payload of dsp");
+			return ret;
+		}
+
+		if (!msg_param) {
+			*data_buf++ = payload;
+			break;
+		}
+
+		if (*data_count >= NAU8360_DSP_DATA_BYTE) {
+			*data_buf++ = payload;
+			*data_count -= NAU8360_DSP_DATA_BYTE;
+		} else if (*data_count > 0) {
+			for (j = 0; j < *data_count; j++)
+				((u8 *)data_buf)[j] = (payload >> (j * 8)) & 0xff;
+
+			*data_count = 0;
+		}
+
+		if (*data_count == 0)
+			break;
+	}
+
+	return 0;
+}
+
+static int nau8360_reply_from_dsp(struct snd_soc_component *cp,
+	const struct nau8360_cmd_info *cmd_info, int data_size,
+	void *data, unsigned short dsp_addr)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct device *dev = cp->dev;
+	int ret, frag_len, pad_len_exp, data_count = 0;
+
+	ret = nau8360_dsp_replied(nau8360, &frag_len, dsp_addr);
+	if (ret)
+		return ret;
+	if (!frag_len || !cmd_info->reply_data)
+		return 0;
+	if (!data || frag_len == 1)
+		return -EINVAL;
+
+	ret = nau8360_read_data_payload(cp, dsp_addr, frag_len,
+		cmd_info->msg_param, data, data_size, &data_count);
+	if (ret)
+		return ret;
+
+	/* check the reply length same as request */
+	if (data_count && (cmd_info->cmd_id == NAU8360_DSP_CMD_GET_KCS_RSLTS ||
+		cmd_info->cmd_id == NAU8360_DSP_CMD_GET_KCS_SETUP))
+		dev_warn(dev, "payload_len %d, expected %d",
+			data_size - data_count, data_size);
+
+	pad_len_exp = cmd_info->msg_param ?
+		(frag_len - 1) * NAU8360_DSP_DATA_BYTE - (data_size - data_count) : 0;
+	return nau8360_validate_trailing(cp, dsp_addr, frag_len, pad_len_exp);
+}
+
+/**
+ * nau8360_send_dsp_command - Send command to DSP
+ *
+ * @cp:  component to register
+ * @cmd_id:  DSP supported command ID
+ * @kcs_setup: KCS setup structure
+ * @dsp_addr: DSP address
+ *
+ * The communication protocol is a Master-Slave type protocol
+ * where the host processor is the master and DSP is the slave.
+ * The Master initiates the communication and can either write or
+ * read back from the slave.
+ * Transactions from the Master are called "Messages",
+ * and read-back data from the Slave is called a "Reply".
+ *
+ * The function sends command to DSP according to the command ID.
+ * These commands include getting the information of DSP,
+ * getting or setting KCS configuration, or making DSP control.
+ */
+static int nau8360_send_dsp_command(struct snd_soc_component *cp, int cmd_id,
+	struct nau8360_kcs_setup *kcs_setup, unsigned short dsp_addr)
+{
+	const struct nau8360_cmd_info *cmd_info;
+	int ret = 0, frag_len = 0;
+
+	cmd_info = &nau8360_dsp_cmd_table[cmd_id];
+	if ((cmd_info->msg_param && !kcs_setup->set_len) ||
+		(cmd_info->setup_data && !kcs_setup->set_kcs_data) ||
+		(cmd_info->reply_data && !kcs_setup->get_data))
+		return -EFAULT;
+
+	/* Read up to 1kB data because the LEN field to request data is 10-bits
+	 * long; and not beyond 3kB offset.
+	 */
+	if (cmd_id == NAU8360_DSP_CMD_GET_KCS_SETUP &&
+		(kcs_setup->set_len > NAU8360_DSP_KCS_DAT_LEN_MAX ||
+		kcs_setup->set_kcs_offset > NAU8360_DSP_KCS_OFFSET_MAX))
+		return -ERANGE;
+
+	/* one fragment for offset and size parameters
+	 * one fragment for a postamble fragment
+	 */
+	if (cmd_info->msg_param)
+		frag_len += 2;
+
+	/* fragments for KCS setup writen */
+	if (cmd_info->setup_data)
+		frag_len += DIV_ROUND_UP(kcs_setup->set_len, NAU8360_DSP_DATA_BYTE);
+
+	ret = nau8360_message_to_dsp(cp, cmd_info, frag_len,
+		kcs_setup->set_kcs_offset, kcs_setup->set_len,
+		kcs_setup->set_kcs_data, dsp_addr);
+	if (ret)
+		return ret;
+
+	return nau8360_reply_from_dsp(cp, cmd_info, kcs_setup->get_len,
+		kcs_setup->get_data, dsp_addr);
+}
+
+static inline int nau8360_dsp_exec_command(struct snd_soc_component *cp, int cmd_id,
+	int offset, int set_len, void *set_data, int get_len, void *get_data,
+	int dsp_addr)
+{
+	struct nau8360_kcs_setup kcs_setup = {
+		.set_kcs_offset = offset,
+		.set_len = set_len,
+		.set_kcs_data = set_data,
+		.get_len = get_len,
+		.get_data = get_data,
+	};
+
+	return nau8360_send_dsp_command(cp, cmd_id, &kcs_setup, dsp_addr);
+}
+
+static inline int nau8360_send_dsp_broadcast(struct snd_soc_component *cp, int cmd_id)
+{
+	int i, ret;
+
+	for (i = 0; i < NAU8360_DSP_FW_NUM; i++) {
+		ret = nau8360_dsp_exec_command(cp, cmd_id, 0, 0, NULL, 0, NULL,
+			nau8360_dsp_addr[i]);
+		if (ret) {
+			dev_err(cp->dev, "DSP %x fail (%d)", nau8360_dsp_addr[i], ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * nau8360_dsp_kcs_setup - Send KCS setup command to DSP
+ *
+ * @cp:  component to register
+ * @offset: address offset relative to KCS start
+ * @size: size of data writen to KCS
+ * @data: data writen to KCS setup
+ * @dsp_addr : DSP address
+ *
+ * The function sends KCS setup command to DSP for
+ * setting KCS configuration. The maximum size that you can transfer into
+ * the DSP is 96 bytes. Therefore, the driver has to split the data into
+ * 96 bytes chucks, if the setup configuration over the threshold.
+ */
+static int nau8360_dsp_kcs_setup(struct snd_soc_component *cp, int offset, int size,
+	const void *data, unsigned short dsp_addr)
+{
+	u8 *data_buf = (u8 *)data;
+	unsigned int kcs_rst = 0;
+	int retries = 0, ret, data_len, data_rem, addr_offset;
+
+	/* Limit full load of KCS_SETUP data and not beyond 3kB offset. */
+	if (!data || size > NAU8360_DSP_KCS_DAT_LEN_MAX ||
+		offset > NAU8360_DSP_KCS_OFFSET_MAX)
+		return -EINVAL;
+
+	/* sending fragments for KCS setup */
+	addr_offset = offset;
+	data_rem = size;
+
+	while (data_rem) {
+		data_len = min(data_rem, NAU8360_DSP_KCS_TX_MAX);
+
+		ret = nau8360_dsp_exec_command(cp, NAU8360_DSP_CMD_SET_KCS_SETUP,
+			addr_offset, data_len, (void *)data_buf, 0, &kcs_rst, dsp_addr);
+		if (ret) {
+			if (retries++ < NAU8360_DSP_RETRY_MAX)
+				continue;
+			return ret;
+		}
+
+		data_buf += (u8)data_len;
+		addr_offset += data_len;
+		data_rem -= data_len;
+
+		/* checking KCS result */
+		ret = nau8360_dsp_exec_command(cp, NAU8360_DSP_CMD_GET_KCS_RSLTS,
+			0, NAU8360_DSP_DATA_BYTE, NULL,
+			NAU8360_DSP_DATA_BYTE, &kcs_rst, dsp_addr);
+		if (ret)
+			return ret;
+		if (kcs_rst != NAU8360_DSP_KCS_RSLTS_SUCCESS)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8360_dsp_get_cmd_put(struct snd_soc_component *cp,
+	int dsp_addr, int cmd, int *value)
+{
+	struct device *dev = cp->dev;
+	int ret;
+
+	dev_dbg(dev, "send DSP %x command %s", dsp_addr, dsp_cmd_table[cmd]);
+
+	ret = nau8360_dsp_exec_command(cp, cmd, 0, sizeof(int), NULL,
+		sizeof(int), value, dsp_addr);
+	if (ret) {
+		dev_err(dev, "do command fail (%d)", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int nau8360_dsp_clock_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *cp = snd_soc_dapm_to_component(w->dapm);
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	int ret = 0;
+
+	mutex_lock(&nau8360->lock);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		ret = nau8360_send_dsp_broadcast(cp, NAU8360_DSP_CMD_CLK_RESTART);
+	else if (SND_SOC_DAPM_EVENT_OFF(event))
+		ret = nau8360_send_dsp_broadcast(cp, NAU8360_DSP_CMD_CLK_STOP);
+
+	mutex_unlock(&nau8360->lock);
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget nau8360_dsp_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("DSP Clock", SND_SOC_NOPM, 0, 0, nau8360_dsp_clock_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route nau8360_dsp_dapm_routes[] = {
+	{ "DSP", NULL, "HW3 Engine" },
+	{ "DSP", NULL, "DSP Clock" },
+};
+
+static int nau8360_dsp_chan_kcs_setup(struct snd_soc_component *cp,
+	const char *fw_name, int dsp_addr)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	const struct firmware *fw;
+	int buf_off, buf_len;
+	int ret = 0, status = 0;
+
+	mutex_lock(&nau8360->lock);
+	ret = nau8360_dsp_get_cmd_put(cp, dsp_addr,
+		NAU8360_DSP_CMD_GET_FRAME_STATUS, &status);
+	mutex_unlock(&nau8360->lock);
+	if (ret || !(status & NAU8360_DSP_ALGO_OK)) {
+		dev_err(cp->dev, "DSP %x is not ready", dsp_addr);
+		return -EIO;
+	}
+
+	dev_info(cp->dev, "DSP %x is ready to load firmware %s, status %x",
+		dsp_addr, fw_name, status);
+
+	ret = request_firmware(&fw, fw_name, cp->dev);
+	if (ret) {
+		dev_err(cp->dev, "failed to load firmware (%d)", ret);
+		return ret;
+	}
+
+	buf_off = 0;
+	buf_len = nau8360->kcs_setup_size = fw->size;
+	mutex_lock(&nau8360->lock);
+	ret = nau8360_dsp_kcs_setup(cp, buf_off, buf_len, fw->data, dsp_addr);
+	mutex_unlock(&nau8360->lock);
+	if (ret) {
+		dev_err(cp->dev, "send DSP command %s fail (%d)",
+			dsp_cmd_table[NAU8360_DSP_CMD_SET_KCS_SETUP], ret);
+	}
+	release_firmware(fw);
+
+	return ret;
+}
+
+int nau8360_dsp_init(struct snd_soc_component *cp)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	int i, ret;
+
+	for (i = 0; i < NAU8360_DSP_FW_NUM; i++) {
+		ret = nau8360_dsp_chan_kcs_setup(cp, nau8360->dsp_firmware[i], nau8360_dsp_addr[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int nau8360_dsp_setup_controls(struct snd_soc_component *cp)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct snd_soc_dapm_context *dapm = nau8360->dapm;
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, nau8360_dsp_dapm_widgets,
+			ARRAY_SIZE(nau8360_dsp_dapm_widgets));
+	if (ret) {
+		dev_err(cp->dev, "add DSP widget fail (%d)", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dapm_add_routes(dapm, nau8360_dsp_dapm_routes,
+			ARRAY_SIZE(nau8360_dsp_dapm_routes));
+	if (ret) {
+		dev_err(cp->dev, "add DSP route fail (%d)", ret);
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/sound/soc/codecs/nau8360-dsp.h b/sound/soc/codecs/nau8360-dsp.h
new file mode 100644
index 0000000..f8c2c97
--- /dev/null
+++ b/sound/soc/codecs/nau8360-dsp.h
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// The NAU83G60 Stereo Class-D Amplifier with DSP and I/V-sense driver.
+//
+// Copyright (C) 2026 Nuvoton Technology Corp.
+// Author: David Lin <ctlin0@nuvoton.com>
+//         Seven Lee <wtli@nuvoton.com>
+//         John Hsu <kchsu0@nuvoton.com>
+//         Neo Chang <ylchang2@nuvoton.com>
+
+#ifndef __NAU8360_DSP_H__
+#define __NAU8360_DSP_H__
+
+#define NAU8360_DSP_COMM_IDLE_WORD		0xf4f3f2f1
+#define NAU8360_DSP_COMM_PREAMBLE		0xb2a1
+#define NAU8360_DSP_DATA_BYTE			4
+#define NAU8360_DSP_DATA_LEN			(NAU8360_DSP_DATA_BYTE << 3)
+/* max bytes of data to transfer into DSP each time during the KCS setup */
+#define NAU8360_DSP_KCS_TX_MAX			96
+#define NAU8360_DSP_RETRY_MAX			3
+#define NAU8360_DSP_KCS_DAT_LEN_MAX		1024
+#define NAU8360_DSP_KCS_OFFSET_MAX		3072
+#define NAU8360_DSP_KCS_RSLTS_SUCCESS	0x10
+
+/* FRAME_STATUS (0x9) */
+#define NAU8360_DSP_SNS_OVF_SFT			31
+#define NAU8360_DSP_SNS_OVF			(0x1 << NAU8360_DSP_SNS_OVF_SFT)
+#define NAU8360_DSP_AUD_UVF_SFT			30
+#define NAU8360_DSP_AUD_UVF			(0x1 << NAU8360_DSP_AUD_UVF_SFT)
+#define NAU8360_DSP_AUD_OVF_SFT			29
+#define NAU8360_DSP_AUD_OVF			(0x1 << NAU8360_DSP_AUD_OVF_SFT)
+#define NAU8360_DSP_ALC_STS_SFT			28
+#define NAU8360_DSP_ALC_STS			(0x1 << NAU8360_DSP_ALC_STS_SFT)
+#define NAU8360_DSP_CLK_STOP_SFT		25
+#define NAU8360_DSP_CLK_STOP			(0x1 << NAU8360_DSP_CLK_STOP_SFT)
+#define NAU8360_DSP_OCP_OTP_SFT			24
+#define NAU8360_DSP_OCP_OTP			(0x1 << NAU8360_DSP_OCP_OTP_SFT)
+#define NAU8360_DSP_UVLO_SFT			22
+#define NAU8360_DSP_UVLO			(0x1 << NAU8360_DSP_UVLO_SFT)
+#define NAU8360_DSP_OVP_SFT			21
+#define NAU8360_DSP_OVP				(0x1 << NAU8360_DSP_OVP_SFT)
+#define NAU8360_DSP_APWR_DWN_SFT		20
+#define NAU8360_DSP_APWR_DWN			(0x1 << NAU8360_DSP_APWR_DWN_SFT)
+#define NAU8360_DSP_SNSR_RATE_SFT		12
+#define NAU8360_DSP_SNSR_RATE_MASK		(0xff << NAU8360_DSP_SNSR_RATE_SFT)
+#define NAU8360_DSP_AUD_RATE_SFT		4
+#define NAU8360_DSP_AUD_RATE_MASK		(0xff << NAU8360_DSP_AUD_RATE_SFT)
+#define NAU8360_DSP_FEED_TRU_SFT		1
+#define NAU8360_DSP_FEED_TRU			(0x1 << NAU8360_DSP_FEED_TRU_SFT)
+#define NAU8360_DSP_ALGO_OK			0x1
+
+#define NAU8360_DSP_FIRMDIR			"Nuvoton/"
+#define NAU8360_DSP_FIRMWARE			NAU8360_DSP_FIRMDIR"NAU83G60.kcs.bin"
+#define NAU8360_DSP_FW_NUM			NAU8360_DSP_CORE_NUM
+#define NAU8360_DSP_FW_NAMELEN			64
+#define NAU8360_IS_DSP_REG(reg) \
+	((reg) == NAU8360_RF000_DSP_COMM || (reg) == NAU8360_RF002_DSP_COMM)
+
+enum {
+	NAU8360_DSP_REPLY_OK,
+	NAU8360_DSP_REPLY_MSG_INTEGRETY_ERR,
+	NAU8360_DSP_REPLY_EXECUTION_ERR,
+	NAU8360_DSP_REPLY_COMMAND_DOESNT_EXISTS_ERR,
+	NAU8360_DSP_REPLY_UNKNOWN_ERR,
+	NAU8360_DSP_REPLY_MSG_TOO_LONG,
+};
+
+enum {
+	NAU8360_DSP_CMD_GET_COUNTER	= 0x1,
+	NAU8360_DSP_CMD_GET_FRAME_STATUS	= 0x9,
+	NAU8360_DSP_CMD_GET_REVISION	= 0xa,
+	NAU8360_DSP_CMD_GET_KCS_RSLTS	= 0x4,
+	NAU8360_DSP_CMD_GET_KCS_SETUP	= 0x6,
+	NAU8360_DSP_CMD_SET_KCS_SETUP	= 0x7,
+	NAU8360_DSP_CMD_CLK_STOP	= 0xb,
+	NAU8360_DSP_CMD_CLK_RESTART	= 0xc,
+};
+
+/**
+ * struct nau8360_cmd_info - DSP command information structure
+ * @cmd_id:     The command identification number
+ * @msg_param:  Message parameters including offset, size, and data
+ * @setup_data: Setup data for write-only operations
+ * @reply_data: Reply data received from the DSP
+ */
+struct nau8360_cmd_info {
+	int cmd_id;
+	bool msg_param;
+	bool setup_data;
+	bool reply_data;
+};
+
+/**
+ * struct nau8360_kcs_setup - KCS setup configuration structure
+ * @set_len:        Length of data written in bytes
+ * @set_kcs_offset: Address offset relative to the start of KCS
+ * @set_kcs_data:   Pointer to the data written to KCS
+ * @get_len:        Length of data from the reply in bytes
+ * @get_data:       Pointer to the buffer for reply data
+ */
+struct nau8360_kcs_setup {
+	int set_len;
+	int set_kcs_offset;
+	void *set_kcs_data;
+	int get_len;
+	void *get_data;
+};
+
+/**
+ * struct nau8360_dsp_ctx - DSP context structure for firmware loading
+ * @cp:       Pointer to the ALSA SoC component structure
+ * @dsp_addr: Register address of the DSP core (Left or Right channel)
+ */
+struct nau8360_dsp_ctx {
+	struct snd_soc_component *cp;
+	int dsp_addr;
+};
+
+int nau8360_dsp_init(struct snd_soc_component *component);
+int nau8360_dsp_setup_controls(struct snd_soc_component *component);
+
+#endif /* __NAU8360_DSP_H__ */
diff --git a/sound/soc/codecs/nau8360.c b/sound/soc/codecs/nau8360.c
new file mode 100644
index 0000000..f094273
--- /dev/null
+++ b/sound/soc/codecs/nau8360.c
@@ -0,0 +1,2309 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// The NAU83G60 Stereo Class-D Amplifier with DSP and I/V-sense driver.
+//
+// Copyright (C) 2026 Nuvoton Technology Corp.
+// Author: David Lin <ctlin0@nuvoton.com>
+//         Seven Lee <wtli@nuvoton.com>
+//         John Hsu <kchsu0@nuvoton.com>
+//         Neo Chang <ylchang2@nuvoton.com>
+
+
+#include <linux/unaligned.h>
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/units.h>
+#include <linux/workqueue.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "nau8360-dsp.h"
+#include "nau8360.h"
+
+/* range of Master Clock MCLK (Hz) */
+#define MASTER_CLK_MIN 11025000
+#define MASTER_CLK_MAX 24576000
+/* DSP Optimal Clock Range 120MHz~126M(Hz) */
+#define DSP_OP_CLK48 122880000
+#define DSP_OP_CLK44 112896000
+/* the maximum frequency of DAC and IV sense clock */
+#define CLK_DA_IVSNS_MAX 6144000
+#define ADSP_SR_48000 48000
+#define ADSP_SR_44100 44100
+
+static const int ivsns_clk_div[] = { 1, 2, 4, 5, 8, 10 };
+
+static const int dac_clk_div[] = { 1, 2, 4, 8 };
+
+static const char * const nau8360_rx_func_names[] = {
+	[NAU8360_TDM_DACL] = "DAC_L",
+	[NAU8360_TDM_DACR] = "DAC_R",
+	[NAU8360_TDM_ANCL] = "ANC_L",
+	[NAU8360_TDM_ANCR] = "ANC_R",
+};
+
+static const char * const nau8360_tx_func_names[] = {
+	[NAU8360_TDM_AECL]  = "AEC_L",
+	[NAU8360_TDM_AECR]  = "AEC_R",
+	[NAU8360_TDM_ISNSL] = "ISNS_L",
+	[NAU8360_TDM_ISNSR] = "ISNS_R",
+	[NAU8360_TDM_VSNSL] = "VSNS_L",
+	[NAU8360_TDM_VSNSR] = "VSNS_R",
+	[NAU8360_TDM_TJ]    = "TJ",
+	[NAU8360_TDM_VBAT]  = "VBAT",
+};
+
+/* PLL threshold */
+#define PLL_FREQ_MIN 1000000
+#define PLL_FREQ_MAX 32000000
+#define PLL_FOUT_MIN 12500000
+#define PLL_FOUT_MAX 125000000
+#define PLL_FREF_MAX 8000000
+#define PLL_FVCO_MIN 50000000
+#define MSEL_MAX 32
+#define RSEL_MAX 4
+
+static const struct reg_default nau8360_reg_defaults[] = {
+	{ NAU8360_R02_I2C_ADDR, 0x0000 },
+	{ NAU8360_R03_CLK_CTRL0, 0x0000 },
+	{ NAU8360_R04_CLK_CTRL1, 0x0000 },
+	{ NAU8360_R05_INTERRUPT_CTRL, 0x40ff },
+	{ NAU8360_R07_GP_CTRL, 0xaa30 },
+	{ NAU8360_R08_GP_CTRL0, 0x1e1e },
+	{ NAU8360_R09_GP_CTRL1, 0x1e1e },
+	{ NAU8360_R0A_GP_CTRL2, 0x0000 },
+	{ NAU8360_R0B_I2S_PCM_CTRL1, 0x0702 },
+	{ NAU8360_R0C_I2S_PCM_CTRL2, 0x0a10 },
+	{ NAU8360_R0D_I2S_PCM_CTRL3, 0x1300 },
+	{ NAU8360_R0E_I2S_DATA_CTRL1, 0x0304 },
+	{ NAU8360_R0F_I2S_DATA_CTRL2, 0x080b },
+	{ NAU8360_R10_I2S_DATA_CTRL3, 0x0014 },
+	{ NAU8360_R11_I2S_DATA_CTRL4, 0x0014 },
+	{ NAU8360_R12_PATH_CTRL, 0x0400 },
+	{ NAU8360_R17_I2S0_DATA_CTRL5, 0x0014 },
+	{ NAU8360_R1A_DSP_CORE_CTRL2, 0x0010 },
+	{ NAU8360_R2C_ALC_CTRL1, 0x2000 },
+	{ NAU8360_R2D_ALC_CTRL2, 0x8400 },
+	{ NAU8360_R2E_ALC_CTRL3, 0x2083 },
+	{ NAU8360_R31_UVLOP_CTRL1, 0x0000 },
+	{ NAU8360_R32_UVLOP_CTRL2, 0x8400 },
+	{ NAU8360_R33_UVLOP_CTRL3, 0x0000 },
+	{ NAU8360_R40_CLK_DET_CTRL, 0xca60 },
+	{ NAU8360_R41_CLK_CTL2, 0xc400 },
+	{ NAU8360_R5D_SINC_CFG, 0x0010 },
+	{ NAU8360_R5F_ANA_TRIM_CFG1, 0x8400 },
+	{ NAU8360_R60_RST, 0x0010 },
+	{ NAU8360_R67_ANALOG_CONTROL_0, 0x0160 },
+	{ NAU8360_R68_ANALOG_CONTROL_1, 0x00d4 },
+	{ NAU8360_R6A_SARADC_CFG0, 0x5c09 },
+	{ NAU8360_R6B_SARADC_CFG1, 0x0008 },
+	{ NAU8360_R6C_IVSNS_CFG0, 0xf040 },
+	{ NAU8360_R6D_IVSNS_CFG1, 0x3555 },
+	{ NAU8360_R6E_DAC_CFG0, 0x0ed5 },
+	{ NAU8360_R71_CLK_DIV_CFG, 0x0211 },
+	{ NAU8360_R72_PLL_CFG0, 0xccc4 },
+	{ NAU8360_R73_PLL_CFG1, 0x0101 },
+	{ NAU8360_R74_PLL_CFG2, 0x0000 },
+	{ NAU8360_R7A_DAC_TRIM_CFG2, 0x0000 },
+	{ NAU8360_R7B_IVSNS_TRIM_CFG, 0x0000 },
+	{ NAU8360_R7C_MISC_TRIM_CFG, 0x72d5 },
+	{ NAU8360_R86_HW3_CTL0, 0x2000 },
+	{ NAU8360_R88_ALC_CTRL6, 0x0000 },
+	{ NAU8360_R8A_HW3_VL_CTL7, 0xc000 },
+	{ NAU8360_R8B_HW3_VR_CTL8, 0xc000 },
+	{ NAU8360_R8C_HW3_CTL6, 0x0000 },
+	{ NAU8360_R8D_HW3_IL_CTL7, 0xc000 },
+	{ NAU8360_R8E_HW3_IR_CTL8, 0xc000 },
+	{ NAU8360_R8F_HW3_CTL9, 0x0000 },
+	{ NAU8360_R90_HW2_CTL0, 0x2000 },
+	{ NAU8360_R96_HW2_CTL6, 0x0000 },
+	{ NAU8360_R97_HW2_CTL7, 0xc000 },
+	{ NAU8360_R98_HW2_CTL8, 0xc000 },
+	{ NAU8360_R99_HW2_CTL9, 0x0000 },
+	{ NAU8360_R9A_HW1_CTL0, 0xc000 },
+	{ NAU8360_R9B_HW1_CTL1, 0xc000 },
+	{ NAU8360_R9C_HW1_CTL2, 0x0800 },
+	{ NAU8360_R9D_PEQ_CTL, 0x0001 },
+	{ NAU8360_RA0_LEFT_XODRC_CTRL, 0x0000 },
+	{ NAU8360_RA2_RIGHT_XODRC_CTRL, 0x0000 },
+	{ NAU8360_RA4_ANA_REG_0, 0x7f86 },
+	{ NAU8360_RA5_ANA_REG_1, 0x276e },
+};
+
+static bool nau8360_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8360_R00_SOFTWARE_RST ... NAU8360_R12_PATH_CTRL:
+	case NAU8360_R17_I2S0_DATA_CTRL5:
+	case NAU8360_R1A_DSP_CORE_CTRL2:
+	case NAU8360_R21_VBAT_READOUT ... NAU8360_R22_TEMP_READOUT:
+	case NAU8360_R2C_ALC_CTRL1 ... NAU8360_R2E_ALC_CTRL3:
+	case NAU8360_R31_UVLOP_CTRL1 ... NAU8360_R33_UVLOP_CTRL3:
+	case NAU8360_R40_CLK_DET_CTRL ... NAU8360_R41_CLK_CTL2:
+	case NAU8360_R46_I2C_DEVICE_ID:
+	case NAU8360_R5D_SINC_CFG:
+	case NAU8360_R5F_ANA_TRIM_CFG1 ... NAU8360_R60_RST:
+	case NAU8360_R67_ANALOG_CONTROL_0 ... NAU8360_R6E_DAC_CFG0:
+	case NAU8360_R71_CLK_DIV_CFG ... NAU8360_R74_PLL_CFG2:
+	case NAU8360_R77_SOFT_SD ... NAU8360_R7C_MISC_TRIM_CFG:
+	case NAU8360_R7E_CLK_GATED_EN:
+	case NAU8360_R86_HW3_CTL0:
+	case NAU8360_R88_ALC_CTRL6:
+	case NAU8360_R8A_HW3_VL_CTL7 ... NAU8360_R90_HW2_CTL0:
+	case NAU8360_R96_HW2_CTL6 ... NAU8360_R9D_PEQ_CTL:
+	case NAU8360_RA0_LEFT_XODRC_CTRL:
+	case NAU8360_RA2_RIGHT_XODRC_CTRL:
+	case NAU8360_RA4_ANA_REG_0 ... NAU8360_RA5_ANA_REG_1:
+	case NAU8360_R100_LEFT_BIQ0_COE ... (NAU8360_R100_LEFT_BIQ0_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R10C_LEFT_BIQ1_COE ... (NAU8360_R10C_LEFT_BIQ1_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R118_LEFT_BIQ2_COE ... (NAU8360_R118_LEFT_BIQ2_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R124_LEFT_BIQ3_COE ... (NAU8360_R124_LEFT_BIQ3_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R130_LEFT_BIQ4_COE ... (NAU8360_R130_LEFT_BIQ4_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R13C_LEFT_BIQ5_COE ... (NAU8360_R13C_LEFT_BIQ5_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R148_LEFT_BIQ6_COE ... (NAU8360_R148_LEFT_BIQ6_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R154_LEFT_BIQ7_COE ... (NAU8360_R154_LEFT_BIQ7_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R160_LEFT_BIQ8_COE ... (NAU8360_R160_LEFT_BIQ8_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R16C_LEFT_BIQ9_COE ... (NAU8360_R16C_LEFT_BIQ9_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R178_LEFT_BIQ10_COE ... (NAU8360_R178_LEFT_BIQ10_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R184_LEFT_BIQ11_COE ... (NAU8360_R184_LEFT_BIQ11_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R190_LEFT_BIQ12_COE ... (NAU8360_R190_LEFT_BIQ12_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R19C_LEFT_BIQ13_COE ... (NAU8360_R19C_LEFT_BIQ13_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R1A8_LEFT_BIQ14_COE ... (NAU8360_R1A8_LEFT_BIQ14_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R200_RIGHT_BIQ0_COE ... (NAU8360_R200_RIGHT_BIQ0_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R20C_RIGHT_BIQ1_COE ... (NAU8360_R20C_RIGHT_BIQ1_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R218_RIGHT_BIQ2_COE ... (NAU8360_R218_RIGHT_BIQ2_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R224_RIGHT_BIQ3_COE ... (NAU8360_R224_RIGHT_BIQ3_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R230_RIGHT_BIQ4_COE ... (NAU8360_R230_RIGHT_BIQ4_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R23C_RIGHT_BIQ5_COE ... (NAU8360_R23C_RIGHT_BIQ5_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R248_RIGHT_BIQ6_COE ... (NAU8360_R248_RIGHT_BIQ6_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R254_RIGHT_BIQ7_COE ... (NAU8360_R254_RIGHT_BIQ7_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R260_RIGHT_BIQ8_COE ... (NAU8360_R260_RIGHT_BIQ8_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R26C_RIGHT_BIQ9_COE ... (NAU8360_R26C_RIGHT_BIQ9_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R278_RIGHT_BIQ10_COE ... (NAU8360_R278_RIGHT_BIQ10_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R284_RIGHT_BIQ11_COE ... (NAU8360_R284_RIGHT_BIQ11_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R290_RIGHT_BIQ12_COE ... (NAU8360_R290_RIGHT_BIQ12_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R29C_RIGHT_BIQ13_COE ... (NAU8360_R29C_RIGHT_BIQ13_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R2A8_RIGHT_BIQ14_COE ... (NAU8360_R2A8_RIGHT_BIQ14_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_RF000_DSP_COMM:
+	case NAU8360_RF002_DSP_COMM:
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+static bool nau8360_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8360_R00_SOFTWARE_RST ... NAU8360_R12_PATH_CTRL:
+	case NAU8360_R17_I2S0_DATA_CTRL5:
+	case NAU8360_R1A_DSP_CORE_CTRL2:
+	case NAU8360_R2C_ALC_CTRL1 ... NAU8360_R2E_ALC_CTRL3:
+	case NAU8360_R31_UVLOP_CTRL1 ... NAU8360_R33_UVLOP_CTRL3:
+	case NAU8360_R40_CLK_DET_CTRL ... NAU8360_R41_CLK_CTL2:
+	case NAU8360_R5D_SINC_CFG:
+	case NAU8360_R5F_ANA_TRIM_CFG1:
+	case NAU8360_R60_RST:
+	case NAU8360_R67_ANALOG_CONTROL_0 ... NAU8360_R68_ANALOG_CONTROL_1:
+	case NAU8360_R6A_SARADC_CFG0 ... NAU8360_R6E_DAC_CFG0:
+	case NAU8360_R71_CLK_DIV_CFG ... NAU8360_R74_PLL_CFG2:
+	case NAU8360_R77_SOFT_SD ... NAU8360_R7C_MISC_TRIM_CFG:
+	case NAU8360_R7E_CLK_GATED_EN:
+	case NAU8360_R86_HW3_CTL0:
+	case NAU8360_R88_ALC_CTRL6:
+	case NAU8360_R8A_HW3_VL_CTL7 ... NAU8360_R90_HW2_CTL0:
+	case NAU8360_R96_HW2_CTL6 ... NAU8360_R9D_PEQ_CTL:
+	case NAU8360_RA4_ANA_REG_0 ... NAU8360_RA5_ANA_REG_1:
+	case NAU8360_R100_LEFT_BIQ0_COE ... (NAU8360_R100_LEFT_BIQ0_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R10C_LEFT_BIQ1_COE ... (NAU8360_R10C_LEFT_BIQ1_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R118_LEFT_BIQ2_COE ... (NAU8360_R118_LEFT_BIQ2_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R124_LEFT_BIQ3_COE ... (NAU8360_R124_LEFT_BIQ3_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R130_LEFT_BIQ4_COE ... (NAU8360_R130_LEFT_BIQ4_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R13C_LEFT_BIQ5_COE ... (NAU8360_R13C_LEFT_BIQ5_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R148_LEFT_BIQ6_COE ... (NAU8360_R148_LEFT_BIQ6_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R154_LEFT_BIQ7_COE ... (NAU8360_R154_LEFT_BIQ7_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R160_LEFT_BIQ8_COE ... (NAU8360_R160_LEFT_BIQ8_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R16C_LEFT_BIQ9_COE ... (NAU8360_R16C_LEFT_BIQ9_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R178_LEFT_BIQ10_COE ... (NAU8360_R178_LEFT_BIQ10_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R184_LEFT_BIQ11_COE ... (NAU8360_R184_LEFT_BIQ11_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R190_LEFT_BIQ12_COE ... (NAU8360_R190_LEFT_BIQ12_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R19C_LEFT_BIQ13_COE ... (NAU8360_R19C_LEFT_BIQ13_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R1A8_LEFT_BIQ14_COE ... (NAU8360_R1A8_LEFT_BIQ14_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R200_RIGHT_BIQ0_COE ... (NAU8360_R200_RIGHT_BIQ0_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R20C_RIGHT_BIQ1_COE ... (NAU8360_R20C_RIGHT_BIQ1_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R218_RIGHT_BIQ2_COE ... (NAU8360_R218_RIGHT_BIQ2_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R224_RIGHT_BIQ3_COE ... (NAU8360_R224_RIGHT_BIQ3_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R230_RIGHT_BIQ4_COE ... (NAU8360_R230_RIGHT_BIQ4_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R23C_RIGHT_BIQ5_COE ... (NAU8360_R23C_RIGHT_BIQ5_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R248_RIGHT_BIQ6_COE ... (NAU8360_R248_RIGHT_BIQ6_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R254_RIGHT_BIQ7_COE ... (NAU8360_R254_RIGHT_BIQ7_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R260_RIGHT_BIQ8_COE ... (NAU8360_R260_RIGHT_BIQ8_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R26C_RIGHT_BIQ9_COE ... (NAU8360_R26C_RIGHT_BIQ9_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R278_RIGHT_BIQ10_COE ... (NAU8360_R278_RIGHT_BIQ10_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R284_RIGHT_BIQ11_COE ... (NAU8360_R284_RIGHT_BIQ11_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R290_RIGHT_BIQ12_COE ... (NAU8360_R290_RIGHT_BIQ12_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R29C_RIGHT_BIQ13_COE ... (NAU8360_R29C_RIGHT_BIQ13_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_R2A8_RIGHT_BIQ14_COE ... (NAU8360_R2A8_RIGHT_BIQ14_COE +
+					NAU8360_PEQ_REG_WIDTH):
+	case NAU8360_RF000_DSP_COMM:
+	case NAU8360_RF002_DSP_COMM:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8360_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8360_R00_SOFTWARE_RST ... NAU8360_R02_I2C_ADDR:
+	case NAU8360_R06_INT_CLR_STATUS:
+	case NAU8360_R21_VBAT_READOUT ... NAU8360_R22_TEMP_READOUT:
+	case NAU8360_R41_CLK_CTL2:
+	case NAU8360_R46_I2C_DEVICE_ID:
+	case NAU8360_R69_ANALOG_CONTROL_3:
+	case NAU8360_R77_SOFT_SD ... NAU8360_R79_EN_HIRC48M:
+	case NAU8360_R7E_CLK_GATED_EN:
+	case NAU8360_R9D_PEQ_CTL:
+	case NAU8360_RF000_DSP_COMM:
+	case NAU8360_RF002_DSP_COMM:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int nau8360_get_tdm_chan_len(struct nau8360 *nau8360)
+{
+	int val = 0;
+
+	regmap_read(nau8360->regmap, NAU8360_R0C_I2S_PCM_CTRL2, &val);
+	val = (val & NAU8360_TDM_CLEN_MASK) >> NAU8360_TDM_CLEN_SFT;
+
+	return (val << 3) + 16;
+}
+
+static inline bool nau8360_dsp_active(struct snd_soc_component *comp)
+{
+	return (snd_soc_component_read(comp, NAU8360_R12_PATH_CTRL) &
+		NAU8360_DAC_SEL_DSP);
+}
+
+static int nau8360_anc_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cp = snd_kcontrol_chip(kcontrol);
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	int ret, value = NAU8360_PEQ_BAND_8;
+
+	mutex_lock(&nau8360->lock);
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	/* update anc flag if return value 1 and register value changed */
+	if (ret != 1)
+		goto unlock;
+
+	nau8360->anc_enable = ucontrol->value.integer.value[0];
+	if (nau8360_dsp_active(cp))
+		value = nau8360->anc_enable ? NAU8360_PEQ_BAND_15 : NAU8360_PEQ_BAND_12;
+	regmap_update_bits(nau8360->regmap, NAU8360_R9D_PEQ_CTL, NAU8360_PEQ_BAND_MASK,
+		value << NAU8360_PEQ_BAND_SFT);
+
+unlock:
+	mutex_unlock(&nau8360->lock);
+
+	return ret;
+}
+
+static inline void nau8360_peq_mem_enable(struct regmap *regmap, bool enable)
+{
+	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL,
+		NAU8360_HW1_MEM_TEST, enable ? NAU8360_HW1_MEM_TEST : 0);
+}
+
+static inline int nau8360_peq_regaddr(const char *id_name)
+{
+	int reg, band_num, dsp_addr = NAU8360_DSP_ADDR_BYNAME(id_name);
+	char *band = strstr(id_name, "BIQ");
+
+	if (!band || kstrtoint((band + 3), 10, &band_num))
+		return -EINVAL;
+	reg = dsp_addr == NAU8360_RF000_DSP_COMM ? NAU8360_R100_LEFT_BIQ0_COE :
+		NAU8360_R200_RIGHT_BIQ0_COE;
+	reg += band_num * NAU8360_TOT_BAND_COE_RANGE;
+
+	return reg;
+}
+
+static int nau8360_peq_coeff_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cp = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cp);
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	int i, value, reg, ret = 0;
+	__be16 *val = (__be16 *)ucontrol->value.bytes.data;
+
+	/* Use the DAPM lock to prevent race conditions during DAPM power-up
+	 * state transitions, and check component active status to prohibit
+	 * PEQ access during active audio streams (playback and capture).
+	 */
+	snd_soc_dapm_mutex_lock(dapm);
+	if (snd_soc_component_active(cp)) {
+		dev_dbg(nau8360->dev,
+			"PEQ coefficient access is ignored during audio is active");
+		ret = -EBUSY;
+		goto unlock_dapm;
+	}
+
+	reg = nau8360_peq_regaddr(kcontrol->id.name);
+	if (reg < 0) {
+		ret = reg;
+		goto unlock_dapm;
+	}
+
+	mutex_lock(&nau8360->lock);
+	nau8360_peq_mem_enable(nau8360->regmap, true);
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		value = snd_soc_component_read(cp, reg + i);
+		*(val + i) = cpu_to_be16(value);
+	}
+	nau8360_peq_mem_enable(nau8360->regmap, false);
+	mutex_unlock(&nau8360->lock);
+
+unlock_dapm:
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
+}
+
+static int nau8360_peq_coeff_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cp = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cp);
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	int i, reg, ret = 0;
+	__be16 *data = NULL;
+	bool changed = false;
+
+	/* Use the DAPM lock to prevent race conditions during DAPM power-up
+	 * state transitions, and check component active status to prohibit
+	 * PEQ access during active audio streams (playback and capture).
+	 */
+	snd_soc_dapm_mutex_lock(dapm);
+	if (snd_soc_component_active(cp)) {
+		dev_dbg(nau8360->dev,
+			"PEQ coefficient access is ignored during audio is active");
+		ret = -EBUSY;
+		goto unlock_dapm;
+	}
+
+	reg = nau8360_peq_regaddr(kcontrol->id.name);
+	if (reg < 0) {
+		ret = reg;
+		goto unlock_dapm;
+	}
+
+	data = kmemdup(ucontrol->value.bytes.data, params->max, GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto unlock_dapm;
+	}
+
+	mutex_lock(&nau8360->lock);
+	nau8360_peq_mem_enable(nau8360->regmap, true);
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		if (snd_soc_component_read(cp, reg + i) != be16_to_cpu(*(data + i))) {
+			snd_soc_component_write(cp, reg + i, be16_to_cpu(*(data + i)));
+			changed = true;
+		}
+	}
+	nau8360_peq_mem_enable(nau8360->regmap, false);
+	mutex_unlock(&nau8360->lock);
+
+	ret = changed ? 1 : 0;
+
+unlock_dapm:
+	snd_soc_dapm_mutex_unlock(dapm);
+	kfree(data);
+
+	return ret;
+}
+
+#define NAU8360_PEQ_COEF_BYTES_EXT(ch, band) \
+	SND_SOC_BYTES_EXT(ch " PEQ Coefficients " band, 20, nau8360_peq_coeff_get, \
+		nau8360_peq_coeff_put)
+
+static const struct snd_kcontrol_new nau8360_snd_controls[] = {
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ0"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ1"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ2"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ3"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ4"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ5"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ6"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ7"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ8"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ9"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ10"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ11"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ12"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ13"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Left", "BIQ14"),
+
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ0"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ1"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ2"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ3"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ4"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ5"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ6"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ7"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ8"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ9"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ10"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ11"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ12"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ13"),
+	NAU8360_PEQ_COEF_BYTES_EXT("Right", "BIQ14"),
+	SOC_SINGLE("Low Latency Switch", NAU8360_R96_HW2_CTL6,
+		NAU8360_HW2_LATENCY_SFT, 1, 0),
+	SOC_SINGLE_EXT("ANC Path Switch", NAU8360_R96_HW2_CTL6, NAU8360_HW1_ANC_EN_SFT,
+		1, 0, snd_soc_get_volsw, nau8360_anc_put),
+};
+
+static int nau8360_adci_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);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_component_update_bits(component, NAU8360_R6C_IVSNS_CFG0,
+			NAU8360_PD_ISNS_R_PMD | NAU8360_PD_ISNS_L_PMD, 0);
+	else if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(component, NAU8360_R6C_IVSNS_CFG0,
+			NAU8360_PD_ISNS_R_PMD | NAU8360_PD_ISNS_L_PMD,
+			NAU8360_PD_ISNS_R_PMD | NAU8360_PD_ISNS_L_PMD);
+
+	return 0;
+}
+
+static int nau8360_adcv_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);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_component_update_bits(component, NAU8360_R6C_IVSNS_CFG0,
+			NAU8360_PD_VSNS_R_PMD | NAU8360_PD_VSNS_L_PMD, 0);
+	else if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(component, NAU8360_R6C_IVSNS_CFG0,
+			NAU8360_PD_VSNS_R_PMD | NAU8360_PD_VSNS_L_PMD,
+			NAU8360_PD_VSNS_R_PMD | NAU8360_PD_VSNS_L_PMD);
+
+	return 0;
+}
+
+static int nau8360_aif_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(component, NAU8360_R67_ANALOG_CONTROL_0,
+			NAU8360_HV_EN, 0);
+
+	return 0;
+}
+
+static int nau8360_hw1_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);
+
+	if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(component, NAU8360_R67_ANALOG_CONTROL_0,
+			NAU8360_ANA_MUTE, NAU8360_ANA_MUTE);
+
+	return 0;
+}
+
+static int nau8360_hw1_mux_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);
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, NAU8360_R68_ANALOG_CONTROL_1,
+			NAU8360_DRVCTL_SEGL_FULL | NAU8360_DRVCTL_SEGR_FULL, 0);
+		snd_soc_component_update_bits(component, NAU8360_RA5_ANA_REG_1,
+			NAU8360_CLASSD_SHT_IN | NAU8360_HVEN_SYNC_SAW,
+			NAU8360_CLASSD_SHT_IN | NAU8360_HVEN_SYNC_SAW);
+		msleep(20);
+	}
+
+	return 0;
+}
+
+static int nau8360_hw2_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);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(component, NAU8360_R99_HW2_CTL9,
+			NAU8360_HW2_CH_MUTE, 0);
+		snd_soc_component_update_bits(component, NAU8360_R9C_HW1_CTL2,
+			NAU8360_HW1_CH_MUTE, 0);
+	}
+
+	return 0;
+}
+
+static int nau8360_dac_power_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *cp = snd_soc_dapm_to_component(w->dapm);
+	unsigned int mask = 1 << w->shift;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_component_update_bits(cp, NAU8360_R6E_DAC_CFG0, mask, 0);
+	else if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(cp, NAU8360_R6E_DAC_CFG0, mask, mask);
+
+	return 0;
+}
+
+static int nau8360_hv_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);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* enable Class D HV power after DAC power is stable */
+		snd_soc_component_update_bits(component, NAU8360_R67_ANALOG_CONTROL_0,
+			NAU8360_HV_EN, NAU8360_HV_EN);
+		msleep(50);
+		/* Class D modulator input short setting for mute and de-pop purpose.
+		 * Restore normal after initiation. Set segment driver as full driving
+		 * strength.
+		 */
+		snd_soc_component_update_bits(component, NAU8360_RA5_ANA_REG_1,
+			NAU8360_CLASSD_SHT_IN | NAU8360_HVEN_SYNC_SAW, 0);
+		snd_soc_component_update_bits(component, NAU8360_R68_ANALOG_CONTROL_1,
+			NAU8360_DRVCTL_SEGL_FULL | NAU8360_DRVCTL_SEGR_FULL,
+			NAU8360_DRVCTL_SEGL_FULL | NAU8360_DRVCTL_SEGR_FULL);
+
+		snd_soc_component_update_bits(component, NAU8360_R67_ANALOG_CONTROL_0,
+			NAU8360_ANA_MUTE, 0);
+	} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, NAU8360_R9C_HW1_CTL2,
+			NAU8360_HW1_CH_MUTE, NAU8360_HW1_CH_MUTE);
+		snd_soc_component_update_bits(component, NAU8360_R99_HW2_CTL9,
+			NAU8360_HW2_CH_MUTE, NAU8360_HW2_CH_MUTE);
+	}
+
+	return 0;
+}
+
+static inline void nau8360_dsp_enable(struct regmap *regmap, bool enable)
+{
+	regmap_update_bits(regmap, NAU8360_R86_HW3_CTL0, NAU8360_HW3_STALL,
+		enable ? 0 : NAU8360_HW3_STALL);
+	regmap_update_bits(regmap, NAU8360_R1A_DSP_CORE_CTRL2, NAU8360_DSP_RUNSTALL,
+		enable ? 0 : NAU8360_DSP_RUNSTALL);
+}
+
+static void nau8360_dsp_switch(struct snd_soc_component *component, bool enable)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = nau8360->regmap;
+	int value = NAU8360_PEQ_BAND_8;
+
+	mutex_lock(&nau8360->lock);
+
+	/* If DSP is enabled, unstall HW3 engine and DSP, loading DSP firmware,
+	 * and configure PEQ after dsp reset.
+	 */
+	if (enable) {
+		value = nau8360->anc_enable ? NAU8360_PEQ_BAND_15 : NAU8360_PEQ_BAND_12;
+		nau8360_dsp_enable(regmap, true);
+	} else {
+		dev_dbg(nau8360->dev, "Bypass DSP path");
+		nau8360_dsp_enable(regmap, false);
+	}
+	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL, NAU8360_PEQ_BAND_MASK,
+		value << NAU8360_PEQ_BAND_SFT);
+
+	mutex_unlock(&nau8360->lock);
+}
+
+static int nau8360_dac_mux_put_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	int ret = 0;
+
+	snd_soc_dapm_mutex_lock(dapm);
+	if (snd_soc_dapm_get_bias_level(dapm) > SND_SOC_BIAS_STANDBY) {
+		dev_warn_ratelimited(nau8360->dev, "changing path is not allowed during playback");
+		snd_soc_dapm_mutex_unlock(dapm);
+		return -EBUSY;
+	}
+
+	if (item[0] == NAU8360_DAC_SRC_DSP && !nau8360->load_fw_done) {
+		dev_warn_ratelimited(nau8360->dev, "Cannot enable DSP: Firmware not ready or disabled\n");
+		snd_soc_dapm_mutex_unlock(dapm);
+		return -EBUSY;
+	}
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+	if (ret <= 0)
+		return ret;
+
+	nau8360_dsp_switch(component, snd_soc_enum_item_to_val(e, item[0]));
+
+	return ret;
+}
+
+/* Select HW1 output source (enables PEQ bypass) */
+static const char *const nau8360_hw1out_src[] = { "Audio", "PEQ" };
+
+static SOC_ENUM_SINGLE_DECL(nau8360_hw1out_enum, NAU8360_R12_PATH_CTRL,
+	NAU8360_SEL_HW1_SFT, nau8360_hw1out_src);
+
+static const struct snd_kcontrol_new nau8360_hw1out_mux =
+	SOC_DAPM_ENUM("HW1 Output Source", nau8360_hw1out_enum);
+
+/* Select DAC input source (enables DSP bypass) */
+static const char *const nau8360_dac_src[] = { "HW1", "DSP" };
+
+static SOC_ENUM_SINGLE_DECL(nau8360_dac_enum, NAU8360_R12_PATH_CTRL,
+	NAU8360_DAC_SEL_SFT, nau8360_dac_src);
+
+static const struct snd_kcontrol_new nau8360_dac_mux =
+	SOC_DAPM_ENUM_EXT("DAC Source", nau8360_dac_enum,
+		snd_soc_dapm_get_enum_double, nau8360_dac_mux_put_enum);
+
+static const struct snd_soc_dapm_widget nau8360_dapm_widgets[] = {
+	SND_SOC_DAPM_SIGGEN("Sense"),
+	SND_SOC_DAPM_ADC_E("ADC_I", NULL, SND_SOC_NOPM, 0, 0, nau8360_adci_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC_V", NULL, SND_SOC_NOPM, 0, 0, nau8360_adcv_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA("DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HW3 Engine", NAU8360_R8C_HW3_CTL6, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_AIF_IN_E("AIFRX", "Playback", 0, SND_SOC_NOPM, 0, 0,
+		nau8360_aif_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_S("HW1 Engine", 0, NAU8360_R9D_PEQ_CTL, 0, 1,
+		nau8360_hw1_event, SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("HW1 Mux", SND_SOC_NOPM, 0, 0, &nau8360_hw1out_mux,
+		nau8360_hw1_mux_event, SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &nau8360_dac_mux),
+
+	SND_SOC_DAPM_PGA_S("HW2 Engine", 1, NAU8360_R96_HW2_CTL6, 5, 0,
+		nau8360_hw2_event, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("DAC Clock", NAU8360_R71_CLK_DIV_CFG, 9, 1, NULL, 0),
+	SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM, NAU8360_PD_DACL_SFT, 0,
+		nau8360_dac_power_event, SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM, NAU8360_PD_DACR_SFT, 0,
+		nau8360_dac_power_event, SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_S("ADACL", 2, SND_SOC_NOPM, NAU8360_PD_DACL_SFT, 0,
+		nau8360_dac_power_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("ADACR", 2, SND_SOC_NOPM, NAU8360_PD_DACR_SFT, 0,
+		nau8360_dac_power_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("Class D", 3, SND_SOC_NOPM, 0, 0,
+		nau8360_hv_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("OUTL"),
+	SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route nau8360_dapm_routes[] = {
+	{ "ADC_I", NULL, "Sense" },
+	{ "ADC_V", NULL, "Sense" },
+	{ "HW3 Engine", NULL, "ADC_I" },
+	{ "HW3 Engine", NULL, "ADC_V" },
+	{ "Capture", NULL, "HW3 Engine" },
+
+	{ "HW1 Engine", NULL, "AIFRX" },
+	{ "HW1 Mux", "Audio", "AIFRX" },
+	{ "HW1 Mux", "PEQ", "HW1 Engine" },
+
+	{ "DSP", NULL, "HW1 Mux" },
+	{ "DAC Mux", "HW1", "HW1 Mux" },
+	{ "DAC Mux", "DSP", "DSP" },
+
+	{ "HW2 Engine", NULL, "DAC Mux" },
+	{ "DACL", NULL, "HW2 Engine" },
+	{ "DACR", NULL, "HW2 Engine" },
+	{ "DACL", NULL, "DAC Clock" },
+	{ "DACR", NULL, "DAC Clock" },
+
+	{ "ADACL", NULL, "DACL" },
+	{ "ADACR", NULL, "DACR" },
+	{ "Class D", NULL, "ADACL" },
+	{ "Class D", NULL, "ADACR" },
+
+	{ "OUTL", NULL, "Class D" },
+	{ "OUTR", NULL, "Class D" },
+};
+
+static int nau8360_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	unsigned int i2s_mask = NAU8360_FRAME_START_MASK | NAU8360_RX_OFFSET_MASK;
+	unsigned int i2s_fmt = NAU8360_FRAME_START_H2L | NAU8360_RX_OFFSET_I2S;
+	int val = 0;
+
+	flush_work(&nau8360->load_fw_work);
+
+	if (nau8360_dsp_active(component) && !nau8360->load_fw_done) {
+		dev_warn(nau8360->dev, "DSP firmware is not ready yet!");
+		return -EBUSY;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_read(nau8360->regmap, NAU8360_R0B_I2S_PCM_CTRL1, &val);
+		if ((val & i2s_mask) == i2s_fmt)
+			regmap_update_bits(nau8360->regmap, NAU8360_R0B_I2S_PCM_CTRL1,
+				NAU8360_EN_TDM_RX, NAU8360_EN_TDM_RX);
+
+		if (nau8360_dsp_active(component))
+			snd_soc_dapm_enable_pin(nau8360->dapm, "Sense");
+	}
+
+	return 0;
+}
+
+static void nau8360_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	unsigned int tdm_mask;
+
+	tdm_mask = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		NAU8360_EN_TDM_RX : NAU8360_EN_TDM_TX;
+	regmap_update_bits(nau8360->regmap, NAU8360_R0B_I2S_PCM_CTRL1,
+		tdm_mask, 0);
+	if (nau8360_dsp_active(component) &&
+		substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_dapm_disable_pin(nau8360->dapm, "Sense");
+}
+
+static int nau8360_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 nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len, val_srate;
+	int dlen = params_width(params);
+
+	if (dlen > nau8360_get_tdm_chan_len(nau8360)) {
+		dev_err(nau8360->dev, "Invalid data length");
+		return -EINVAL;
+	}
+
+	switch (dlen) {
+	case 16:
+		val_len = NAU8360_TDM_DLEN_16;
+		break;
+	case 20:
+		val_len = NAU8360_TDM_DLEN_20;
+		break;
+	case 24:
+		val_len = NAU8360_TDM_DLEN_24;
+		break;
+	case 32:
+		val_len = NAU8360_TDM_DLEN_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 16000:
+		val_srate = NAU8360_SRATE_16000;
+		break;
+	case 32000:
+		val_srate = NAU8360_SRATE_32000;
+		break;
+	case 44100:
+	case 48000:
+		val_srate = NAU8360_SRATE_48000;
+		break;
+	case 88200:
+	case 96000:
+		val_srate = NAU8360_SRATE_96000;
+		break;
+	case 176400:
+	case 192000:
+		val_srate = NAU8360_SRATE_192000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8360->regmap, NAU8360_R0C_I2S_PCM_CTRL2,
+		NAU8360_TDM_DLEN_MASK, val_len);
+	regmap_update_bits(nau8360->regmap, NAU8360_R40_CLK_DET_CTRL,
+		NAU8360_SRATE_MASK, val_srate);
+
+	return 0;
+}
+
+static int nau8360_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int ctrl_val, ctrl1_val;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl_val = NAU8360_FRAME_START_H2L | NAU8360_RX_OFFSET_I2S;
+		ctrl1_val = NAU8360_TX_OFFSET_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl_val = NAU8360_RX_OFFSET_LEFT | NAU8360_RX_LEFT_JUSTIFY;
+		ctrl1_val = NAU8360_TX_OFFSET_LEFT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl_val = NAU8360_RX_OFFSET_RIGHT | NAU8360_RX_RIGHT_JUSTIFY;
+		ctrl1_val = NAU8360_TX_OFFSET_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl_val = NAU8360_RX_OFFSET_PCM_A;
+		ctrl1_val = NAU8360_TX_OFFSET_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl_val = NAU8360_RX_OFFSET_PCM_B;
+		ctrl1_val = NAU8360_TX_OFFSET_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, NAU8360_R0B_I2S_PCM_CTRL1,
+		NAU8360_FRAME_START_MASK | NAU8360_RX_OFFSET_MASK |
+		NAU8360_RX_JUSTIFY_MASK, ctrl_val);
+	snd_soc_component_update_bits(component, NAU8360_R0D_I2S_PCM_CTRL3,
+		NAU8360_TX_OFFSET_MASK, ctrl1_val);
+	return 0;
+}
+
+static void nau8360_set_tdm_rx_slot(struct snd_soc_component *cp, int type, int slot)
+{
+	switch (type) {
+	case NAU8360_TDM_DACL:
+		snd_soc_component_update_bits(cp, NAU8360_R0C_I2S_PCM_CTRL2,
+			NAU8360_RX_DACL_MASK, slot);
+		break;
+
+	case NAU8360_TDM_DACR:
+		snd_soc_component_update_bits(cp, NAU8360_R0C_I2S_PCM_CTRL2,
+			NAU8360_RX_DACR_MASK, (slot << NAU8360_RX_DACR_SFT));
+		break;
+
+	case NAU8360_TDM_ANCL:
+		snd_soc_component_update_bits(cp, NAU8360_R10_I2S_DATA_CTRL3,
+			NAU8360_RX_ANC_L_MASK, (slot << NAU8360_RX_ANC_L_SFT));
+		break;
+
+	case NAU8360_TDM_ANCR:
+		snd_soc_component_update_bits(cp, NAU8360_R10_I2S_DATA_CTRL3,
+			NAU8360_RX_ANC_R_MASK, (slot << NAU8360_RX_ANC_R_SFT));
+		break;
+	}
+}
+
+static void nau8360_set_tdm_tx_slot(struct snd_soc_component *cp, int type, int slot)
+{
+	switch (type) {
+	case NAU8360_TDM_AECL:
+		snd_soc_component_update_bits(cp, NAU8360_R17_I2S0_DATA_CTRL5,
+			NAU8360_AEC_L_SLOT_MASK, slot << NAU8360_AEC_L_SLOT_SFT);
+		break;
+
+	case NAU8360_TDM_AECR:
+		snd_soc_component_update_bits(cp, NAU8360_R17_I2S0_DATA_CTRL5,
+			NAU8360_AEC_R_SLOT_MASK, slot);
+		break;
+
+	case NAU8360_TDM_ISNSL:
+		snd_soc_component_update_bits(cp, NAU8360_R0E_I2S_DATA_CTRL1,
+			NAU8360_ISNS_L_SLOT_MASK, slot << NAU8360_ISNS_L_SLOT_SFT);
+		break;
+
+	case NAU8360_TDM_ISNSR:
+		snd_soc_component_update_bits(cp, NAU8360_R11_I2S_DATA_CTRL4,
+			NAU8360_ISNS_R_SLOT_MASK, slot);
+		break;
+
+	case NAU8360_TDM_VSNSL:
+		snd_soc_component_update_bits(cp, NAU8360_R0D_I2S_PCM_CTRL3,
+			NAU8360_VSNS_L_SLOT_MASK, slot);
+		break;
+
+	case NAU8360_TDM_VSNSR:
+		snd_soc_component_update_bits(cp, NAU8360_R11_I2S_DATA_CTRL4,
+			NAU8360_VSNS_R_SLOT_MASK, slot << NAU8360_VSNS_R_SLOT_SFT);
+		break;
+
+	case NAU8360_TDM_TJ:
+		snd_soc_component_update_bits(cp, NAU8360_R10_I2S_DATA_CTRL3,
+			NAU8360_TEMP_SLOT_MASK, slot);
+		break;
+
+	case NAU8360_TDM_VBAT:
+		snd_soc_component_update_bits(cp, NAU8360_R0F_I2S_DATA_CTRL2,
+			NAU8360_VBAT_SLOT_MASK, slot << NAU8360_VBAT_SLOT_SFT);
+		break;
+	}
+}
+
+static void nau8360_set_tdm_tx_func(struct snd_soc_component *cp, int type, bool enable)
+{
+	switch (type) {
+	case NAU8360_TDM_AECL:
+		snd_soc_component_update_bits(cp, NAU8360_R17_I2S0_DATA_CTRL5,
+			NAU8360_AEC_L_EN, enable ? NAU8360_AEC_L_EN : 0);
+		break;
+	case NAU8360_TDM_AECR:
+		snd_soc_component_update_bits(cp, NAU8360_R17_I2S0_DATA_CTRL5,
+			NAU8360_AEC_R_EN, enable ? NAU8360_AEC_R_EN : 0);
+		break;
+	case NAU8360_TDM_ISNSL:
+		snd_soc_component_update_bits(cp, NAU8360_R0E_I2S_DATA_CTRL1,
+			NAU8360_ISNS_L_TX_EN, enable ? NAU8360_ISNS_L_TX_EN : 0);
+		break;
+	case NAU8360_TDM_ISNSR:
+		snd_soc_component_update_bits(cp, NAU8360_R11_I2S_DATA_CTRL4,
+			NAU8360_ISNS_R_TX_EN, enable ? NAU8360_ISNS_R_TX_EN : 0);
+		break;
+	case NAU8360_TDM_VSNSL:
+		snd_soc_component_update_bits(cp, NAU8360_R0D_I2S_PCM_CTRL3,
+			NAU8360_VSNS_L_TX_EN, enable ? NAU8360_VSNS_L_TX_EN : 0);
+		break;
+	case NAU8360_TDM_VSNSR:
+		snd_soc_component_update_bits(cp, NAU8360_R11_I2S_DATA_CTRL4,
+			NAU8360_VSNS_R_TX_EN, enable ? NAU8360_VSNS_R_TX_EN : 0);
+		break;
+	case NAU8360_TDM_TJ:
+		snd_soc_component_update_bits(cp, NAU8360_R10_I2S_DATA_CTRL3,
+			NAU8360_TEMP_TX_EN, enable ? NAU8360_TEMP_TX_EN : 0);
+		break;
+	case NAU8360_TDM_VBAT:
+		snd_soc_component_update_bits(cp, NAU8360_R0F_I2S_DATA_CTRL2,
+			NAU8360_VBAT_TX_EN, enable ? NAU8360_VBAT_TX_EN : 0);
+		break;
+	}
+}
+
+static int nau8360_validate_tdm_slots(struct device *dev, unsigned int mask,
+	const u32 *func_slots, const char * const *func_names,
+	int num_funcs, const char *dir,
+	unsigned int *slot_used)
+{
+	int i;
+	unsigned int func_slot;
+	*slot_used = 0;
+
+	if (!mask)
+		return 0;
+
+	for (i = 0; i < num_funcs; i++) {
+		func_slot = func_slots[i];
+		if (func_slot == TDM_SLOT_NONE) {
+			dev_warn(dev, "%s %s slot disabled",
+				dir, func_names[i]);
+			continue;
+		}
+
+		if (!(mask & BIT(func_slot))) {
+			dev_warn(dev, "%s %s mapped to slot %d, but disabled by mask!",
+				dir, func_names[i], func_slot);
+			continue;
+		}
+
+		if (*slot_used & BIT(func_slot)) {
+			dev_err(dev, "%s %s slot %d collision!",
+				dir, func_names[i], func_slot);
+			return -EINVAL;
+		}
+
+		*slot_used |= BIT(func_slot);
+	}
+
+	return 0;
+}
+
+static void nau8360_enable_tdm_channels(struct snd_soc_component *cp,
+	int rx_slot_used, int tx_slot_used)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	int i, slot;
+	unsigned int val = 0;
+	bool enable;
+
+	for (i = 0; i < NAU8360_TDM_TXN; i++) {
+		slot = nau8360->tdm_tx_func_slot[i];
+		enable = (slot != TDM_SLOT_NONE) && (tx_slot_used & BIT(slot));
+		nau8360_set_tdm_tx_func(cp, i, enable);
+	}
+
+	if (rx_slot_used)
+		val |= NAU8360_EN_TDM_RX;
+	if (tx_slot_used)
+		val |= NAU8360_EN_TDM_TX;
+
+	snd_soc_component_update_bits(cp, NAU8360_R0B_I2S_PCM_CTRL1,
+		NAU8360_EN_TDM_RX | NAU8360_EN_TDM_TX, val);
+}
+
+static void nau8360_tdm_apply(struct snd_soc_component *cp, int slot_width)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	int i, chan_tx;
+
+	for (i = 0; i < NAU8360_TDM_TXN; i++) {
+		if (nau8360->tdm_tx_func_slot[i] == TDM_SLOT_NONE)
+			continue;
+
+		/* compute the slot location in bytes according to slot/chan width */
+		chan_tx = (slot_width >> 3) * nau8360->tdm_tx_func_slot[i];
+		nau8360_set_tdm_tx_slot(cp, i, chan_tx);
+	}
+
+	regmap_update_bits(nau8360->regmap, NAU8360_R0C_I2S_PCM_CTRL2,
+		NAU8360_TDM_CLEN_MASK,
+		((slot_width - 16) >> 3) << NAU8360_TDM_CLEN_SFT);
+}
+
+static int nau8360_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 *cp = dai->component;
+	struct device *dev = cp->dev;
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	unsigned int tx_slot_used = 0, rx_slot_used = 0;
+	int ret = 0;
+
+	if (!slots || !slot_width) {
+		nau8360_enable_tdm_channels(cp, 0, 0);
+		return ret;
+	}
+
+	if (slots > NAU8360_TDM_MAX_CHAN) {
+		dev_err(dev, "Invalid TDM slots: %d", slots);
+		return -EINVAL;
+	}
+
+	if (slot_width != 16 && slot_width != 24 && slot_width != 32) {
+		dev_err(dev, "Invalid TDM channel length: %d", slot_width);
+		return -EINVAL;
+	}
+
+	ret = nau8360_validate_tdm_slots(cp->dev, rx_mask,
+		nau8360->tdm_rx_func_slot,
+		nau8360_rx_func_names,
+		NAU8360_TDM_RXN, "RX",
+		&rx_slot_used);
+	if (ret < 0)
+		goto err;
+
+	ret = nau8360_validate_tdm_slots(cp->dev, tx_mask,
+		nau8360->tdm_tx_func_slot,
+		nau8360_tx_func_names,
+		NAU8360_TDM_TXN, "TX",
+		&tx_slot_used);
+	if (ret < 0)
+		goto err;
+
+	if (nau8360_get_tdm_chan_len(nau8360) != slot_width)
+		nau8360_tdm_apply(cp, slot_width);
+
+	nau8360_enable_tdm_channels(cp, rx_slot_used, tx_slot_used);
+
+	dev_dbg(dev, "TDM: tx_mask 0x%x, rx_mask 0x%x", tx_mask, rx_mask);
+err:
+	return ret;
+}
+
+static inline int dyn_clk_div(int div_max, int fin, int fout)
+{
+	int clk_div;
+
+	if (!fin || !fout)
+		return -EINVAL;
+
+	for (clk_div = 0; clk_div <= div_max; clk_div++)
+		if (fin / (clk_div + 1) <= fout)
+			break;
+	if (clk_div > div_max)
+		return -EINVAL;
+
+	return clk_div;
+}
+
+static inline int tab_clk_div(const int clk_div[], int num_div, int fin)
+{
+	int i;
+
+	if (!fin)
+		return -EINVAL;
+
+	for (i = 0; i < num_div; i++)
+		if ((fin / clk_div[i]) <= CLK_DA_IVSNS_MAX)
+			break;
+	if (i == num_div)
+		return -EINVAL;
+
+	return i;
+}
+
+static int nau8360_set_sysclk_output(struct nau8360 *nau8360, unsigned int freq)
+{
+	struct device *dev = nau8360->dev;
+	int ratio = 0, mclk_rate;
+
+	if (freq < MASTER_CLK_MIN || freq > MASTER_CLK_MAX) {
+		dev_err(dev, "system clock %d Hz exceed range", freq);
+		return -EINVAL;
+	}
+
+	if (freq % ADSP_SR_48000 == 0)
+		ratio = freq / ADSP_SR_48000;
+	else if (freq % ADSP_SR_44100 == 0)
+		ratio = freq / ADSP_SR_44100;
+
+	switch (ratio) {
+	case NAU8360_MCLK_FS_RATIO_250:
+		mclk_rate = NAU8360_MCLK_RATE_12000;
+		break;
+	case NAU8360_MCLK_FS_RATIO_256:
+		mclk_rate = NAU8360_MCLK_RATE_12288;
+		break;
+	case NAU8360_MCLK_FS_RATIO_400:
+		mclk_rate = NAU8360_MCLK_RATE_19200;
+		break;
+	case NAU8360_MCLK_FS_RATIO_500:
+		mclk_rate = NAU8360_MCLK_RATE_24000;
+		break;
+	case NAU8360_MCLK_FS_RATIO_512:
+		mclk_rate = NAU8360_MCLK_RATE_24576;
+		break;
+	default:
+		dev_err(dev, "invalid sysclk %d", freq);
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "sysclk %d Hz, ratio %d", freq, ratio);
+
+	nau8360->sys_clk = freq;
+	regmap_update_bits(nau8360->regmap, NAU8360_R40_CLK_DET_CTRL,
+		NAU8360_MCLK_RATE_MASK, mclk_rate);
+
+	return 0;
+}
+
+static int nau8360_dig_sys_clk(struct nau8360 *nau8360, int source, unsigned int freq)
+{
+	struct device *dev = nau8360->dev;
+	struct regmap *regmap = nau8360->regmap;
+	int value, mclk_div;
+
+	switch (source) {
+	case NAU8360_CLK_SRC_MCLK:
+		value = NAU8360_MCLK_SEL_MCLK;
+		break;
+
+	case NAU8360_CLK_SRC_PLL:
+		value = NAU8360_MCLK_SEL_PLL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(regmap, NAU8360_R04_CLK_CTRL1, NAU8360_MCLK_SEL_MASK, value);
+
+	mclk_div = dyn_clk_div(NAU8360_MCLK_DIV_MAX, freq, nau8360->sys_clk);
+	if (mclk_div < 0) {
+		dev_err(dev, "mclk_div (%d -> %d):  error", freq, nau8360->sys_clk);
+		return -EINVAL;
+	}
+	regmap_update_bits(regmap, NAU8360_R03_CLK_CTRL0, NAU8360_MCLK_DIV_MASK,
+		mclk_div << NAU8360_MCLK_DIV_SFT);
+
+	dev_dbg(dev, " mclk_div (%d -> %d): %d", freq, nau8360->sys_clk, mclk_div + 1);
+
+	return 0;
+}
+
+static int nau8360_ana_sys_clk(struct nau8360 *nau8360, int source, unsigned int freq)
+{
+	struct device *dev = nau8360->dev;
+	struct regmap *regmap = nau8360->regmap;
+	struct nau8360_pll *pll = &nau8360->pll;
+	int value, pclk_div, ivdiv_sel, ddiv_sel;
+
+	switch (source) {
+	case NAU8360_CLK_SRC_PLL:
+		value = NAU8360_CLK_ANA_SEL_PLL;
+		break;
+	case NAU8360_CLK_SRC_MCLK:
+		value = NAU8360_CLK_ANA_SEL_MCLK;
+		break;
+	case NAU8360_CLK_SRC_BCLK:
+		value = NAU8360_CLK_ANA_SEL_BCLK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (source == NAU8360_CLK_SRC_PLL) {
+		freq = pll->output;
+		pclk_div = dyn_clk_div(NAU8360_PLLOUT_DIV_MAX, freq, nau8360->sys_clk);
+		if (pclk_div < 0) {
+			dev_err(dev, "pll_div (%d -> %d): error", freq, nau8360->sys_clk);
+			return -EINVAL;
+		}
+
+		dev_dbg(dev, " pll_div (%d -> %d): %d", freq, nau8360->sys_clk, pclk_div + 1);
+
+		regmap_update_bits(regmap, NAU8360_R72_PLL_CFG0, NAU8360_PLLOUT_DIV_MASK,
+			pclk_div << NAU8360_PLLOUT_DIV_SFT);
+		freq /= (pclk_div + 1);
+	}
+
+	ivdiv_sel = tab_clk_div(ivsns_clk_div, ARRAY_SIZE(ivsns_clk_div), freq);
+	if (ivdiv_sel < 0) {
+		dev_err(dev, "iv_div (%d -> %d): error", freq, CLK_DA_IVSNS_MAX);
+		return -EINVAL;
+	}
+	value |= ivdiv_sel << NAU8360_IVSNS_CLK_DIV_SFT;
+
+	ddiv_sel = tab_clk_div(dac_clk_div, ARRAY_SIZE(dac_clk_div), freq);
+	if (ddiv_sel < 0) {
+		dev_err(dev, "dac_div (%d -> %d): error", freq, CLK_DA_IVSNS_MAX);
+		return -EINVAL;
+	}
+	value |= ddiv_sel << NAU8360_DAC_CLK_DIV_SFT;
+
+	dev_dbg(dev, " clk_div (%d -> %d): ivsns %d, dac %d", freq, CLK_DA_IVSNS_MAX,
+		ivsns_clk_div[ivdiv_sel], dac_clk_div[ddiv_sel]);
+
+	regmap_update_bits(regmap, NAU8360_R71_CLK_DIV_CFG, NAU8360_CLK_ANA_SEL_MASK |
+		NAU8360_IVSNS_CLK_DIV_MASK | NAU8360_DAC_CLK_DIV_MASK, value);
+
+	return 0;
+}
+
+static int nau8360_dsp_hw_clk(struct nau8360 *nau8360, int source, unsigned int freq)
+{
+	struct device *dev = nau8360->dev;
+	struct regmap *regmap = nau8360->regmap;
+	int val_dsp, val_hw, clk_div, dsp_clk;
+
+	if (freq % ADSP_SR_48000 == 0)
+		dsp_clk = DSP_OP_CLK48;
+	else if (freq % ADSP_SR_44100 == 0)
+		dsp_clk = DSP_OP_CLK44;
+	else
+		return -EINVAL;
+	clk_div = dyn_clk_div(NAU8360_DSP_CLK_DIV_MAX, freq, dsp_clk);
+	if (clk_div < 0) {
+		dev_err(dev, "dsp/hw clk_div (%d -> %d): error", freq, dsp_clk);
+		return -EINVAL;
+	}
+	val_dsp = clk_div << NAU8360_DSP_CLK_DIV_SFT;
+	val_hw = clk_div << NAU8360_HW_CLK_DIV_SFT;
+	if (source == NAU8360_CLK_SRC_MCLK) {
+		val_dsp |= NAU8360_DSP_CLK_SEL_MCLK;
+		val_hw |= NAU8360_HW_CLK_SEL_MCLK;
+	} else if (source == NAU8360_CLK_SRC_PLL) {
+		val_dsp |= NAU8360_DSP_CLK_SEL_PLL;
+		val_hw |= NAU8360_HW_CLK_SEL_PLL;
+	} else
+		return -EINVAL;
+
+	dev_dbg(dev, " dsp/hw clk_div (%d -> %d): %d", freq, dsp_clk, clk_div + 1);
+
+	regmap_update_bits(regmap, NAU8360_R03_CLK_CTRL0, NAU8360_DSP_CLK_SEL_MASK |
+		NAU8360_DSP_CLK_DIV_MASK, val_dsp);
+	regmap_update_bits(regmap, NAU8360_R04_CLK_CTRL1, NAU8360_HW_CLK_SEL_MASK |
+		NAU8360_HW_CLK_DIV_MASK, val_hw);
+
+	return 0;
+}
+
+static int nau8360_set_sysclk(struct snd_soc_component *cp,
+	int clk_id, int source, unsigned int freq, int dir)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct regmap *regmap = nau8360->regmap;
+	struct device *dev = nau8360->dev;
+	static const char * const idtab[] = { "DIG", "ANA", "Internal" };
+	static const char * const srctab[] = { "MCLK", "PLL", "HIRC48M", "BCLK" };
+	int ret;
+
+	if (clk_id < 0 || clk_id >= ARRAY_SIZE(idtab))
+		return -EINVAL;
+
+	if (source < 0 || source >= ARRAY_SIZE(srctab))
+		return -EINVAL;
+
+	if (dir == SND_SOC_CLOCK_OUT) {
+		dev_dbg(dev, "sysclk: freq %d (out)", freq);
+		return nau8360_set_sysclk_output(nau8360, freq);
+	}
+
+	switch (clk_id) {
+	case NAU8360_CLK_ID_INT:
+		source = NAU8360_CLK_SRC_ICLK;
+		dev_dbg(dev, "sysclk: id %d (%s), src %d (%s) (in)",
+			clk_id, idtab[clk_id], source, srctab[source]);
+		regmap_update_bits(regmap, NAU8360_R03_CLK_CTRL0,
+			NAU8360_DSP_CLK_SEL_MASK, NAU8360_DSP_CLK_SEL_HIRC48M);
+		regmap_update_bits(regmap, NAU8360_R04_CLK_CTRL1,
+			NAU8360_HW_CLK_SEL_MASK | NAU8360_MCLK_SEL_MASK,
+			NAU8360_HW_CLK_SEL_HIRC48M | NAU8360_MCLK_SEL_HIRC48M);
+		regmap_update_bits(regmap, NAU8360_R72_PLL_CFG0,
+			NAU8360_PD_PLL_MASK, NAU8360_PD_PLL_DIS);
+		break;
+
+	case NAU8360_CLK_ID_DIG:
+		dev_dbg(dev, "sysclk: id %d (%s), src %d (%s), freq %d (in)",
+			clk_id, idtab[clk_id], source, srctab[source], freq);
+
+		if (source == NAU8360_CLK_SRC_BCLK)
+			return -EINVAL;
+
+		if (source == NAU8360_CLK_SRC_MCLK)
+			regmap_update_bits(regmap, NAU8360_R72_PLL_CFG0,
+				NAU8360_PD_PLL_MASK, NAU8360_PD_PLL_DIS);
+
+		ret = nau8360_dig_sys_clk(nau8360, source, freq);
+		if (ret)
+			return -EINVAL;
+		ret = nau8360_dsp_hw_clk(nau8360, source, freq);
+		if (ret)
+			return -EINVAL;
+		break;
+
+	case NAU8360_CLK_ID_ANA:
+		dev_dbg(dev, "sysclk: id %d (%s), src %d (%s), freq %d (in)",
+			clk_id, idtab[clk_id], source, srctab[source], freq);
+
+		if (source == NAU8360_CLK_SRC_MCLK || source == NAU8360_CLK_SRC_BCLK)
+			regmap_update_bits(regmap, NAU8360_R72_PLL_CFG0,
+				NAU8360_PD_PLL_MASK, NAU8360_PD_PLL_DIS);
+
+		ret = nau8360_ana_sys_clk(nau8360, source, freq);
+		if (ret)
+			return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8360_calc_pll(struct nau8360 *nau8360)
+{
+	struct nau8360_pll *pll = &nau8360->pll;
+	u64 fref = 0ULL, fvco = 0ULL, ratio;
+	int fr, fv;
+
+	if (pll->src != NAU8360_PLL_INTERNAL &&
+		(pll->input > PLL_FREQ_MAX || pll->input < PLL_FREQ_MIN))
+		return -EINVAL;
+
+	if (pll->output > PLL_FOUT_MAX || pll->output < PLL_FOUT_MIN)
+		return -EINVAL;
+
+	for (pll->msel = 1; pll->msel <= MSEL_MAX; pll->msel++) {
+		fr = pll->input / pll->msel;
+		if (fr <= PLL_FREF_MAX) {
+			fref = fr;
+			break;
+		}
+	}
+	if (!fref)
+		return -ERANGE;
+
+	for (pll->rsel = 1; pll->rsel <= RSEL_MAX; pll->rsel++) {
+		fv = pll->output * pll->rsel;
+		if (fv >= PLL_FVCO_MIN) {
+			fvco = fv;
+			break;
+		}
+	}
+	if (!fvco)
+		return -ERANGE;
+
+	dev_dbg(nau8360->dev, "fref(1-8MHz): %lld, fvco(50-125MHz): %lld", fref, fvco);
+
+	/* Calculate the PLL 8-bit integer input and 12-bit fractional */
+	ratio = div_u64(fvco << 12, fref);
+	pll->nsel = (ratio >> 12) & 0xff;
+	pll->xsel = ratio & 0xfff;
+
+	return 0;
+}
+
+static int nau8360_set_pll(struct snd_soc_component *cp, int pll_id, int source,
+	unsigned int freq_in, unsigned int freq_out)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	struct device *dev = nau8360->dev;
+	struct nau8360_pll *pll = &nau8360->pll;
+	int ctrl_val, ret;
+
+	switch (source) {
+	case NAU8360_PLL_MCLK:
+		ctrl_val = NAU8360_PLL_CLK_SEL_MCLK;
+		break;
+	case NAU8360_PLL_BCLK:
+		ctrl_val = NAU8360_PLL_CLK_SEL_BCLK;
+		break;
+	case NAU8360_PLL_INTERNAL:
+		ctrl_val = NAU8360_PLL_CLK_SEL_HIRC;
+		break;
+	default:
+		return -EINVAL;
+	}
+	pll->src = source;
+	pll->input = freq_in;
+	pll->output = freq_out;
+	ret = nau8360_calc_pll(nau8360);
+	if (ret) {
+		dev_err(dev, "clock error input %d output %d", freq_in, freq_out);
+		return ret;
+	}
+	dev_dbg(dev, "src:%d, input:%d, output:%d, M:%d, R:%d, N:%d, X:%d", pll->src,
+		pll->input, pll->output, pll->msel, pll->rsel, pll->nsel, pll->xsel);
+
+	regmap_update_bits(nau8360->regmap, NAU8360_R72_PLL_CFG0, NAU8360_PD_PLL_MASK |
+		NAU8360_PLL_CLK_SEL_MASK, NAU8360_PD_PLL_EN | ctrl_val);
+	regmap_write_bits(nau8360->regmap, NAU8360_R73_PLL_CFG1,
+		NAU8360_RSEL_MASK | NAU8360_MSEL_MASK | NAU8360_NSEL_MASK,
+		(pll->rsel - 1) << NAU8360_RSEL_SFT |
+		(pll->msel - 1) << NAU8360_MSEL_SFT | (pll->nsel - 1));
+	regmap_write_bits(nau8360->regmap, NAU8360_R74_PLL_CFG2, NAU8360_XSEL_MASK,
+		pll->xsel);
+
+	return 0;
+}
+
+static void nau8360_coeff_set_def(struct nau8360 *nau8360)
+{
+	struct regmap *regmap = nau8360->regmap;
+	int i;
+
+	mutex_lock(&nau8360->lock);
+	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL, NAU8360_HW1_MEM_CLEAR,
+		NAU8360_HW1_MEM_CLEAR);
+	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL, NAU8360_HW1_MEM_CLEAR, 0);
+	nau8360_peq_mem_enable(regmap, true);
+	for (i = 0; i < NAU8360_TOT_BAND_PER_CH; i++) {
+		regmap_write(regmap, NAU8360_R100_LEFT_BIQ0_COE + 1 +
+			i * NAU8360_TOT_BAND_COE_RANGE, 0x20);
+		regmap_write(regmap, NAU8360_R200_RIGHT_BIQ0_COE + 1 +
+			i * NAU8360_TOT_BAND_COE_RANGE, 0x20);
+	}
+	nau8360_peq_mem_enable(regmap, false);
+	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL, NAU8360_PEQ_BAND_MASK,
+		NAU8360_PEQ_BAND_8 << NAU8360_PEQ_BAND_SFT);
+	mutex_unlock(&nau8360->lock);
+}
+
+static inline int nau8360_vbat_level(struct regmap *regmap, int *vbat)
+{
+	struct device *dev = regmap_get_device(regmap);
+	int value = 0, ret;
+
+	ret = regmap_read(regmap, NAU8360_R21_VBAT_READOUT, &value);
+	if (ret)
+		return ret;
+
+	/* multiple 100 on value scale */
+	*vbat = (value * 100 + NAU8360_VBAT_BASE) / NAU8360_VBAT_STEP;
+	if (*vbat < NAU8360_VBAT_MIN || *vbat > NAU8360_VBAT_MAX) {
+		dev_err(dev, "VBAT %dV is out of valid range (%dV-%dV)",
+			*vbat, NAU8360_VBAT_MIN, NAU8360_VBAT_MAX);
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+static inline void nau8360_sawtooth_params(int vbat, int *vsaw_level, int *vsaw_slope)
+{
+	if (vbat < NAU8360_VBAT_MID_THRES) {
+		*vsaw_level = 0x1;
+		*vsaw_slope = 0x0;
+	} else if (vbat < NAU8360_VBAT_HIGH_THRES) {
+		*vsaw_level = 0x2;
+		*vsaw_slope = 0x1;
+	} else {
+		*vsaw_level = 0x3;
+		*vsaw_slope = 0x2;
+	}
+}
+
+static inline void nau8360_dsp_software_reset(struct snd_soc_component *component)
+{
+	/* Enable PLL for successful DSP reset. After DSP is alive,
+	 * system clock switches to internal clock and disable PLL.
+	 */
+	snd_soc_component_update_bits(component, NAU8360_R72_PLL_CFG0,
+		NAU8360_PD_PLL_MASK, NAU8360_PD_PLL_EN);
+	msleep(50);
+	snd_soc_component_write(component, NAU8360_R01_DSP_SOFTWARE_RST, 0x5a5a);
+	snd_soc_component_write(component, NAU8360_R01_DSP_SOFTWARE_RST, 0xa5a5);
+	snd_soc_component_set_sysclk(component, NAU8360_CLK_ID_INT, 0, 0,
+		SND_SOC_CLOCK_IN);
+}
+
+static void nau8360_dsp_bootup(struct snd_soc_component *component)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = nau8360->regmap;
+
+	regmap_update_bits(regmap, NAU8360_R90_HW2_CTL0, NAU8360_HW2_STALL, 0);
+	nau8360_dsp_software_reset(component);
+	nau8360_dsp_enable(regmap, true);
+}
+
+static void nau8360_tdm_function_config(struct snd_soc_component *cp)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(cp);
+	int i, chan_tx, tdm_chan_len;
+
+	for (i = 0; i < NAU8360_TDM_RXN; i++) {
+		if (nau8360->tdm_rx_func_slot[i] == TDM_SLOT_NONE)
+			continue;
+
+		nau8360_set_tdm_rx_slot(cp, i, nau8360->tdm_rx_func_slot[i]);
+	}
+
+	tdm_chan_len = nau8360_get_tdm_chan_len(nau8360) >> 3;
+	for (i = 0; i < NAU8360_TDM_TXN; i++) {
+		if (nau8360->tdm_tx_func_slot[i] == TDM_SLOT_NONE)
+			continue;
+
+		/* compute the slot location in bytes according to slot/chan width */
+		chan_tx = (tdm_chan_len * nau8360->tdm_tx_func_slot[i]);
+		nau8360_set_tdm_tx_slot(cp, i, chan_tx);
+	}
+}
+
+static void nau8360_dsp_fw_load(struct nau8360 *nau8360)
+{
+	nau8360->load_fw_done = false;
+	schedule_work(&nau8360->load_fw_work);
+}
+
+static void nau8360_load_fw_work(struct work_struct *work)
+{
+	struct nau8360 *nau8360 = container_of(work, struct nau8360, load_fw_work);
+	struct snd_soc_component *cp = snd_soc_dapm_to_component(nau8360->dapm);
+	int ret;
+
+	ret = nau8360_dsp_init(cp);
+	if (ret) {
+		dev_err(nau8360->dev, "Failed to initialize DSP: %d\n", ret);
+		nau8360_dsp_enable(nau8360->regmap, false);
+		return;
+	}
+	nau8360->load_fw_done = true;
+}
+
+static int nau8360_codec_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = nau8360->regmap;
+	struct device *dev = nau8360->dev;
+	int ret, vbat, vsaw_level, vsaw_slope;
+
+	nau8360->dapm = dapm;
+	nau8360_dsp_bootup(component);
+	nau8360_dsp_fw_load(nau8360);
+	ret = nau8360_dsp_setup_controls(component);
+	if (ret) {
+		nau8360_dsp_enable(regmap, false);
+		dev_err(dev, "DSP setup controls failed(%d)", ret);
+		goto err;
+	}
+	nau8360_tdm_function_config(component);
+
+	/* default disable Sense signal after booting */
+	snd_soc_dapm_disable_pin(nau8360->dapm, "Sense");
+	snd_soc_dapm_sync(nau8360->dapm);
+
+	nau8360_coeff_set_def(nau8360);
+	/* VBAT is sensed by chip. */
+	ret = nau8360_vbat_level(regmap, &vbat);
+	if (ret) {
+		dev_err(dev, "Failed to get valid VBAT level: %d", ret);
+		goto err;
+	}
+	dev_dbg(dev, "VBAT %dV for nau8360", vbat);
+
+	/* Config sawtooth clock according to VBAT. Class D modulator input short setting
+	 * for mute and de-pop purpose. Restore normal after initiation.
+	 */
+	nau8360_sawtooth_params(vbat, &vsaw_level, &vsaw_slope);
+
+	regmap_update_bits(regmap, NAU8360_RA5_ANA_REG_1, NAU8360_VSAW_LV_MASK |
+		NAU8360_KVCO_SAW_MASK, (vsaw_level << NAU8360_VSAW_LV_SFT) |
+		(vsaw_slope << NAU8360_KVCO_SAW_SFT));
+
+	return 0;
+
+err:
+	cancel_work_sync(&nau8360->load_fw_work);
+	return ret;
+}
+
+static int __maybe_unused nau8360_suspend(struct snd_soc_component *component)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+
+	cancel_work_sync(&nau8360->load_fw_work);
+
+	regmap_update_bits(nau8360->regmap, NAU8360_R90_HW2_CTL0, NAU8360_HW2_STALL,
+		NAU8360_HW2_STALL);
+	nau8360_dsp_enable(nau8360->regmap, false);
+
+	regcache_cache_only(nau8360->regmap, true);
+	regcache_mark_dirty(nau8360->regmap);
+
+	return 0;
+}
+
+static int __maybe_unused nau8360_resume(struct snd_soc_component *component)
+{
+	struct nau8360 *nau8360 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = nau8360->regmap;
+
+	regcache_cache_only(regmap, false);
+
+	nau8360_dsp_bootup(component);
+
+	nau8360_peq_mem_enable(regmap, true);
+	regcache_sync(regmap);
+	nau8360_peq_mem_enable(regmap, false);
+
+	/* disable Sense at standby */
+	snd_soc_dapm_disable_pin(nau8360->dapm, "Sense");
+	snd_soc_dapm_sync(nau8360->dapm);
+
+	nau8360_dsp_fw_load(nau8360);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_comp_dev_nau8360 = {
+	.probe			= nau8360_codec_probe,
+	.set_sysclk		= nau8360_set_sysclk,
+	.set_pll		= nau8360_set_pll,
+	.suspend		= nau8360_suspend,
+	.resume			= nau8360_resume,
+	.controls		= nau8360_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8360_snd_controls),
+	.dapm_widgets		= nau8360_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8360_dapm_widgets),
+	.dapm_routes		= nau8360_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8360_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+};
+
+static const struct snd_soc_dai_ops nau8360_dai_ops = {
+	.startup	= nau8360_startup,
+	.shutdown	= nau8360_shutdown,
+	.hw_params	= nau8360_hw_params,
+	.set_fmt	= nau8360_set_fmt,
+	.set_tdm_slot	= nau8360_set_tdm_slot,
+};
+
+#define NAU8360_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
+	SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
+	SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define NAU8360_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8360_dai = {
+	.name = NAU8360_CODEC_DAI,
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = NAU8360_RATES,
+		.formats = NAU8360_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = NAU8360_RATES,
+		.formats = NAU8360_FORMATS,
+	},
+	.ops = &nau8360_dai_ops,
+	.symmetric_rate = 1,
+};
+
+static int nau8360_reg_write(void *context, unsigned int reg, unsigned int value)
+{
+	struct i2c_client *client = context;
+	struct nau8360 *nau8360 = i2c_get_clientdata(client);
+	int ret, count = 0;
+
+	put_unaligned_be16(reg, &nau8360->i2c_write_buf[count]);
+	count += 2;
+
+	if (NAU8360_IS_DSP_REG(reg)) {
+		/* format for DSP, 4 bytes value and native */
+		put_unaligned_le32(value, &nau8360->i2c_write_buf[count]);
+		count += 4;
+	} else {
+		/* format for Codec, 2 bytes value and endian big */
+		put_unaligned_be16(value, &nau8360->i2c_write_buf[count]);
+		count += 2;
+	}
+
+	ret = i2c_master_send(client, nau8360->i2c_write_buf, count);
+
+	if (ret == count)
+		return 0;
+	if (ret < 0)
+		return ret;
+
+	return -EIO;
+}
+
+static int nau8360_reg_read(void *context, unsigned int reg, unsigned int *value)
+{
+	struct i2c_client *client = context;
+	struct nau8360 *nau8360 = i2c_get_clientdata(client);
+	struct i2c_msg xfer[2];
+	int ret;
+
+	put_unaligned_be16(reg, &nau8360->i2c_read_reg);
+	xfer[0].addr = client->addr;
+	xfer[0].len = 2;
+	xfer[0].buf = nau8360->i2c_read_reg;
+	xfer[0].flags = 0;
+
+	xfer[1].addr = client->addr;
+	xfer[1].len = (NAU8360_IS_DSP_REG(reg)) ? 4 : 2;
+	xfer[1].buf = nau8360->i2c_read_buf;
+	xfer[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(xfer))
+		return -EIO;
+
+	if (NAU8360_IS_DSP_REG(reg))
+		*value = get_unaligned_le32(nau8360->i2c_read_buf);
+	else
+		*value = get_unaligned_be16(nau8360->i2c_read_buf);
+
+	return 0;
+}
+
+static const struct regmap_config nau8360_regmap_config = {
+	.reg_bits = NAU8360_REG_ADDR_LEN,
+	.val_bits = NAU8360_REG_DATA_LEN,
+
+	.max_register = NAU8360_REG_MAX,
+	.readable_reg = nau8360_readable_reg,
+	.writeable_reg = nau8360_writeable_reg,
+	.volatile_reg = nau8360_volatile_reg,
+	.reg_read = nau8360_reg_read,
+	.reg_write = nau8360_reg_write,
+
+	.cache_type = REGCACHE_MAPLE,
+	.reg_defaults = nau8360_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8360_reg_defaults),
+};
+
+static inline void nau8360_reset_chip(struct regmap *regmap)
+{
+	regmap_write(regmap, NAU8360_R00_SOFTWARE_RST, 0x5a5a);
+	regmap_write(regmap, NAU8360_R00_SOFTWARE_RST, 0xa5a5);
+}
+
+static void nau8360_init_regs(struct nau8360 *nau8360)
+{
+	struct regmap *regmap = nau8360->regmap;
+
+	/* Enable Digital LDO */
+	regmap_write(regmap, NAU8360_R78_PD_SW_DLDO, NAU8360_PD_SW_DLDO_EN);
+	/* Enable Software Shutdown Mode */
+	regmap_write(regmap, NAU8360_R77_SOFT_SD, NAU8360_SOFT_SD_EN);
+	/* Stall HW1 PEQ Engine and Clear DRAM to Zero */
+	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL, NAU8360_PEQ_STALL,
+		NAU8360_PEQ_STALL);
+	/* Stall HW2 engine */
+	regmap_update_bits(regmap, NAU8360_R90_HW2_CTL0, NAU8360_HW2_STALL,
+		NAU8360_HW2_STALL);
+	/* Stall HW3 engine and DSP processor */
+	nau8360_dsp_enable(regmap, false);
+	/* Enable Clock Gate */
+	regmap_write(regmap, NAU8360_R7E_CLK_GATED_EN, NAU8360_CLK_GATED_EN);
+	/* Latch I2C LSB Value */
+	regmap_write(regmap, NAU8360_R02_I2C_ADDR, 0x0001);
+	/* ANC Left/Right Channel as Slot 2/3 and switch */
+	regmap_update_bits(regmap, NAU8360_R10_I2S_DATA_CTRL3,
+		NAU8360_RX_ANC_R_MASK | NAU8360_RX_ANC_L_MASK,
+		0x3 << NAU8360_RX_ANC_R_SFT | 0x2 << NAU8360_RX_ANC_L_SFT);
+	/* Set DAC Clock Divider as 2 and Chopper Divider as 16 */
+	regmap_update_bits(regmap, NAU8360_R71_CLK_DIV_CFG,
+		NAU8360_DAC_CLK_DIV_MASK | NAU8360_DAC_CHOP_CLK_DIV_MASK,
+		NAU8360_DAC_CLK_DIV_2 | NAU8360_DAC_CHOP_CLK_DIV_16);
+	/* Set DAC SINC OSR as 128 and IVSENSE BS OSR as 32 */
+	regmap_update_bits(regmap, NAU8360_R5D_SINC_CFG,
+		NAU8360_DAC_SINC_OSR_MASK | NAU8360_IVSENSE_BS_OSR_MASK,
+		NAU8360_DAC_SINC_OSR_128 | NAU8360_IVSENSE_BS_OSR_32);
+
+	/* Set Trim Bit Control of DLDO and GVDD to The Highest Voltage */
+	regmap_write(regmap, NAU8360_R5F_ANA_TRIM_CFG1, 0xf407);
+
+	/* Disable Data Det and Clock Detection Settings*/
+	regmap_update_bits(regmap, NAU8360_R40_CLK_DET_CTRL, NAU8360_APWRUPEN |
+		NAU8360_CLKPWRUPEN | NAU8360_FS_MCLK_DET | NAU8360_FS_BCLK_DET, 0);
+
+	/* Set HW3 Droop and Filter Sample as 192K */
+	regmap_update_bits(regmap, NAU8360_R8C_HW3_CTL6, NAU8360_HW3_DROOP_MASK |
+		NAU8360_HW3_FS_MASK, NAU8360_HW3_DROOP_192K | NAU8360_HW3_FS_192K);
+	/* Set HW1 Mute, Mute Interval as 699ms and HW1 Zero THD as 0xff */
+	regmap_update_bits(regmap, NAU8360_R9C_HW1_CTL2, NAU8360_MUTE_INTRVL_MASK |
+		NAU8360_HW1_CH_MUTE | NAU8360_HW1_ZERO_THD_MASK,
+		NAU8360_MUTE_INTRVL_699MS | NAU8360_HW1_CH_MUTE | 0xff);
+	/* set HW2 droop with 192K*/
+	regmap_update_bits(regmap, NAU8360_R96_HW2_CTL6, NAU8360_HW2_DROOP_SEL_MASK |
+		NAU8360_HW2_DROOP_EN | NAU8360_HW2_FS_MASK,
+		NAU8360_HW2_DROOP_SEL_LARGE | NAU8360_HW2_DROOP_EN | NAU8360_HW2_FS_192K);
+	/* Set HW2 default volume */
+	regmap_write(regmap, NAU8360_R97_HW2_CTL7, 0xbf66);
+	regmap_write(regmap, NAU8360_R98_HW2_CTL8, 0xbf66);
+	/* Set HW2 Mute and Threshold of Zero Crossing */
+	regmap_update_bits(regmap, NAU8360_R99_HW2_CTL9, NAU8360_HW2_CH_MUTE |
+		NAU8360_HW2_ZERO_THD_MASK, NAU8360_HW2_CH_MUTE | 0xff);
+	/* According to DSP enabled or not, set stream path as
+	 * HW1->DSP->HW2->SINC->HW3 or HW1->HW2->SINC->HW3
+	 */
+	regmap_update_bits(regmap, NAU8360_R12_PATH_CTRL, NAU8360_SEL_HW1_MASK |
+		NAU8360_AUD_SEL_MASK | NAU8360_SEL_HW2_MASK | NAU8360_SEL_HW3_MASK |
+		NAU8360_DAC_SEL_MASK, NAU8360_SEL_HW1_OUT | NAU8360_AUD_SEL_SINCOUT |
+		NAU8360_SEL_HW2_OUT | NAU8360_SEL_HW3_OUT);
+	/* Set Input Status as Low and Input/Output Mode Disable for All GPIO */
+	regmap_write(regmap, NAU8360_R07_GP_CTRL, 0x0000);
+	/* enable SARADC with extra average filter of VBAT */
+	regmap_update_bits(regmap, NAU8360_R6A_SARADC_CFG0, NAU8360_SARADC_EN |
+		NAU8360_VBAT_AVG_EN, NAU8360_SARADC_EN | NAU8360_VBAT_AVG_EN);
+	/* Enable Temperature Sensor, VBATDIV and VRF.
+	 * Set Average Filter Data as 512 for VTEMP and VBAT.
+	 */
+	regmap_update_bits(regmap, NAU8360_R6B_SARADC_CFG1, NAU8360_VTEMP_EN |
+		NAU8360_VBATDIV_EN | NAU8360_VREF_EN | NAU8360_PRELOAD_VREF_EN |
+		NAU8360_VTEMP_AVG_N_MASK | NAU8360_VBAT_AVG_N_MASK, NAU8360_VTEMP_EN |
+		NAU8360_VBATDIV_EN | NAU8360_VREF_EN | NAU8360_PRELOAD_VREF_EN |
+		NAU8360_VTEMP_AVG_N_512 | NAU8360_VBAT_AVG_N_512);
+	/* Enable IV sense internal LDO */
+	regmap_update_bits(regmap, NAU8360_R6C_IVSNS_CFG0,
+		NAU8360_PD_LDO_SDM_IVSNS_PMD, 0);
+	/* Enable Bias Current and Reference Voltage for IVSENSE. Set VSNS Gain
+	 * as 1/12 and ISNS Gain as x16(24dB). Set PGA Current as 2'b11 and SDN
+	 * Delay as 2'b00.
+	 */
+	regmap_write(regmap, NAU8360_R6D_IVSNS_CFG1, 0x0f5c);
+	/* sawtooth clock from ivsense clock, PWM frequency 432 Khz */
+	regmap_update_bits(regmap, NAU8360_RA4_ANA_REG_0, NAU8360_SEL_STCLK_MASK |
+		NAU8360_NSEL_SAW_MASK, NAU8360_SEL_STCLK_IVCLK | 0x8);
+	/* sawtooth PLL APR */
+	regmap_update_bits(regmap, NAU8360_RA5_ANA_REG_1, NAU8360_SAW_PLL_MASK,
+		NAU8360_SAW_PLL_NOR);
+
+	/* Set DAC gain (0dB/+3.2dB) by current cell adjustment */
+	regmap_update_bits(regmap, NAU8360_R6E_DAC_CFG0, NAU8360_DAC_CUR_MASK,
+		nau8360->dac_cur_enable ? NAU8360_DAC_CUR_3_2DB : NAU8360_DAC_CUR_0DB);
+	/* Config trim short current reference. Enable Non-overlap longer delay.
+	 * Set segment driver as half driving strength.
+	 */
+	regmap_update_bits(regmap, NAU8360_R68_ANALOG_CONTROL_1, NAU8360_DTX_EN |
+		NAU8360_TRIMSCR_MASK | NAU8360_DRVCTL_SEGL_FULL |
+		NAU8360_DRVCTL_SEGR_FULL, NAU8360_TRIMSCR_MLOW | NAU8360_DTX_EN);
+	/* Enable SCP Clear Mode and Class D Modulator to Common Mode */
+	regmap_update_bits(regmap, NAU8360_R67_ANALOG_CONTROL_0,
+		NAU8360_SCP_CLEAR_MODE_MASK | NAU8360_CM_COMP_EN,
+		NAU8360_SCP_CLEAR_MODE_AUTO | NAU8360_CM_COMP_EN);
+	/* Set Analog Mute and Class D Modulator Gain as 14dB */
+	regmap_update_bits(regmap, NAU8360_R67_ANALOG_CONTROL_0, NAU8360_ANA_MUTE |
+		NAU8360_MOD_GAIN_MASK, NAU8360_ANA_MUTE | NAU8360_MOD_GAIN_14DB);
+	/* Set Stereo or PBTL Mode */
+	regmap_update_bits(regmap, NAU8360_R67_ANALOG_CONTROL_0,
+		NAU8360_V_PBTL_EN, nau8360->pbtl_enable ? NAU8360_V_PBTL_EN : 0);
+	regmap_update_bits(regmap, NAU8360_R6C_IVSNS_CFG0,
+		NAU8360_PBTL_ISENE_LR_MASK, NAU8360_PBTL_ISENE_LR_ILR);
+	/* adjust HW3 default volume of voltage/current sense */
+	regmap_write(regmap, NAU8360_R8A_HW3_VL_CTL7, 0xbe90);
+	regmap_write(regmap, NAU8360_R8B_HW3_VR_CTL8, 0xbe90);
+	regmap_write(regmap, NAU8360_R8D_HW3_IL_CTL7, nau8360->pbtl_enable ? 0xc3aa : 0xc24c);
+	regmap_write(regmap, NAU8360_R8E_HW3_IR_CTL8, nau8360->pbtl_enable ? 0xc3aa : 0xc24c);
+	/* Set HW3 Zero THD as 0xff */
+	regmap_update_bits(regmap, NAU8360_R8F_HW3_CTL9,
+		NAU8360_HW3_ZERO_THD_MASK, 0xff);
+	/* Enable TX SDOUT and Data at BCLK Rising. */
+	regmap_update_bits(regmap, NAU8360_R0D_I2S_PCM_CTRL3, NAU8360_TX_FILL_MASK,
+		NAU8360_TX_FILL_ZERO);
+	regmap_update_bits(regmap, NAU8360_R0D_I2S_PCM_CTRL3,
+		NAU8360_VSNS_L_SLEN_MASK, NAU8360_VSNS_L_SLEN_16);
+	regmap_update_bits(regmap, NAU8360_R0E_I2S_DATA_CTRL1,
+		NAU8360_ISNS_L_SLEN_MASK, NAU8360_ISNS_L_SLEN_16);
+	regmap_update_bits(regmap, NAU8360_R11_I2S_DATA_CTRL4,
+		NAU8360_VSNS_R_SLEN_MASK | NAU8360_ISNS_R_SLEN_MASK,
+		NAU8360_VSNS_R_SLEN_16 | NAU8360_ISNS_R_SLEN_16);
+	/* set DAC channel temperature trim code slope as 0x7D */
+	regmap_update_bits(regmap, NAU8360_R7A_DAC_TRIM_CFG2,
+		NAU8360_DAC_TEMP_SLOPE_MASK, 0x7D << NAU8360_DAC_TEMP_SLOPE_SFT);
+	/* set ISNS temperature trim code slope as 0x1a */
+	regmap_update_bits(regmap, NAU8360_R7B_IVSNS_TRIM_CFG,
+		NAU8360_ISNS_TEMP_SLOPE_MASK, 0x1a << NAU8360_ISNS_TEMP_SLOPE_SFT);
+	/* set misc trim config as 0x67F0 */
+	regmap_update_bits(regmap, NAU8360_R7C_MISC_TRIM_CFG, NAU8360_DAC_GAIN_SB_MASK |
+		NAU8360_DAC_TEMP_SB_MASK | NAU8360_ISNS_TEMP_SB_MASK |
+		NAU8360_VSNS_TEMP_SB_MASK | NAU8360_ISNS_GAIN_SB_MASK |
+		NAU8360_VSNS_GAIN_SB_MASK, (0x3 << NAU8360_DAC_TEMP_SB_SFT) |
+		(0x7 << NAU8360_ISNS_TEMP_SB_SFT) | (0x3 << NAU8360_VSNS_TEMP_SB_SFT));
+	/* Enable Efuse Initianllization */
+	regmap_update_bits(regmap, NAU8360_R60_RST, NAU8360_EFUSE_CTRL_EN,
+		NAU8360_EFUSE_CTRL_EN);
+	/* Clear HW2 DRAM */
+	regmap_update_bits(regmap, NAU8360_R90_HW2_CTL0,
+		NAU8360_HW2_DRAM_CLR, NAU8360_HW2_DRAM_CLR);
+	/* Finish HW DRAM Clear */
+	regmap_update_bits(regmap, NAU8360_R90_HW2_CTL0, NAU8360_HW2_DRAM_CLR, 0);
+	/* Clear HW3 DRAM */
+	regmap_update_bits(regmap, NAU8360_R86_HW3_CTL0,
+		NAU8360_HW3_DRAM_CLR, NAU8360_HW3_DRAM_CLR);
+	/* Finish HW DRAM Clear */
+	regmap_update_bits(regmap, NAU8360_R86_HW3_CTL0, NAU8360_HW3_DRAM_CLR, 0);
+}
+
+static void nau8360_print_device_properties(struct nau8360 *nau8360)
+{
+	int i;
+
+	dev_dbg(nau8360->dev, "pbtl-enable:         %d", nau8360->pbtl_enable);
+	dev_dbg(nau8360->dev, "dac-cur-enable:      %d", nau8360->dac_cur_enable);
+	for (i = 0; i < NAU8360_DSP_FW_NUM; i++)
+		dev_dbg(nau8360->dev, "firmware-name[%d]:     %s", i,
+			nau8360->dsp_firmware[i]);
+
+	for (i = 0; i < NAU8360_TDM_TXN; i++)
+		dev_dbg(nau8360->dev, "dsp-tx-slot[%d] (%s): %d%s", i,
+			nau8360_tx_func_names[i], nau8360->tdm_tx_func_slot[i],
+			nau8360->tdm_tx_func_slot[i] == TDM_SLOT_NONE ? " (none)" : "");
+
+	for (i = 0; i < NAU8360_TDM_RXN; i++)
+		dev_dbg(nau8360->dev, "dsp-rx-slot[%d] (%s): %d%s", i,
+			nau8360_rx_func_names[i], nau8360->tdm_rx_func_slot[i],
+			nau8360->tdm_rx_func_slot[i] == TDM_SLOT_NONE ? " (none)" : "");
+}
+
+static int nau8360_read_device_properties(struct nau8360 *nau8360)
+{
+	const char *def_fws[NAU8360_DSP_FW_NUM] = {
+		NAU8360_DSP_FIRMWARE".l", NAU8360_DSP_FIRMWARE".r"
+	};
+	struct device *dev = nau8360->dev;
+	const char *firmware_names[NAU8360_DSP_FW_NUM];
+	int i, ret;
+
+	ret = device_property_read_u32_array(dev, "nuvoton,dsp-tx-slot-mapping",
+		nau8360->tdm_tx_func_slot, NAU8360_TDM_TXN);
+	if (ret) {
+		for (i = 0; i < NAU8360_TDM_TXN; i++)
+			nau8360->tdm_tx_func_slot[i] = TDM_SLOT_NONE;
+	} else {
+		for (i = 0; i < NAU8360_TDM_TXN; i++) {
+			if (nau8360->tdm_tx_func_slot[i] == TDM_SLOT_NONE)
+				continue;
+			if (nau8360->tdm_tx_func_slot[i] >= NAU8360_TDM_MAX_CHAN) {
+				dev_warn(dev, "Invalid TX slot %d, set to none\n",
+					nau8360->tdm_tx_func_slot[i]);
+				nau8360->tdm_tx_func_slot[i] = TDM_SLOT_NONE;
+			}
+		}
+	}
+
+	ret = device_property_read_u32_array(dev, "nuvoton,dsp-rx-slot-mapping",
+		nau8360->tdm_rx_func_slot, NAU8360_TDM_RXN);
+	if (ret) {
+		nau8360->tdm_rx_func_slot[NAU8360_TDM_DACL] = 0;
+		nau8360->tdm_rx_func_slot[NAU8360_TDM_DACR] = 1;
+		nau8360->tdm_rx_func_slot[NAU8360_TDM_ANCL] = TDM_SLOT_NONE;
+		nau8360->tdm_rx_func_slot[NAU8360_TDM_ANCR] = TDM_SLOT_NONE;
+	} else {
+		for (i = 0; i < NAU8360_TDM_RXN; i++) {
+			if (nau8360->tdm_rx_func_slot[i] == TDM_SLOT_NONE)
+				continue;
+			if (nau8360->tdm_rx_func_slot[i] >= NAU8360_TDM_MAX_CHAN) {
+				dev_warn(dev, "Invalid RX slot %d, set to none\n",
+					nau8360->tdm_rx_func_slot[i]);
+				nau8360->tdm_rx_func_slot[i] = TDM_SLOT_NONE;
+			}
+		}
+	}
+
+	nau8360->pbtl_enable = device_property_read_bool(dev, "nuvoton,pbtl-enable");
+	nau8360->dac_cur_enable = device_property_read_bool(dev, "nuvoton,dac-cur-enable");
+
+	ret = device_property_read_string_array(dev, "firmware-name",
+		firmware_names, NAU8360_DSP_FW_NUM);
+	if (ret !=  NAU8360_DSP_FW_NUM) {
+		dev_warn(dev, "The firmware-name was not found, using default.");
+		for (i = 0; i < NAU8360_DSP_FW_NUM; i++) {
+			nau8360->dsp_firmware[i] = devm_kstrdup(dev, def_fws[i], GFP_KERNEL);
+
+			if (!nau8360->dsp_firmware[i])
+				return -ENOMEM;
+		}
+	} else {
+		for (i = 0; i < NAU8360_DSP_FW_NUM; i++) {
+			nau8360->dsp_firmware[i] = devm_kasprintf(dev, GFP_KERNEL,
+				NAU8360_DSP_FIRMDIR "%s", firmware_names[i]);
+
+			if (!nau8360->dsp_firmware[i])
+				return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static struct reg_default *nau8360_alloc_defaults(struct device *dev, int *total_regs)
+{
+	struct reg_default *dyn_defaults;
+	int reg_num = ARRAY_SIZE(nau8360_reg_defaults);
+	int total = reg_num + (2 * NAU8360_TOT_BAND_PER_CH * NAU8360_TOT_BAND_COE);
+	int i, j, idx;
+
+	dyn_defaults = devm_kzalloc(dev, total * sizeof(*dyn_defaults), GFP_KERNEL);
+	if (!dyn_defaults)
+		return NULL;
+
+	memcpy(dyn_defaults, nau8360_reg_defaults, sizeof(*dyn_defaults) * reg_num);
+	idx = reg_num;
+
+	for (i = 0; i < NAU8360_TOT_BAND_PER_CH; i++) {
+		unsigned int range = i * NAU8360_TOT_BAND_COE_RANGE;
+		unsigned int l_base = NAU8360_R100_LEFT_BIQ0_COE + range;
+		unsigned int r_base = NAU8360_R200_RIGHT_BIQ0_COE + range;
+
+		for (j = 0; j < NAU8360_TOT_BAND_COE; j++) {
+			dyn_defaults[idx++].reg = l_base + j;
+			dyn_defaults[idx++].reg = r_base + j;
+		}
+	}
+
+	*total_regs = total;
+
+	return dyn_defaults;
+}
+
+static int nau8360_i2c_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8360 *nau8360;
+	struct regmap_config regmap_cfg = nau8360_regmap_config;
+	struct reg_default *dyn_defaults;
+	int num_total_regs;
+	int ret, value;
+
+	nau8360 = devm_kzalloc(dev, sizeof(*nau8360), GFP_KERNEL);
+	if (!nau8360)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, nau8360);
+	mutex_init(&nau8360->lock);
+	INIT_WORK(&nau8360->load_fw_work, nau8360_load_fw_work);
+
+	dyn_defaults = nau8360_alloc_defaults(dev, &num_total_regs);
+	if (!dyn_defaults)
+		return -ENOMEM;
+
+	regmap_cfg.reg_defaults = dyn_defaults;
+	regmap_cfg.num_reg_defaults = num_total_regs;
+
+	nau8360->regmap = devm_regmap_init(dev, NULL, i2c, &regmap_cfg);
+	if (IS_ERR(nau8360->regmap))
+		return PTR_ERR(nau8360->regmap);
+	nau8360->dev = dev;
+
+	nau8360_reset_chip(nau8360->regmap);
+	ret = regmap_read(nau8360->regmap, NAU8360_R46_I2C_DEVICE_ID, &value);
+	if (ret) {
+		dev_err(dev, "Failed to read NAU83G60 device id %d", ret);
+		return ret;
+	}
+
+	ret = nau8360_read_device_properties(nau8360);
+	if (ret)
+		return ret;
+
+	nau8360_print_device_properties(nau8360);
+	nau8360_init_regs(nau8360);
+
+	return devm_snd_soc_register_component(dev, &soc_comp_dev_nau8360, &nau8360_dai, 1);
+}
+
+static void nau8360_i2c_remove(struct i2c_client *client)
+{
+	struct nau8360 *nau8360 = i2c_get_clientdata(client);
+
+	cancel_work_sync(&nau8360->load_fw_work);
+}
+
+static const struct i2c_device_id nau8360_i2c_ids[] = {
+	{ .name = "nau8360" },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, nau8360_i2c_ids);
+
+static const struct of_device_id nau8360_of_ids[] = {
+	{ .compatible = "nuvoton,nau8360" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, nau8360_of_ids);
+
+static const struct acpi_device_id nau8360_acpi_match[] = {
+	{ .id = "NVTN2002" },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, nau8360_acpi_match);
+
+static struct i2c_driver nau8360_i2c_driver = {
+	.driver = {
+		.name = "nau8360",
+		.of_match_table = of_match_ptr(nau8360_of_ids),
+		.acpi_match_table = ACPI_PTR(nau8360_acpi_match),
+	},
+	.probe = nau8360_i2c_probe,
+	.remove = nau8360_i2c_remove,
+	.id_table = nau8360_i2c_ids,
+};
+module_i2c_driver(nau8360_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU83G60 Stereo Class-D Amplifier with DSP and I/V-sense driver");
+MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
+MODULE_AUTHOR("Seven Lee <wtli@nuvoton.com>");
+MODULE_AUTHOR("John Hsu <kchsu0@nuvoton.com>");
+MODULE_AUTHOR("Neo Chang <ylchang2@nuvoton.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/nau8360.h b/sound/soc/codecs/nau8360.h
new file mode 100644
index 0000000..7139674
--- /dev/null
+++ b/sound/soc/codecs/nau8360.h
@@ -0,0 +1,917 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// The NAU83G60 Stereo Class-D Amplifier with DSP and I/V-sense driver.
+//
+// Copyright (C) 2026 Nuvoton Technology Corp.
+// Author: David Lin <ctlin0@nuvoton.com>
+//         Seven Lee <wtli@nuvoton.com>
+//         John Hsu <kchsu0@nuvoton.com>
+//         Neo Chang <ylchang2@nuvoton.com>
+
+#ifndef __NAU8360_H__
+#define __NAU8360_H__
+
+#define NAU8360_R00_SOFTWARE_RST		0x00
+#define NAU8360_R01_DSP_SOFTWARE_RST		0x01
+#define NAU8360_R02_I2C_ADDR			0x02
+#define NAU8360_R03_CLK_CTRL0			0x03
+#define NAU8360_R04_CLK_CTRL1			0x04
+#define NAU8360_R05_INTERRUPT_CTRL		0x05
+#define NAU8360_R06_INT_CLR_STATUS		0x06
+#define NAU8360_R07_GP_CTRL			0x07
+#define NAU8360_R08_GP_CTRL0			0x08
+#define NAU8360_R09_GP_CTRL1			0x09
+#define NAU8360_R0A_GP_CTRL2			0x0a
+#define NAU8360_R0B_I2S_PCM_CTRL1		0x0b
+#define NAU8360_R0C_I2S_PCM_CTRL2		0x0c
+#define NAU8360_R0D_I2S_PCM_CTRL3		0x0d
+#define NAU8360_R0E_I2S_DATA_CTRL1		0x0e
+#define NAU8360_R0F_I2S_DATA_CTRL2		0x0f
+#define NAU8360_R10_I2S_DATA_CTRL3		0x10
+#define NAU8360_R11_I2S_DATA_CTRL4		0x11
+#define NAU8360_R12_PATH_CTRL			0x12
+#define NAU8360_R16_NO_NAME			0x16
+#define NAU8360_R17_I2S0_DATA_CTRL5		0x17
+#define NAU8360_R1A_DSP_CORE_CTRL2		0x1a
+#define NAU8360_R21_VBAT_READOUT		0x21
+#define NAU8360_R22_TEMP_READOUT		0x22
+#define NAU8360_R2C_ALC_CTRL1			0x2c
+#define NAU8360_R2D_ALC_CTRL2			0x2d
+#define NAU8360_R2E_ALC_CTRL3			0x2e
+#define NAU8360_R31_UVLOP_CTRL1			0x31
+#define NAU8360_R32_UVLOP_CTRL2			0x32
+#define NAU8360_R33_UVLOP_CTRL3			0x33
+#define NAU8360_R40_CLK_DET_CTRL		0x40
+#define NAU8360_R41_CLK_CTL2			0x41
+#define NAU8360_R46_I2C_DEVICE_ID		0x46
+#define NAU8360_R5D_SINC_CFG			0x5d
+#define NAU8360_R5F_ANA_TRIM_CFG1		0x5f
+#define NAU8360_R60_RST				0x60
+#define NAU8360_R67_ANALOG_CONTROL_0		0x67
+#define NAU8360_R68_ANALOG_CONTROL_1		0x68
+#define NAU8360_R69_ANALOG_CONTROL_3		0x69
+#define NAU8360_R6A_SARADC_CFG0			0x6a
+#define NAU8360_R6B_SARADC_CFG1			0x6b
+#define NAU8360_R6C_IVSNS_CFG0			0x6c
+#define NAU8360_R6D_IVSNS_CFG1			0x6d
+#define NAU8360_R6E_DAC_CFG0			0x6e
+#define NAU8360_R71_CLK_DIV_CFG			0x71
+#define NAU8360_R72_PLL_CFG0			0x72
+#define NAU8360_R73_PLL_CFG1			0x73
+#define NAU8360_R74_PLL_CFG2			0x74
+#define NAU8360_R77_SOFT_SD			0x77
+#define NAU8360_R78_PD_SW_DLDO			0x78
+#define NAU8360_R79_EN_HIRC48M			0x79
+#define NAU8360_R7A_DAC_TRIM_CFG2		0x7a
+#define NAU8360_R7B_IVSNS_TRIM_CFG		0x7b
+#define NAU8360_R7C_MISC_TRIM_CFG		0x7c
+#define NAU8360_R7E_CLK_GATED_EN		0x7e
+#define NAU8360_R86_HW3_CTL0			0x86
+#define NAU8360_R88_ALC_CTRL6			0x88
+#define NAU8360_R8A_HW3_VL_CTL7			0x8a
+#define NAU8360_R8B_HW3_VR_CTL8			0x8b
+#define NAU8360_R8C_HW3_CTL6			0x8c
+#define NAU8360_R8D_HW3_IL_CTL7			0x8d
+#define NAU8360_R8E_HW3_IR_CTL8			0x8e
+#define NAU8360_R8F_HW3_CTL9			0x8f
+#define NAU8360_R90_HW2_CTL0			0x90
+#define NAU8360_R96_HW2_CTL6			0x96
+#define NAU8360_R97_HW2_CTL7			0x97
+#define NAU8360_R98_HW2_CTL8			0x98
+#define NAU8360_R99_HW2_CTL9			0x99
+#define NAU8360_R9A_HW1_CTL0			0x9a
+#define NAU8360_R9B_HW1_CTL1			0x9b
+#define NAU8360_R9C_HW1_CTL2			0x9c
+#define NAU8360_R9D_PEQ_CTL			0x9d
+#define NAU8360_RA0_LEFT_XODRC_CTRL		0xa0
+#define NAU8360_RA2_RIGHT_XODRC_CTRL		0xa2
+#define NAU8360_RA4_ANA_REG_0			0xa4
+#define NAU8360_RA5_ANA_REG_1			0xa5
+/* Left PEQ includes 15 band, 10 coeff per band, from start addr 0x100 */
+#define NAU8360_R100_LEFT_BIQ0_COE		0x100
+#define NAU8360_R10C_LEFT_BIQ1_COE		0x10c
+#define NAU8360_R118_LEFT_BIQ2_COE		0x118
+#define NAU8360_R124_LEFT_BIQ3_COE		0x124
+#define NAU8360_R130_LEFT_BIQ4_COE		0x130
+#define NAU8360_R13C_LEFT_BIQ5_COE		0x13c
+#define NAU8360_R148_LEFT_BIQ6_COE		0x148
+#define NAU8360_R154_LEFT_BIQ7_COE		0x154
+#define NAU8360_R160_LEFT_BIQ8_COE		0x160
+#define NAU8360_R16C_LEFT_BIQ9_COE		0x16c
+#define NAU8360_R178_LEFT_BIQ10_COE		0x178
+#define NAU8360_R184_LEFT_BIQ11_COE		0x184
+#define NAU8360_R190_LEFT_BIQ12_COE		0x190
+#define NAU8360_R19C_LEFT_BIQ13_COE		0x19c
+#define NAU8360_R1A8_LEFT_BIQ14_COE		0x1a8
+/* Right PEQ includes 15 band, 10 coeff per band, from start addr 0x200 */
+#define NAU8360_R200_RIGHT_BIQ0_COE		0x200
+#define NAU8360_R20C_RIGHT_BIQ1_COE		0x20c
+#define NAU8360_R218_RIGHT_BIQ2_COE		0x218
+#define NAU8360_R224_RIGHT_BIQ3_COE		0x224
+#define NAU8360_R230_RIGHT_BIQ4_COE		0x230
+#define NAU8360_R23C_RIGHT_BIQ5_COE		0x23c
+#define NAU8360_R248_RIGHT_BIQ6_COE		0x248
+#define NAU8360_R254_RIGHT_BIQ7_COE		0x254
+#define NAU8360_R260_RIGHT_BIQ8_COE		0x260
+#define NAU8360_R26C_RIGHT_BIQ9_COE		0x26c
+#define NAU8360_R278_RIGHT_BIQ10_COE		0x278
+#define NAU8360_R284_RIGHT_BIQ11_COE		0x284
+#define NAU8360_R290_RIGHT_BIQ12_COE		0x290
+#define NAU8360_R29C_RIGHT_BIQ13_COE		0x29c
+#define NAU8360_R2A8_RIGHT_BIQ14_COE		0x2a8
+#define NAU8360_RF000_DSP_COMM			0xf000
+#define NAU8360_RF002_DSP_COMM			0xf002
+#define NAU8360_REG_MAX				NAU8360_RF002_DSP_COMM
+
+/* 16-bit control register address, and 16-bits control register data */
+#define NAU8360_REG_ADDR_LEN			16
+#define NAU8360_REG_DATA_LEN			16
+
+/* NAU8360_R03_CLK_CTRL0 (0x03) */
+#define NAU8360_MCLK_DIV_SFT			10
+#define NAU8360_MCLK_DIV_MAX			0x3f
+#define NAU8360_MCLK_DIV_MASK			(0x3f << NAU8360_MCLK_DIV_SFT)
+#define NAU8360_DSP_CLK_DIV_SFT			7
+#define NAU8360_DSP_CLK_DIV_MAX			0x7
+#define NAU8360_DSP_CLK_DIV_MASK		(0x7 << NAU8360_DSP_CLK_DIV_SFT)
+#define NAU8360_DSP_CLK_SEL_SFT			5
+#define NAU8360_DSP_CLK_SEL_MASK		(0x3 << NAU8360_DSP_CLK_SEL_SFT)
+#define NAU8360_DSP_CLK_SEL_PLL			(0x2 << NAU8360_DSP_CLK_SEL_SFT)
+#define NAU8360_DSP_CLK_SEL_HIRC48M		(0x1 << NAU8360_DSP_CLK_SEL_SFT)
+#define NAU8360_DSP_CLK_SEL_MCLK		(0x0 << NAU8360_DSP_CLK_SEL_SFT)
+
+/* NAU8360_R04_CLK_CTRL1 (0x4) */
+#define NAU8360_MCLK_SEL_SFT			14
+#define NAU8360_MCLK_SEL_MASK			(0x3 << NAU8360_MCLK_SEL_SFT)
+#define NAU8360_MCLK_SEL_PLL			(0x2 << NAU8360_MCLK_SEL_SFT)
+#define NAU8360_MCLK_SEL_HIRC48M		(0x1 << NAU8360_MCLK_SEL_SFT)
+#define NAU8360_MCLK_SEL_MCLK			(0x0 << NAU8360_MCLK_SEL_SFT)
+#define NAU8360_HW_CLK_SEL_SFT			10
+#define NAU8360_HW_CLK_SEL_MASK			(0x3 << NAU8360_HW_CLK_SEL_SFT)
+#define NAU8360_HW_CLK_SEL_PLL			(0x2 << NAU8360_HW_CLK_SEL_SFT)
+#define NAU8360_HW_CLK_SEL_HIRC48M		(0x1 << NAU8360_HW_CLK_SEL_SFT)
+#define NAU8360_HW_CLK_SEL_MCLK			(0x0 << NAU8360_HW_CLK_SEL_SFT)
+#define NAU8360_HW_CLK_DIV_SFT			7
+#define NAU8360_HW_CLK_DIV_MAX			NAU8360_DSP_CLK_DIV_MAX
+#define NAU8360_HW_CLK_DIV_MASK			(0x7 << NAU8360_HW_CLK_DIV_SFT)
+
+/* NAU8360_R07_GP_CTRL (0x7) */
+#define NAU8360_GPIO1_IEOE_SFT			14
+#define NAU8360_GPIO1_IEOE_MASK			(0x3 << NAU8360_GPIO1_IEOE_SFT)
+#define NAU8360_GPIO2_IEOE_SFT			12
+#define NAU8360_GPIO2_IEOE_MASK			(0x3 << NAU8360_GPIO2_IEOE_SFT)
+#define NAU8360_GPIO3_IEOE_SFT			10
+#define NAU8360_GPIO3_IEOE_MASK			(0x3 << NAU8360_GPIO3_IEOE_SFT)
+#define NAU8360_GPIO4_IEOE_SFT			8
+#define NAU8360_GPIO4_IEOE_MASK			(0x3 << NAU8360_GPIO4_IEOE_SFT)
+#define NAU8360_GPIO1_IN_STAT_SFT		7
+#define NAU8360_GPIO1_IN_STAT_MASK		(0x1 << NAU8360_GPIO1_IN_STAT_SFT)
+#define NAU8360_GPIO2_IN_STAT_SFT		6
+#define NAU8360_GPIO2_IN_STAT_MASK		(0x1 << NAU8360_GPIO2_IN_STAT_SFT)
+#define NAU8360_GPIO3_IN_STAT_SFT		5
+#define NAU8360_GPIO3_IN_STAT_MASK		(0x1 << NAU8360_GPIO3_IN_STAT_SFT)
+#define NAU8360_GPIO4_IN_STAT_SFT		4
+#define NAU8360_GPIO4_IN_STAT_MASK		(0x1 << NAU8360_GPIO4_IN_STAT_SFT)
+
+/* NAU8360_R08_GP_CTRL0 (0x8) */
+#define NAU8360_GPIO2_MUX_SFT			14
+#define NAU8360_GPIO2_MUX_MASK			(0x3 << NAU8360_GPIO2_MUX_SFT)
+#define NAU8360_GPIO2_SR_SFT			13
+#define NAU8360_GPIO2_SR_MASK			(0x1 << NAU8360_GPIO2_SR_SFT)
+#define NAU8360_GPIO2_CDS_SFT			11
+#define NAU8360_GPIO2_CDS_MASK			(0x3 << NAU8360_GPIO2_CDS_SFT)
+#define NAU8360_GPIO2_PS_SFT			10
+#define NAU8360_GPIO2_PS_MASK			(0x1 << NAU8360_GPIO2_PS_SFT)
+#define NAU8360_GPIO2_PE_SFT			9
+#define NAU8360_GPIO2_PE_EN			(0x1 << NAU8360_GPIO2_PE_SFT)
+#define NAU8360_GPIO1_MUX_SFT			6
+#define NAU8360_GPIO1_MUX_MASK			(0x3 << NAU8360_GPIO1_MUX_SFT)
+#define NAU8360_GPIO1_SR_SFT			5
+#define NAU8360_GPIO1_SR_MASK			(0x1 << NAU8360_GPIO1_SR_SFT)
+#define NAU8360_GPIO1_CDS_SFT			3
+#define NAU8360_GPIO1_CDS_MASK			(0x3 << NAU8360_GPIO1_CDS_SFT)
+#define NAU8360_GPIO1_PS_SFT			2
+#define NAU8360_GPIO1_PS_MASK			(0x1 << NAU8360_GPIO1_PS_SFT)
+#define NAU8360_GPIO1_PE_SFT			1
+#define NAU8360_GPIO1_PE_EN			(0x1 << NAU8360_GPIO1_PE_SFT)
+
+/* NAU8360_R09_GP_CTRL1 (0x9) */
+#define NAU8360_GPIO4_MUX_SFT			14
+#define NAU8360_GPIO4_MUX_MASK			(0x3 << NAU8360_GPIO4_MUX_SFT)
+#define NAU8360_GPIO4_SR_SFT			13
+#define NAU8360_GPIO4_SR_MASK			(0x1 << NAU8360_GPIO4_SR_SFT)
+#define NAU8360_GPIO4_CDS_SFT			11
+#define NAU8360_GPIO4_CDS_MASK			(0x3 << NAU8360_GPIO4_CDS_SFT)
+#define NAU8360_GPIO4_PS_SFT			10
+#define NAU8360_GPIO4_PS_MASK			(0x1 << NAU8360_GPIO4_PS_SFT)
+#define NAU8360_GPIO4_PE_SFT			9
+#define NAU8360_GPIO4_PE_EN			(0x1 << NAU8360_GPIO4_PE_SFT)
+#define NAU8360_GPIO3_MUX_SFT			6
+#define NAU8360_GPIO3_MUX_MASK			(0x3 << NAU8360_GPIO3_MUX_SFT)
+#define NAU8360_GPIO3_SR_SFT			5
+#define NAU8360_GPIO3_SR_MASK			(0x1 << NAU8360_GPIO3_SR_SFT)
+#define NAU8360_GPIO3_CDS_SFT			3
+#define NAU8360_GPIO3_CDS_MASK			(0x3 << NAU8360_GPIO3_CDS_SFT)
+#define NAU8360_GPIO3_PS_SFT			2
+#define NAU8360_GPIO3_PS_MASK			(0x1 << NAU8360_GPIO3_PS_SFT)
+#define NAU8360_GPIO3_PE_SFT			1
+#define NAU8360_GPIO3_PE_EN			(0x1 << NAU8360_GPIO3_PE_SFT)
+
+/* NAU8360_R0B_I2S_PCM_CTRL1 (0x0b) */
+#define NAU8360_EN_TDM_TX_SFT			15
+#define NAU8360_EN_TDM_TX			(0x1 << NAU8360_EN_TDM_TX_SFT)
+#define NAU8360_EN_TDM_RX_SFT			14
+#define NAU8360_EN_TDM_RX			(0x1 << NAU8360_EN_TDM_RX_SFT)
+#define NAU8360_FRAME_START_SFT			8
+#define NAU8360_FRAME_START_MASK		(0x1 << NAU8360_FRAME_START_SFT)
+#define NAU8360_FRAME_START_H2L			(0x1 << NAU8360_FRAME_START_SFT)
+#define NAU8360_FRAME_START_L2H			(0x0 << NAU8360_FRAME_START_SFT)
+#define NAU8360_RX_JUSTIFY_SFT			7
+#define NAU8360_RX_JUSTIFY_MASK			(0x1 << NAU8360_RX_JUSTIFY_SFT)
+#define NAU8360_RX_RIGHT_JUSTIFY		(0x1 << NAU8360_RX_JUSTIFY_SFT)
+#define NAU8360_RX_LEFT_JUSTIFY			(0x0 << NAU8360_RX_JUSTIFY_SFT)
+#define NAU8360_RX_OFFSET_SFT			2
+#define NAU8360_RX_OFFSET_MASK			(0x1f << NAU8360_RX_OFFSET_SFT)
+#define NAU8360_RX_OFFSET_I2S			(0x1 << NAU8360_RX_OFFSET_SFT)
+#define NAU8360_RX_OFFSET_LEFT			(0x0 << NAU8360_RX_OFFSET_SFT)
+#define NAU8360_RX_OFFSET_RIGHT			(0x0 << NAU8360_RX_OFFSET_SFT)
+#define NAU8360_RX_OFFSET_PCM_A			(0x1 << NAU8360_RX_OFFSET_SFT)
+#define NAU8360_RX_OFFSET_PCM_B			(0x0 << NAU8360_RX_OFFSET_SFT)
+
+/* NAU8360_R0C_I2S_PCM_CTRL2 (0xc) */
+#define NAU8360_TDM_DLEN_SFT			10
+#define NAU8360_TDM_DLEN_MASK			(0x3 << NAU8360_TDM_DLEN_SFT)
+#define NAU8360_TDM_DLEN_32			(0x3 << NAU8360_TDM_DLEN_SFT)
+#define NAU8360_TDM_DLEN_24			(0x2 << NAU8360_TDM_DLEN_SFT)
+#define NAU8360_TDM_DLEN_20			(0x1 << NAU8360_TDM_DLEN_SFT)
+#define NAU8360_TDM_DLEN_16			(0x0 << NAU8360_TDM_DLEN_SFT)
+#define NAU8360_TDM_CLEN_SFT			8
+#define NAU8360_TDM_CLEN_MASK			(0x3 << NAU8360_TDM_CLEN_SFT)
+#define NAU8360_TDM_CLEN_32			(0x2 << NAU8360_TDM_CLEN_SFT)
+#define NAU8360_TDM_CLEN_24			(0x1 << NAU8360_TDM_CLEN_SFT)
+#define NAU8360_TDM_CLEN_16			(0x0 << NAU8360_TDM_CLEN_SFT)
+#define NAU8360_RX_DACR_SFT			4
+#define NAU8360_RX_DACR_MASK			(0xf << NAU8360_RX_DACR_SFT)
+#define NAU8360_RX_DACL_MASK			0xf
+
+/* NAU8360_R0D_I2S_PCM_CTRL3 (0x0d) */
+#define NAU8360_TX_FILL_SFT			12
+#define NAU8360_TX_FILL_MASK			(0x1 << NAU8360_TX_FILL_SFT)
+#define NAU8360_TX_FILL_HIGHZ			(0x1 << NAU8360_TX_FILL_SFT)
+#define NAU8360_TX_FILL_ZERO			(0x0 << NAU8360_TX_FILL_SFT)
+#define NAU8360_TX_OFFSET_SFT			9
+#define NAU8360_TX_OFFSET_MASK			(0x7 << NAU8360_TX_OFFSET_SFT)
+#define NAU8360_TX_OFFSET_I2S			(0x1 << NAU8360_TX_OFFSET_SFT)
+#define NAU8360_TX_OFFSET_LEFT			(0x0 << NAU8360_TX_OFFSET_SFT)
+#define NAU8360_TX_OFFSET_RIGHT			(0x0 << NAU8360_TX_OFFSET_SFT)
+#define NAU8360_TX_OFFSET_PCM_A			(0x1 << NAU8360_TX_OFFSET_SFT)
+#define NAU8360_TX_OFFSET_PCM_B			(0x0 << NAU8360_TX_OFFSET_SFT)
+#define NAU8360_VSNS_L_SLEN_SFT			7
+#define NAU8360_VSNS_L_SLEN_MASK		(0x1 << NAU8360_VSNS_L_SLEN_SFT)
+#define NAU8360_VSNS_L_SLEN_16			(0x1 << NAU8360_VSNS_L_SLEN_SFT)
+#define NAU8360_VSNS_L_SLEN_8			(0x0 << NAU8360_VSNS_L_SLEN_SFT)
+#define NAU8360_VSNS_L_TX_EN_SFT		6
+#define NAU8360_VSNS_L_TX_EN			(0x1 << NAU8360_VSNS_L_TX_EN_SFT)
+#define NAU8360_VSNS_L_SLOT_MASK		0x3f
+
+/* NAU8360_R0E_I2S_DATA_CTRL1 (0x0e) */
+#define NAU8360_ISNS_L_SLEN_SFT			15
+#define NAU8360_ISNS_L_SLEN_MASK		(0x1 << NAU8360_ISNS_L_SLEN_SFT)
+#define NAU8360_ISNS_L_SLEN_16			(0x1 << NAU8360_ISNS_L_SLEN_SFT)
+#define NAU8360_ISNS_L_SLEN_8			(0x0 << NAU8360_ISNS_L_SLEN_SFT)
+#define NAU8360_ISNS_L_TX_EN_SFT		14
+#define NAU8360_ISNS_L_TX_EN			(0x1 << NAU8360_ISNS_L_TX_EN_SFT)
+#define NAU8360_ISNS_L_SLOT_SFT			8
+#define NAU8360_ISNS_L_SLOT_MASK		(0x3f << NAU8360_ISNS_L_SLOT_SFT)
+#define NAU8360_PDM_L_SLEN_SFT			7
+#define NAU8360_PDM_L_SLEN_MASK			(0x1 << NAU8360_PDM_L_SLEN_SFT)
+#define NAU8360_PDM_L_SLEN_24			(0x1 << NAU8360_PDM_L_SLEN_SFT)
+#define NAU8360_PDM_L_SLEN_16			(0x0 << NAU8360_PDM_L_SLEN_SFT)
+#define NAU8360_PDM_L_TX_EN_SFT			6
+#define NAU8360_PDM_L_TX_EN			(0x1 << NAU8360_PDM_L_TX_EN_SFT)
+#define NAU8360_PDM_L_SLOT_MASK			0x3f
+
+/* NAU8360_R0F_I2S_DATA_CTRL2 (0xf) */
+#define NAU8360_VBAT_TX_EN_SFT			14
+#define NAU8360_VBAT_TX_EN			(0x1 << NAU8360_VBAT_TX_EN_SFT)
+#define NAU8360_VBAT_SLOT_SFT			8
+#define NAU8360_VBAT_SLOT_MASK			(0x3f << NAU8360_VBAT_SLOT_SFT)
+#define NAU8360_PDM_R_SLEN_SFT			7
+#define NAU8360_PDM_R_SLEN_MASK			(0x1 << NAU8360_PDM_R_SLEN_SFT)
+#define NAU8360_PDM_R_SLEN_24			(0x1 << NAU8360_PDM_R_SLEN_SFT)
+#define NAU8360_PDM_R_SLEN_16			(0x0 << NAU8360_PDM_R_SLEN_SFT)
+#define NAU8360_PDM_R_TX_EN_SFT			6
+#define NAU8360_PDM_R_TX_EN			(0x1 << NAU8360_PDM_R_TX_EN_SFT)
+#define NAU8360_PDM_R_SLOT_MASK			0x3f
+
+/* NAU8360_R10_I2S_DATA_CTRL3 (0x10) */
+#define NAU8360_RX_ANC_R_SFT			12
+#define NAU8360_RX_ANC_R_MASK			(0xf << NAU8360_RX_ANC_R_SFT)
+#define NAU8360_RX_ANC_L_SFT			8
+#define NAU8360_RX_ANC_L_MASK			(0xf << NAU8360_RX_ANC_L_SFT)
+#define NAU8360_TDM_LOOPBACK_SFT		7
+#define NAU8360_TDM_LOOPBACK			(0x1 << NAU8360_TDM_LOOPBACK_SFT)
+#define NAU8360_TEMP_TX_EN_SFT			6
+#define NAU8360_TEMP_TX_EN			(0x1 << NAU8360_TEMP_TX_EN_SFT)
+#define NAU8360_TEMP_SLOT_MASK			0x3f
+
+/* NAU8360_R11_I2S_DATA_CTRL4 (0x11) */
+#define NAU8360_VSNS_R_SLEN_SFT			15
+#define NAU8360_VSNS_R_SLEN_MASK		(0x1 << NAU8360_VSNS_R_SLEN_SFT)
+#define NAU8360_VSNS_R_SLEN_16			(0x1 << NAU8360_VSNS_R_SLEN_SFT)
+#define NAU8360_VSNS_R_SLEN_8			(0x0 << NAU8360_VSNS_R_SLEN_SFT)
+#define NAU8360_VSNS_R_TX_EN_SFT		14
+#define NAU8360_VSNS_R_TX_EN			(0x1 << NAU8360_VSNS_R_TX_EN_SFT)
+#define NAU8360_VSNS_R_SLOT_SFT			8
+#define NAU8360_VSNS_R_SLOT_MASK		(0x3f << NAU8360_VSNS_R_SLOT_SFT)
+#define NAU8360_ISNS_R_SLEN_SFT			7
+#define NAU8360_ISNS_R_SLEN_MASK		(0x1 << NAU8360_ISNS_R_SLEN_SFT)
+#define NAU8360_ISNS_R_SLEN_16			(0x1 << NAU8360_ISNS_R_SLEN_SFT)
+#define NAU8360_ISNS_R_SLEN_8			(0x0 << NAU8360_ISNS_R_SLEN_SFT)
+#define NAU8360_ISNS_R_TX_EN_SFT		6
+#define NAU8360_ISNS_R_TX_EN			(0x1 << NAU8360_ISNS_R_TX_EN_SFT)
+#define NAU8360_ISNS_R_SLOT_MASK		0x3f
+
+/* NAU8360_R12_PATH_CTRL (0x12) */
+#define NAU8360_SEL_HW1_SFT			9
+#define NAU8360_SEL_HW1_MASK			(0x1 << NAU8360_SEL_HW1_SFT)
+#define NAU8360_SEL_HW1_OUT			(0x1 << NAU8360_SEL_HW1_SFT)
+#define NAU8360_SEL_HW1_BYP			(0x0 << NAU8360_SEL_HW1_SFT)
+#define NAU8360_AUD_SEL_SFT			7
+#define NAU8360_AUD_SEL_MASK			(0x1 << NAU8360_AUD_SEL_SFT)
+#define NAU8360_AUD_SEL_SINCOUT			(0x1 << NAU8360_AUD_SEL_SFT)
+#define NAU8360_AUD_SEL_SINCBYP			(0x0 << NAU8360_AUD_SEL_SFT)
+#define NAU8360_SEL_HW2_SFT			6
+#define NAU8360_SEL_HW2_MASK			(0x1 << NAU8360_SEL_HW2_SFT)
+#define NAU8360_SEL_HW2_OUT			(0x1 << NAU8360_SEL_HW2_SFT)
+#define NAU8360_SEL_HW2_BYP			(0x0 << NAU8360_SEL_HW2_SFT)
+#define NAU8360_DAC_SEL_SFT			5
+#define NAU8360_DAC_SEL_MASK			(0x1 << NAU8360_DAC_SEL_SFT)
+#define NAU8360_DAC_SEL_DSP			(0x1 << NAU8360_DAC_SEL_SFT)
+#define NAU8360_DAC_SEL_BYP			(0x0 << NAU8360_DAC_SEL_SFT)
+#define NAU8360_SEL_HW3_SFT			4
+#define NAU8360_SEL_HW3_MASK			(0x1 << NAU8360_SEL_HW3_SFT)
+#define NAU8360_SEL_HW3_OUT			(0x1 << NAU8360_SEL_HW3_SFT)
+#define NAU8360_SEL_HW3_BYP			(0x0 << NAU8360_SEL_HW3_SFT)
+
+/* NAU8360_R17_I2S0_DATA_CTRL5 (0x17)*/
+#define NAU8360_AEC_L_SLEN_SFT			15
+#define NAU8360_AEC_L_SLEN_MASK			(0x1 << NAU8360_AEC_L_SLEN_SFT)
+#define NAU8360_AEC_L_SLEN_32			(0x1 << NAU8360_AEC_L_SLEN_SFT)
+#define NAU8360_AEC_L_SLEN_16			(0x0 << NAU8360_AEC_L_SLEN_SFT)
+#define NAU8360_AEC_L_EN_SFT			14
+#define NAU8360_AEC_L_EN			(0x1 << NAU8360_AEC_L_EN_SFT)
+#define NAU8360_AEC_L_SLOT_SFT			8
+#define NAU8360_AEC_L_SLOT_MASK			(0x3f << NAU8360_AEC_L_SLOT_SFT)
+#define NAU8360_AEC_R_SLEN_SFT			7
+#define NAU8360_AEC_R_SLEN_MASK			(0x1 << NAU8360_AEC_R_SLEN_SFT)
+#define NAU8360_AEC_R_SLEN_32			(0x1 << NAU8360_AEC_R_SLEN_SFT)
+#define NAU8360_AEC_R_SLEN_16			(0x0 << NAU8360_AEC_R_SLEN_SFT)
+#define NAU8360_AEC_R_EN_SFT			6
+#define NAU8360_AEC_R_EN			(0x1 << NAU8360_AEC_R_EN_SFT)
+#define NAU8360_AEC_R_SLOT_MASK			0x3f
+
+/* NAU8360_R1A_DSP_CORE_CTRL2 (0x1a) */
+#define NAU8360_DSP_RUNSTALL_SFT		4
+#define NAU8360_DSP_RUNSTALL			(0x1 << NAU8360_DSP_RUNSTALL_SFT)
+
+/* NAU8360_R21_VBAT_READOUT (0x21) */
+#define NAU8360_VBAT_BASE 1108
+#define NAU8360_VBAT_STEP 12353
+
+/* NAU8360_R40_CLK_DET_CTRL (0x40) */
+#define NAU8360_APWRUPEN_SFT			15
+#define NAU8360_APWRUPEN			(0x1 << NAU8360_APWRUPEN_SFT)
+#define NAU8360_CLKPWRUPEN_SFT			14
+#define NAU8360_CLKPWRUPEN			(0x1 << NAU8360_CLKPWRUPEN_SFT)
+#define NAU8360_SRATE_SFT			10
+#define NAU8360_SRATE_MASK			(0x7 << NAU8360_SRATE_SFT)
+#define NAU8360_SRATE_192000			(0x4 << NAU8360_SRATE_SFT)
+#define NAU8360_SRATE_96000			(0x3 << NAU8360_SRATE_SFT)
+#define NAU8360_SRATE_48000			(0x2 << NAU8360_SRATE_SFT)
+#define NAU8360_SRATE_32000			(0x1 << NAU8360_SRATE_SFT)
+#define NAU8360_SRATE_16000			(0x0 << NAU8360_SRATE_SFT)
+#define NAU8360_MCLK_RATE_SFT			7
+#define NAU8360_MCLK_RATE_MASK			(0x7 << NAU8360_MCLK_RATE_SFT)
+#define NAU8360_MCLK_RATE_24576			(0x4 << NAU8360_MCLK_RATE_SFT)
+#define NAU8360_MCLK_RATE_24000			(0x3 << NAU8360_MCLK_RATE_SFT)
+#define NAU8360_MCLK_RATE_19200			(0x2 << NAU8360_MCLK_RATE_SFT)
+#define NAU8360_MCLK_RATE_12288			(0x1 << NAU8360_MCLK_RATE_SFT)
+#define NAU8360_MCLK_RATE_12000			(0x0 << NAU8360_MCLK_RATE_SFT)
+#define NAU8360_FS_MCLK_DET_SFT			6
+#define NAU8360_FS_MCLK_DET			(0x1 << NAU8360_FS_MCLK_DET_SFT)
+#define NAU8360_FS_BCLK_DET_SFT			5
+#define NAU8360_FS_BCLK_DET			(0x1 << NAU8360_FS_BCLK_DET_SFT)
+
+/* NAU8360_R41_CLK_CTL2 (0x41) */
+#define NAU8360_NOISE_FILTER_THD_SFT		12
+#define NAU8360_NOISE_FILTER_THDT_MASK		(0xf << NAU8360_NOISE_FILTER_THD_SFT)
+#define NAU8360_SEL_BLOCK_SIZE_SFT		6
+#define NAU8360_SEL_BLOCK_SIZE_MASK		(0x7 << NAU8360_SEL_BLOCK_SIZE_SFT)
+#define NAU8360_EN_ABCLKDET_SFT			3
+#define NAU8360_EN_ABCLKDET			(0x1 << NAU8360_EN_ABCLKDET_SFT)
+#define NAU8360_EN_DBCLKDET_SFT			2
+#define NAU8360_EN_DBCLKDET			(0x1 << NAU8360_EN_DBCLKDET_SFT)
+#define NAU8360_EN_AMCLKDET_SFT			1
+#define NAU8360_EN_AMCLKDET			(0x1 << NAU8360_EN_AMCLKDET_SFT)
+#define NAU8360_EN_DMCLKDET			0x1
+
+/* NAU8360_R46_I2C_DEVICE_ID (0x46) */
+#define NAU8360_REG_SI_REV_MASK			0xff
+#define NAU8360_REG_SI_REV_B			0xf2
+#define NAU8360_REG_SI_REV_C			0xf5
+
+/* NAU8360_R5D_SINC_CFG (0x5d) */
+#define NAU8360_DAC_SINC_OSR_SFT		4
+#define NAU8360_DAC_SINC_OSR_MASK		(0x3 << NAU8360_DAC_SINC_OSR_SFT)
+#define NAU8360_DAC_SINC_OSR_250		(0x3 << NAU8360_DAC_SINC_OSR_SFT)
+#define NAU8360_DAC_SINC_OSR_200		(0x2 << NAU8360_DAC_SINC_OSR_SFT)
+#define NAU8360_DAC_SINC_OSR_128		(0x1 << NAU8360_DAC_SINC_OSR_SFT)
+#define NAU8360_DAC_SINC_OSR_0			(0x0 << NAU8360_DAC_SINC_OSR_SFT)
+#define NAU8360_IVSENSE_BS_OSR_MASK		0x3
+#define NAU8360_IVSENSE_BS_OSR_25		0x3
+#define NAU8360_IVSENSE_BS_OSR_64		0x2
+#define NAU8360_IVSENSE_BS_OSR_32		0x1
+#define NAU8360_IVSENSE_BS_OSR_16		0x0
+
+/* NAU8360_R60_RST (0x60) */
+#define NAU8360_PD_POR5_SFT			4
+#define NAU8360_PD_POR5_PWD			(0x1 << NAU8360_PD_POR5_SFT)
+#define NAU8360_EFUSE_CTRL_SFT			3
+#define NAU8360_EFUSE_CTRL_EN			(0x1 << NAU8360_EFUSE_CTRL_SFT)
+
+/*  NAU8360_R67_ANALOG_CONTROL_0 (0x67) */
+#define NAU8360_SCP_CLEAR_MODE_SFT		15
+#define NAU8360_SCP_CLEAR_MODE_MASK		(0x1 << NAU8360_SCP_CLEAR_MODE_SFT)
+#define NAU8360_SCP_CLEAR_MODE_AUTO		(0x1 << NAU8360_SCP_CLEAR_MODE_SFT)
+#define NAU8360_SCP_CLEAR_MODE_MANU		(0x0 << NAU8360_SCP_CLEAR_MODE_SFT)
+#define NAU8360_SCP_CLEAR_SFT			14
+#define NAU8360_SCP_CLEAR			(0x1 << NAU8360_SCP_CLEAR_SFT)
+#define NAU8360_HV_EN_SFT			13
+#define NAU8360_HV_EN				(0x1 << NAU8360_HV_EN_SFT)
+#define NAU8360_ANA_MUTE_SFT			8
+#define NAU8360_ANA_MUTE			(0x1 << NAU8360_ANA_MUTE_SFT)
+#define NAU8360_MOD_GAIN_SFT			5
+#define NAU8360_MOD_GAIN_MASK			(0x7 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_20DB			(0x7 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_18DB			(0x6 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_16DB			(0x5 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_14DB			(0x4 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_12DB			(0x3 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_10DB			(0x2 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_8DB			(0x1 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_MOD_GAIN_6DB			(0x0 << NAU8360_MOD_GAIN_SFT)
+#define NAU8360_CM_COMP_SFT			4
+#define NAU8360_CM_COMP_EN			(0x1 << NAU8360_CM_COMP_SFT)
+#define NAU8360_V_PBTL_SFT			3
+#define NAU8360_V_PBTL_EN			(0x1 << NAU8360_V_PBTL_SFT)
+
+/* NAU8360_R68_ANALOG_CONTROL_1 (0x68) */
+#define NAU8360_TRIMSCR_SFT			6
+#define NAU8360_TRIMSCR_MASK			(0x3 << NAU8360_TRIMSCR_SFT)
+#define NAU8360_TRIMSCR_HIGH			(0x3 << NAU8360_TRIMSCR_SFT)
+#define NAU8360_TRIMSCR_MHIGH			(0x2 << NAU8360_TRIMSCR_SFT)
+#define NAU8360_TRIMSCR_MLOW			(0x1 << NAU8360_TRIMSCR_SFT)
+#define NAU8360_TRIMSCR_LOW			(0x0 << NAU8360_TRIMSCR_SFT)
+#define NAU8360_DTX_SFT				5
+#define NAU8360_DTX_EN				(0x1 << NAU8360_DTX_SFT)
+#define NAU8360_DRVCTL_SEGL_SFT			4
+#define NAU8360_DRVCTL_SEGL_FULL		(0x1 << NAU8360_DRVCTL_SEGL_SFT)
+#define NAU8360_DRVCTL_SEGR_SFT			2
+#define NAU8360_DRVCTL_SEGR_FULL		(0x1 << NAU8360_DRVCTL_SEGR_SFT)
+#define NAU8360_SCP_TEST_SFT			1
+#define NAU8360_SCP_TEST			(0x1 << NAU8360_SCP_TEST_SFT)
+#define NAU8360_SEG_AUTO_CTRL_EN		0x1
+
+/* NAU8360_R69_ANALOG_CONTROL_3 (0x69) */
+#define NAU8360_ANA_STATUS_OTP_SFT		8
+#define NAU8360_ANA_STATUS_OTP_MASK		(0x1 << NAU8360_ANA_STATUS_OTP_SFT)
+#define NAU8360_ANA_STATUS_OVLO_SFT		7
+#define NAU8360_ANA_STATUS_OVLO_MASK		(0x1 << NAU8360_ANA_STATUS_OVLO_SFT)
+#define NAU8360_ANA_STATUS_UVLO_SFT		6
+#define NAU8360_ANA_STATUS_UVLO_MASK		(0x1 << NAU8360_ANA_STATUS_UVLO_SFT)
+#define NAU8360_ANA_STATUS_SCP_SFT		4
+#define NAU8360_ANA_STATUS_SCP_MASK		(0x1 << NAU8360_ANA_STATUS_SCP_SFT)
+#define NAU8360_ANA_STATUS_EN_V2I_SFT		3
+#define NAU8360_ANA_STATUS_EN_V2I_MASK		(0x1 << NAU8360_ANA_STATUS_EN_V2I_SFT)
+#define NAU8360_ANA_STATUS_FAULT_SFT		2
+#define NAU8360_ANA_STATUS_FAULT_MASK		(0x1 << NAU8360_ANA_STATUS_FAULT_SFT)
+#define NAU8360_ANA_STATUS_DC_DET_SFT		1
+#define NAU8360_ANA_STATUS_DC_DET_MASK		(0x1 << NAU8360_ANA_STATUS_DC_DET_SFT)
+#define NAU8360_ANA_STATUS_EN_ALL_MASK		0x1
+
+/* NAU8360_R6A_SARADC_CFG0 (0x6a) */
+#define NAU8360_SARADC_SFT			15
+#define NAU8360_SARADC_EN			(0x1 << NAU8360_SARADC_SFT)
+#define NAU8360_RESETB_SARADC_SFT		14
+#define NAU8360_RESETB_SARADC_MASK		(0x1 << NAU8360_RESETB_SARADC_SFT)
+#define NAU8360_RESETB_SARADC_NOR		(0x1 << NAU8360_RESETB_SARADC_SFT)
+#define NAU8360_RESETB_SARADC_RST		(0x0 << NAU8360_RESETB_SARADC_SFT)
+#define NAU8360_SARADC_CAL_SFT			13
+#define NAU8360_SARADC_CAL			(0x1 << NAU8360_SARADC_CAL_SFT)
+#define NAU8360_SARADC_DIV_SFT			12
+#define NAU8360_SARADC_DIV			(0x1 << NAU8360_SARADC_DIV_SFT)
+#define NAU8360_SARADC_CALSEL_SFT		9
+#define NAU8360_SARADC_CALSEL_MASK		(0x7 << NAU8360_SARADC_CALSEL_SFT)
+#define NAU8360_TRIMSMPL_SFT			3
+#define NAU8360_TRIMSMPL_MASK			(0x7 << NAU8360_TRIMSMPL_SFT)
+#define NAU8360_SAR_INPUT_CH_SEL_SFT		2
+#define NAU8360_SAR_INPUT_CH_SEL_MASK		(0x1 << NAU8360_SAR_INPUT_CH_SEL_SFT)
+#define NAU8360_VBAT_AVG_SFT			1
+#define NAU8360_VBAT_AVG_EN			(0x1 << NAU8360_VBAT_AVG_SFT)
+#define NAU8360_VTEMP_AVG_EN			0x1
+
+/* NAU8360_R6B_SARADC_CFG1 (0x6b) */
+#define NAU8360_VTEMP_SFT			15
+#define NAU8360_VTEMP_EN			(0x1 << NAU8360_VTEMP_SFT)
+#define NAU8360_VBATDIV_SFT			14
+#define NAU8360_VBATDIV_EN			(0x1 << NAU8360_VBATDIV_SFT)
+#define NAU8360_VREF_SFT			10
+#define NAU8360_VREF_EN				(0x1 << NAU8360_VREF_SFT)
+#define NAU8360_PRELOAD_VREF_SFT		9
+#define NAU8360_PRELOAD_VREF_EN			(0x1 << NAU8360_PRELOAD_VREF_SFT)
+#define NAU8360_VTEMP_AVG_N_SFT			2
+#define NAU8360_VTEMP_AVG_N_MASK		(0x3 << NAU8360_VTEMP_AVG_N_SFT)
+#define NAU8360_VTEMP_AVG_N_512			(0x3 << NAU8360_VTEMP_AVG_N_SFT)
+#define NAU8360_VTEMP_AVG_N_128			(0x2 << NAU8360_VTEMP_AVG_N_SFT)
+#define NAU8360_VTEMP_AVG_N_32			(0x1 << NAU8360_VTEMP_AVG_N_SFT)
+#define NAU8360_VTEMP_AVG_N_1			(0x0 << NAU8360_VTEMP_AVG_N_SFT)
+#define NAU8360_VBAT_AVG_N_MASK			0x3
+#define NAU8360_VBAT_AVG_N_512			0x3
+#define NAU8360_VBAT_AVG_N_128			0x2
+#define NAU8360_VBAT_AVG_N_32			0x1
+#define NAU8360_VBAT_AVG_N_1			0
+
+/* NAU8360_R6C_IVSNS_CFG0 (0x6c) */
+#define NAU8360_PD_VSNS_R_SFT			15
+#define NAU8360_PD_VSNS_R_PMD			(0x1 << NAU8360_PD_VSNS_R_SFT)
+#define NAU8360_PD_VSNS_L_SFT			14
+#define NAU8360_PD_VSNS_L_PMD			(0x1 << NAU8360_PD_VSNS_L_SFT)
+#define NAU8360_PD_ISNS_R_SFT			13
+#define NAU8360_PD_ISNS_R_PMD			(0x1 << NAU8360_PD_ISNS_R_SFT)
+#define NAU8360_PD_ISNS_L_SFT			12
+#define NAU8360_PD_ISNS_L_PMD			(0x1 << NAU8360_PD_ISNS_L_SFT)
+#define NAU8360_RESET_SC_VADC_R_SFT		11
+#define NAU8360_RESET_SC_VADC_R_RST		(0x1 << NAU8360_RESET_SC_VADC_R_SFT)
+#define NAU8360_RESET_SC_VADC_L_SFT		10
+#define NAU8360_RESET_SC_VADC_L_RST		(0x1 << NAU8360_RESET_SC_VADC_L_SFT)
+#define NAU8360_RESET_SC_IADC_R_SFT		9
+#define NAU8360_RESET_SC_IADC_R_RST		(0x1 << NAU8360_RESET_SC_IADC_R_SFT)
+#define NAU8360_RESET_SC_IADC_L_SFT		8
+#define NAU8360_RESET_SC_IADC_L_RST		(0x1 << NAU8360_RESET_SC_IADC_L_SFT)
+#define NAU8360_PBTL_ISENE_LR_SFT		7
+#define NAU8360_PBTL_ISENE_LR_MASK		(0x1 << NAU8360_PBTL_ISENE_LR_SFT)
+#define NAU8360_PBTL_ISENE_LR_ILR		(0x1 << NAU8360_PBTL_ISENE_LR_SFT)
+#define NAU8360_PBTL_ISENE_LR_I2R		(0x0 << NAU8360_PBTL_ISENE_LR_SFT)
+#define NAU8360_PD_LDO_SDM_IVSNS_SFT		6
+#define NAU8360_PD_LDO_SDM_IVSNS_PMD		(0x1 << NAU8360_PD_LDO_SDM_IVSNS_SFT)
+
+/* NAU8360_R6D_IVSNS_CFG1 (0x6d) */
+#define NAU8360_PD_V2I_IVSNS_SFT		13
+#define NAU8360_PD_V2I_IVSNS_MASK		(0x1 << NAU8360_PD_V2I_IVSNS_SFT)
+#define NAU8360_PD_VREF_SDM_IVSNS_SFT		12
+#define NAU8360_PD_VREF_SDM_IVSNS_MASK		(0x1 << NAU8360_PD_VREF_SDM_IVSNS_SFT)
+#define NAU8360_VSNS_PGA_CUR_SET_SFT		10
+#define NAU8360_VSNS_PGA_CUR_SET_MASK		(0x3 << NAU8360_VSNS_PGA_CUR_SET_SFT)
+#define NAU8360_VSNS_GAIN_SFT			8
+#define NAU8360_VSNS_GAIN_MASK			(0x3 << NAU8360_VSNS_GAIN_SFT)
+#define NAU8360_VREF_CUR_SFT			6
+#define NAU8360_VREF_CUR_MASK			(0x3 << NAU8360_VREF_CUR_SFT)
+#define NAU8360_ISNS_PGA_CUR_SFT		4
+#define NAU8360_ISNS_PGA_CUR_MASK		(0x3 << NAU8360_ISNS_PGA_CUR_SFT)
+#define NAU8360_ISNS_GAIN_SFT			2
+#define NAU8360_ISNS_GAIN_MASK			(0x3 << NAU8360_ISNS_GAIN_SFT)
+#define NAU8360_SDM_DELAY_TRIM_MASK		0x3
+
+/* NAU8360_R6E_DAC_CFG0 (0x6e) */
+#define NAU8360_PD_DACL_SFT			11
+#define NAU8360_PD_DACL_DIS			(0x1 << NAU8360_PD_DACL_SFT)
+#define NAU8360_PD_DACR_SFT			10
+#define NAU8360_PD_DACR_DIS			(0x1 << NAU8360_PD_DACR_SFT)
+#define NAU8360_PD_CHOP_DAC_SFT			9
+#define NAU8360_PD_CHOP_DAC_MASK		(0x1 << NAU8360_PD_CHOP_DAC_SFT)
+#define NAU8360_DAC_RES_SFT			7
+#define NAU8360_DAC_RES_MASK			(0x1 << NAU8360_DAC_RES_SFT)
+#define NAU8360_DAC_CUR_SFT			6
+#define NAU8360_DAC_CUR_MASK			(0x1 << NAU8360_DAC_CUR_SFT)
+#define NAU8360_DAC_CUR_3_2DB			(0x1 << NAU8360_DAC_CUR_SFT)
+#define NAU8360_DAC_CUR_0DB			(0x0 << NAU8360_DAC_CUR_SFT)
+#define NAU8360_DAC_BUFOPCUR_SFT		4
+#define NAU8360_DAC_BUFOPCUR_MASK		(0x3 << NAU8360_DAC_BUFOPCUR_SFT)
+#define NAU8360_DAC_IVOPCUR_SFT			2
+#define NAU8360_DAC_IVOPCUR_MASK		(0x3 << NAU8360_DAC_IVOPCUR_SFT)
+#define NAU8360_DAC_LPFOP_CUR_MASK		0x3
+
+/* NAU8360_R71_CLK_DIV_CFG (0x71) */
+#define NAU8360_IVSNS_CLK_INV_SEL_SFT		10
+#define NAU8360_IVSNS_CLK_INV_SEL_MASK		(0x1 << NAU8360_IVSNS_CLK_INV_SEL_SFT)
+#define NAU8360_CLK_ANA_SEL_SFT			7
+#define NAU8360_CLK_ANA_SEL_MASK		(0x3 << NAU8360_CLK_ANA_SEL_SFT)
+#define NAU8360_CLK_ANA_SEL_PLL			(0x2 << NAU8360_CLK_ANA_SEL_SFT)
+#define NAU8360_CLK_ANA_SEL_BCLK		(0x1 << NAU8360_CLK_ANA_SEL_SFT)
+#define NAU8360_CLK_ANA_SEL_MCLK		(0x0 << NAU8360_CLK_ANA_SEL_SFT)
+#define NAU8360_IVSNS_CLK_DIV_SFT		4
+#define NAU8360_IVSNS_CLK_DIV_MASK		(0x7 << NAU8360_IVSNS_CLK_DIV_SFT)
+#define NAU8360_DAC_OUTPUT_EDGE_SFT		3
+#define NAU8360_DAC_OUTPUT_EDGE_MASK		(0x1 << NAU8360_DAC_OUTPUT_EDGE_SFT)
+#define NAU8360_DAC_CLK_DIV_SFT			1
+#define NAU8360_DAC_CLK_DIV_MASK		(0x3 << NAU8360_DAC_CLK_DIV_SFT)
+#define NAU8360_DAC_CLK_DIV_8			(0x3 << NAU8360_DAC_CLK_DIV_SFT)
+#define NAU8360_DAC_CLK_DIV_4			(0x2 << NAU8360_DAC_CLK_DIV_SFT)
+#define NAU8360_DAC_CLK_DIV_2			(0x1 << NAU8360_DAC_CLK_DIV_SFT)
+#define NAU8360_DAC_CLK_DIV_1			(0x0 << NAU8360_DAC_CLK_DIV_SFT)
+#define NAU8360_DAC_CHOP_CLK_DIV_MASK		0x1
+#define NAU8360_DAC_CHOP_CLK_DIV_32		0x1
+#define NAU8360_DAC_CHOP_CLK_DIV_16		0x0
+
+/* NAU8360_R72_PLL_CFG0 (0x72) */
+#define NAU8360_PLLOUT_DIV_SFT			10
+#define NAU8360_PLLOUT_DIV_MAX			0x1f
+#define NAU8360_PLLOUT_DIV_MASK			(0x1f << NAU8360_PLLOUT_DIV_SFT)
+#define NAU8360_PLLOUT_DIV_BYPASS		(0x0 << NAU8360_PLLOUT_DIV_SFT)
+#define NAU8360_PLL_CLK_SEL_SFT			8
+#define NAU8360_PLL_CLK_SEL_MASK		(0x3 << NAU8360_PLL_CLK_SEL_SFT)
+#define NAU8360_PLL_CLK_SEL_HIRC		(0x3 << NAU8360_PLL_CLK_SEL_SFT)
+#define NAU8360_PLL_CLK_SEL_BCLK		(0x1 << NAU8360_PLL_CLK_SEL_SFT)
+#define NAU8360_PLL_CLK_SEL_MCLK		(0x0 << NAU8360_PLL_CLK_SEL_SFT)
+#define NAU8360_PD_PLL_SFT			7
+#define NAU8360_PD_PLL_MASK			(0x1 << NAU8360_PD_PLL_SFT)
+#define NAU8360_PD_PLL_DIS			(0x1 << NAU8360_PD_PLL_SFT)
+#define NAU8360_PD_PLL_EN			(0x0 << NAU8360_PD_PLL_SFT)
+
+/* NAU8360_R73_PLL_CFG1 (0x73) */
+#define NAU8360_RSEL_SFT			13
+#define NAU8360_RSEL_MASK			(0x3 << NAU8360_RSEL_SFT)
+#define NAU8360_MSEL_SFT			8
+#define NAU8360_MSEL_MASK			(0x1f << NAU8360_MSEL_SFT)
+#define NAU8360_NSEL_MASK			0xff
+
+/* NAU8360_R74_PLL_CFG2 (0x74) */
+#define NAU8360_XSEL_MASK			0xfff
+
+/* NAU8360_R77_SOFT_SD (0x77) */
+#define NAU8360_SOFT_SD				0x55AA
+#define NAU8360_SOFT_SD_EN			0
+
+/* NAU8360_R78_PD_SW_DLDO (0x78) */
+#define NAU8360_PD_SW_DLDO			0xAA55
+#define NAU8360_PD_SW_DLDO_EN			0
+
+/* NAU8360_R7A_DAC_TRIM_CFG2 (0x7a) */
+#define NAU8360_DAC_TEMP_SLOPE_SFT		8
+#define NAU8360_DAC_TEMP_SLOPE_MASK		(0x7f << NAU8360_DAC_TEMP_SLOPE_SFT)
+
+/* NAU8360_R7B_IVSNS_TRIM_CFG (0x7b) */
+#define NAU8360_ISNS_TEMP_SLOPE_SFT		8
+#define NAU8360_ISNS_TEMP_SLOPE_MASK		(0x7f << NAU8360_ISNS_TEMP_SLOPE_SFT)
+#define NAU8360_VSNS_TEMP_SLOPE_MASK		0x7f
+
+/* NAU8360_R7C_MISC_TRIM_CFG (0x7c) */
+#define NAU8360_DAC_OS_SB_SFT			13
+#define NAU8360_DAC_OS_SB_SFT_MASK		(0x7 << NAU8360_DAC_OS_SB_SFT)
+#define NAU8360_DAC_GAIN_SB_SFT			11
+#define NAU8360_DAC_GAIN_SB_MASK		(0x3 << NAU8360_DAC_GAIN_SB_SFT)
+#define NAU8360_DAC_TEMP_SB_SFT			9
+#define NAU8360_DAC_TEMP_SB_MASK		(0x3 << NAU8360_DAC_TEMP_SB_SFT)
+#define NAU8360_ISNS_TEMP_SB_SFT		6
+#define NAU8360_ISNS_TEMP_SB_MASK		(0x7 << NAU8360_ISNS_TEMP_SB_SFT)
+#define NAU8360_VSNS_TEMP_SB_SFT		4
+#define NAU8360_VSNS_TEMP_SB_MASK		(0x3 << NAU8360_VSNS_TEMP_SB_SFT)
+#define NAU8360_ISNS_GAIN_SB_SFT		2
+#define NAU8360_ISNS_GAIN_SB_MASK		(0x3 << NAU8360_ISNS_GAIN_SB_SFT)
+#define NAU8360_VSNS_GAIN_SB_MASK		0x3
+
+/* NAU8360_R7E_CLK_GATED_EN (0x7e)*/
+#define NAU8360_CLK_GATED_EN			0xa5a5
+#define NAU8360_CLK_GATED_DIS			0
+
+/* NAU8360_R86_HW3_CTL0 (0x86) */
+#define NAU8360_HW3_DRAM_CLR_SFT		14
+#define NAU8360_HW3_DRAM_CLR			(0x1 << NAU8360_HW3_DRAM_CLR_SFT)
+#define NAU8360_HW3_STALL_SFT			13
+#define NAU8360_HW3_STALL			(0x1 << NAU8360_HW3_STALL_SFT)
+
+/* NAU8360_R8C_HW3_CTL6 (0x8c)*/
+#define NAU8360_HW3_DROOP_SFT			2
+#define NAU8360_HW3_DROOP_MASK			(0x1 << NAU8360_HW3_DROOP_SFT)
+#define NAU8360_HW3_DROOP_192K			(0x1 << NAU8360_HW3_DROOP_SFT)
+#define NAU8360_HW3_DROOP_96K			(0x0 << NAU8360_HW3_DROOP_SFT)
+#define NAU8360_HW3_FS_MASK			0x1
+#define NAU8360_HW3_FS_192K			0x1
+#define NAU8360_HW3_FS_96K			0x0
+
+/* NAU8360_R8F_HW3_CTL9 (0x8f)*/
+#define NAU8360_HW3_CH_MUTE_SFT			8
+#define NAU8360_HW3_CH_MUTE			(0x1 << NAU8360_HW3_CH_MUTE_SFT)
+#define NAU8360_HW3_ZERO_THD_MASK		0xff
+
+/* NAU8360_R90_HW2_CTL0 (0x90) */
+#define NAU8360_HW2_DRAM_CLR_SFT		14
+#define NAU8360_HW2_DRAM_CLR			(0x1 << NAU8360_HW2_DRAM_CLR_SFT)
+#define NAU8360_HW2_STALL_SFT			13
+#define NAU8360_HW2_STALL			(0x1 << NAU8360_HW2_STALL_SFT)
+
+/* NAU8360_R96_HW2_CTL6 (0x96) */
+#define NAU8360_HW1_ANC_EN_SFT			15
+#define NAU8360_HW1_ANC_EN			(0x1 << NAU8360_HW1_ANC_EN_SFT)
+#define NAU8360_HW2_DROOP_SEL_SFT		3
+#define NAU8360_HW2_DROOP_SEL_MASK		(0x1 << NAU8360_HW2_DROOP_SEL_SFT)
+#define NAU8360_HW2_DROOP_SEL_LARGE		(0x1 << NAU8360_HW2_DROOP_SEL_SFT)
+#define NAU8360_HW2_DROOP_SEL_SMALL		(0x0 << NAU8360_HW2_DROOP_SEL_SFT)
+#define NAU8360_HW2_DROOP_EN_SFT		2
+#define NAU8360_HW2_DROOP_EN			(0x1 << NAU8360_HW2_DROOP_EN_SFT)
+#define NAU8360_HW2_LATENCY_SFT			1
+#define NAU8360_HW2_LATENCY_MASK		(0x1 << NAU8360_HW2_LATENCY_SFT)
+#define NAU8360_HW2_LATENCY_LOW			(0x1 << NAU8360_HW2_LATENCY_SFT)
+#define NAU8360_HW2_LATENCY_NOR			(0x0 << NAU8360_HW2_LATENCY_SFT)
+#define NAU8360_HW2_FS_MASK			0x1
+#define NAU8360_HW2_FS_192K			0x1
+#define NAU8360_HW2_FS_96K			0x0
+
+/* NAU8360_R99_HW2_CTL9 (0x99) */
+#define NAU8360_HW2_VSR_SFT			9
+#define NAU8360_HW2_VSR_MASK			(0x3 << NAU8360_HW2_VSR_SFT)
+#define NAU8360_HW2_CH_MUTE_SFT			8
+#define NAU8360_HW2_CH_MUTE			(0x1 << NAU8360_HW2_CH_MUTE_SFT)
+#define NAU8360_HW2_ZERO_THD_MASK		0xff
+
+/* NAU8360_R9C_HW1_CTL2 (0x9c) */
+#define NAU8360_MUTE_INTRVL_SFT			11
+#define NAU8360_MUTE_INTRVL_MASK		(0x3 << NAU8360_MUTE_INTRVL_SFT)
+#define NAU8360_MUTE_INTRVL_699MS		(0x3 << NAU8360_MUTE_INTRVL_SFT)
+#define NAU8360_MUTE_INTRVL_466MS		(0x2 << NAU8360_MUTE_INTRVL_SFT)
+#define NAU8360_MUTE_INTRVL_233MS		(0x1 << NAU8360_MUTE_INTRVL_SFT)
+#define NAU8360_HW1_CH_MUTE_SFT			8
+#define NAU8360_HW1_CH_MUTE			(0x1 << NAU8360_HW1_CH_MUTE_SFT)
+#define NAU8360_HW1_ZERO_THD_MASK		0xff
+
+/* NAU8360_R9D_PEQ_CTL (0x9d) */
+#define NAU8360_PEQ_BAND_SFT			12
+#define NAU8360_PEQ_BAND_MASK			(0xf << NAU8360_PEQ_BAND_SFT)
+#define NAU8360_HW1_MEM_TEST_SFT		2
+#define NAU8360_HW1_MEM_TEST			(0x1 << NAU8360_HW1_MEM_TEST_SFT)
+#define NAU8360_HW1_MEM_CLEAR_SFT		1
+#define NAU8360_HW1_MEM_CLEAR			(0x1 << NAU8360_HW1_MEM_CLEAR_SFT)
+#define NAU8360_PEQ_STALL			0x1
+
+/* NAU8360_RA4_ANA_REG_0 (0xa4) */
+#define NAU8360_MSEL_SAW_SFT			8
+#define NAU8360_MSEL_SAW_MASK			(0xff << NAU8360_MSEL_SAW_SFT)
+#define NAU8360_FTRIM_PWM_SFT			6
+#define NAU8360_FTRIM_PWM_MASK			(0x3 << NAU8360_MSEL_SAW_SFT)
+#define NAU8360_SEL_STCLK_SFT			5
+#define NAU8360_SEL_STCLK_MASK			(0x1 << NAU8360_SEL_STCLK_SFT)
+#define NAU8360_SEL_STCLK_IVCLK			(0x1 << NAU8360_SEL_STCLK_SFT)
+#define NAU8360_SEL_STCLK_FREERUN		(0x0 << NAU8360_SEL_STCLK_SFT)
+#define NAU8360_NSEL_SAW_MASK			0x1f
+
+/* NAU8360_RA5_ANA_REG_1 (0xa5) */
+#define NAU8360_ICP_SAW_SET_SFT			14
+#define NAU8360_ICP_SAW_SET_MASK		(0x3 << NAU8360_ICP_SAW_SET_SFT)
+#define NAU8360_VSAW_LV_SFT			12
+#define NAU8360_VSAW_LV_MASK			(0x3 << NAU8360_VSAW_LV_SFT)
+#define NAU8360_KVCO_SAW_SFT			10
+#define NAU8360_KVCO_SAW_MASK			(0x3 << NAU8360_KVCO_SAW_SFT)
+#define NAU8360_TRIM_LPF_SFT			8
+#define NAU8360_TRIM_LPF_MASK			(0x3 << NAU8360_TRIM_LPF_SFT)
+#define NAU8360_SAW_PLL_SFT			7
+#define NAU8360_SAW_PLL_MASK			(0x1 << NAU8360_SAW_PLL_SFT)
+#define NAU8360_SAW_PLL_NOR			(0x1 << NAU8360_SAW_PLL_SFT)
+#define NAU8360_SAW_PLL_RST			(0x0 << NAU8360_SAW_PLL_SFT)
+#define NAU8360_CLASSD_SHT_SFT			6
+#define NAU8360_CLASSD_SHT_IN			(0x1 << NAU8360_CLASSD_SHT_SFT)
+#define NAU8360_HVEN_SYNC_SFT			5
+#define NAU8360_HVEN_SYNC_SAW			(0x1 << NAU8360_HVEN_SYNC_SFT)
+#define NAU8360_SYNC_SAW_CLK_SFT		4
+#define NAU8360_SYNC_SAW_CLK_INVT		(0x1 << NAU8360_SYNC_SAW_CLK_SFT)
+#define NAU8360_DEPOP_CAP_SFT			2
+#define NAU8360_DEPOP_CAP_MASK			(0x3 << NAU8360_DEPOP_CAP_SFT)
+#define NAU8360_DEPOP_CAP_48PF			(0x3 << NAU8360_DEPOP_CAP_SFT)
+#define NAU8360_DEPOP_CAP_36PF			(0x2 << NAU8360_DEPOP_CAP_SFT)
+#define NAU8360_DEPOP_CAP_24PF			(0x1 << NAU8360_DEPOP_CAP_SFT)
+#define NAU8360_DEPOP_CAP_12PF			(0x0 << NAU8360_DEPOP_CAP_SFT)
+#define NAU8360_SW_BG_IO_SFT			1
+#define NAU8360_SW_BG_IO_CONN			(0x1 << NAU8360_SW_BG_IO_SFT)
+#define NAU8360_SW_VPTC_IO_EN			0x1
+
+/* NAU8360 VBAT Range Thresholds */
+#define NAU8360_VBAT_MIN		8
+#define NAU8360_VBAT_MID_THRES		13
+#define NAU8360_VBAT_HIGH_THRES		19
+#define NAU8360_VBAT_MAX		24
+
+/* NAU8360_R100_LEFT_BIQ0_COE (0x100)
+ * NAU8360_R200_RIGHT_BIQ0_COE (0x200)
+ */
+#define NAU8360_TOT_BAND_PER_CH 15
+#define NAU8360_TOT_BAND_COE 10
+#define NAU8360_TOT_BAND_COE_RANGE (NAU8360_TOT_BAND_COE + 2)
+#define NAU8360_PEQ_REG_WIDTH (NAU8360_TOT_BAND_COE - 1)
+
+/* DSP stereo core */
+#define NAU8360_DSP_CORE_NUM 2
+#define NAU8360_DSP_ADDR_BYNAME(x) \
+	(strstr((x), "Left") ? NAU8360_RF000_DSP_COMM : NAU8360_RF002_DSP_COMM)
+
+#define NAU8360_I2C_REG_LEN 2
+#define NAU8360_I2C_RXBUF_LEN 4
+#define NAU8360_I2C_TXBUF_LEN 6
+#define NAU8360_CODEC_DAI "nau8360-hifi"
+
+/* clock source */
+enum {
+	NAU8360_CLK_SRC_MCLK,
+	NAU8360_CLK_SRC_PLL,
+	NAU8360_CLK_SRC_ICLK,
+	NAU8360_CLK_SRC_BCLK,
+};
+
+/* clock target */
+enum {
+	NAU8360_CLK_ID_DIG, /* DIG_SYS + DSP + HW */
+	NAU8360_CLK_ID_ANA, /* IV + DAC */
+	NAU8360_CLK_ID_INT, /* HIRC48M standby  */
+};
+
+enum {
+	NAU8360_MCLK_FS_RATIO_250 = 250,
+	NAU8360_MCLK_FS_RATIO_256 = 256,
+	NAU8360_MCLK_FS_RATIO_400 = 400,
+	NAU8360_MCLK_FS_RATIO_500 = 500,
+	NAU8360_MCLK_FS_RATIO_512 = 512,
+};
+
+enum {
+	NAU8360_PEQ_BAND_8  = 8,
+	NAU8360_PEQ_BAND_12 = 12,
+	NAU8360_PEQ_BAND_15 = 15,
+};
+
+#define NAU8360_TDM_MAX_CHAN 8
+#define TDM_SLOT_NONE 255
+
+enum {
+	NAU8360_TDM_DACL,
+	NAU8360_TDM_DACR,
+	NAU8360_TDM_ANCL,
+	NAU8360_TDM_ANCR,
+	NAU8360_TDM_RXN,
+};
+
+enum {
+	NAU8360_TDM_AECL,
+	NAU8360_TDM_AECR,
+	NAU8360_TDM_ISNSL,
+	NAU8360_TDM_ISNSR,
+	NAU8360_TDM_VSNSL,
+	NAU8360_TDM_VSNSR,
+	NAU8360_TDM_TJ,
+	NAU8360_TDM_VBAT,
+	NAU8360_TDM_TXN,
+};
+
+/* DAC Source Path*/
+enum {
+	NAU8360_DAC_SRC_HW1 = 0,
+	NAU8360_DAC_SRC_DSP,
+};
+
+/* PLL Source */
+enum {
+	NAU8360_PLL_MCLK,
+	NAU8360_PLL_BCLK,
+	NAU8360_PLL_INTERNAL,
+};
+
+struct nau8360_pll {
+	int src;
+	int input;
+	int output;
+	int msel;
+	int rsel;
+	int nsel;
+	int xsel;
+};
+
+struct nau8360 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex lock;
+	struct snd_soc_dapm_context *dapm;
+	int sys_clk;
+	int anc_enable;
+	int pbtl_enable;
+	int dac_cur_enable;
+	int kcs_setup_size;
+	struct nau8360_pll pll;
+	u32 tdm_tx_func_slot[NAU8360_TDM_TXN];
+	u32 tdm_rx_func_slot[NAU8360_TDM_RXN];
+	u8 i2c_read_reg[NAU8360_I2C_REG_LEN] ____cacheline_aligned;
+	u8 i2c_read_buf[NAU8360_I2C_RXBUF_LEN] ____cacheline_aligned;
+	u8 i2c_write_buf[NAU8360_I2C_TXBUF_LEN] ____cacheline_aligned;
+	struct work_struct load_fw_work;
+	const char *dsp_firmware[NAU8360_DSP_CORE_NUM];
+	bool load_fw_done;
+};
+
+#endif /* __NAU8360_H__ */
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index fefbd57..a939f4b 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -623,12 +623,23 @@ static int nau8540_dai_trigger(struct snd_pcm_substream *substream,
 	return ret;
 }
 
+static const u64 nau8540_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops nau8540_dai_ops = {
 	.startup = nau8540_dai_startup,
 	.hw_params = nau8540_hw_params,
 	.set_fmt = nau8540_set_fmt,
 	.set_tdm_slot = nau8540_set_tdm_slot,
 	.trigger = nau8540_dai_trigger,
+	.auto_selectable_formats = &nau8540_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define NAU8540_RATES SNDRV_PCM_RATE_8000_48000
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index a050387..eb3e933 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -817,11 +817,23 @@ static int nau8810_set_bias_level(struct snd_soc_component *component,
 #define NAU8810_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 nau8810_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops nau8810_ops = {
 	.hw_params = nau8810_pcm_hw_params,
 	.set_fmt = nau8810_set_dai_fmt,
 	.set_sysclk = nau8810_set_sysclk,
 	.set_pll = nau8810_set_pll,
+	.auto_selectable_formats = &nau8810_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver nau8810_dai = {
diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
index c45c5b8..ecadbae 100644
--- a/sound/soc/codecs/nau8821.c
+++ b/sound/soc/codecs/nau8821.c
@@ -981,11 +981,22 @@ static int nau8821_digital_mute(struct snd_soc_dai *dai, int mute,
 		NAU8821_R31_MUTE_CTRL, NAU8821_DAC_SOFT_MUTE, val);
 }
 
+static const u64 nau8821_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops nau8821_dai_ops = {
 	.startup = nau8821_dai_startup,
 	.hw_params = nau8821_hw_params,
 	.set_fmt = nau8821_set_dai_fmt,
 	.mute_stream = nau8821_digital_mute,
+	.auto_selectable_formats = &nau8821_selectable_formats,
+	.num_auto_selectable_formats = 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index 830164e..db1931d 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -1026,12 +1026,24 @@ static int nau8822_set_bias_level(struct snd_soc_component *component,
 #define NAU8822_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 nau8822_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops nau8822_dai_ops = {
 	.hw_params	= nau8822_hw_params,
 	.mute_stream	= nau8822_mute,
 	.set_fmt	= nau8822_set_dai_fmt,
 	.set_sysclk	= nau8822_set_dai_sysclk,
 	.set_pll	= nau8822_set_pll,
+	.auto_selectable_formats	= &nau8822_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1059,10 +1071,14 @@ static int nau8822_suspend(struct snd_soc_component *component)
 {
 	struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
 	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+	int ret;
 
 	snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
-	regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
+	ret = regulator_bulk_disable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
+	if (ret)
+		return ret;
 
+	regcache_cache_only(nau8822->regmap, true);
 	regcache_mark_dirty(nau8822->regmap);
 
 	return 0;
@@ -1072,7 +1088,9 @@ static int nau8822_resume(struct snd_soc_component *component)
 {
 	struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
 	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
-	int ret = regulator_bulk_enable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
+	int ret;
+
+	ret = regulator_bulk_enable(NAU8822_NUM_SUPPLIES, nau8822->supplies);
 
 	if (ret) {
 		dev_err(component->dev,
@@ -1082,7 +1100,10 @@ static int nau8822_resume(struct snd_soc_component *component)
 
 	fsleep(100);
 
-	regcache_sync(nau8822->regmap);
+	regcache_cache_only(nau8822->regmap, false);
+	ret = regcache_sync(nau8822->regmap);
+	if (ret)
+		return ret;
 
 	snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
 
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 426a488..853eb94 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -1580,11 +1580,22 @@ static const struct snd_soc_component_driver nau8824_component_driver = {
 	.endianness		= 1,
 };
 
+static const u64 nau8824_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops nau8824_dai_ops = {
 	.startup = nau8824_dai_startup,
 	.hw_params = nau8824_hw_params,
 	.set_fmt = nau8824_set_fmt,
 	.set_tdm_slot = nau8824_set_tdm_slot,
+	.auto_selectable_formats = &nau8824_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index ae83b77..2eb0efc 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -345,10 +345,10 @@ static u32 nau8825_intlog10_dec3(u32 value)
 /**
  * nau8825_xtalk_sidetone - computes cross talk suppression sidetone gain.
  *
- * @sig_org: orignal signal level
+ * @sig_org: original signal level
  * @sig_cros: cross talk signal level
  *
- * The orignal and cross talk signal vlues need to be characterized.
+ * The original and cross talk signal vlues need to be characterized.
  * Once these values have been characterized, this sidetone value
  * can be converted to decibel with the equation below.
  * sidetone = 20 * log (original signal level / crosstalk signal level)
@@ -671,11 +671,11 @@ static void nau8825_xtalk_imm_stop(struct nau8825 *nau8825)
  * Thus, the measurement function has four states to complete whole sequence.
  * 1. Prepare state : Prepare the resource for detection and transfer to HPR
  *     IMM stat to make JKR1(HPR) impedance measure.
- * 2. HPR IMM state : Read out orignal signal level of JKR1(HPR) and transfer
+ * 2. HPR IMM state : Read out original signal level of JKR1(HPR) and transfer
  *     to HPL IMM state to make JKTIP(HPL) impedance measure.
  * 3. HPL IMM state : Read out cross talk signal level of JKTIP(HPL) and
  *     transfer to IMM state to determine suppression sidetone gain.
- * 4. IMM state : Computes cross talk suppression sidetone gain with orignal
+ * 4. IMM state : Computes cross talk suppression sidetone gain with original
  *     and cross talk signal level. Apply this gain and then restore codec
  *     configuration. Then transfer to Done state for ending.
  */
@@ -724,7 +724,7 @@ static void nau8825_xtalk_measure(struct nau8825 *nau8825)
 		nau8825->xtalk_state = NAU8825_XTALK_IMM;
 		break;
 	case NAU8825_XTALK_IMM:
-		/* In impedance measure state, the orignal and cross talk
+		/* In impedance measure state, the original and cross talk
 		 * signal level vlues are ready. The side tone gain is deter-
 		 * mined with these signal level. After all, restore codec
 		 * configuration.
@@ -1507,11 +1507,22 @@ static int nau8825_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
+static const u64 nau8825_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops nau8825_dai_ops = {
 	.startup	= nau8825_dai_startup,
 	.hw_params	= nau8825_hw_params,
 	.set_fmt	= nau8825_set_dai_fmt,
 	.set_tdm_slot	= nau8825_set_tdm_slot,
+	.auto_selectable_formats	= &nau8825_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define NAU8825_RATES	SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/codecs/ntp8835.c b/sound/soc/codecs/ntp8835.c
index 5837b93..39620b8 100644
--- a/sound/soc/codecs/ntp8835.c
+++ b/sound/soc/codecs/ntp8835.c
@@ -385,9 +385,16 @@ static int ntp8835_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 };
 
+static const u64 ntp8835_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ntp8835_dai_ops = {
 	.hw_params = ntp8835_hw_params,
 	.set_fmt = ntp8835_set_fmt,
+	.auto_selectable_formats = &ntp8835_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver ntp8835_dai = {
diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c
index a18d79a..eca34fa 100644
--- a/sound/soc/codecs/ntp8918.c
+++ b/sound/soc/codecs/ntp8918.c
@@ -306,10 +306,17 @@ static int ntp8918_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
 					     mute_mask, mute ? mute_mask : 0);
 }
 
+static const u64 ntp8918_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops ntp8918_dai_ops = {
 	.hw_params = ntp8918_hw_params,
 	.set_fmt = ntp8918_set_fmt,
 	.mute_stream = ntp8918_digital_mute,
+	.auto_selectable_formats = &ntp8918_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver ntp8918_dai = {
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
index 9bca53d..ed1e29e 100644
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -6,12 +6,17 @@
  *		Copyright 2013
  */
 
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include <sound/soc.h>
 
+struct pcm5102a_priv {
+	struct gpio_desc *gpio_reset;
+};
+
 static struct snd_soc_dai_driver pcm5102a_dai = {
 	.name = "pcm5102a-hifi",
 	.playback = {
@@ -32,10 +37,32 @@ static const struct snd_soc_component_driver soc_component_dev_pcm5102a = {
 
 static int pcm5102a_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_pcm5102a,
+	struct device *dev = &pdev->dev;
+	struct pcm5102a_priv *pcm5102a;
+
+	pcm5102a = devm_kzalloc(dev, sizeof(*pcm5102a), GFP_KERNEL);
+	if (!pcm5102a)
+		return -ENOMEM;
+
+	pcm5102a->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+
+	if (IS_ERR(pcm5102a->gpio_reset))
+		return dev_err_probe(dev, PTR_ERR(pcm5102a->gpio_reset),
+					"failed to acquire reset gpio\n");
+
+	platform_set_drvdata(pdev, pcm5102a);
+
+	return devm_snd_soc_register_component(dev, &soc_component_dev_pcm5102a,
 			&pcm5102a_dai, 1);
 }
 
+static void pcm5102a_remove(struct platform_device *pdev)
+{
+	struct pcm5102a_priv *priv = platform_get_drvdata(pdev);
+
+	gpiod_set_value_cansleep(priv->gpio_reset, 1);
+}
+
 static const struct of_device_id pcm5102a_of_match[] = {
 	{ .compatible = "ti,pcm5102a", },
 	{ }
@@ -44,6 +71,7 @@ MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
 
 static struct platform_driver pcm5102a_codec_driver = {
 	.probe		= pcm5102a_probe,
+	.remove		= pcm5102a_remove,
 	.driver		= {
 		.name	= "pcm5102a-codec",
 		.of_match_table = pcm5102a_of_match,
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index db85ae2..4b5569a 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -620,12 +620,12 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
 		/* Set to wide-range mode, before using vol ctrl. */
 		if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) {
 			ucontrol->value.integer.value[0] = -25500;
-			return ret;
+			return 0;
 		}
 		/* Set to fine mode, before using fine vol ctrl. */
 		if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) {
 			ucontrol->value.integer.value[0] = -12750;
-			return ret;
+			return 0;
 		}
 	}
 
@@ -641,7 +641,7 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
 	val = mc->invert ? max - val : val;
 	ucontrol->value.integer.value[0] = val;
 
-	return ret;
+	return 0;
 }
 
 static int pcmdevice_get_volsw(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c
index 60befe9..abed31b 100644
--- a/sound/soc/codecs/rk3308_codec.c
+++ b/sound/soc/codecs/rk3308_codec.c
@@ -679,9 +679,20 @@ static int rk3308_codec_hw_params(struct snd_pcm_substream *substream,
 		rk3308_codec_adc_dig_config(rk3308, params);
 }
 
+static const u64 rk3308_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rk3308_codec_dai_ops = {
 	.hw_params = rk3308_codec_hw_params,
 	.set_fmt = rk3308_codec_set_dai_fmt,
+	.auto_selectable_formats = &rk3308_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rk3308_codec_dai_driver = {
diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c
index 5871b5a..c2798ee9 100644
--- a/sound/soc/codecs/rk3328_codec.c
+++ b/sound/soc/codecs/rk3328_codec.c
@@ -312,12 +312,21 @@ static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream,
 	rk3328_codec_close_playback(rk3328);
 }
 
+static const u64 rk3328_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rk3328_dai_ops = {
 	.hw_params = rk3328_hw_params,
 	.set_fmt = rk3328_set_dai_fmt,
 	.mute_stream = rk3328_mute_stream,
 	.startup = rk3328_pcm_startup,
 	.shutdown = rk3328_pcm_shutdown,
+	.auto_selectable_formats = &rk3328_selectable_formats,
+	.num_auto_selectable_formats = 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index 15488a0..d47b037 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -2133,10 +2133,20 @@ static int rt1011_set_bias_level(struct snd_soc_component *component,
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 rt1011_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1011_aif_dai_ops = {
 	.hw_params = rt1011_hw_params,
 	.set_fmt = rt1011_set_dai_fmt,
 	.set_tdm_slot = rt1011_set_tdm_slot,
+	.auto_selectable_formats = &rt1011_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt1011_dai[] = {
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index ff0c08f..5d6be7c 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -488,35 +488,72 @@ static int rt1015_bypass_boost_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static void rt1015_calibrate(struct rt1015_priv *rt1015)
+static int rt1015_calibrate(struct rt1015_priv *rt1015)
 {
 	struct snd_soc_component *component = rt1015->component;
 	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 	struct regmap *regmap = rt1015->regmap;
+	int ret, sync_ret;
 
 	snd_soc_dapm_mutex_lock(dapm);
 	regcache_cache_bypass(regmap, true);
 
-	regmap_write(regmap, RT1015_CLK_DET, 0x0000);
-	regmap_write(regmap, RT1015_PWR4, 0x00B2);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0009);
+	ret = regmap_write(regmap, RT1015_CLK_DET, 0x0000);
+	if (ret)
+		goto restore_cache;
+
+	ret = regmap_write(regmap, RT1015_PWR4, 0x00B2);
+	if (ret)
+		goto restore_cache;
+
+	ret = regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0009);
+	if (ret)
+		goto restore_cache;
+
 	msleep(100);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000A);
+	ret = regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000A);
+	if (ret)
+		goto restore_cache;
+
 	msleep(100);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000C);
+	ret = regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000C);
+	if (ret)
+		goto restore_cache;
+
 	msleep(100);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000D);
+	ret = regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028);
+	if (ret)
+		goto restore_cache;
+
+	ret = regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
+	if (ret)
+		goto restore_cache;
+
+	ret = regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000D);
+	if (ret)
+		goto restore_cache;
+
 	msleep(300);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008);
-	regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
-	regmap_write(regmap, RT1015_CLK_DET, 0x8000);
+	ret = regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008);
+	if (ret)
+		goto restore_cache;
+
+	ret = regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
+	if (ret)
+		goto restore_cache;
+
+	ret = regmap_write(regmap, RT1015_CLK_DET, 0x8000);
+
+restore_cache:
 
 	regcache_cache_bypass(regmap, false);
 	regcache_mark_dirty(regmap);
-	regcache_sync(regmap);
+	sync_ret = regcache_sync(regmap);
+	if (!ret)
+		ret = sync_ret;
 	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
 }
 
 static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
@@ -525,6 +562,8 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct rt1015_priv *rt1015 =
 		snd_soc_component_get_drvdata(component);
+	int bypass_boost = rt1015->bypass_boost;
+	int ret;
 
 	if (rt1015->dac_is_used) {
 		dev_err(component->dev, "DAC is being used!\n");
@@ -534,13 +573,23 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
 	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;
+		ret = rt1015_calibrate(rt1015);
+		if (ret)
+			goto restore_boost;
 
-		regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL, 0x0010);
+		ret = regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL,
+				   0x0010);
+		if (ret)
+			goto restore_boost;
+
+		rt1015->cali_done = 1;
 	}
 
 	return 0;
+
+restore_boost:
+	rt1015->bypass_boost = bypass_boost;
+	return ret;
 }
 
 static const char * const rt1015_dac_output_vol_select[] = {
@@ -1016,10 +1065,20 @@ static void rt1015_remove(struct snd_soc_component *component)
 #define RT1015_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt1015_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1015_aif_dai_ops = {
 	.hw_params = rt1015_hw_params,
 	.set_fmt = rt1015_set_dai_fmt,
 	.set_tdm_slot = rt1015_set_tdm_slot,
+	.auto_selectable_formats = &rt1015_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt1015_dai[] = {
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
index 11c8c45..56a2f3d 100644
--- a/sound/soc/codecs/rt1016.c
+++ b/sound/soc/codecs/rt1016.c
@@ -534,9 +534,19 @@ static void rt1016_remove(struct snd_soc_component *component)
 #define RT1016_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt1016_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1016_aif_dai_ops = {
 	.hw_params = rt1016_hw_params,
 	.set_fmt = rt1016_set_dai_fmt,
+	.auto_selectable_formats	= &rt1016_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt1016_dai[] = {
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
index 3705211..3998abc 100644
--- a/sound/soc/codecs/rt1019.c
+++ b/sound/soc/codecs/rt1019.c
@@ -492,12 +492,22 @@ static int rt1019_probe(struct snd_soc_component *component)
 #define RT1019_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt1019_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1019_aif_dai_ops = {
 	.hw_params = rt1019_hw_params,
 	.set_fmt = rt1019_set_dai_fmt,
 	.set_sysclk = rt1019_set_dai_sysclk,
 	.set_pll = rt1019_set_dai_pll,
 	.set_tdm_slot = rt1019_set_tdm_slot,
+	.auto_selectable_formats = &rt1019_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt1019_dai[] = {
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
index 2d5fad7..92998ec 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -910,9 +910,19 @@ static int rt1305_resume(struct snd_soc_component *component)
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 rt1305_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1305_aif_dai_ops = {
 	.hw_params = rt1305_hw_params,
 	.set_fmt = rt1305_set_dai_fmt,
+	.auto_selectable_formats = &rt1305_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt1305_dai[] = {
diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c
index 630946c..28c2587 100644
--- a/sound/soc/codecs/rt1308.c
+++ b/sound/soc/codecs/rt1308.c
@@ -729,9 +729,19 @@ static int rt1308_resume(struct snd_soc_component *component)
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 rt1308_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1308_aif_dai_ops = {
 	.hw_params = rt1308_hw_params,
 	.set_fmt = rt1308_set_dai_fmt,
+	.auto_selectable_formats	= &rt1308_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt1308_dai[] = {
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
index 55607f1..5f61de9 100644
--- a/sound/soc/codecs/rt1318.c
+++ b/sound/soc/codecs/rt1318.c
@@ -1087,12 +1087,22 @@ static int rt1318_resume(struct snd_soc_component *component)
 #define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt1318_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
 	.hw_params = rt1318_hw_params,
 	.set_fmt = rt1318_set_dai_fmt,
 	.set_sysclk = rt1318_set_dai_sysclk,
 	.set_pll = rt1318_set_dai_pll,
 	.set_tdm_slot = rt1318_set_tdm_slot,
+	.auto_selectable_formats = &rt1318_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt1318_dai[] = {
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 72af413..b13622e 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -2084,7 +2084,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
 		regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80);
 		/* RAE run */
 		regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01);
-		/* Phase sync eanble */
+		/* Phase sync enable */
 		regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
 		break;
 	}
@@ -2470,7 +2470,7 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
 	dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
 
 	/* initialization write */
-	if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || !rt1320->first_hw_init) {
+	if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) {
 		switch (rt1320->dev_id) {
 		case RT1320_DEV_ID:
 			if (rt1320->version_id < RT1320_VC)
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index f8c3701..62fc071 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -1027,6 +1027,12 @@ static int rt274_resume(struct snd_soc_component *component)
 #define RT274_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt274_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rt274_aif_dai_ops = {
 	.hw_params = rt274_hw_params,
 	.set_fmt = rt274_set_dai_fmt,
@@ -1034,6 +1040,8 @@ static const struct snd_soc_dai_ops rt274_aif_dai_ops = {
 	.set_pll = rt274_set_dai_pll,
 	.set_bclk_ratio = rt274_set_bclk_ratio,
 	.set_tdm_slot = rt274_set_tdm_slot,
+	.auto_selectable_formats = &rt274_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt274_dai[] = {
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 4217467..51b407b 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -995,11 +995,19 @@ static int rt286_resume(struct snd_soc_component *component)
 #define RT286_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt286_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rt286_aif_dai_ops = {
 	.hw_params = rt286_hw_params,
 	.set_fmt = rt286_set_dai_fmt,
 	.set_sysclk = rt286_set_dai_sysclk,
 	.set_bclk_ratio = rt286_set_bclk_ratio,
+	.auto_selectable_formats	= &rt286_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt286_dai[] = {
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index 09aed08..72407fe 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1056,11 +1056,19 @@ static int rt298_resume(struct snd_soc_component *component)
 #define RT298_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt298_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rt298_aif_dai_ops = {
 	.hw_params = rt298_hw_params,
 	.set_fmt = rt298_set_dai_fmt,
 	.set_sysclk = rt298_set_dai_sysclk,
 	.set_bclk_ratio = rt298_set_bclk_ratio,
+	.auto_selectable_formats = &rt298_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt298_dai[] = {
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 58aecd4..8dad8ba 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1142,12 +1142,24 @@ static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val)
 #define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5514_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rt5514_aif_dai_ops = {
 	.hw_params = rt5514_hw_params,
 	.set_fmt = rt5514_set_dai_fmt,
 	.set_sysclk = rt5514_set_dai_sysclk,
 	.set_pll = rt5514_set_dai_pll,
 	.set_tdm_slot = rt5514_set_tdm_slot,
+	.auto_selectable_formats = &rt5514_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt5514_dai[] = {
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 46ee412..3f9d97d 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -1260,11 +1260,21 @@ static int rt5616_resume(struct snd_soc_component *component)
 #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5616_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5616_aif_dai_ops = {
 	.hw_params = rt5616_hw_params,
 	.set_fmt = rt5616_set_dai_fmt,
 	.set_sysclk = rt5616_set_dai_sysclk,
 	.set_pll = rt5616_set_dai_pll,
+	.auto_selectable_formats = &rt5616_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt5616_dai[] = {
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index ed12339..f97fd24 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1626,11 +1626,21 @@ static int rt5631_probe(struct snd_soc_component *component)
 			SNDRV_PCM_FMTBIT_S24_LE | \
 			SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5631_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5631_ops = {
 	.hw_params = rt5631_hifi_pcm_params,
 	.set_fmt = rt5631_hifi_codec_set_dai_fmt,
 	.set_sysclk = rt5631_hifi_codec_set_dai_sysclk,
 	.set_pll = rt5631_codec_set_dai_pll,
+	.auto_selectable_formats = &rt5631_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt5631_dai[] = {
diff --git a/sound/soc/codecs/rt5631.h b/sound/soc/codecs/rt5631.h
index 8a6b99a..0073420 100644
--- a/sound/soc/codecs/rt5631.h
+++ b/sound/soc/codecs/rt5631.h
@@ -415,7 +415,7 @@
 #define RT5631_ADDA_FILTER_CLK_SEL_256FS		(0 << 7) /* 256FS */
 #define RT5631_ADDA_FILTER_CLK_SEL_384FS		(1 << 7) /* 384FS */
 
-/* Power managment addition 1 (0x3A) */
+/* Power management addition 1 (0x3A) */
 #define RT5631_PWR_MAIN_I2S_EN			(0x1 << 15)
 #define RT5631_PWR_MAIN_I2S_BIT			15
 #define RT5631_PWR_CLASS_D				(0x1 << 12)
@@ -435,7 +435,7 @@
 #define RT5631_PWR_DAC_R_TO_MIXER			(0x1 << 5)
 #define RT5631_PWR_DAC_R_TO_MIXER_BIT		5
 
-/* Power managment addition 2 (0x3B) */
+/* Power management addition 2 (0x3B) */
 #define RT5631_PWR_OUTMIXER_L				(0x1 << 15)
 #define RT5631_PWR_OUTMIXER_L_BIT			15
 #define RT5631_PWR_OUTMIXER_R				(0x1 << 14)
@@ -461,7 +461,7 @@
 #define RT5631_PWR_PLL2				(0x1 << 0)
 #define RT5631_PWR_PLL2_BIT				0
 
-/* Power managment addition 3(0x3C) */
+/* Power management addition 3(0x3C) */
 #define RT5631_PWR_VREF				(0x1 << 15)
 #define RT5631_PWR_VREF_BIT				15
 #define RT5631_PWR_FAST_VREF_CTRL			(0x1 << 14)
@@ -489,7 +489,7 @@
 #define RT5631_PWR_HP_AMP_DRIVING			(0x1 << 0)
 #define RT5631_PWR_HP_AMP_DRIVING_BIT		0
 
-/* Power managment addition 4(0x3E) */
+/* Power management addition 4(0x3E) */
 #define RT5631_PWR_SPK_L_VOL				(0x1 << 15)
 #define RT5631_PWR_SPK_L_VOL_BIT			15
 #define RT5631_PWR_SPK_R_VOL				(0x1 << 14)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 74fd051..03d0ac3 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1216,7 +1216,7 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
 		0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
 	SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,
 		0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)),
-	/* Ouput Volume */
+	/* Output Volume */
 	SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,
 		RT5640_PWR_SV_L_BIT, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("SPKVOL R", RT5640_PWR_VOL,
@@ -2877,11 +2877,21 @@ static int rt5640_resume(struct snd_soc_component *component)
 #define RT5640_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5640_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5640_aif_dai_ops = {
 	.hw_params = rt5640_hw_params,
 	.set_fmt = rt5640_set_dai_fmt,
 	.set_sysclk = rt5640_set_dai_sysclk,
 	.set_pll = rt5640_set_dai_pll,
+	.auto_selectable_formats	= &rt5640_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5640_dai[] = {
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 7313ea7..bb44825 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -2209,7 +2209,7 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 		0, rt5645_out_l_mix, ARRAY_SIZE(rt5645_out_l_mix)),
 	SND_SOC_DAPM_MIXER("OUT MIXR", RT5645_PWR_MIXER, RT5645_PWR_OM_R_BIT,
 		0, rt5645_out_r_mix, ARRAY_SIZE(rt5645_out_r_mix)),
-	/* Ouput Volume */
+	/* Output Volume */
 	SND_SOC_DAPM_SWITCH("SPKVOL L", RT5645_PWR_VOL, RT5645_PWR_SV_L_BIT, 0,
 		&spk_l_vol_control),
 	SND_SOC_DAPM_SWITCH("SPKVOL R", RT5645_PWR_VOL, RT5645_PWR_SV_R_BIT, 0,
@@ -3541,12 +3541,22 @@ static int rt5645_resume(struct snd_soc_component *component)
 #define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5645_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5645_aif_dai_ops = {
 	.hw_params = rt5645_hw_params,
 	.set_fmt = rt5645_set_dai_fmt,
 	.set_sysclk = rt5645_set_dai_sysclk,
 	.set_tdm_slot = rt5645_set_tdm_slot,
 	.set_pll = rt5645_set_dai_pll,
+	.auto_selectable_formats	= &rt5645_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5645_dai[] = {
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 5c72913..b911757 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1024,7 +1024,7 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
 			   0, rt5651_out_l_mix, ARRAY_SIZE(rt5651_out_l_mix)),
 	SND_SOC_DAPM_MIXER("OUT MIXR", RT5651_PWR_MIXER, RT5651_PWR_OM_R_BIT,
 			   0, rt5651_out_r_mix, ARRAY_SIZE(rt5651_out_r_mix)),
-	/* Ouput Volume */
+	/* Output Volume */
 	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5651_PWR_VOL,
 			    RT5651_PWR_OV_L_BIT, 0, &outvol_l_control),
 	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5651_PWR_VOL,
@@ -2102,11 +2102,21 @@ static int rt5651_resume(struct snd_soc_component *component)
 #define RT5651_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5651_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5651_aif_dai_ops = {
 	.hw_params = rt5651_hw_params,
 	.set_fmt = rt5651_set_dai_fmt,
 	.set_sysclk = rt5651_set_dai_sysclk,
 	.set_pll = rt5651_set_dai_pll,
+	.auto_selectable_formats	= &rt5651_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5651_dai[] = {
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 3097ee6..3d782f4 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3716,11 +3716,21 @@ static int rt5659_resume(struct snd_soc_component *component)
 #define RT5659_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5659_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5659_aif_dai_ops = {
 	.hw_params = rt5659_hw_params,
 	.set_fmt = rt5659_set_dai_fmt,
 	.set_tdm_slot = rt5659_set_tdm_slot,
 	.set_bclk_ratio = rt5659_set_bclk_ratio,
+	.auto_selectable_formats	= &rt5659_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5659_dai[] = {
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index edf2e3e..8076041 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1161,11 +1161,21 @@ static int rt5660_resume(struct snd_soc_component *component)
 #define RT5660_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5660_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5660_aif_dai_ops = {
 	.hw_params = rt5660_hw_params,
 	.set_fmt = rt5660_set_dai_fmt,
 	.set_sysclk = rt5660_set_dai_sysclk,
 	.set_pll = rt5660_set_dai_pll,
+	.auto_selectable_formats	= &rt5660_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5660_dai[] = {
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 262d3bb..ec46e61 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -3222,6 +3222,14 @@ static int rt5663_resume(struct snd_soc_component *component)
 #define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5663_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5663_aif_dai_ops = {
 	.hw_params = rt5663_hw_params,
 	.set_fmt = rt5663_set_dai_fmt,
@@ -3229,6 +3237,8 @@ static const struct snd_soc_dai_ops rt5663_aif_dai_ops = {
 	.set_pll = rt5663_set_dai_pll,
 	.set_tdm_slot = rt5663_set_tdm_slot,
 	.set_bclk_ratio = rt5663_set_bclk_ratio,
+	.auto_selectable_formats	= &rt5663_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5663_dai[] = {
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 1d98747..9545758 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4401,11 +4401,21 @@ static int rt5665_resume(struct snd_soc_component *component)
 #define RT5665_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5665_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5665_aif_dai_ops = {
 	.hw_params = rt5665_hw_params,
 	.set_fmt = rt5665_set_dai_fmt,
 	.set_tdm_slot = rt5665_set_tdm_slot,
 	.set_bclk_ratio = rt5665_set_bclk_ratio,
+	.auto_selectable_formats	= &rt5665_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5665_dai[] = {
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index 4154bad..cd6245d 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -2254,16 +2254,38 @@ static int rt5668_resume(struct snd_soc_component *component)
 #define RT5668_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5668_selectable_formats_aif1 =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
+static const u64 rt5668_selectable_formats_aif2 =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5668_aif1_dai_ops = {
 	.hw_params = rt5668_hw_params,
 	.set_fmt = rt5668_set_dai_fmt,
 	.set_tdm_slot = rt5668_set_tdm_slot,
+	.auto_selectable_formats	= &rt5668_selectable_formats_aif1,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops rt5668_aif2_dai_ops = {
 	.hw_params = rt5668_hw_params,
 	.set_fmt = rt5668_set_dai_fmt,
 	.set_bclk_ratio = rt5668_set_bclk_ratio,
+	.auto_selectable_formats	= &rt5668_selectable_formats_aif2,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5668_dai[] = {
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 1d120b5..62d4e7c 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -1901,7 +1901,7 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
 			   0, rt5670_out_l_mix, ARRAY_SIZE(rt5670_out_l_mix)),
 	SND_SOC_DAPM_MIXER("OUT MIXR", RT5670_PWR_MIXER, RT5670_PWR_OM_R_BIT,
 			   0, rt5670_out_r_mix, ARRAY_SIZE(rt5670_out_r_mix)),
-	/* Ouput Volume */
+	/* Output Volume */
 	SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5670_PWR_VOL,
 			   RT5670_PWR_HV_L_BIT, 0,
 			   rt5670_hpvoll_mix, ARRAY_SIZE(rt5670_hpvoll_mix)),
@@ -2791,12 +2791,22 @@ static int rt5670_resume(struct snd_soc_component *component)
 #define RT5670_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5670_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5670_aif_dai_ops = {
 	.hw_params = rt5670_hw_params,
 	.set_fmt = rt5670_set_dai_fmt,
 	.set_tdm_slot = rt5670_set_tdm_slot,
 	.set_pll = rt5670_set_dai_pll,
 	.set_bclk_ratio = rt5670_set_bclk_ratio,
+	.auto_selectable_formats	= &rt5670_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt5670_dai[] = {
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 4757017..7b80922 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -5031,12 +5031,22 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val)
 #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
+static const u64 rt5677_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5677_aif_dai_ops = {
 	.hw_params = rt5677_hw_params,
 	.set_fmt = rt5677_set_dai_fmt,
 	.set_sysclk = rt5677_set_dai_sysclk,
 	.set_pll = rt5677_set_dai_pll,
 	.set_tdm_slot = rt5677_set_tdm_slot,
+	.auto_selectable_formats	= &rt5677_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops rt5677_dsp_dai_ops = {
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 6f7e68c..1aceb08 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -3043,11 +3043,31 @@ static int rt5682_resume(struct snd_soc_component *component)
 #define rt5682_resume NULL
 #endif
 
+static const u64 rt5682_selectable_formats_aif1 =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
+static const u64 rt5682_selectable_formats_aif2 =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 const struct snd_soc_dai_ops rt5682_aif1_dai_ops = {
 	.hw_params = rt5682_hw_params,
 	.set_fmt = rt5682_set_dai_fmt,
 	.set_tdm_slot = rt5682_set_tdm_slot,
 	.set_bclk_ratio = rt5682_set_bclk1_ratio,
+	.auto_selectable_formats	= &rt5682_selectable_formats_aif1,
+	.num_auto_selectable_formats	= 1,
 };
 EXPORT_SYMBOL_GPL(rt5682_aif1_dai_ops);
 
@@ -3055,6 +3075,8 @@ const struct snd_soc_dai_ops rt5682_aif2_dai_ops = {
 	.hw_params = rt5682_hw_params,
 	.set_fmt = rt5682_set_dai_fmt,
 	.set_bclk_ratio = rt5682_set_bclk2_ratio,
+	.auto_selectable_formats	= &rt5682_selectable_formats_aif2,
+	.num_auto_selectable_formats	= 1,
 };
 EXPORT_SYMBOL_GPL(rt5682_aif2_dai_ops);
 
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 34997cf..6dd0d36 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -2926,17 +2926,39 @@ static int rt5682s_resume(struct snd_soc_component *component)
 #define rt5682s_resume NULL
 #endif
 
+static const u64 rt5682s_selectable_formats_aif1 =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
+static const u64 rt5682s_selectable_formats_aif2 =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rt5682s_aif1_dai_ops = {
 	.hw_params = rt5682s_hw_params,
 	.set_fmt = rt5682s_set_dai_fmt,
 	.set_tdm_slot = rt5682s_set_tdm_slot,
 	.set_bclk_ratio = rt5682s_set_bclk1_ratio,
+	.auto_selectable_formats	= &rt5682s_selectable_formats_aif1,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops rt5682s_aif2_dai_ops = {
 	.hw_params = rt5682s_hw_params,
 	.set_fmt = rt5682s_set_dai_fmt,
 	.set_bclk_ratio = rt5682s_set_bclk2_ratio,
+	.auto_selectable_formats	= &rt5682s_selectable_formats_aif2,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_component_driver rt5682s_soc_component_dev = {
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index 9105831..0ebb568 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -25,16 +25,22 @@ static bool rt721_sdca_readable_register(struct device *dev, unsigned int reg)
 	case 0x2f50:
 	case 0x2f51:
 	case 0x2f58 ... 0x2f5d:
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT0,
+		RT721_SDCA_CTL_FUNC_STATUS, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV,
 		RT721_SDCA_CTL_XUV, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
 		RT721_SDCA_CTL_SELECTED_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
 		RT721_SDCA_CTL_DETECTED_MODE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT0,
+		RT721_SDCA_CTL_FUNC_STATUS, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
 		RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
 		RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
 	case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT0,
+		RT721_SDCA_CTL_FUNC_STATUS, 0):
 		return true;
 	default:
 		return false;
@@ -46,14 +52,20 @@ static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg)
 	switch (reg) {
 	case 0x2f01:
 	case 0x2f51:
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT0,
+		RT721_SDCA_CTL_FUNC_STATUS, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
 		RT721_SDCA_CTL_DETECTED_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV,
 		RT721_SDCA_CTL_XUV, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT0,
+		RT721_SDCA_CTL_FUNC_STATUS, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
 		RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
 		RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
 	case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT0,
+		RT721_SDCA_CTL_FUNC_STATUS, 0):
 		return true;
 	default:
 		return false;
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
index 73864401..dbf61fa 100644
--- a/sound/soc/codecs/rt721-sdca.c
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -142,151 +142,192 @@ static void rt721_sdca_btn_check_handler(struct work_struct *work)
 
 static void rt721_sdca_dmic_preset(struct rt721_sdca_priv *rt721)
 {
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_MISC_POWER_CTL31, 0x8000);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
-		RT721_VREF1_HV_CTRL1, 0xe000);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_MISC_POWER_CTL31, 0x8007);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL9, 0x2a2a);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL10, 0x2a00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL6, 0x2a2a);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL5, 0x2626);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL8, 0x1e00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL7, 0x1515);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_CH_FLOAT_CTL3, 0x0304);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_CH_FLOAT_CTL4, 0x0304);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_HDA_LEGACY_CTL1, 0x0000);
-	regmap_write(rt721->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
-			RT721_SDCA_CTL_VENDOR_DEF, 0), 0x01);
-	regmap_write(rt721->mbq_regmap, 0x5910009, 0x2e01);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
-		RT721_RC_CALIB_CTRL0, 0x0b00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
-		RT721_RC_CALIB_CTRL0, 0x0b40);
-	regmap_write(rt721->regmap, 0x2f5c, 0x25);
+	unsigned int mic_func_status;
+	struct device *dev = &rt721->slave->dev;
+
+	regmap_read(rt721->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT0, RT721_SDCA_CTL_FUNC_STATUS, 0),
+		&mic_func_status);
+	dev_dbg(dev, "%s mic func_status=0x%x\n", __func__, mic_func_status);
+
+	if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt721->first_hw_init)) {
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_MISC_POWER_CTL31, 0x8000);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+			RT721_VREF1_HV_CTRL1, 0xe000);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_MISC_POWER_CTL31, 0x8007);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL9, 0x2a2a);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL10, 0x2a00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL6, 0x2a2a);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL5, 0x2626);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL8, 0x1e00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL7, 0x1515);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_CH_FLOAT_CTL3, 0x0304);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_CH_FLOAT_CTL4, 0x0304);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_HDA_LEGACY_CTL1, 0x0000);
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
+				RT721_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+		regmap_write(rt721->mbq_regmap, 0x5910009, 0x2e01);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+			RT721_RC_CALIB_CTRL0, 0x0b00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+			RT721_RC_CALIB_CTRL0, 0x0b40);
+		regmap_write(rt721->regmap, 0x2f5c, 0x25);
+		/* clear flag */
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT0,
+			RT721_SDCA_CTL_FUNC_STATUS, 0), FUNCTION_NEEDS_INITIALIZATION);
+	}
 }
 
 static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721)
 {
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_MISC_POWER_CTL31, 0x8000);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
-		RT721_VREF1_HV_CTRL1, 0xe000);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_MISC_POWER_CTL31, 0x8007);
-	regmap_write(rt721->mbq_regmap, 0x5810000, 0x6420);
-	regmap_write(rt721->mbq_regmap, 0x5810000, 0x6421);
-	regmap_write(rt721->mbq_regmap, 0x5810000, 0xe421);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_CH_FLOAT_CTL6, 0x5561);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_REG,
-		RT721_GPIO_PAD_CTRL5, 0x8003);
-	regmap_write(rt721->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
-			RT721_SDCA_CTL_VENDOR_DEF, 0), 0x04);
-	regmap_write(rt721->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
-			RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
-	regmap_write(rt721->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
-			RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
-	regmap_write(rt721->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
-			RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
-	regmap_write(rt721->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
-			RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
-	regmap_write(rt721->regmap, 0x2f5d, 0x1);
+	unsigned int amp_func_status;
+	struct device *dev = &rt721->slave->dev;
+
+	regmap_read(rt721->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT0, RT721_SDCA_CTL_FUNC_STATUS, 0),
+		&amp_func_status);
+	dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
+
+	if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt721->first_hw_init)) {
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_MISC_POWER_CTL31, 0x8000);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+			RT721_VREF1_HV_CTRL1, 0xe000);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_MISC_POWER_CTL31, 0x8007);
+		regmap_write(rt721->mbq_regmap, 0x5810000, 0x6420);
+		regmap_write(rt721->mbq_regmap, 0x5810000, 0x6421);
+		regmap_write(rt721->mbq_regmap, 0x5810000, 0xe421);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_CH_FLOAT_CTL6, 0x5561);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_REG,
+			RT721_GPIO_PAD_CTRL5, 0x8003);
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+				RT721_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+				RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+				RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+				RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+				RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+		regmap_write(rt721->regmap, 0x2f5d, 0x1);
+		/* clear flag */
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT0, RT721_SDCA_CTL_FUNC_STATUS, 0),
+			FUNCTION_NEEDS_INITIALIZATION);
+	}
 }
 
 static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
 {
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_MISC_POWER_CTL31, 0x8000);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
-		RT721_VREF1_HV_CTRL1, 0xe000);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_MISC_POWER_CTL31, 0x8007);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_GE_REL_CTRL1, 0x8011);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_UMP_HID_CTRL3, 0xcf00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_UMP_HID_CTRL4, 0x000f);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_UMP_HID_CTRL1, 0x1100);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_UMP_HID_CTRL5, 0x0c12);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_JD_CTRL,
-		RT721_JD_1PIN_GAT_CTRL2, 0xc002);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
-		RT721_RC_CALIB_CTRL0, 0x0b00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
-		RT721_RC_CALIB_CTRL0, 0x0b40);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_UAJ_TOP_TCON14, 0x3333);
-	regmap_write(rt721->mbq_regmap, 0x5810035, 0x0036);
-	regmap_write(rt721->mbq_regmap, 0x5810030, 0xee00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
-		RT721_HP_AMP_2CH_CAL1, 0x0140);
-	regmap_write(rt721->mbq_regmap, 0x5810000, 0x0021);
-	regmap_write(rt721->mbq_regmap, 0x5810000, 0x8021);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
-		RT721_HP_AMP_2CH_CAL18, 0x5522);
-	regmap_write(rt721->mbq_regmap, 0x5b10007, 0x2000);
-	regmap_write(rt721->mbq_regmap, 0x5B10017, 0x1b0f);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_CBJ_CTRL,
-		RT721_CBJ_A0_GAT_CTRL1, 0x2205);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
-		RT721_HP_AMP_2CH_CAL4, 0xa105);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_UAJ_TOP_TCON14, 0x3b33);
-	regmap_write(rt721->mbq_regmap, 0x310400, 0x3043);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_UAJ_TOP_TCON14, 0x3f33);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_UAJ_TOP_TCON13, 0x6048);
-	regmap_write(rt721->mbq_regmap, 0x310401, 0x3000);
-	regmap_write(rt721->mbq_regmap, 0x310402, 0x1b00);
-	regmap_write(rt721->mbq_regmap, 0x310300, 0x000f);
-	regmap_write(rt721->mbq_regmap, 0x310301, 0x3000);
-	regmap_write(rt721->mbq_regmap, 0x310302, 0x1b00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
-		RT721_UAJ_TOP_TCON17, 0x0008);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
-		RT721_DAC_2CH_CTRL3, 0x55ff);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
-		RT721_DAC_2CH_CTRL4, 0xcc00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
-		RT721_MBIAS_LV_CTRL2, 0x6677);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
-		RT721_VREF2_LV_CTRL1, 0x7600);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL2, 0x1234);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL3, 0x3512);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL1, 0x4040);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_ENT_FLOAT_CTL4, 0x1201);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_BOOST_CTRL,
-		RT721_BST_4CH_TOP_GATING_CTRL1, 0x002a);
-	regmap_write(rt721->regmap, 0x2f58, 0x07);
+	unsigned int jack_func_status;
+	struct device *dev = &rt721->slave->dev;
 
-	regmap_write(rt721->regmap, 0x2f51, 0x00);
-	rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
-		RT721_MISC_CTL, 0x0004);
+	regmap_read(rt721->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT0, RT721_SDCA_CTL_FUNC_STATUS, 0),
+			&jack_func_status);
+	dev_dbg(dev, "%s jack func_status=0x%x\n", __func__, jack_func_status);
+
+	if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt721->first_hw_init)) {
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_MISC_POWER_CTL31, 0x8000);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+			RT721_VREF1_HV_CTRL1, 0xe000);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_MISC_POWER_CTL31, 0x8007);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_GE_REL_CTRL1, 0x8011);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_UMP_HID_CTRL3, 0xcf00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_UMP_HID_CTRL4, 0x000f);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_UMP_HID_CTRL1, 0x1100);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_UMP_HID_CTRL5, 0x0c12);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_JD_CTRL,
+			RT721_JD_1PIN_GAT_CTRL2, 0xc002);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+			RT721_RC_CALIB_CTRL0, 0x0b00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+			RT721_RC_CALIB_CTRL0, 0x0b40);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_UAJ_TOP_TCON14, 0x3333);
+		regmap_write(rt721->mbq_regmap, 0x5810035, 0x0036);
+		regmap_write(rt721->mbq_regmap, 0x5810030, 0xee00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+			RT721_HP_AMP_2CH_CAL1, 0x0140);
+		regmap_write(rt721->mbq_regmap, 0x5810000, 0x0021);
+		regmap_write(rt721->mbq_regmap, 0x5810000, 0x8021);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+			RT721_HP_AMP_2CH_CAL18, 0x5522);
+		regmap_write(rt721->mbq_regmap, 0x5b10007, 0x2000);
+		regmap_write(rt721->mbq_regmap, 0x5B10017, 0x1b0f);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_CBJ_CTRL,
+			RT721_CBJ_A0_GAT_CTRL1, 0x2205);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+			RT721_HP_AMP_2CH_CAL4, 0xa105);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_UAJ_TOP_TCON14, 0x3b33);
+		regmap_write(rt721->mbq_regmap, 0x310400, 0x3043);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_UAJ_TOP_TCON14, 0x3f33);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_UAJ_TOP_TCON13, 0x6048);
+		regmap_write(rt721->mbq_regmap, 0x310401, 0x3000);
+		regmap_write(rt721->mbq_regmap, 0x310402, 0x1b00);
+		regmap_write(rt721->mbq_regmap, 0x310300, 0x000f);
+		regmap_write(rt721->mbq_regmap, 0x310301, 0x3000);
+		regmap_write(rt721->mbq_regmap, 0x310302, 0x1b00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+			RT721_UAJ_TOP_TCON17, 0x0008);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
+			RT721_DAC_2CH_CTRL3, 0x55ff);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
+			RT721_DAC_2CH_CTRL4, 0xcc00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+			RT721_MBIAS_LV_CTRL2, 0x6677);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+			RT721_VREF2_LV_CTRL1, 0x7600);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL2, 0x1234);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL3, 0x3512);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL1, 0x4040);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_ENT_FLOAT_CTL4, 0x1201);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_BOOST_CTRL,
+			RT721_BST_4CH_TOP_GATING_CTRL1, 0x002a);
+		regmap_write(rt721->regmap, 0x2f58, 0x07);
+		regmap_write(rt721->regmap, 0x2f51, 0x00);
+		rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+			RT721_MISC_CTL, 0x0004);
+		/* clear flag */
+		regmap_write(rt721->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT0,
+			RT721_SDCA_CTL_FUNC_STATUS, 0), FUNCTION_NEEDS_INITIALIZATION);
+	}
 }
 
 static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
diff --git a/sound/soc/codecs/rt721-sdca.h b/sound/soc/codecs/rt721-sdca.h
index 24ce188..b8873b1 100644
--- a/sound/soc/codecs/rt721-sdca.h
+++ b/sound/soc/codecs/rt721-sdca.h
@@ -214,6 +214,7 @@ struct rt721_sdca_dmic_kctrl_priv {
 #define RT721_SDCA_ENT_XU03			0x03
 #define RT721_SDCA_ENT_XU0D			0x0d
 #define RT721_SDCA_ENT_FU55			0x55
+#define RT721_SDCA_ENT0				0x00
 
 /* RT721 SDCA control */
 #define RT721_SDCA_CTL_SAMPLE_FREQ_INDEX		0x10
@@ -229,6 +230,7 @@ struct rt721_sdca_dmic_kctrl_priv {
 #define RT721_SDCA_CTL_VENDOR_DEF			0x30
 #define RT721_SDCA_CTL_XUV				0x34
 #define RT721_SDCA_CTL_FU_CH_GAIN			0x0b
+#define RT721_SDCA_CTL_FUNC_STATUS			0x10
 
 /* RT721 SDCA channel */
 #define CH_L	0x01
@@ -261,6 +263,9 @@ struct rt721_sdca_dmic_kctrl_priv {
 /* RT721 HID ID */
 #define RT721_SDCA_HID_ID		0x11
 
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION	BIT(5)
+
 enum {
 	RT721_AIF1, /* For headset mic and headphone */
 	RT721_AIF2, /* For speaker */
diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
index e51cd4a..1445e82 100644
--- a/sound/soc/codecs/rt9120.c
+++ b/sound/soc/codecs/rt9120.c
@@ -289,9 +289,18 @@ static int rt9120_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 rt9120_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rt9120_dai_ops = {
 	.set_fmt = rt9120_set_fmt,
 	.hw_params = rt9120_hw_params,
+	.auto_selectable_formats = &rt9120_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver rt9120_dai = {
diff --git a/sound/soc/codecs/rt9123.c b/sound/soc/codecs/rt9123.c
index 07eaf27..251bad4 100644
--- a/sound/soc/codecs/rt9123.c
+++ b/sound/soc/codecs/rt9123.c
@@ -299,10 +299,23 @@ static int rt9123_dai_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+/*
+ * NOTE
+ *
+ * auto_select doesn't include _DSP_A / _DSP_B, because it has limitaion for TDM
+ * (= rt9123_dai_hw_params()). It can be selected via Card directly if needed.
+ */
+static const u64 rt9123_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops rt9123_dai_ops = {
 	.set_fmt	= rt9123_dai_set_format,
 	.set_tdm_slot	= rt9123_dai_set_tdm_slot,
 	.hw_params	= rt9123_dai_hw_params,
+	.auto_selectable_formats	= &rt9123_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rt9123_dai_driver = {
diff --git a/sound/soc/codecs/rtq9124.c b/sound/soc/codecs/rtq9124.c
index 2a04189..cc1c687 100644
--- a/sound/soc/codecs/rtq9124.c
+++ b/sound/soc/codecs/rtq9124.c
@@ -286,10 +286,19 @@ static int rtq9124_dai_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 rtq9124_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rtq9124_dai_ops = {
 	.set_fmt	= rtq9124_dai_set_format,
 	.set_tdm_slot	= rtq9124_dai_set_tdm_slot,
 	.hw_params	= rtq9124_dai_hw_params,
+	.auto_selectable_formats	= &rtq9124_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rtq9124_dai_driver = {
diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c
index 573200e..9567e90 100644
--- a/sound/soc/codecs/rtq9128.c
+++ b/sound/soc/codecs/rtq9128.c
@@ -727,11 +727,20 @@ static int rtq9128_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream
 	return ret < 0 ? ret : 0;
 }
 
+static const u64 rtq9128_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops rtq9128_dai_ops = {
 	.set_fmt = rtq9128_dai_set_fmt,
 	.set_tdm_slot = rtq9128_dai_set_tdm_slot,
 	.hw_params = rtq9128_dai_hw_params,
 	.mute_stream = rtq9128_dai_mute_stream,
+	.auto_selectable_formats	= &rtq9128_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 35df1a8..97bea75 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1158,12 +1158,23 @@ static int sgtl5000_set_bias_level(struct snd_soc_component *component,
 			SNDRV_PCM_FMTBIT_S24_LE |\
 			SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 sgtl5000_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops sgtl5000_ops = {
 	.hw_params = sgtl5000_pcm_hw_params,
 	.mute_stream = sgtl5000_mute_stream,
 	.set_fmt = sgtl5000_set_dai_fmt,
 	.set_sysclk = sgtl5000_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &sgtl5000_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver sgtl5000_dai = {
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index d87141b..9b90445 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -199,9 +199,27 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
 	return err;
 }
 
+static const u64 si476x_selectable_formats[] = {
+	/* Hi Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* Low Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops si476x_dai_ops = {
 	.hw_params	= si476x_codec_hw_params,
 	.set_fmt	= si476x_codec_set_dai_fmt,
+	.auto_selectable_formats	= si476x_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(si476x_selectable_formats),
 };
 
 static struct snd_soc_dai_driver si476x_dai = {
diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c
index 15758eb..0bff3255 100644
--- a/sound/soc/codecs/sma1303.c
+++ b/sound/soc/codecs/sma1303.c
@@ -1412,12 +1412,25 @@ static int sma1303_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 sma1303_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops sma1303_dai_ops_amp = {
 	.set_sysclk = sma1303_dai_set_sysclk_amp,
 	.set_fmt = sma1303_dai_set_fmt_amp,
 	.hw_params = sma1303_dai_hw_params_amp,
 	.mute_stream = sma1303_dai_mute,
 	.set_tdm_slot = sma1303_dai_set_tdm_slot,
+	.auto_selectable_formats = &sma1303_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define SMA1303_RATES SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
index adb369a..57f34f2 100644
--- a/sound/soc/codecs/sma1307.c
+++ b/sound/soc/codecs/sma1307.c
@@ -1552,12 +1552,25 @@ static int sma1307_dai_mute_stream(struct snd_soc_dai *dai, int mute,
 	return 0;
 }
 
+static const u64 sma1307_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops sma1307_dai_ops_amp = {
 	.hw_params = sma1307_dai_hw_params_amp,
 	.set_fmt = sma1307_dai_set_fmt_amp,
 	.set_sysclk = sma1307_dai_set_sysclk_amp,
 	.set_tdm_slot = sma1307_dai_set_tdm_slot,
 	.mute_stream = sma1307_dai_mute_stream,
+	.auto_selectable_formats	= &sma1307_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define SMA1307_RATES_PLAYBACK SNDRV_PCM_RATE_8000_96000
@@ -1701,7 +1714,9 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
 			__func__, setting_file, ERR_PTR(ret));
 		sma1307->set.status = false;
 		return;
-	} else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) {
+	} else if (fw->size % sizeof(int) ||
+		   fw->size < (SMA1307_SETTING_HEADER_SIZE +
+				       SMA1307_SETTING_DEFAULT_SIZE) * sizeof(int)) {
 		dev_err(sma1307->dev, "%s: Invalid file\n", __func__);
 		sma1307->set.status = false;
 		return;
@@ -1720,6 +1735,10 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
 	sma1307->set.checksum = data[sma1307->set.header_size - 2];
 	sma1307->set.num_mode = data[sma1307->set.header_size - 1];
 	num_mode = sma1307->set.num_mode;
+	if (num_mode < 0 || num_mode > ARRAY_SIZE(sma1307->set.mode_set)) {
+		sma1307->set.status = false;
+		return;
+	}
 	sma1307->set.header = devm_kmalloc_array(sma1307->dev,
 						 sma1307->set.header_size,
 						 sizeof(int),
@@ -1755,7 +1774,11 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
 
 	/* MODE */
 	offset = sma1307->set.header_size + sma1307->set.def_size;
-	sma1307->set.mode_size = DIV_ROUND_CLOSEST(size - offset, num_mode + 1);
+	if ((size - offset) % (num_mode + 1)) {
+		sma1307->set.status = false;
+		return;
+	}
+	sma1307->set.mode_size = (size - offset) / (num_mode + 1);
 	for (int i = 0; i < num_mode; i++) {
 		sma1307->set.mode_set[i]
 		    = devm_kzalloc(sma1307->dev,
diff --git a/sound/soc/codecs/sn624x-sdca-sdw.c b/sound/soc/codecs/sn624x-sdca-sdw.c
new file mode 100644
index 0000000..c9e6904
--- /dev/null
+++ b/sound/soc/codecs/sn624x-sdca-sdw.c
@@ -0,0 +1,1888 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// sn624x-sdw-sdca.c -- SN624X SDCA ALSA SoC SoundWire audio driver
+//
+// Copyright(c) 2025 Senary Semiconductor Corp.
+//
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/find.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/sdca.h>
+#include <sound/sdca_asoc.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_regmap.h>
+#include <sound/sdw.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "sn624x-sdca.h"
+
+/* Resume wait after bus re-enumeration (rt722-style probe timeout) */
+#define SN624X_PROBE_TIMEOUT_MS			5000U
+#define SN624X_PWR_D0				SDCA_PDE_PS0
+#define SN624X_PWR_D3				SDCA_PDE_PS3
+#define SN624X_MUTE_ON				1
+/*
+ * Budget for ACTUAL_PS poll via sdca_asoc_pde_poll_actual_ps() (100 polls).
+ * Matches previous ~2s hand-rolled loop for slow PDE transitions.
+ */
+#define SN624X_PDE_PS_POLL_BUDGET_US		2000000U
+
+/*
+ * Prefer ACPI mipi-sdca-function-initialization-table via
+ * sdca_regmap_write_init(). If absent or DisCo parse is incomplete,
+ * a temporary vendor-window OEM fallback is used until firmware tables land.
+ *
+ * Jack detection is poll-driven (UAJ pulse + GE35); SDCA INTMASK bits stay
+ * masked so interrupt storms cannot schedule extra work.
+ */
+
+struct sn624x_sdca_priv;
+
+static void sn624x_sdca_sdca_irq_mask_all(struct sn624x_sdca_priv *sn624x);
+static int sn624x_uaj_ge35_apply_detected_mode(struct device *dev,
+					       struct sn624x_sdca_priv *sn624x);
+#define SN624X_DBG(dev, fmt, ...) dev_dbg(dev, "sn624x: " fmt, ##__VA_ARGS__)
+
+/*
+ * SDCA control addresses via SDW_SDCA_CTL(fun, ent, ctl, ch).
+ * Pass ch=0 for single-value controls (power/rate/status); use CH_L/CH_R
+ * only for multi-channel FU mute/volume. CH_ENABLE_* are not SDCA Control
+ * Prefix addresses — keep as raw windows.
+ */
+/* Speaker amp (function 4) — PDE/FU power/mute/vol; rate on CS01 */
+#define SN624X_REG_PWR_STATE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_PDE03, \
+		     SDCA_CTL_PDE_ACTUAL_PS, 0)
+#define SN624X_REG_PWR_STATE_WRITE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_PDE03, \
+		     SDCA_CTL_PDE_REQUESTED_PS, 0)
+#define SN624X_REG_RATE_SEL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_CS01, \
+		     SN624X_SDCA_CTL_SAMPLE_FREQ_INDEX, 0)
+#define SN624X_REG_CH_ENABLE_A			0x00000220u
+#define SN624X_REG_CH_ENABLE_B			0x00000230u
+#define SN624X_REG_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_USER_FU10, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_L)
+#define SN624X_REG_CHR_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_USER_FU10, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_R)
+#define SN624X_REG_MUTE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_USER_FU10, \
+		     SN624X_SDCA_CTL_FU_MUTE, SN624X_SDCA_CH_L)
+#define SN624X_REG_RIGHT_MUTE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_SPEAKER_AMP, SN624X_SDCA_ENT_USER_FU10, \
+		     SN624X_SDCA_CTL_FU_MUTE, SN624X_SDCA_CH_R)
+
+/* Jack playback (function 1) */
+#define SN624X_REG_JACK_OUT_PWR_STATE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_PDE03, \
+		     SDCA_CTL_PDE_ACTUAL_PS, 0)
+#define SN624X_REG_JACK_OUT_PWR_STATE_WRITE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_PDE03, \
+		     SDCA_CTL_PDE_REQUESTED_PS, 0)
+#define SN624X_REG_JACK_OUT_RATE_SEL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_CS01, \
+		     SN624X_SDCA_CTL_SAMPLE_FREQ_INDEX, 0)
+#define SN624X_REG_JACK_OUT_CH_ENABLE_A		0x00000120u
+#define SN624X_REG_JACK_OUT_CH_ENABLE_B		0x00000130u
+#define SN624X_REG_JACK_OUT_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_L)
+#define SN624X_REG_JACK_OUT_CHR_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_R)
+#define SN624X_REG_JACK_OUT_MUTE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_MUTE, SN624X_SDCA_CH_L)
+#define SN624X_REG_JACK_OUT_CLUSTER_INDEX \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_CRU05, \
+		     SN624X_SDCA_CTL_CLUSTER_INDEX, 0)
+
+/* Jack headset capture (function 1) */
+#define SN624X_REG_JACK_CAP_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_USER_FU1E, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_L)
+#define SN624X_REG_JACK_CAP_CHR_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_USER_FU1E, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_R)
+#define SN624X_REG_JACK_CAP_MUTE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_USER_FU1E, \
+		     SN624X_SDCA_CTL_FU_MUTE, SN624X_SDCA_CH_L)
+#define SN624X_REG_JACK_CAP_PWR_STATE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_PDE04, \
+		     SDCA_CTL_PDE_ACTUAL_PS, 0)
+#define SN624X_REG_JACK_CAP_PWR_STATE_WRITE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_PDE04, \
+		     SDCA_CTL_PDE_REQUESTED_PS, 0)
+#define SN624X_REG_JACK_CAP_RATE_SEL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_CS02, \
+		     SN624X_SDCA_CTL_SAMPLE_FREQ_INDEX, 0)
+#define SN624X_REG_JACK_CAP_CH_ENABLE_A		0x00000420u	/* low bits: 0x3=both */
+#define SN624X_REG_JACK_CAP_CH_ENABLE_B		0x00000430u
+
+#define SN624X_REG_JACK_FUN_STATUS_CTL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_ENTITY0, \
+		     SN624X_SDCA_CTL_FUNCTION_STATUS, 0)
+#define SN624X_JACK_FUN_NEEDS_INIT		BIT(5)
+#define SN624X_JACK_FUN_HAS_BEEN_RESET		BIT(6)
+
+/* DMIC capture (function 2) */
+#define SN624X_REG_DMIC_CAP_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_L)
+#define SN624X_REG_DMIC_CAP_CHR_VOL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_VOLUME, SN624X_SDCA_CH_R)
+/* Q7.8 channel volume: integer in bits 15:8, fraction in bits 7:0 */
+#define SN624X_VOL_Q78(int_part, frac_part) \
+	((((unsigned int)(int_part) & 0xff) << 8) | ((unsigned int)(frac_part) & 0xff))
+#define SN624X_REG_DMIC_CAP_MUTE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_MUTE, SN624X_SDCA_CH_L)
+#define SN624X_REG_DMIC_CAP_CHR_MUTE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_USER_FU14, \
+		     SN624X_SDCA_CTL_FU_MUTE, SN624X_SDCA_CH_R)
+#define SN624X_REG_DMIC_CAP_RATE_SEL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_CS02, \
+		     SN624X_SDCA_CTL_SAMPLE_FREQ_INDEX, 0)
+/* OEM sheet used ctl=0; SDCA Actual PS is 0x10 — poll the standard selector */
+#define SN624X_REG_DMIC_CAP_PWR_STATE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_PDE03, \
+		     SDCA_CTL_PDE_ACTUAL_PS, 0)
+#define SN624X_REG_DMIC_CAP_PWR_STATE_WRITE \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_PDE03, \
+		     SDCA_CTL_PDE_REQUESTED_PS, 0)
+#define SN624X_REG_DMIC_CAP_CH_ENABLE_A		0x00000520u	/* low bits: 0x3=both */
+#define SN624X_REG_DMIC_CAP_CH_ENABLE_B		0x00000530u
+
+#define SN624X_REG_DMIC_FUN_STATUS_CTL \
+	SDW_SDCA_CTL(SN624X_FUNC_NUM_MIC_ARRAY, SN624X_SDCA_ENT_ENTITY0, \
+		     SN624X_SDCA_CTL_FUNCTION_STATUS, 0)
+
+/*
+ * Write REQUESTED_PS then poll ACTUAL_PS with the shared SDCA helper
+ * (sdca_asoc_pde_poll_actual_ps). Caller must not hand-roll ACTUAL_PS waits.
+ */
+static int sn624x_pde_request_ps(struct device *dev, struct regmap *regmap,
+				 unsigned int fun, unsigned int ent,
+				 unsigned int ps);
+
+/*
+ * DAPM PDE supplies (rt711/rt712 style): write REQUESTED_PS then poll ACTUAL_PS.
+ * Mute-before-D3 is handled by FU widget PRE_PMD, which runs before SUPPLY PRE_PMD
+ * when the FU lists the PDE as a dependency.
+ */
+static int sn624x_dapm_pde_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event,
+				 unsigned int fun, unsigned int ent)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct sn624x_sdca_priv *sn624x =
+		snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
+	int ret;
+
+	if (!sn624x || !sn624x->regmap)
+		return -ENODEV;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		ret = sn624x_pde_request_ps(dev, sn624x->regmap, fun, ent,
+					    SN624X_PWR_D0);
+		if (ret < 0)
+			dev_warn(dev,
+				 "sn624x: DAPM %s PDE fun=%u ent=0x%x -> PS0 failed (%d)\n",
+				 w->name, fun, ent, ret);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		ret = sn624x_pde_request_ps(dev, sn624x->regmap, fun, ent,
+					    SN624X_PWR_D3);
+		if (ret < 0)
+			dev_warn(dev,
+				 "sn624x: DAPM %s PDE fun=%u ent=0x%x -> PS3 failed (%d)\n",
+				 w->name, fun, ent, ret);
+		break;
+	default:
+		return 0;
+	}
+	return ret;
+}
+
+static int sn624x_pde_hp_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_dapm_pde_event(w, kcontrol, event,
+				     SN624X_FUNC_NUM_JACK_CODEC,
+				     SN624X_SDCA_ENT_PDE03);
+}
+
+static int sn624x_pde_spk_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_dapm_pde_event(w, kcontrol, event,
+				     SN624X_FUNC_NUM_SPEAKER_AMP,
+				     SN624X_SDCA_ENT_PDE03);
+}
+
+static int sn624x_pde_mic2_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_dapm_pde_event(w, kcontrol, event,
+				     SN624X_FUNC_NUM_JACK_CODEC,
+				     SN624X_SDCA_ENT_PDE04);
+}
+
+static int sn624x_pde_dmic_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_dapm_pde_event(w, kcontrol, event,
+				     SN624X_FUNC_NUM_MIC_ARRAY,
+				     SN624X_SDCA_ENT_PDE03);
+}
+
+static int sn624x_fu_mute_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event,
+				unsigned int mute_l, unsigned int mute_r,
+				unsigned int vol_l, unsigned int vol_r,
+				unsigned int vol_val)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct sn624x_sdca_priv *sn624x =
+		snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
+	int ret;
+
+	if (!sn624x || !sn624x->regmap)
+		return -ENODEV;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (vol_l) {
+			ret = regmap_write(sn624x->regmap, vol_l, vol_val);
+			if (ret < 0)
+				dev_warn(dev, "sn624x: DAPM %s vol(L) failed (%d)\n",
+					 w->name, ret);
+		}
+		if (vol_r) {
+			ret = regmap_write(sn624x->regmap, vol_r, vol_val);
+			if (ret < 0)
+				dev_warn(dev, "sn624x: DAPM %s vol(R) failed (%d)\n",
+					 w->name, ret);
+		}
+		ret = regmap_write(sn624x->regmap, mute_l, 0);
+		if (ret < 0)
+			dev_warn(dev, "sn624x: DAPM %s unmute(L) failed (%d)\n",
+				 w->name, ret);
+		if (mute_r) {
+			ret = regmap_write(sn624x->regmap, mute_r, 0);
+			if (ret < 0)
+				dev_warn(dev, "sn624x: DAPM %s unmute(R) failed (%d)\n",
+					 w->name, ret);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Mute and settle before PDE SUPPLY PRE_PMD takes the domain to PS3 */
+		ret = regmap_write(sn624x->regmap, mute_l, SN624X_MUTE_ON);
+		if (ret < 0)
+			dev_warn(dev, "sn624x: DAPM %s mute(L) failed (%d)\n",
+				 w->name, ret);
+		if (mute_r) {
+			ret = regmap_write(sn624x->regmap, mute_r, SN624X_MUTE_ON);
+			if (ret < 0)
+				dev_warn(dev, "sn624x: DAPM %s mute(R) failed (%d)\n",
+					 w->name, ret);
+		}
+		usleep_range(SN624X_ROUTE_AFTER_MUTE_US_MIN,
+			     SN624X_ROUTE_AFTER_MUTE_US_MAX);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int sn624x_fu_hp_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_fu_mute_event(w, kcontrol, event,
+				    SN624X_REG_JACK_OUT_MUTE, 0,
+				    SN624X_REG_JACK_OUT_VOL,
+				    SN624X_REG_JACK_OUT_CHR_VOL, 0);
+}
+
+static int sn624x_fu_spk_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_fu_mute_event(w, kcontrol, event,
+				    SN624X_REG_MUTE, SN624X_REG_RIGHT_MUTE,
+				    SN624X_REG_VOL, SN624X_REG_CHR_VOL, 0);
+}
+
+static int sn624x_fu_mic2_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 sn624x_sdca_priv *sn624x =
+		snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (event == SND_SOC_DAPM_POST_PMU && sn624x)
+		sn624x_uaj_ge35_apply_detected_mode(component->dev, sn624x);
+
+	ret = sn624x_fu_mute_event(w, kcontrol, event,
+				   SN624X_REG_JACK_CAP_MUTE, 0,
+				   SN624X_REG_JACK_CAP_VOL,
+				   SN624X_REG_JACK_CAP_CHR_VOL,
+				   SN624X_VOL_Q78(6, 0));
+	return ret;
+}
+
+static int sn624x_fu_dmic_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	return sn624x_fu_mute_event(w, kcontrol, event,
+				    SN624X_REG_DMIC_CAP_MUTE,
+				    SN624X_REG_DMIC_CAP_CHR_MUTE,
+				    SN624X_REG_DMIC_CAP_VOL,
+				    SN624X_REG_DMIC_CAP_CHR_VOL,
+				    SN624X_VOL_Q78(6, 0));
+}
+
+static int sn624x_pde_request_ps(struct device *dev, struct regmap *regmap,
+				 unsigned int fun, unsigned int ent,
+				 unsigned int ps)
+{
+	static const struct sdca_pde_delay delays[] = {
+		{ .from_ps = SDCA_PDE_PS0, .to_ps = SDCA_PDE_PS3,
+		  .us = SN624X_PDE_PS_POLL_BUDGET_US },
+		{ .from_ps = SDCA_PDE_PS3, .to_ps = SDCA_PDE_PS0,
+		  .us = SN624X_PDE_PS_POLL_BUDGET_US },
+		{ .from_ps = SDCA_PDE_PS1, .to_ps = SDCA_PDE_PS0,
+		  .us = SN624X_PDE_PS_POLL_BUDGET_US },
+		{ .from_ps = SDCA_PDE_PS2, .to_ps = SDCA_PDE_PS0,
+		  .us = SN624X_PDE_PS_POLL_BUDGET_US },
+		{ .from_ps = SDCA_PDE_PS0, .to_ps = SDCA_PDE_PS0,
+		  .us = SN624X_PDE_PS_POLL_BUDGET_US },
+		{ .from_ps = SDCA_PDE_PS3, .to_ps = SDCA_PDE_PS3,
+		  .us = SN624X_PDE_PS_POLL_BUDGET_US },
+	};
+	unsigned int req = SDW_SDCA_CTL(fun, ent, SDCA_CTL_PDE_REQUESTED_PS, 0);
+	unsigned int act = SDW_SDCA_CTL(fun, ent, SDCA_CTL_PDE_ACTUAL_PS, 0);
+	unsigned int from_ps = SDCA_PDE_PS3;
+	int ret;
+
+	ret = regmap_read(regmap, act, &from_ps);
+	if (ret < 0) {
+		dev_warn(dev,
+			 "sn624x: PDE fun=%u ent=0x%x ACTUAL_PS read failed (%d)\n",
+			 fun, ent, ret);
+		from_ps = (ps == SN624X_PWR_D0) ? SN624X_PWR_D3 : SN624X_PWR_D0;
+	} else {
+		from_ps &= 0xffu;
+	}
+
+	ret = regmap_write(regmap, req, ps);
+	if (ret < 0) {
+		dev_warn(dev,
+			 "sn624x: PDE fun=%u ent=0x%x REQUESTED_PS=%u write failed (%d)\n",
+			 fun, ent, ps, ret);
+		return ret;
+	}
+
+	ret = sdca_asoc_pde_poll_actual_ps(regmap, fun, ent,
+					   from_ps, ps,
+					   delays, ARRAY_SIZE(delays));
+	if (ret < 0)
+		dev_warn(dev,
+			 "sn624x: PDE fun=%u ent=0x%x ACTUAL_PS poll failed (%d; want %u)\n",
+			 fun, ent, ret, ps);
+	return ret;
+}
+
+static void sn624x_jack_type_from_det_mode(struct sn624x_sdca_priv *sn624x,
+					   unsigned int det_mode)
+{
+	switch (det_mode) {
+	case 0x00:
+		sn624x->jack_type = 0;
+		break;
+	case 0x03:
+		sn624x->jack_type = SND_JACK_HEADPHONE;
+		break;
+	case 0x05:
+		sn624x->jack_type = SND_JACK_HEADSET;
+		break;
+	default:
+		SN624X_DBG(&sn624x->slave->dev,
+			   "unknown GE35 detected_mode 0x%x\n", det_mode);
+		sn624x->jack_type = 0;
+		break;
+	}
+}
+
+static int sn624x_uaj_ge35_select_mode(struct device *dev,
+				       struct sn624x_sdca_priv *sn624x,
+				       unsigned int mode)
+{
+	int ret;
+
+	ret = regmap_write(sn624x->regmap,
+			   SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC,
+					SN624X_SDCA_ENT_GE35,
+					SN624X_SDCA_CTL_SELECTED_MODE, 0),
+			   mode);
+	if (ret < 0)
+		dev_warn(dev,
+			 "sn624x: jack_cap: GE35 SELECTED_MODE=0x%x failed (%d)\n",
+			 mode, ret);
+	else
+		dev_dbg(dev,
+			 "sn624x: jack_cap: GE35 SELECTED_MODE=0x%x\n",
+			 mode);
+	return ret;
+}
+
+/*
+ * Follow DETECTED_MODE → SELECTED_MODE (rt711/rt722 pattern). Never force
+ * headset: mic path is only valid when the jack hardware reports one.
+ * Also updates sn624x->jack_type from DETECTED_MODE.
+ */
+static int sn624x_uaj_ge35_apply_detected_mode(struct device *dev,
+					       struct sn624x_sdca_priv *sn624x)
+{
+	unsigned int det_mode = 0;
+	int ret;
+
+	ret = regmap_read(sn624x->regmap,
+			  SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC,
+				       SN624X_SDCA_ENT_GE35,
+				       SN624X_SDCA_CTL_DETECTED_MODE, 0),
+			  &det_mode);
+	if (ret < 0) {
+		dev_warn(dev,
+			 "sn624x: jack_cap: GE35 DETECTED_MODE read failed (%d)\n",
+			 ret);
+		return ret;
+	}
+
+	dev_dbg(dev, "sn624x: jack_cap: GE35 DETECTED_MODE=0x%x\n", det_mode);
+	sn624x_jack_type_from_det_mode(sn624x, det_mode);
+
+	if (!det_mode) {
+		dev_dbg(dev,
+			"sn624x: jack_cap: no jack detected — skip SELECTED_MODE\n");
+		return 0;
+	}
+
+	return sn624x_uaj_ge35_select_mode(dev, sn624x, det_mode);
+}
+
+static const char *sn624x_status_str(enum sdw_slave_status status)
+{
+	switch (status) {
+	case SDW_SLAVE_UNATTACHED:
+		return "UNATTACHED";
+	case SDW_SLAVE_ATTACHED:
+		return "ATTACHED";
+	case SDW_SLAVE_ALERT:
+		return "ALERT";
+	case SDW_SLAVE_RESERVED:
+		return "RESERVED";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int sn624x_sdca_mbq_size(struct device *dev, unsigned int reg)
+{
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return 1;
+
+	/*
+	 * FU_VOLUME and GE35 DETECTED_MODE share control selector 0x02.
+	 * Only list known FU volume addresses as 16-bit MBQ — matching
+	 * DETECTED_MODE by csel alone makes GE35 use SDW_SDCA_MBQ_CTL and
+	 * fails with -ENODATA (-61), which breaks jack plug/unplug.
+	 */
+	switch (reg) {
+	case SN624X_REG_VOL:
+	case SN624X_REG_CHR_VOL:
+	case SN624X_REG_JACK_OUT_VOL:
+	case SN624X_REG_JACK_OUT_CHR_VOL:
+	case SN624X_REG_JACK_CAP_VOL:
+	case SN624X_REG_JACK_CAP_CHR_VOL:
+	case SN624X_REG_DMIC_CAP_VOL:
+	case SN624X_REG_DMIC_CAP_CHR_VOL:
+		return 2;
+	default:
+		return 1;
+	}
+}
+
+static bool sn624x_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return true;
+
+	switch (reg) {
+	case SN624X_REG_PWR_STATE:
+	case SN624X_REG_JACK_OUT_PWR_STATE:
+	case SN624X_REG_JACK_CAP_PWR_STATE:
+	case SN624X_REG_DMIC_CAP_PWR_STATE:
+	case SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_SDCA_ENT_GE35,
+			  SN624X_SDCA_CTL_DETECTED_MODE, 0):
+		return true;
+	default:
+		if (SDW_SDCA_CTL_CSEL(reg) == SDCA_CTL_PDE_ACTUAL_PS)
+			return true;
+		return false;
+	}
+}
+
+static const struct regmap_sdw_mbq_cfg sn624x_sdca_mbq_cfg = {
+	.mbq_size = sn624x_sdca_mbq_size,
+};
+
+static const struct regmap_config sn624x_sdca_regmap = {
+	.reg_bits = 32,
+	.val_bits = 16,
+	.volatile_reg = sn624x_sdca_volatile_register,
+	.max_register = 0xffffffff,
+	.cache_type = REGCACHE_MAPLE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+/*
+ * Prefer ACPI mipi-sdca-function-initialization-table (sdca_regmap_write_init).
+ * sdca_parse_function() loads that table before entity parsing, so a later
+ * DisCo parse failure can still leave fn->num_init_table usable.
+ */
+static int sn624x_write_sdca_init_table(struct device *dev,
+					struct sn624x_sdca_priv *sn624x,
+					struct sdca_function_data *fn,
+					const char *label)
+{
+	int ret;
+
+	if (!fn || !fn->num_init_table)
+		return -ENOENT;
+
+	ret = sdca_regmap_write_init(dev, sn624x->regmap, fn);
+	if (ret < 0) {
+		dev_warn(dev,
+			 "sn624x: %s function-initialization-table write failed (%d)\n",
+			 label, ret);
+		return ret;
+	}
+
+	dev_info(dev,
+		 "sn624x: applied %s function-initialization-table (%d writes)\n",
+		 label, fn->num_init_table);
+	return 0;
+}
+
+/*
+ * Temporary vendor-window fallback when ACPI has no init table.
+ * Validated on current platforms; remove once DisCo init tables are complete.
+ */
+static int sn624x_jack_oem_fallback_init(struct device *dev,
+					 struct sn624x_sdca_priv *sn624x)
+{
+	static const struct reg_sequence jack_oem_table[] = {
+		REG_SEQ0(SN624X_UAJ_CTL_IT33_MIC_BIAS, 0x06),
+		REG_SEQ0(SN624X_UAJ_CTL_IT31_MIC_BIAS, 0x06),
+		REG_SEQ0(SN624X_UAJ_CTL_FU41_CH1_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU41_CH2_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU31_CH0_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU32_CH0_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU33_CH0_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU36_CH1_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU36_CH2_MUTE, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU31_CH0_GAIN_HIGH, 0x12),
+		REG_SEQ0(SN624X_UAJ_CTL_FU31_CH0_GAIN_LOW, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU32_CH0_GAIN_HIGH, 0x0C),
+		REG_SEQ0(SN624X_UAJ_CTL_FU32_CH0_GAIN_LOW, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_FU33_CH0_GAIN_HIGH, 0x12),
+		REG_SEQ0(SN624X_UAJ_CTL_FU33_CH0_GAIN_LOW, 0x00),
+		REG_SEQ0(SN624X_UAJ_CTL_INPUT_DELAY_TIME, 0x0F),
+		REG_SEQ0(SN624X_UAJ_CTL_PORTA_CHARGE_PUMP, 0x0B),
+	};
+	int ret;
+
+	dev_warn_once(dev,
+		      "sn624x: using temporary jack OEM init fallback (no ACPI init table)\n");
+	ret = regmap_multi_reg_write_bypassed(sn624x->regmap, jack_oem_table,
+					      ARRAY_SIZE(jack_oem_table));
+	if (ret < 0) {
+		dev_warn(dev, "sn624x: jack OEM fallback failed (%d)\n", ret);
+		return ret;
+	}
+	usleep_range(1000, 1500);
+	return 0;
+}
+
+static int sn624x_dmic_oem_fallback_init(struct device *dev,
+					 struct sn624x_sdca_priv *sn624x)
+{
+	static const struct reg_sequence dmic_oem_table[] = {
+		REG_SEQ0(0x00002041, 0x00),
+		REG_SEQ0(SN624X_UAJ_DMIC_PPU11, 0x30),
+		REG_SEQ0(0x00002105, 0x66),
+		REG_SEQ0(0x00002107, 0x26),
+		REG_SEQ0(0x00002109, 0x62),
+		REG_SEQ0(0x40800a09, 0x00),
+		REG_SEQ0(0x40800a0a, 0x00),
+		REG_SEQ0(0x40802a11, 0x00),
+		REG_SEQ0(0x40800a11, 0x00),
+		REG_SEQ0(0x40802a12, 0x00),
+		REG_SEQ0(0x40800a12, 0x00),
+		REG_SEQ0(0x40802a13, 0x00),
+		REG_SEQ0(0x40800a13, 0x00),
+		REG_SEQ0(0x40802a14, 0x00),
+		REG_SEQ0(0x40800a14, 0x00),
+		REG_SEQ0(0x408029d8, 0x0c),
+		REG_SEQ0(0x408009d8, 0x00),
+		REG_SEQ0(0x408029d9, 0x0c),
+		REG_SEQ0(0x408009d9, 0x00),
+		REG_SEQ0(0x00002140, 0x18),
+		REG_SEQ0(0x00002045, 0x01),
+	};
+	int ret;
+
+	dev_warn_once(dev,
+		      "sn624x: using temporary dmic OEM init fallback (no ACPI init table)\n");
+	ret = regmap_multi_reg_write_bypassed(sn624x->regmap, dmic_oem_table,
+					      ARRAY_SIZE(dmic_oem_table));
+	if (ret < 0) {
+		dev_warn(dev, "sn624x: dmic OEM fallback failed (%d)\n", ret);
+		return ret;
+	}
+	usleep_range(1000, 1500);
+	return 0;
+}
+
+static void sn624x_uaj_apply_io_defaults(struct sn624x_sdca_priv *sn624x)
+{
+	struct device *dev = &sn624x->slave->dev;
+	int ret;
+
+	ret = sn624x_write_sdca_init_table(dev, sn624x, sn624x->jack_func,
+					   "jack");
+	if (ret)
+		sn624x_jack_oem_fallback_init(dev, sn624x);
+}
+
+static int sn624x_parse_sdca_functions(struct sn624x_sdca_priv *sn624x)
+{
+	struct sdw_slave *slave = sn624x->slave;
+	struct device *dev = &slave->dev;
+	int i, ret;
+
+	if (!slave->sdca_data.num_functions) {
+		dev_dbg(dev, "sn624x: no SDCA function descriptors from DisCo\n");
+		return 0;
+	}
+
+	for (i = 0; i < slave->sdca_data.num_functions; i++) {
+		struct sdca_function_desc *desc = &slave->sdca_data.function[i];
+		struct sdca_function_data *fn;
+		bool is_jack = false, is_mic = false, is_amp = false;
+
+		switch (desc->type) {
+		case SDCA_FUNCTION_TYPE_UAJ:
+		case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
+		case SDCA_FUNCTION_TYPE_RJ:
+			is_jack = true;
+			break;
+		case SDCA_FUNCTION_TYPE_SMART_MIC:
+		case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
+			is_mic = true;
+			break;
+		case SDCA_FUNCTION_TYPE_SMART_AMP:
+		case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
+		case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
+			is_amp = true;
+			break;
+		default:
+			break;
+		}
+
+		if (desc->adr == SN624X_FUNC_NUM_JACK_CODEC)
+			is_jack = true;
+		else if (desc->adr == SN624X_FUNC_NUM_MIC_ARRAY)
+			is_mic = true;
+		else if (desc->adr == SN624X_FUNC_NUM_SPEAKER_AMP)
+			is_amp = true;
+
+		if (!is_jack && !is_mic && !is_amp)
+			continue;
+
+		fn = devm_kzalloc(dev, sizeof(*fn), GFP_KERNEL);
+		if (!fn)
+			return -ENOMEM;
+
+		fn->desc = desc;
+		ret = sdca_parse_function(dev, fn);
+		if (ret) {
+			/*
+			 * sdca_parse_function() reads the ACPI
+			 * mipi-sdca-function-initialization-table first,
+			 * then parses entities/controls. On some platforms
+			 * DisCo entity data is incomplete so the later
+			 * steps fail (-EINVAL), but fn->init_table is
+			 * already filled. Keep that partial function so
+			 * io_init can still apply the ACPI table; if the
+			 * table was never loaded, drop this function and
+			 * let the OEM register fallback run instead.
+			 */
+			dev_warn(dev,
+				 "sn624x: sdca_parse_function(%s adr=%u) failed (%d)%s\n",
+				 desc->name ? desc->name : "?", desc->adr, ret,
+				 fn->num_init_table ?
+				 ", keeping ACPI init table" : "");
+			if (!fn->num_init_table)
+				continue;
+		} else {
+			dev_dbg(dev,
+				"sn624x: parsed SDCA function %s type=%u adr=%u init_writes=%d\n",
+				desc->name ? desc->name : "?", desc->type,
+				desc->adr, fn->num_init_table);
+		}
+
+		if (is_jack && !sn624x->jack_func)
+			sn624x->jack_func = fn;
+		else if (is_mic && !sn624x->mic_func)
+			sn624x->mic_func = fn;
+		else if (is_amp && !sn624x->amp_func)
+			sn624x->amp_func = fn;
+	}
+
+	return 0;
+}
+
+/*
+ * Poll-driven jack detect: pulse UAJ jack-detect, then apply GE35
+ * DETECTED_MODE → SELECTED_MODE via sn624x_uaj_ge35_apply_detected_mode().
+ */
+static int sn624x_sdca_headset_detect(struct sn624x_sdca_priv *sn624x)
+{
+	struct device *dev = &sn624x->slave->dev;
+	int ret;
+
+	SN624X_DBG(dev, "headset_detect: pulse UAJ jack-detect, read GE35\n");
+	ret = regmap_write(sn624x->regmap,
+			   SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC,
+					SN624X_UAJ_ENT_BLOCK,
+					SN624X_UAJ_CTL_JACK_DETECT, 0),
+			   0x08);
+	if (ret < 0)
+		goto io_error;
+
+	usleep_range(5000, 5500);
+
+	ret = sn624x_uaj_ge35_apply_detected_mode(dev, sn624x);
+
+	/* Clear the detect pulse even if GE35 apply failed. */
+	regmap_write(sn624x->regmap,
+		     SDW_SDCA_CTL(SN624X_FUNC_NUM_JACK_CODEC, SN624X_UAJ_ENT_BLOCK,
+				  SN624X_UAJ_CTL_JACK_DETECT, 0),
+		     0x00);
+
+	if (ret < 0)
+		goto io_error;
+
+	SN624X_DBG(dev, "headset_detect: jack_type=0x%x\n", sn624x->jack_type);
+	return 0;
+
+io_error:
+	if (ret == -ENODATA)
+		SN624X_DBG(dev, "%s: UAJ/GE35 access ignored (-ENODATA)\n",
+			   __func__);
+	else
+		dev_err_ratelimited(dev, "%s failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static void sn624x_sdca_sdca_irq_mask_all(struct sn624x_sdca_priv *sn624x)
+{
+	if (!sn624x->slave)
+		return;
+
+	sdw_write_no_pm(sn624x->slave, SDW_SCP_SDCA_INTMASK1, 0);
+	sdw_write_no_pm(sn624x->slave, SDW_SCP_SDCA_INTMASK2, 0);
+	sdw_write_no_pm(sn624x->slave, SDW_SCP_SDCA_INTMASK3, 0);
+	sdw_write_no_pm(sn624x->slave, SDW_SCP_SDCA_INTMASK4, 0);
+	SN624X_DBG(&sn624x->slave->dev,
+		   "SDCA INTMASK1-4 = 0 (all SDCA sources masked)\n");
+}
+
+static void sn624x_sdca_jack_irq_unmask(struct sn624x_sdca_priv *sn624x)
+{
+	/* Jack detection is poll-driven; SDCA jack IRQs remain masked. */
+	(void)sn624x;
+}
+
+static void sn624x_sdca_jack_irq_mask(struct sn624x_sdca_priv *sn624x)
+{
+	if (!sn624x->slave)
+		return;
+
+	sn624x_sdca_sdca_irq_mask_all(sn624x);
+}
+
+/*
+ * Hold a runtime PM reference for the lifetime of jack detection so the
+ * device cannot autosuspend while the poll worker needs register access.
+ */
+static int sn624x_jack_rpm_get(struct sn624x_sdca_priv *sn624x)
+{
+	struct device *dev;
+	int ret;
+
+	if (!sn624x)
+		return -EINVAL;
+	if (sn624x->jack_rpm)
+		return 0;
+	if (!sn624x->component)
+		return -ENODEV;
+
+	dev = sn624x->component->dev;
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0) {
+		if (ret != -EACCES) {
+			dev_err(dev, "sn624x: jack rpm get failed (%d)\n", ret);
+			return ret;
+		}
+		/* pm_runtime not enabled yet (before first ATTACHED io_init) */
+		return 0;
+	}
+
+	sn624x->jack_rpm = true;
+	return 0;
+}
+
+static void sn624x_jack_rpm_put(struct sn624x_sdca_priv *sn624x)
+{
+	if (!sn624x || !sn624x->jack_rpm || !sn624x->component)
+		return;
+
+	pm_runtime_mark_last_busy(sn624x->component->dev);
+	pm_runtime_put_autosuspend(sn624x->component->dev);
+	sn624x->jack_rpm = false;
+}
+
+static void sn624x_jack_schedule_poll(struct sn624x_sdca_priv *sn624x)
+{
+	if (!sn624x || !sn624x->hs_jack || !sn624x->slave)
+		return;
+
+	mod_delayed_work(system_power_efficient_wq, &sn624x->jack_detect_work,
+			 msecs_to_jiffies(SN624X_JACK_POLL_MS));
+}
+
+static void sn624x_sdca_jack_poll_and_report(struct sn624x_sdca_priv *sn624x)
+{
+	struct device *dev;
+
+	if (!sn624x->hs_jack || !sn624x->slave)
+		return;
+
+	dev = &sn624x->slave->dev;
+	if (sn624x_sdca_headset_detect(sn624x) < 0)
+		return;
+
+	snd_soc_jack_report(sn624x->hs_jack, sn624x->jack_type,
+			    SND_JACK_HEADSET | SND_JACK_HEADPHONE);
+	sn624x->jack_type_last = sn624x->jack_type;
+	dev_dbg(dev, "sn624x: jack polled: detected_mode -> jack_type=0x%x\n",
+		 sn624x->jack_type);
+}
+
+static void sn624x_sdca_jack_detect_handler(struct work_struct *work)
+{
+	struct sn624x_sdca_priv *sn624x =
+		container_of(work, struct sn624x_sdca_priv, jack_detect_work.work);
+	struct device *dev;
+
+	if (!sn624x->slave) {
+		sn624x_jack_schedule_poll(sn624x);
+		return;
+	}
+
+	dev = &sn624x->slave->dev;
+
+	if (!sn624x->hs_jack) {
+		SN624X_DBG(dev, "jack_work: skip (no hs_jack)\n");
+		goto out_reschedule;
+	}
+
+	/* Registers are only valid after ATTACHED → io_init (hw_init). */
+	if (!sn624x->hw_init) {
+		SN624X_DBG(dev, "jack_work: skip (hw_init not ready)\n");
+		goto out_reschedule;
+	}
+
+	/* Poll GE35 every interval; do not rely on SDCA_0 IRQ or PCM activity */
+	sn624x_sdca_headset_detect(sn624x);
+
+	if (sn624x->jack_type != sn624x->jack_type_last) {
+		dev_dbg(dev,
+			 "sn624x: jack event: %s (jack_type=0x%x; HP=0x%x HS=0x%x)\n",
+			 sn624x->jack_type ? "plug" : "unplug",
+			 sn624x->jack_type, SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+		sn624x->jack_type_last = sn624x->jack_type;
+
+		snd_soc_jack_report(sn624x->hs_jack, sn624x->jack_type,
+				    SND_JACK_HEADSET | SND_JACK_HEADPHONE);
+	}
+
+out_reschedule:
+	sn624x_jack_schedule_poll(sn624x);
+}
+
+static void sn624x_sdca_jack_init(struct sn624x_sdca_priv *sn624x)
+{
+	/* No machine set_jack() yet — not "jack unsupported". */
+	if (!sn624x->hs_jack)
+		return;
+
+	sn624x_sdca_jack_irq_unmask(sn624x);
+	sn624x_sdca_jack_poll_and_report(sn624x);
+	sn624x_jack_schedule_poll(sn624x);
+
+	dev_dbg(&sn624x->slave->dev,
+		 "sn624x: jack_init: poll scheduled every %ums\n", SN624X_JACK_POLL_MS);
+}
+
+static int sn624x_sdca_set_jack_detect(struct snd_soc_component *component,
+				       struct snd_soc_jack *hs_jack, void *data)
+{
+	struct sn624x_sdca_priv *sn624x = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	dev_dbg(component->dev,
+		 "sn624x: set_jack: hs_jack=%p first_hw_init=%d hw_init=%d\n",
+		 hs_jack, sn624x->first_hw_init, sn624x->hw_init);
+
+	if (!hs_jack) {
+		cancel_delayed_work_sync(&sn624x->jack_detect_work);
+		sn624x->hs_jack = NULL;
+		sn624x_jack_rpm_put(sn624x);
+		return 0;
+	}
+
+	/*
+	 * Component registration happens before runtime PM is enabled (RPM is
+	 * enabled from io_init on first ATTACHED). Do not touch runtime PM
+	 * until then, or get/put counts can go out of sync.
+	 */
+	if (!sn624x->first_hw_init) {
+		sn624x->hs_jack = hs_jack;
+		sn624x->jack_type_last = -1;
+		sn624x_jack_schedule_poll(sn624x);
+		return 0;
+	}
+
+	/*
+	 * Take the runtime PM reference before publishing hs_jack, so a
+	 * failed get cannot leave jack detection marked as enabled.
+	 */
+	ret = sn624x_jack_rpm_get(sn624x);
+	if (ret < 0)
+		return ret;
+
+	sn624x->hs_jack = hs_jack;
+	sn624x->jack_type_last = -1;
+	sn624x_sdca_jack_init(sn624x);
+	return 0;
+}
+
+/* Prefer ACPI init table; OEM vendor-window fallback only if absent. */
+static int sn624x_jack_apply_defaults(struct device *dev,
+				      struct sn624x_sdca_priv *sn624x)
+{
+	int ret;
+
+	if (!sn624x || !sn624x->regmap || !sn624x->slave)
+		return -ENODEV;
+
+	ret = sn624x_write_sdca_init_table(dev, sn624x, sn624x->jack_func,
+					   "jack");
+	if (ret == 0) {
+		usleep_range(1000, 1500);
+		return 0;
+	}
+
+	return sn624x_jack_oem_fallback_init(dev, sn624x);
+}
+
+static int sn624x_dmic_apply_defaults(struct device *dev,
+				      struct sn624x_sdca_priv *sn624x)
+{
+	int ret;
+
+	if (!sn624x || !sn624x->regmap || !sn624x->slave)
+		return -ENODEV;
+
+	ret = sn624x_write_sdca_init_table(dev, sn624x, sn624x->mic_func,
+					   "dmic");
+	if (ret == 0) {
+		usleep_range(1000, 1500);
+		return 0;
+	}
+
+	return sn624x_dmic_oem_fallback_init(dev, sn624x);
+}
+
+static int sn624x_sdca_jack_function_init(struct device *dev,
+					  struct sn624x_sdca_priv *sn624x)
+{
+	unsigned int jack_func_status;
+	const struct reg_sequence clear_status =
+		REG_SEQ0(SN624X_REG_JACK_FUN_STATUS_CTL, 0x61);
+	int ret;
+
+	ret = regmap_read_bypassed(sn624x->regmap,
+				   SN624X_REG_JACK_FUN_STATUS_CTL,
+				   &jack_func_status);
+	if (ret < 0)
+		return ret;
+
+	if (!(jack_func_status & (SN624X_JACK_FUN_NEEDS_INIT |
+				  SN624X_JACK_FUN_HAS_BEEN_RESET)))
+		return 0;
+
+	ret = sn624x_jack_apply_defaults(dev, sn624x);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_multi_reg_write_bypassed(sn624x->regmap, &clear_status, 1);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(1000, 1500);
+	return 0;
+}
+
+static int sn624x_sdca_dmic_function_init(struct device *dev,
+					  struct sn624x_sdca_priv *sn624x)
+{
+	unsigned int dmic_func_status;
+	const struct reg_sequence clear_status =
+		REG_SEQ0(SN624X_REG_DMIC_FUN_STATUS_CTL, 0x61);
+	int ret;
+
+	ret = regmap_read_bypassed(sn624x->regmap,
+				   SN624X_REG_DMIC_FUN_STATUS_CTL,
+				   &dmic_func_status);
+	if (ret < 0)
+		return ret;
+
+	if (!(dmic_func_status & (SN624X_JACK_FUN_NEEDS_INIT |
+				  SN624X_JACK_FUN_HAS_BEEN_RESET)))
+		return 0;
+
+	ret = sn624x_dmic_apply_defaults(dev, sn624x);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_multi_reg_write_bypassed(sn624x->regmap, &clear_status, 1);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(1000, 1500);
+	return 0;
+}
+
+static int sn624x_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(dev);
+	int ret;
+
+	if (sn624x->hw_init) {
+		SN624X_DBG(dev, "io_init: skip (hw_init already true)\n");
+		return 0;
+	}
+
+	SN624X_DBG(dev, "io_init: start (first hardware bring-up)\n");
+	sn624x->disable_irq = false;
+
+	sn624x_sdca_sdca_irq_mask_all(sn624x);
+
+	regcache_cache_only(sn624x->regmap, false);
+	if (!sn624x->first_hw_init) {
+		/*
+		 * PM runtime is only enabled when a Slave reports as Attached
+		 * (same pattern as rt722).
+		 */
+		pm_runtime_set_autosuspend_delay(dev, 3000);
+		pm_runtime_use_autosuspend(dev);
+		pm_runtime_set_active(dev);
+		pm_runtime_mark_last_busy(dev);
+		pm_runtime_enable(dev);
+	}
+
+	pm_runtime_get_noresume(dev);
+
+	sn624x_uaj_apply_io_defaults(sn624x);
+
+	/*
+	 * set_jack() may have run before RPM was enabled (-EACCES). Take the
+	 * long-lived jack PM ref now that runtime PM is active.
+	 */
+	if (sn624x->hs_jack) {
+		sn624x_jack_rpm_get(sn624x);
+		sn624x_sdca_jack_init(sn624x);
+	}
+
+	ret = sn624x_sdca_jack_function_init(dev, sn624x);
+	if (ret < 0) {
+		dev_err(dev, "sn624x: jack function init failed (%d)\n", ret);
+		goto err;
+	}
+
+	ret = sn624x_sdca_dmic_function_init(dev, sn624x);
+	if (ret < 0) {
+		dev_err(dev, "sn624x: dmic function init failed (%d)\n", ret);
+		goto err;
+	}
+
+	/*
+	 * Re-attach after bus reset: force a full cache write-back on the
+	 * following resume/sync path (same idea as rt722).
+	 */
+	if (sn624x->first_hw_init)
+		regcache_mark_dirty(sn624x->regmap);
+
+	sn624x->hw_init = true;
+	sn624x->first_hw_init = true;
+
+	pm_runtime_put_autosuspend(dev);
+
+	SN624X_DBG(dev, "io_init: complete (hw_init set), jack %s\n",
+		   sn624x->hs_jack ? "registered" : "not registered yet");
+	return 0;
+
+err:
+	pm_runtime_put_noidle(dev);
+	return ret;
+}
+
+/*
+ * Bus lifecycle (same as rt722): enumerate → assign dev_num → ATTACHED →
+ * io_init(). Do not poll enumeration/init around each register access; after
+ * unattach, resume uses sdw_slave_wait_for_init() then regcache_sync.
+ */
+static int sn624x_sdca_update_status(struct sdw_slave *slave,
+				     enum sdw_slave_status status)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(&slave->dev);
+	bool need_io_init;
+	int ret;
+
+	SN624X_DBG(&slave->dev, "update_status: %s hw_init=%d dev_num=%u\n",
+		   sn624x_status_str(status), sn624x->hw_init, slave->dev_num);
+
+	if (status == SDW_SLAVE_UNATTACHED) {
+		cancel_delayed_work_sync(&sn624x->jack_detect_work);
+		sn624x->hw_init = false;
+		SN624X_DBG(&slave->dev,
+			   "slave UNATTACHED: cleared hw_init, jack work cancelled\n");
+	}
+
+	if (status != SDW_SLAVE_ATTACHED)
+		return 0;
+
+	sn624x_sdca_sdca_irq_mask_all(sn624x);
+
+	need_io_init = !sn624x->hw_init;
+	if (need_io_init) {
+		dev_notice(&slave->dev, "sn624x: update_status ATTACHED -> io_init()\n");
+		ret = sn624x_sdca_io_init(&slave->dev, slave);
+		if (ret < 0)
+			return ret;
+	} else {
+		dev_dbg(&slave->dev,
+			"sn624x: update_status ATTACHED: io_init already done\n");
+	}
+
+	/* Re-ATTACHED without io_init: restore jack detect after bus is up. */
+	if (sn624x->hs_jack && sn624x->hw_init && !need_io_init) {
+		sn624x_sdca_jack_irq_unmask(sn624x);
+		sn624x_sdca_jack_poll_and_report(sn624x);
+		sn624x_jack_schedule_poll(sn624x);
+	}
+
+	return 0;
+}
+
+static int sn624x_sdca_read_prop(struct sdw_slave *slave)
+{
+	struct sdw_slave_prop *prop = &slave->prop;
+	struct sdw_dpn_prop *dpn;
+	unsigned long addr;
+	unsigned int bit;
+	int nval;
+	int i, j;
+
+	sdw_slave_read_lane_mapping(slave);
+	prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+	prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+	prop->paging_support = true;
+	prop->use_domain_irq = true;
+	prop->wake_capable = true;
+
+	prop->source_ports = BIT(SN624X_PORT_JACK_CAPTURE) |
+			     BIT(SN624X_PORT_DMIC_CAPTURE);
+	prop->sink_ports = BIT(SN624X_PORT_JACK_PLAYBACK) |
+			   BIT(SN624X_PORT_SPEAKER_PLAYBACK);
+
+	nval = hweight32(prop->source_ports);
+	prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+					   sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+	if (!prop->src_dpn_prop)
+		return -ENOMEM;
+	i = 0;
+	dpn = prop->src_dpn_prop;
+	addr = prop->source_ports;
+	for_each_set_bit(bit, &addr, 32) {
+		dpn[i].num = bit;
+		dpn[i].type = SDW_DPN_FULL;
+		dpn[i].simple_ch_prep_sm = true;
+		dpn[i].ch_prep_timeout = 10;
+		i++;
+	}
+	nval = hweight32(prop->sink_ports);
+	prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+					   sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+	if (!prop->sink_dpn_prop)
+		return -ENOMEM;
+	j = 0;
+	dpn = prop->sink_dpn_prop;
+	addr = prop->sink_ports;
+	for_each_set_bit(bit, &addr, 32) {
+		dpn[j].num = bit;
+		dpn[j].type = SDW_DPN_FULL;
+		dpn[j].simple_ch_prep_sm = true;
+		dpn[j].ch_prep_timeout = 10;
+		j++;
+	}
+	prop->clk_stop_timeout = 900;
+	prop->simple_clk_stop_capable = true;
+	prop->lane_control_support = true;
+	SN624X_DBG(&slave->dev,
+		   "read_prop: src_ports=0x%x sink_ports=0x%x lane irq paging\n",
+		   prop->source_ports, prop->sink_ports);
+
+	return 0;
+}
+
+/*
+ * Clear SDCA INT1/2 only. DP0_INT standard fields (PORT_READY, etc.) are
+ * owned by the SoundWire bus core; cascade clears when SDCA status is clear.
+ * Pending SDCA IRQs can block clock-stop prepare (CLK_STP_NF -> -ETIMEDOUT).
+ */
+static int sn624x_sdca_flush_pending_irqs(struct sn624x_sdca_priv *sn624x,
+					  struct device *dev)
+{
+	int ret, stat = 0;
+	int count = 0;
+	const int retry = 3;
+	unsigned int scp_sdca_stat1, scp_sdca_stat2 = 0;
+
+	if (!sn624x || !sn624x->slave)
+		return 0;
+
+	ret = sdw_read_no_pm(sn624x->slave, SDW_SCP_SDCA_INT1);
+	if (ret < 0)
+		return ret;
+	sn624x->scp_sdca_stat1 = ret;
+
+	ret = sdw_read_no_pm(sn624x->slave, SDW_SCP_SDCA_INT2);
+	if (ret < 0)
+		return ret;
+	sn624x->scp_sdca_stat2 = ret;
+
+	do {
+		ret = sdw_read_no_pm(sn624x->slave, SDW_SCP_SDCA_INT1);
+		if (ret < 0)
+			return ret;
+		if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) {
+			ret = sdw_write_no_pm(sn624x->slave, SDW_SCP_SDCA_INT1,
+					      SDW_SCP_SDCA_INTMASK_SDCA_0);
+			if (ret < 0)
+				return ret;
+		}
+
+		ret = sdw_read_no_pm(sn624x->slave, SDW_SCP_SDCA_INT2);
+		if (ret < 0)
+			return ret;
+		if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) {
+			ret = sdw_write_no_pm(sn624x->slave, SDW_SCP_SDCA_INT2,
+					      SDW_SCP_SDCA_INTMASK_SDCA_8);
+			if (ret < 0)
+				return ret;
+		}
+
+		ret = sdw_read_no_pm(sn624x->slave, SDW_SCP_SDCA_INT1);
+		if (ret < 0)
+			return ret;
+		scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0;
+
+		ret = sdw_read_no_pm(sn624x->slave, SDW_SCP_SDCA_INT2);
+		if (ret < 0)
+			return ret;
+		scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8;
+
+		stat = scp_sdca_stat1 || scp_sdca_stat2;
+		count++;
+	} while (stat != 0 && count < retry);
+
+	if (stat && dev)
+		dev_warn(dev,
+			 "sn624x: SDCA IRQ flush incomplete (stat=%u)\n", stat);
+
+	return stat ? -EBUSY : 0;
+}
+
+static int sn624x_sdca_interrupt_callback(struct sdw_slave *slave,
+					  struct sdw_slave_intr_status *status)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(&slave->dev);
+	int ret;
+
+	if (!sn624x)
+		return 0;
+
+	/*
+	 * Bus expects the codec to clear SCP SDCA INT1/2 when cascade is set.
+	 * Leaving them set can stall alert handling.
+	 */
+
+	SN624X_DBG(&slave->dev,
+		   "irq: control_port=%#x sdca_cascade=%u disable_irq=%d\n",
+		   status->control_port, status->sdca_cascade, sn624x->disable_irq);
+
+	cancel_delayed_work_sync(&sn624x->jack_detect_work);
+
+	mutex_lock(&sn624x->disable_irq_lock);
+
+	ret = sn624x_sdca_flush_pending_irqs(sn624x, &slave->dev);
+	if (ret < 0 && ret != -EBUSY)
+		goto io_error;
+
+	SN624X_DBG(&slave->dev, "irq: INT1=0x%x INT2=0x%x\n",
+		   sn624x->scp_sdca_stat1, sn624x->scp_sdca_stat2);
+
+	/*
+	 * Always restart the jack poll after IRQ handling so a cancel above
+	 * cannot stop detection. SDCA INTMASK stays masked; any residual SCP
+	 * IRQ still triggers an early poll. The poll itself does the UAJ
+	 * pulse + GE35 read.
+	 */
+	if (!sn624x->disable_irq)
+		sn624x_jack_schedule_poll(sn624x);
+
+	mutex_unlock(&sn624x->disable_irq_lock);
+	return 0;
+
+io_error:
+	mutex_unlock(&sn624x->disable_irq_lock);
+	dev_err_ratelimited(&slave->dev, "%s: IO error (%d)\n", __func__, ret);
+	return ret;
+}
+
+static const struct sdw_slave_ops sn624x_sdca_slave_ops = {
+	.read_prop = sn624x_sdca_read_prop,
+	.interrupt_callback = sn624x_sdca_interrupt_callback,
+	.update_status = sn624x_sdca_update_status,
+};
+
+static int sn624x_sdca_probe(struct snd_soc_component *component)
+{
+	struct sn624x_sdca_priv *sn624x = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	sn624x->component = component;
+
+	if (!sn624x->first_hw_init)
+		return 0;
+
+	ret = pm_runtime_resume(component->dev);
+	if (ret < 0 && ret != -EACCES)
+		return ret;
+
+	return 0;
+}
+
+static int sn624x_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sn624x_sdca_priv *sn624x = snd_soc_component_get_drvdata(component);
+	struct sdw_stream_config stream_config = {};
+	struct sdw_port_config port_config = {};
+	struct sdw_stream_runtime *sdw_stream;
+	unsigned int sampling_rate;
+	int port;
+	int ret;
+
+	dev_dbg(dai->dev,
+		 "sn624x: hw_params: entered dai=%s id=%d stream=%s\n",
+		 dai->name, dai->id, snd_pcm_stream_str(substream));
+
+	sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+	if (!sdw_stream) {
+		dev_warn(dai->dev,
+			 "sn624x: hw_params: no SDW stream (set_stream not run yet?)\n");
+		return -EINVAL;
+	}
+	if (!sn624x->slave) {
+		dev_warn(dai->dev, "sn624x: hw_params: slave NULL\n");
+		return -EINVAL;
+	}
+
+	ret = pm_runtime_resume(component->dev);
+	if (ret < 0 && ret != -EACCES) {
+		dev_err(dai->dev,
+			"sn624x: hw_params: pm_runtime_resume failed (%d)\n", ret);
+		return ret;
+	}
+
+	snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (dai->id == SN624X_DAI_JACK)
+			port = SN624X_PORT_JACK_PLAYBACK;
+		else if (dai->id == SN624X_DAI_SPEAKER)
+			port = SN624X_PORT_SPEAKER_PLAYBACK;
+		else
+			return -EINVAL;
+	} else {
+		if (dai->id == SN624X_DAI_JACK)
+			port = SN624X_PORT_JACK_CAPTURE;
+		else if (dai->id == SN624X_DAI_DMIC)
+			port = SN624X_PORT_DMIC_CAPTURE;
+		else
+			return -EINVAL;
+	}
+	port_config.num = port;
+
+	ret = sdw_stream_add_slave(sn624x->slave, &stream_config,
+				   &port_config, 1, sdw_stream);
+	if (ret) {
+		dev_err(dai->dev, "%s: sdw_stream_add_slave port %d failed: %d\n",
+			__func__, port, ret);
+		return ret;
+	}
+
+	/* SDCA SampleFreqIndex (same encoding as other SDCA codecs) */
+	switch (params_rate(params)) {
+	case 44100:
+		sampling_rate = SN624X_SDCA_RATE_44100HZ;
+		break;
+	case 48000:
+		sampling_rate = SN624X_SDCA_RATE_48000HZ;
+		break;
+	case 96000:
+		sampling_rate = SN624X_SDCA_RATE_96000HZ;
+		break;
+	case 192000:
+		sampling_rate = SN624X_SDCA_RATE_192000HZ;
+		break;
+	default:
+		dev_err(dai->dev, "%s: Rate %d is not supported\n",
+			__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	if (dai->id == SN624X_DAI_JACK) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = regmap_write(sn624x->regmap,
+					   SN624X_REG_JACK_OUT_RATE_SEL,
+					   sampling_rate);
+		else
+			ret = regmap_write(sn624x->regmap,
+					   SN624X_REG_JACK_CAP_RATE_SEL,
+					   sampling_rate);
+	} else if (dai->id == SN624X_DAI_SPEAKER) {
+		ret = regmap_write(sn624x->regmap, SN624X_REG_RATE_SEL,
+				   sampling_rate);
+	} else if (dai->id == SN624X_DAI_DMIC) {
+		ret = regmap_write(sn624x->regmap, SN624X_REG_DMIC_CAP_RATE_SEL,
+				   sampling_rate);
+	} else {
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sn624x_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct sn624x_sdca_priv *sn624x = snd_soc_component_get_drvdata(dai->component);
+	struct sdw_stream_runtime *sdw_stream =
+		snd_soc_dai_get_dma_data(dai, substream);
+
+	if (!sn624x->slave)
+		return -EINVAL;
+
+	return sdw_stream_remove_slave(sn624x->slave, sdw_stream);
+}
+
+static int sn624x_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+				      int direction)
+{
+	snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+	return 0;
+}
+
+static void sn624x_sdca_shutdown(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static const struct snd_soc_dapm_widget sn624x_sdca_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SPK RX", "Speaker Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("DMIC TX", "DMic Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("PDE HP", SND_SOC_NOPM, 0, 0,
+			    sn624x_pde_hp_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("PDE SPK", SND_SOC_NOPM, 0, 0,
+			    sn624x_pde_spk_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("PDE MIC2", SND_SOC_NOPM, 0, 0,
+			    sn624x_pde_mic2_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("PDE DMIC", SND_SOC_NOPM, 0, 0,
+			    sn624x_pde_dmic_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_DAC_E("FU HP", NULL, SND_SOC_NOPM, 0, 0,
+			   sn624x_fu_hp_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_DAC_E("FU SPK", NULL, SND_SOC_NOPM, 0, 0,
+			   sn624x_fu_spk_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("FU MIC2", NULL, SND_SOC_NOPM, 0, 0,
+			   sn624x_fu_mic2_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("FU DMIC", NULL, SND_SOC_NOPM, 0, 0,
+			   sn624x_fu_dmic_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_OUTPUT("HP"),
+	SND_SOC_DAPM_OUTPUT("SPK"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("DMIC"),
+};
+
+static const struct snd_soc_dapm_route sn624x_sdca_audio_map[] = {
+	{ "FU HP", NULL, "RX" },
+	{ "FU HP", NULL, "PDE HP" },
+	{ "HP", NULL, "FU HP" },
+
+	{ "FU SPK", NULL, "SPK RX" },
+	{ "FU SPK", NULL, "PDE SPK" },
+	{ "SPK", NULL, "FU SPK" },
+
+	{ "FU MIC2", NULL, "MIC2" },
+	{ "FU MIC2", NULL, "PDE MIC2" },
+	/* UAJ headset capture also needs jack PDE03 (shared with HP) */
+	{ "FU MIC2", NULL, "PDE HP" },
+	{ "TX", NULL, "FU MIC2" },
+
+	{ "FU DMIC", NULL, "DMIC" },
+	{ "FU DMIC", NULL, "PDE DMIC" },
+	{ "DMIC TX", NULL, "FU DMIC" },
+};
+
+static const struct snd_soc_dai_ops sn624x_sdca_ops = {
+	.hw_params	= sn624x_sdca_pcm_hw_params,
+	.hw_free	= sn624x_sdca_pcm_hw_free,
+	.set_stream	= sn624x_sdca_set_sdw_stream,
+	.shutdown	= sn624x_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver sn624x_sdca_dai[] = {
+	{
+		.name = "sn624x-sdca-aif",
+		.id = 0,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SN624X_STEREO_RATES,
+			.formats = SN624X_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SN624X_STEREO_RATES,
+			.formats = SN624X_FORMATS,
+		},
+		.ops = &sn624x_sdca_ops,
+	},
+	{
+		.name = "sn624x-sdca-aif2",
+		.id = 1,
+		.playback = {
+			.stream_name = "Speaker Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SN624X_STEREO_RATES,
+			.formats = SN624X_FORMATS,
+		},
+		.ops = &sn624x_sdca_ops,
+	},
+	{
+		.name = "sn624x-sdca-aif3",
+		.id = 2,
+		.capture = {
+			.stream_name = "DMic Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = SN624X_STEREO_RATES,
+			.formats = SN624X_FORMATS,
+		},
+		.ops = &sn624x_sdca_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_sdca_dev_sn624x = {
+	.probe = sn624x_sdca_probe,
+	.dapm_widgets = sn624x_sdca_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(sn624x_sdca_dapm_widgets),
+	.dapm_routes = sn624x_sdca_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(sn624x_sdca_audio_map),
+	.set_jack = sn624x_sdca_set_jack_detect,
+	.endianness = 1,
+};
+
+int sn624x_sdca_init(struct device *dev, struct regmap *regmap,
+		      struct sdw_slave *slave)
+{
+	struct sn624x_sdca_priv *sn624x;
+	int ret;
+
+	sn624x = devm_kzalloc(dev, sizeof(*sn624x), GFP_KERNEL);
+	if (!sn624x)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, sn624x);
+	sn624x->slave = slave;
+	sn624x->regmap = regmap;
+
+	ret = sn624x_parse_sdca_functions(sn624x);
+	if (ret < 0)
+		return ret;
+
+	mutex_init(&sn624x->disable_irq_lock);
+	INIT_DELAYED_WORK(&sn624x->jack_detect_work, sn624x_sdca_jack_detect_handler);
+
+	regcache_cache_only(sn624x->regmap, true);
+
+	ret = devm_snd_soc_register_component(dev,
+					      &soc_sdca_dev_sn624x, sn624x_sdca_dai,
+					      ARRAY_SIZE(sn624x_sdca_dai));
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Do not enable runtime PM here. SoundWire slaves are only powered /
+	 * accessible after ATTACHED; enable RPM from io_init() then.
+	 */
+	SN624X_DBG(dev, "snd_soc_register_component OK (DAI sn624x-sdca-aif)\n");
+	return 0;
+}
+
+static int sn624x_sdca_sdw_probe(struct sdw_slave *slave,
+				 const struct sdw_device_id *id)
+{
+	struct regmap *regmap;
+	int ret;
+
+	SN624X_DBG(&slave->dev, "sdw_probe: dev_num=%u status=%s\n",
+		   slave->dev_num, sn624x_status_str(slave->status));
+
+	regmap = devm_regmap_init_sdw_mbq_cfg(&slave->dev, slave,
+					      &sn624x_sdca_regmap,
+					      &sn624x_sdca_mbq_cfg);
+	if (IS_ERR(regmap)) {
+		dev_err(&slave->dev, "sn624x: devm_regmap_init_sdw_mbq_cfg failed (%ld)\n",
+			PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	ret = sn624x_sdca_init(&slave->dev, regmap, slave);
+	if (ret < 0)
+		dev_err(&slave->dev, "sn624x: sn624x_sdca_init failed (%d)\n", ret);
+	else {
+		struct sn624x_sdca_priv *sn624x = dev_get_drvdata(&slave->dev);
+
+		if (sn624x)
+			sn624x_sdca_sdca_irq_mask_all(sn624x);
+		SN624X_DBG(&slave->dev, "SoundWire probe finished OK\n");
+	}
+
+	return ret;
+}
+
+static void sn624x_sdca_sdw_remove(struct sdw_slave *slave)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(&slave->dev);
+
+	SN624X_DBG(&slave->dev, "SoundWire driver remove\n");
+	cancel_delayed_work_sync(&sn624x->jack_detect_work);
+	sn624x_jack_rpm_put(sn624x);
+	if (sn624x->first_hw_init)
+		pm_runtime_disable(&slave->dev);
+	mutex_destroy(&sn624x->disable_irq_lock);
+}
+
+static const struct sdw_device_id sn624x_sdca_id[] = {
+	SDW_SLAVE_ENTRY_EXT(0x0496, 0x6242, 0x3, 0x1, 0),
+	SDW_SLAVE_ENTRY_EXT(0x0496, 0x6244, 0x3, 0x1, 0),
+	SDW_SLAVE_ENTRY_EXT(0x0496, 0x6247, 0x3, 0x1, 0),
+	{ }
+};
+MODULE_DEVICE_TABLE(sdw, sn624x_sdca_id);
+
+static int sn624x_sdca_dev_suspend(struct device *dev)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(dev);
+
+	if (!sn624x->first_hw_init)
+		return 0;
+
+	regcache_cache_only(sn624x->regmap, true);
+	/*
+	 * Suspend / clock-stop may reset the peripheral. Mark the cache dirty
+	 * so resume's regcache_sync restores software state to hardware.
+	 */
+	regcache_mark_dirty(sn624x->regmap);
+
+	return 0;
+}
+
+static int sn624x_sdca_dev_system_suspend(struct device *dev)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(dev);
+
+	if (!sn624x->first_hw_init)
+		return 0;
+
+	/* Mask first so IRQ cannot re-schedule work between cancel and disable. */
+	mutex_lock(&sn624x->disable_irq_lock);
+	sn624x->disable_irq = true;
+	sn624x_sdca_jack_irq_mask(sn624x);
+	mutex_unlock(&sn624x->disable_irq_lock);
+
+	cancel_delayed_work_sync(&sn624x->jack_detect_work);
+
+	return sn624x_sdca_dev_suspend(dev);
+}
+
+static int sn624x_sdca_regmap_resume(struct device *dev)
+{
+	struct sdw_slave *slave = dev_to_sdw_dev(dev);
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(dev);
+	int ret;
+
+	if (!sn624x->first_hw_init)
+		return 0;
+
+	SN624X_DBG(dev, "resume: unattach_request=%u\n", slave->unattach_request);
+	if (slave->unattach_request) {
+		ret = sdw_slave_wait_for_init(slave, SN624X_PROBE_TIMEOUT_MS);
+		if (ret) {
+			sdw_show_ping_status(slave->bus, true);
+			return ret;
+		}
+	}
+
+	regcache_cache_only(sn624x->regmap, false);
+	regcache_sync(sn624x->regmap);
+
+	return 0;
+}
+
+static int sn624x_sdca_dev_resume(struct device *dev)
+{
+	return sn624x_sdca_regmap_resume(dev);
+}
+
+static int sn624x_sdca_dev_system_resume(struct device *dev)
+{
+	struct sn624x_sdca_priv *sn624x = dev_get_drvdata(dev);
+	int ret;
+
+	ret = sn624x_sdca_regmap_resume(dev);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&sn624x->disable_irq_lock);
+	if (sn624x->disable_irq) {
+		sn624x_sdca_jack_irq_unmask(sn624x);
+		sn624x->disable_irq = false;
+	}
+	mutex_unlock(&sn624x->disable_irq_lock);
+
+	if (sn624x->hs_jack && sn624x->hw_init) {
+		sn624x_sdca_jack_poll_and_report(sn624x);
+		sn624x_jack_schedule_poll(sn624x);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops sn624x_sdca_pm = {
+	SYSTEM_SLEEP_PM_OPS(sn624x_sdca_dev_system_suspend, sn624x_sdca_dev_system_resume)
+	RUNTIME_PM_OPS(sn624x_sdca_dev_suspend, sn624x_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver sn624x_sdca_sdw_driver = {
+	.driver = {
+		.name = "sn624x-sdca",
+		.pm = pm_ptr(&sn624x_sdca_pm),
+	},
+	.probe = sn624x_sdca_sdw_probe,
+	.remove = sn624x_sdca_sdw_remove,
+	.ops = &sn624x_sdca_slave_ops,
+	.id_table = sn624x_sdca_id,
+};
+module_sdw_driver(sn624x_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC SN624X SDCA SoundWire driver with UAJ jack support");
+MODULE_AUTHOR("Senary Semiconductor Corp.");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
+MODULE_SOFTDEP("pre: snd-soc-sdca");
diff --git a/sound/soc/codecs/sn624x-sdca.h b/sound/soc/codecs/sn624x-sdca.h
new file mode 100644
index 0000000..6eb588b
--- /dev/null
+++ b/sound/soc/codecs/sn624x-sdca.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * sn624x-sdca.h -- SN624X SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2025 Senary Semiconductor Corp.
+ */
+
+#ifndef __SN624X_H__
+#define __SN624X_H__
+
+#include <linux/mutex.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/workqueue.h>
+#include <sound/sdca_function.h>
+#include <sound/soc.h>
+
+struct sn624x_sdca_priv {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct sdw_slave *slave;
+	/* Parsed DisCo functions (init tables / defaults from ACPI) */
+	struct sdca_function_data *jack_func;
+	struct sdca_function_data *mic_func;
+	struct sdca_function_data *amp_func;
+	bool hw_init;
+	bool first_hw_init;
+	struct snd_soc_jack *hs_jack;
+	struct delayed_work jack_detect_work;
+	struct mutex disable_irq_lock;
+	bool disable_irq;
+	/* Long-lived runtime PM ref while jack detection is enabled */
+	bool jack_rpm;
+	int jack_type;
+	int jack_type_last;
+	unsigned int scp_sdca_stat1;
+	unsigned int scp_sdca_stat2;
+};
+
+/* SoundWire data port numbers (slave prop source/sink port masks) */
+#define SN624X_PORT_JACK_PLAYBACK		1
+#define SN624X_PORT_SPEAKER_PLAYBACK		2
+#define SN624X_PORT_JACK_CAPTURE		4
+#define SN624X_PORT_DMIC_CAPTURE		5
+
+/* Order matches sn624x_sdca_dai[] .id */
+enum sn624x_dai_id {
+	SN624X_DAI_JACK = 0,
+	SN624X_DAI_SPEAKER = 1,
+	SN624X_DAI_DMIC = 2,
+};
+
+/*
+ * SDCA Function Numbers (from platform ACPI / device topology).
+ * Address with SDW_SDCA_CTL(fun, ent, ctl, ch) from sdw_registers.h.
+ */
+#define SN624X_FUNC_NUM_JACK_CODEC		0x01
+#define SN624X_FUNC_NUM_MIC_ARRAY		0x02
+#define SN624X_FUNC_NUM_SPEAKER_AMP		0x04
+
+/* Entity instance IDs (from platform ACPI / SN624X topology) */
+#define SN624X_SDCA_ENT_ENTITY0			0x00
+#define SN624X_SDCA_ENT_CS01			0x01
+#define SN624X_SDCA_ENT_CS02			0x02
+#define SN624X_SDCA_ENT_PDE03			0x03
+#define SN624X_SDCA_ENT_PDE04			0x04
+#define SN624X_SDCA_ENT_CRU05			0x05
+#define SN624X_SDCA_ENT_USER_FU10		0x10
+#define SN624X_SDCA_ENT_USER_FU14		0x14
+#define SN624X_SDCA_ENT_USER_FU1E		0x1e
+#define SN624X_UAJ_ENT_BLOCK			0x20
+#define SN624X_SDCA_ENT_GE35			0x1F
+/* UAJ power domains from ssdt26.dsl AF01 entity list (PDE 34 / PDE 47) */
+#define SN624X_UAJ_ENT_PDE47			SN624X_SDCA_ENT_PDE03
+#define SN624X_UAJ_ENT_PDE34			SN624X_SDCA_ENT_PDE04
+
+/* Control selectors (SDCA; same values as sound/sdca_function.h) */
+/* PDE power state selectors — use standard SDCA defines from sdca_function.h */
+#define SN624X_SDCA_CTL_FU_MUTE			0x01
+#define SN624X_SDCA_CTL_FU_VOLUME		0x02
+#define SN624X_SDCA_CTL_SAMPLE_FREQ_INDEX	0x10
+#define SN624X_SDCA_CTL_CLUSTER_INDEX		0x10
+#define SN624X_SDCA_CTL_FUNCTION_STATUS		0x10	/* Entity 0 */
+#define SN624X_SDCA_CTL_SELECTED_MODE		0x01
+#define SN624X_SDCA_CTL_DETECTED_MODE		0x02
+
+/*
+ * Control Number / channel for multi-channel FU controls (mute/volume).
+ * Single-value controls (PDE power, rate, function status, …) pass 0
+ * directly to SDW_SDCA_CTL — no CH_0 alias.
+ */
+#define SN624X_SDCA_CH_L			0x01
+#define SN624X_SDCA_CH_R			0x02
+
+/* GE35 Selected_Mode / Detected_Mode (SDCA Table 153, UAJ §5.5) */
+#define SN624X_GE35_MODE_HEADPHONE		0x03
+#define SN624X_GE35_MODE_HEADSET		0x05
+
+/* Vendor UAJ SCP windows */
+#define SN624X_UAJ_CTL_INPUT_DELAY		0x30
+#define SN624X_UAJ_CTL_CHARGE_PUMP		0x31
+#define SN624X_UAJ_CTL_JACK_DETECT		0x32
+
+/*
+ * Vendor SCP addresses used only when ACPI
+ * mipi-sdca-function-initialization-table is missing (temporary fallback).
+ * Remove once platform DisCo ships a complete init table.
+ */
+#define SN624X_UAJ_CTL_IT33_MIC_BIAS		0x40400418
+#define SN624X_UAJ_CTL_IT31_MIC_BIAS		0x40400318
+#define SN624X_UAJ_CTL_FU41_CH1_MUTE		0x40400A09
+#define SN624X_UAJ_CTL_FU41_CH2_MUTE		0x40400A0A
+#define SN624X_UAJ_CTL_FU31_CH0_MUTE		0x40400C08
+#define SN624X_UAJ_CTL_FU32_CH0_MUTE		0x40400C88
+#define SN624X_UAJ_CTL_FU33_CH0_MUTE		0x40400D08
+#define SN624X_UAJ_CTL_FU36_CH1_MUTE		0x40400F09
+#define SN624X_UAJ_CTL_FU36_CH2_MUTE		0x40400F0A
+#define SN624X_UAJ_CTL_FU31_CH0_GAIN_HIGH	0x40402C58
+#define SN624X_UAJ_CTL_FU31_CH0_GAIN_LOW	0x40400C58
+#define SN624X_UAJ_CTL_FU32_CH0_GAIN_HIGH	0x40402CD8
+#define SN624X_UAJ_CTL_FU32_CH0_GAIN_LOW	0x40400CD8
+#define SN624X_UAJ_CTL_FU33_CH0_GAIN_HIGH	0x40402D58
+#define SN624X_UAJ_CTL_FU33_CH0_GAIN_LOW	0x40400D58
+#define SN624X_UAJ_CTL_INPUT_DELAY_TIME		0x00002124
+#define SN624X_UAJ_CTL_PORTA_CHARGE_PUMP	0x00002086
+#define SN624X_UAJ_DMIC_PPU11			0x40880380
+
+/* Jack poll interval (ms) */
+#define SN624X_JACK_POLL_MS			1000
+
+/* µs settle times for headphone <-> speaker route switch during active PCM */
+#define SN624X_ROUTE_AFTER_MUTE_US_MIN		5000
+#define SN624X_ROUTE_AFTER_MUTE_US_MAX		8000
+#define SN624X_ROUTE_AFTER_D3_US_MIN		10000
+#define SN624X_ROUTE_AFTER_D3_US_MAX		15000
+#define SN624X_ROUTE_BEFORE_ACTIVE_US_MIN	10000
+#define SN624X_ROUTE_BEFORE_ACTIVE_US_MAX	15000
+
+/* SDCA SampleFreqIndex (same encoding as other SDCA codecs, e.g. rt722) */
+#define SN624X_SDCA_RATE_44100HZ		0x08
+#define SN624X_SDCA_RATE_48000HZ		0x09
+#define SN624X_SDCA_RATE_96000HZ		0x0b
+#define SN624X_SDCA_RATE_192000HZ		0x0d
+
+#define SN624X_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define SN624X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+int sn624x_sdca_init(struct device *dev, struct regmap *regmap,
+		      struct sdw_slave *slave);
+
+#endif /* __SN624X_H__ */
diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c
index 5a348947..6e187c9 100644
--- a/sound/soc/codecs/src4xxx.c
+++ b/sound/soc/codecs/src4xxx.c
@@ -326,10 +326,18 @@ static int src4xxx_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 };
 
+static const u64 src4xxx_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops src4xxx_dai_ops = {
 	.hw_params	= src4xxx_hw_params,
 	.set_sysclk	= src4xxx_set_mclk_hz,
 	.set_fmt	= src4xxx_set_dai_fmt,
+	.auto_selectable_formats	= &src4xxx_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define SRC4XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |	SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 5192569..32e81b3 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -620,12 +620,25 @@ static int ssm2518_startup(struct snd_pcm_substream *substream,
 #define SSM2518_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
 
+static const u64 ssm2518_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops ssm2518_dai_ops = {
 	.startup = ssm2518_startup,
 	.hw_params	= ssm2518_hw_params,
 	.mute_stream	= ssm2518_mute,
 	.set_fmt	= ssm2518_set_dai_fmt,
 	.set_tdm_slot	= ssm2518_set_tdm_slot,
+	.auto_selectable_formats	= &ssm2518_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index fccd2ea..92df44f 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -523,12 +523,25 @@ static int ssm2602_set_bias_level(struct snd_soc_component *component,
 #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 ssm2602_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops ssm2602_dai_ops = {
 	.startup	= ssm2602_startup,
 	.hw_params	= ssm2602_hw_params,
 	.mute_stream	= ssm2602_mute,
 	.set_sysclk	= ssm2602_set_dai_sysclk,
 	.set_fmt	= ssm2602_set_dai_fmt,
+	.auto_selectable_formats	= &ssm2602_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c
index 8c66656..f715092 100644
--- a/sound/soc/codecs/ssm3515.c
+++ b/sound/soc/codecs/ssm3515.c
@@ -356,12 +356,22 @@ static int ssm3515_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 ssm3515_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops ssm3515_dai_ops = {
 	.mute_stream	= ssm3515_mute,
 	.hw_params	= ssm3515_hw_params,
 	.set_fmt	= ssm3515_set_fmt,
 	.set_tdm_slot	= ssm3515_set_tdm_slot,
 	.hw_free	= ssm3515_hw_free,
+	.auto_selectable_formats	= &ssm3515_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ssm3515_dai_driver = {
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 8415dd1..181047b 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -389,11 +389,24 @@ static int ssm4567_set_bias_level(struct snd_soc_component *component,
 	return ret;
 }
 
+static const u64 ssm4567_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_PDM	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops ssm4567_dai_ops = {
 	.hw_params	= ssm4567_hw_params,
 	.mute_stream	= ssm4567_mute,
 	.set_fmt	= ssm4567_set_dai_fmt,
 	.set_tdm_slot	= ssm4567_set_tdm_slot,
+	.auto_selectable_formats	= &ssm4567_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index d6de739..2865a07 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -342,27 +342,48 @@ static int sta32x_sync_coef_shadow(struct snd_soc_component *component)
 {
 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	unsigned int cfud;
-	int i;
+	int i, ret;
 
 	/* preserve reserved bits in STA32X_CFUD */
-	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	ret = regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	if (ret)
+		return ret;
+
 	cfud &= 0xf0;
 
 	for (i = 0; i < STA32X_COEF_COUNT; i++) {
-		regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
-		regmap_write(sta32x->regmap, STA32X_B1CF1,
-			     (sta32x->coef_shadow[i] >> 16) & 0xff);
-		regmap_write(sta32x->regmap, STA32X_B1CF2,
-			     (sta32x->coef_shadow[i] >> 8) & 0xff);
-		regmap_write(sta32x->regmap, STA32X_B1CF3,
-			     (sta32x->coef_shadow[i]) & 0xff);
+		ret = regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
+		if (ret)
+			return ret;
+
+		ret = regmap_write(sta32x->regmap, STA32X_B1CF1,
+				   (sta32x->coef_shadow[i] >> 16) & 0xff);
+		if (ret)
+			return ret;
+
+		ret = regmap_write(sta32x->regmap, STA32X_B1CF2,
+				   (sta32x->coef_shadow[i] >> 8) & 0xff);
+		if (ret)
+			return ret;
+
+		ret = regmap_write(sta32x->regmap, STA32X_B1CF3,
+				   sta32x->coef_shadow[i] & 0xff);
+		if (ret)
+			return ret;
+
 		/*
 		 * chip documentation does not say if the bits are
 		 * self-clearing, so do it explicitly
 		 */
-		regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
-		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
+		ret = regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+		if (ret)
+			return ret;
+
+		ret = regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
+		if (ret)
+			return ret;
 	}
+
 	return 0;
 }
 
@@ -370,15 +391,24 @@ static int sta32x_cache_sync(struct snd_soc_component *component)
 {
 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	unsigned int mute;
-	int rc;
+	int restore_ret, ret;
 
 	/* mute during register sync */
-	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
-	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
-	sta32x_sync_coef_shadow(component);
-	rc = regcache_sync(sta32x->regmap);
-	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
-	return rc;
+	ret = regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(sta32x->regmap, STA32X_MMUTE,
+			   mute | STA32X_MMUTE_MMUTE);
+	if (ret)
+		return ret;
+
+	ret = sta32x_sync_coef_shadow(component);
+	if (!ret)
+		ret = regcache_sync(sta32x->regmap);
+
+	restore_ret = regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
+	return ret ?: restore_ret;
 }
 
 /* work around ESD issue where sta32x resets and loses all configuration */
@@ -794,9 +824,9 @@ static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
 static int sta32x_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	int ret;
 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+	int cleanup_ret, ret;
 
 	dev_dbg(component->dev, "level = %d\n", level);
 	switch (level) {
@@ -820,15 +850,28 @@ static int sta32x_set_bias_level(struct snd_soc_component *component,
 				return ret;
 			}
 
-			sta32x_startup_sequence(sta32x);
-			sta32x_cache_sync(component);
+			ret = sta32x_startup_sequence(sta32x);
+			if (!ret)
+				ret = sta32x_cache_sync(component);
+			if (ret)
+				goto restore_failed;
+
+			ret = regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+						 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+						 0);
+			if (ret)
+				goto restore_failed;
+
 			sta32x_watchdog_start(sta32x);
+			break;
 		}
 
 		/* Power down */
-		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
-				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-				   0);
+		ret = regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+					 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+					 0);
+		if (ret)
+			return ret;
 
 		break;
 
@@ -846,12 +889,31 @@ static int sta32x_set_bias_level(struct snd_soc_component *component,
 		break;
 	}
 	return 0;
+
+restore_failed:
+	gpiod_set_value(sta32x->gpiod_nreset, 0);
+	regcache_mark_dirty(sta32x->regmap);
+	cleanup_ret = regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
+					     sta32x->supplies);
+	if (cleanup_ret)
+		dev_warn(component->dev, "Failed to disable supplies: %d\n",
+			 cleanup_ret);
+	return ret;
 }
 
+static const u64 sta32x_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF;
+
 static const struct snd_soc_dai_ops sta32x_dai_ops = {
 	.hw_params	= sta32x_hw_params,
 	.set_sysclk	= sta32x_set_dai_sysclk,
 	.set_fmt	= sta32x_set_dai_fmt,
+	.auto_selectable_formats	= &sta32x_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver sta32x_dai = {
@@ -1035,7 +1097,7 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
 {
 	struct device_node *np = dev->of_node;
 	struct sta32x_platform_data *pdata;
-	u16 tmp;
+	u32 tmp;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -1060,8 +1122,8 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
 		of_property_read_bool(np, "st,needs_esd_watchdog");
 
 	tmp = 140;
-	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
-	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+	of_property_read_u32(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u32, tmp, 0, 300) / 20;
 
 	/* CONFE */
 	pdata->max_power_use_mpcc =
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 2ba3507..d2b6f73 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -882,10 +882,19 @@ static int sta350_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 sta350_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF;
+
 static const struct snd_soc_dai_ops sta350_dai_ops = {
 	.hw_params	= sta350_hw_params,
 	.set_sysclk	= sta350_set_dai_sysclk,
 	.set_fmt	= sta350_set_dai_fmt,
+	.auto_selectable_formats	= &sta350_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver sta350_dai = {
@@ -1087,7 +1096,7 @@ static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
 	struct device_node *np = dev->of_node;
 	struct sta350_platform_data *pdata;
 	const char *ffx_power_mode;
-	u16 tmp;
+	u32 tmp;
 	u8 tmp8;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -1127,8 +1136,8 @@ static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
 	}
 
 	tmp = 140;
-	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
-	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+	of_property_read_u32(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u32, tmp, 0, 300) / 20;
 
 	pdata->oc_warning_adjustment =
 		of_property_read_bool(np, "st,overcurrent-warning-adjustment");
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 7d57999..0faf439 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -286,10 +286,17 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 	return 0;
 }
 
+static const u64 sta529_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops sta529_dai_ops = {
 	.hw_params	=	sta529_hw_params,
 	.set_fmt	=	sta529_set_dai_fmt,
 	.mute_stream	=	sta529_mute,
+	.auto_selectable_formats	= &sta529_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index be2c9a0..beb5654 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -518,6 +518,18 @@ static const struct dev_pm_ops tas2552_pm = {
 	RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume, NULL)
 };
 
+static const u64 tas2552_selectable_formats[] = {
+	/* Hi Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF,
+	/* Low Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
 	.hw_params	= tas2552_hw_params,
 	.prepare	= tas2552_prepare,
@@ -525,6 +537,8 @@ static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
 	.set_fmt	= tas2552_set_dai_fmt,
 	.set_tdm_slot	= tas2552_set_dai_tdm_slot,
 	.mute_stream	= tas2552_mute,
+	.auto_selectable_formats	= tas2552_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(tas2552_selectable_formats),
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index 0b8644a..1fe17b0 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -604,11 +604,21 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = {
 	.endianness		= 1,
 };
 
+static const u64 tas2562_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = {
 	.hw_params	= tas2562_hw_params,
 	.set_fmt	= tas2562_set_dai_fmt,
 	.set_tdm_slot	= tas2562_set_dai_tdm_slot,
 	.mute_stream	= tas2562_mute,
+	.auto_selectable_formats	= &tas2562_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index f9c65c9..6654100 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -602,6 +602,16 @@ static int tas2764_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 	return tas2764_write_sdout_idle_mask(tas2764, tas2764->idle_slot_config.tx_mask);
 }
 
+static const u64 tas2764_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops tas2764_dai_ops = {
 	.mute_stream = tas2764_mute,
 	.hw_params  = tas2764_hw_params,
@@ -609,6 +619,8 @@ static const struct snd_soc_dai_ops tas2764_dai_ops = {
 	.set_bclk_ratio = tas2764_set_bclk_ratio,
 	.set_tdm_slot = tas2764_set_dai_tdm_slot,
 	.set_tdm_idle = tas2764_set_dai_tdm_idle,
+	.auto_selectable_formats	= &tas2764_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -960,7 +972,7 @@ static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764)
 		}
 	}
 
-	tas2764->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
+	tas2764->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_LOW);
 	if (IS_ERR(tas2764->sdz_gpio)) {
 		if (PTR_ERR(tas2764->sdz_gpio) == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index e79754e..882e198 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -566,12 +566,24 @@ static int tas2770_set_dai_tdm_idle(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 tas2770_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops tas2770_dai_ops = {
 	.mute_stream = tas2770_mute,
 	.hw_params  = tas2770_hw_params,
 	.set_fmt    = tas2770_set_fmt,
 	.set_tdm_slot = tas2770_set_dai_tdm_slot,
 	.set_tdm_idle = tas2770_set_dai_tdm_idle,
+	.auto_selectable_formats	= &tas2770_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -886,7 +898,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770)
 	if (rc)
 		tas2770->pdm_slot = -1;
 
-	tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
+	tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_LOW);
 	if (IS_ERR(tas2770->sdz_gpio)) {
 		if (PTR_ERR(tas2770->sdz_gpio) == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index f1fce43..991d0c0 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -441,11 +441,21 @@ static int tas2780_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return ret;
 }
 
+static const u64 tas2780_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops tas2780_dai_ops = {
 	.mute_stream = tas2780_mute,
 	.hw_params  = tas2780_hw_params,
 	.set_fmt    = tas2780_set_fmt,
 	.set_tdm_slot = tas2780_set_dai_tdm_slot,
+	.auto_selectable_formats	= &tas2780_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c
index 79b5f5b..dd86fc9 100644
--- a/sound/soc/codecs/tas2781-comlib-i2c.c
+++ b/sound/soc/codecs/tas2781-comlib-i2c.c
@@ -2,7 +2,7 @@
 //
 // TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers based on I2C
 //
-// Copyright 2025 Texas Instruments, Inc.
+// Copyright 2025 - 2026 Texas Instruments, Inc.
 //
 // Author: Shenghao Ding <shenghao-ding@ti.com>
 
@@ -131,7 +131,10 @@ int tasdevice_dev_update_bits(
 		ret = regmap_update_bits(map, TASDEVICE_PGRG(reg),
 			mask, value);
 		if (ret < 0)
-			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+			dev_err(tas_priv->dev, "%s, Bx%02xPx%02xRx%02x E=%d\n",
+				__func__, TASDEVICE_BOOK_ID(reg),
+				TASDEVICE_PAGE_ID(reg),
+				TASDEVICE_PAGE_REG(reg), ret);
 	} else {
 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
 			chn);
diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c
index 4cec9f8..e4c8a04 100644
--- a/sound/soc/codecs/tas2781-comlib.c
+++ b/sound/soc/codecs/tas2781-comlib.c
@@ -2,7 +2,7 @@
 //
 // TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers
 //
-// Copyright 2023 - 2025 Texas Instruments, Inc.
+// Copyright 2023 - 2026 Texas Instruments, Inc.
 //
 // Author: Shenghao Ding <shenghao-ding@ti.com>
 
@@ -34,7 +34,10 @@ int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
 
 		ret = regmap_read(map, TASDEVICE_PGRG(reg), val);
 		if (ret < 0)
-			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+			dev_err(tas_priv->dev, "%s, Bx%02xPx%02xRx%02x E=%d\n",
+				__func__, TASDEVICE_BOOK_ID(reg),
+				TASDEVICE_PAGE_ID(reg),
+				TASDEVICE_PAGE_REG(reg), ret);
 	} else {
 		ret = -EINVAL;
 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
@@ -62,7 +65,10 @@ int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
 
 		ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len);
 		if (ret < 0)
-			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+			dev_err(tas_priv->dev, "%s, Bx%02xPx%02xRx%02x E=%d\n",
+				__func__, TASDEVICE_BOOK_ID(reg),
+				TASDEVICE_PAGE_ID(reg),
+				TASDEVICE_PAGE_REG(reg), ret);
 	} else
 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
 			chn);
@@ -88,7 +94,10 @@ int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
 		ret = regmap_write(map, TASDEVICE_PGRG(reg),
 			value);
 		if (ret < 0)
-			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+			dev_err(tas_priv->dev, "%s, Bx%02xPx%02xRx%02x E=%d\n",
+				__func__, TASDEVICE_BOOK_ID(reg),
+				TASDEVICE_PAGE_ID(reg),
+				TASDEVICE_PAGE_REG(reg), ret);
 	} else {
 		ret = -EINVAL;
 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
@@ -118,7 +127,10 @@ int tasdevice_dev_bulk_write(
 		ret = regmap_bulk_write(map, TASDEVICE_PGRG(reg),
 			data, len);
 		if (ret < 0)
-			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+			dev_err(tas_priv->dev, "%s, Bx%02xPx%02xRx%02x E=%d\n",
+				__func__, TASDEVICE_BOOK_ID(reg),
+				TASDEVICE_PAGE_ID(reg),
+				TASDEVICE_PAGE_REG(reg), ret);
 	} else {
 		ret = -EINVAL;
 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 2b9efcc..dc1c552 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -110,7 +110,7 @@ struct tas2781_cali_specific {
 };
 
 static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
-	1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2
+	1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2, 1, 2, 3, 4,
 };
 
 /* fixed m68k compiling issue: mapping table can save code field */
@@ -1959,6 +1959,8 @@ static void dspbin_type_check(struct tasdevice_priv *tas_priv,
 		else
 			tas_priv->dspbin_typ = TASDEV_ALPHA;
 	}
+	if (tas_priv->chip_id == TAS2573)
+		return;
 	if ((tas_priv->dspbin_typ != TASDEV_BASIC) &&
 		(ppcver < PPC3_VERSION_TAS5825_BASE))
 		tas_priv->fw_parse_fct_param_address =
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 7fcf821..85ab3fd 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -185,35 +185,17 @@ static const struct reg_default tas2783_reg_default[] = {
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0},
@@ -222,40 +204,28 @@ static const struct reg_default tas2783_reg_default[] = {
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 5), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
@@ -286,7 +256,6 @@ static const struct reg_default tas2783_reg_default[] = {
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
@@ -364,7 +333,6 @@ static int tas2783_sdca_mbq_size(struct device *dev, u32 reg)
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0):
@@ -450,7 +418,6 @@ static int tas2783_sdca_mbq_size(struct device *dev, u32 reg)
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0):
@@ -462,27 +429,8 @@ static int tas2783_sdca_mbq_size(struct device *dev, u32 reg)
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0):
 		return 2;
 
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0):
 	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0):
-	case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0):
 		return 4;
 
 	default:
@@ -495,59 +443,52 @@ static bool tas2783_readable_register(struct device *dev, unsigned int reg)
 	return tas2783_sdca_mbq_size(dev, reg) > 0;
 }
 
-static bool tas2783_writeable_register(struct device *dev, unsigned int reg)
+/*
+ * The read-only SDCA Controls the driver describes: the Clock Valid of every
+ * Clock Source, the actual power state of the Power Domain Entity, the
+ * protection status and the algorithm ready flags.  None of them is a
+ * setting; every one is a reading of device state.
+ */
+static bool tas2783_read_only_control(unsigned int reg)
 {
-	/*
-	 * The Latency Control of every Entity, together with the Power Domain
-	 * actual state and the protection status, is read-only. They are
-	 * listed in tas2783_reg_default[] with a placeholder value, so without
-	 * this a regcache_sync() would try to write them back and the
-	 * peripheral would reject the transaction, aborting the sync.
-	 */
 	switch (reg) {
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU21, 0x10, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU23, 0x10, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU26, 0x10, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x06, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x07, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x08, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS24, 0x02, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS21, 0x02, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS25, 0x02, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS26, 0x02, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS28, 0x02, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PDE23, 0x10, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_UDMPU23, 0x06, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x05, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x11, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU21, 0x06, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU26, 0x06, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT21, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT29, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT26, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT28, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT24, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT23, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT25, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT28, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MU26, 0x06, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT127, 0x08, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU127, 0x10, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS127, 0x02, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x08, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x04, 0):
-	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x08, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x04, 0):
-		return false;
+		return true;
 
 	default:
-		return tas2783_sdca_mbq_size(dev, reg) > 0;
+		return false;
 	}
 }
 
+static bool tas2783_writeable_register(struct device *dev, unsigned int reg)
+{
+	if (tas2783_read_only_control(reg))
+		return false;
+
+	return tas2783_sdca_mbq_size(dev, reg) > 0;
+}
+
 static bool tas2783_volatile_register(struct device *dev, u32 reg)
 {
+	if (tas2783_read_only_control(reg))
+		return true;
+
 	switch (reg) {
+	/*
+	 * The File Download Status is a handshake: the device raises its own
+	 * bits on its own schedule and the host writes back a response, so it
+	 * is writable, but it must never be answered from the cache.
+	 */
+	case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x14, 0):
 	case 0x000 ... 0x080: /* Data port 0. */
 	case 0x100 ... 0x140: /* Data port 1. */
 	case 0x200 ... 0x240: /* Data port 2. */
@@ -564,7 +505,13 @@ static bool tas2783_volatile_register(struct device *dev, u32 reg)
 
 static const struct regmap_config tas_regmap = {
 	.reg_bits = 32,
-	.val_bits = 8,
+	/*
+	 * tas2783_sdca_mbq_size() declares registers of one, two and four
+	 * bytes. val_bits has to cover the widest of those: the SoundWire MBQ
+	 * bus rejects any register whose declared size exceeds val_bits, which
+	 * would make every multi-byte register unreachable in both directions.
+	 */
+	.val_bits = 32,
 	.readable_reg = tas2783_readable_register,
 	.writeable_reg = tas2783_writeable_register,
 	.volatile_reg = tas2783_volatile_register,
@@ -667,9 +614,9 @@ static s32 tas2783_validate_calibdata(struct tas2783_prv *tas_dev,
 
 static void tas2783_set_calib_params_to_device(struct tas2783_prv *tas_dev, u32 *cali_data)
 {
-	u32 dev_count, offset, i, device_num;
+	u32 dev_count, offset, i, j, device_num;
 	u32 reg_value;
-	u8 buf[4];
+	s32 ret;
 
 	dev_count = cali_data[1];
 	offset = 3;
@@ -683,12 +630,25 @@ static void tas2783_set_calib_params_to_device(struct tas2783_prv *tas_dev, u32
 
 		for (i = 0; i < ARRAY_SIZE(tas2783_cali_reg); i++) {
 			reg_value = cali_data[offset + i];
-			buf[0] = reg_value >> 24;
-			buf[1] = reg_value >> 16;
-			buf[2] = reg_value >> 8;
-			buf[3] = reg_value & 0xff;
-			regmap_bulk_write(tas_dev->regmap, tas2783_cali_reg[i],
-					  buf, sizeof(u32));
+
+			/*
+			 * A calibration value occupies four consecutive
+			 * single-byte registers, most significant byte first.
+			 * Write them one by one: these registers are declared
+			 * as one byte wide by tas2783_sdca_mbq_size(), so a
+			 * multi-byte regmap access would not match the layout.
+			 */
+			for (j = 0; j < sizeof(u32); j++) {
+				ret = regmap_write(tas_dev->regmap,
+						   tas2783_cali_reg[i] + j,
+						   (reg_value >> (24 - 8 * j)) & 0xff);
+				if (ret) {
+					dev_err(tas_dev->dev,
+						"calib write to 0x%x failed, err=%d\n",
+						tas2783_cali_reg[i] + j, ret);
+					break;
+				}
+			}
 		}
 		break;
 	}
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 4d1c122..1ab82ef 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -743,11 +743,18 @@ static const struct snd_soc_dapm_route tas5086_dapm_routes[] = {
 
 };
 
+static const u64 tas5086_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops tas5086_dai_ops = {
 	.hw_params	= tas5086_hw_params,
 	.set_sysclk	= tas5086_set_dai_sysclk,
 	.set_fmt	= tas5086_set_dai_fmt,
 	.mute_stream	= tas5086_mute_stream,
+	.auto_selectable_formats	= &tas5086_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver tas5086_dai = {
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index 8b5f9ac..5e25603 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -352,10 +352,17 @@ static int tas571x_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
+static const u64 tas571x_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops tas571x_dai_ops = {
 	.set_fmt	= tas571x_set_dai_fmt,
 	.hw_params	= tas571x_hw_params,
 	.mute_stream	= tas571x_mute,
+	.auto_selectable_formats	= &tas571x_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index 0bbcfaa..2539a09 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -682,11 +682,20 @@ static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
 #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
 			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 tas5720_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
 	.hw_params	= tas5720_hw_params,
 	.set_fmt	= tas5720_set_dai_fmt,
 	.set_tdm_slot	= tas5720_set_dai_tdm_slot,
 	.mute_stream	= tas5720_mute,
+	.auto_selectable_formats	= &tas5720_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index f5d50f8..2718183 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -378,11 +378,20 @@ static const struct snd_soc_component_driver soc_codec_dev_tas6424 = {
 	.endianness		= 1,
 };
 
+static const u64 tas6424_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
 	.hw_params	= tas6424_hw_params,
 	.set_fmt	= tas6424_set_dai_fmt,
 	.set_tdm_slot	= tas6424_set_dai_tdm_slot,
 	.mute_stream	= tas6424_mute,
+	.auto_selectable_formats	= &tas6424_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index f30479f..51910373 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -248,10 +248,19 @@ static const struct regmap_config tfa9879_regmap = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+static const u64 tfa9879_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops tfa9879_dai_ops = {
 	.hw_params = tfa9879_hw_params,
 	.mute_stream = tfa9879_mute_stream,
 	.set_fmt = tfa9879_set_fmt,
+	.auto_selectable_formats	= &tfa9879_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index d7d958e..528c444 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -1362,10 +1362,24 @@ static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	return 0;
 }
 
+static const u64 adc3xxx_selectable_formats[] = {
+	/* Hi Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF,
+	/* Low Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops adc3xxx_dai_ops = {
 	.hw_params	= adc3xxx_hw_params,
 	.set_sysclk	= adc3xxx_set_dai_sysclk,
 	.set_fmt	= adc3xxx_set_dai_fmt,
+	.auto_selectable_formats	= adc3xxx_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(adc3xxx_selectable_formats),
 };
 
 static struct snd_soc_dai_driver adc3xxx_dai = {
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 4eb9cea..c29584d 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -916,10 +916,22 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
+static const u64 adcx140_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops adcx140_dai_ops = {
 	.hw_params	= adcx140_hw_params,
 	.set_fmt	= adcx140_set_dai_fmt,
 	.set_tdm_slot	= adcx140_set_dai_tdm_slot,
+	.auto_selectable_formats	= &adcx140_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static int adcx140_configure_gpo(struct adcx140_priv *adcx140)
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 04ec8fb..f31ffa1 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -507,6 +507,13 @@ static int tlv320aic23_set_bias_level(struct snd_soc_component *component,
 #define AIC23_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 tlv320aic23_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops tlv320aic23_dai_ops = {
 	.prepare	= tlv320aic23_pcm_prepare,
 	.hw_params	= tlv320aic23_hw_params,
@@ -514,6 +521,8 @@ static const struct snd_soc_dai_ops tlv320aic23_dai_ops = {
 	.mute_stream	= tlv320aic23_mute,
 	.set_fmt	= tlv320aic23_set_dai_fmt,
 	.set_sysclk	= tlv320aic23_set_dai_sysclk,
+	.auto_selectable_formats	= &tlv320aic23_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 84e9543..7dcc960 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -208,11 +208,19 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 #define AIC26_FORMATS	(SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_BE |\
 			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
+static const u64 aic26_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 static const struct snd_soc_dai_ops aic26_dai_ops = {
 	.hw_params	= aic26_hw_params,
 	.mute_stream	= aic26_mute,
 	.set_sysclk	= aic26_set_sysclk,
 	.set_fmt	= aic26_set_fmt,
+	.auto_selectable_formats	= &aic26_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 43bcbc5..e0a8db4 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1366,27 +1366,12 @@ static int aic31xx_set_jack(struct snd_soc_component *component,
 static int aic31xx_codec_probe(struct snd_soc_component *component)
 {
 	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
-	int i, ret;
+	int ret;
 
 	dev_dbg(aic31xx->dev, "## %s\n", __func__);
 
 	aic31xx->component = component;
 
-	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
-		aic31xx->disable_nb[i].nb.notifier_call =
-			aic31xx_regulator_event;
-		aic31xx->disable_nb[i].aic31xx = aic31xx;
-		ret = devm_regulator_register_notifier(
-						aic31xx->supplies[i].consumer,
-						&aic31xx->disable_nb[i].nb);
-		if (ret) {
-			dev_err(component->dev,
-				"Failed to request regulator notifier: %d\n",
-				ret);
-			return ret;
-		}
-	}
-
 	regcache_cache_only(aic31xx->regmap, true);
 	regcache_mark_dirty(aic31xx->regmap);
 
@@ -1422,11 +1407,22 @@ static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
 	.endianness		= 1,
 };
 
+static const u64 aic31xx_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops aic31xx_dai_ops = {
 	.hw_params	= aic31xx_hw_params,
 	.set_sysclk	= aic31xx_set_dai_sysclk,
 	.set_fmt	= aic31xx_set_dai_fmt,
 	.mute_stream	= aic31xx_dac_mute,
+	.auto_selectable_formats	= &aic31xx_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
@@ -1791,6 +1787,19 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c)
 	if (ret)
 		return dev_err_probe(aic31xx->dev, ret, "Failed to request supplies\n");
 
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
+		aic31xx->disable_nb[i].nb.notifier_call = aic31xx_regulator_event;
+		aic31xx->disable_nb[i].aic31xx = aic31xx;
+		ret = devm_regulator_register_notifier(aic31xx->supplies[i].consumer,
+						       &aic31xx->disable_nb[i].nb);
+		if (ret) {
+			dev_err(aic31xx->dev,
+				"Failed to request regulator notifier: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
 	aic31xx_configure_ocmv(aic31xx);
 
 	if (aic31xx->irq > 0) {
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index deed616..ad15ce9 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -451,8 +451,8 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 static struct clk *aic32x4_register_clk(struct device *dev,
 					struct aic32x4_clkdesc *desc)
 {
-	struct clk_init_data init;
 	struct clk_aic32x4 *priv;
+	struct clk_init_data init = {};
 	const char *devname = dev_name(dev);
 
 	init.ops = desc->ops;
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 9e0e4aa..af4be5b 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -916,11 +916,19 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
 			 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE \
 			 | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 aic32x4_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
 static const struct snd_soc_dai_ops aic32x4_ops = {
 	.hw_params = aic32x4_hw_params,
 	.mute_stream = aic32x4_mute,
 	.set_fmt = aic32x4_set_dai_fmt,
 	.set_sysclk = aic32x4_set_dai_sysclk,
+	.auto_selectable_formats	= &aic32x4_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 	.no_capture_mute = 1,
 };
 
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index b38393a..be83111 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1500,6 +1500,18 @@ static int aic3x_set_bias_level(struct snd_soc_component *component,
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
 			 SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 aic3x_selectable_formats[] = {
+	/* Hi Priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF,
+	/* Low Priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops aic3x_dai_ops = {
 	.hw_params	= aic3x_hw_params,
 	.prepare	= aic3x_prepare,
@@ -1507,6 +1519,8 @@ static const struct snd_soc_dai_ops aic3x_dai_ops = {
 	.set_sysclk	= aic3x_set_dai_sysclk,
 	.set_fmt	= aic3x_set_dai_fmt,
 	.set_tdm_slot	= aic3x_set_dai_tdm_slot,
+	.auto_selectable_formats	= aic3x_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(aic3x_selectable_formats),
 	.no_capture_mute = 1,
 };
 
@@ -1627,24 +1641,9 @@ static int aic3x_init(struct snd_soc_component *component)
 static int aic3x_component_probe(struct snd_soc_component *component)
 {
 	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
-	int ret, i;
 
 	aic3x->component = component;
 
-	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
-		aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
-		aic3x->disable_nb[i].aic3x = aic3x;
-		ret = devm_regulator_register_notifier(
-						aic3x->supplies[i].consumer,
-						&aic3x->disable_nb[i].nb);
-		if (ret) {
-			dev_err(component->dev,
-				"Failed to request regulator notifier: %d\n",
-				 ret);
-			return ret;
-		}
-	}
-
 	regcache_mark_dirty(aic3x->regmap);
 	aic3x_init(component);
 
@@ -1845,6 +1844,19 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to request supplies\n");
 
+	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
+		aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
+		aic3x->disable_nb[i].aic3x = aic3x;
+		ret = devm_regulator_register_notifier(aic3x->supplies[i].consumer,
+						       &aic3x->disable_nb[i].nb);
+		if (ret) {
+			dev_err(dev,
+				"Failed to request regulator notifier: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
 	aic3x_configure_ocmv(dev, aic3x);
 
 	ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 9bd2ddd..b91ab42 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -914,7 +914,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 	/* OSC calibration time */
 	dac33_write(component, DAC33_CALIB_TIME, 96);
 
-	/* adjustment treshold & step */
+	/* adjustment threshold & step */
 	dac33_write(component, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
 						 DAC33_ADJSTEP(1));
 
@@ -1435,6 +1435,12 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320dac33 = {
 			 SNDRV_PCM_RATE_48000)
 #define DAC33_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 dac33_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 static const struct snd_soc_dai_ops dac33_dai_ops = {
 	.startup	= dac33_startup,
 	.shutdown	= dac33_shutdown,
@@ -1443,6 +1449,8 @@ static const struct snd_soc_dai_ops dac33_dai_ops = {
 	.delay		= dac33_dai_delay,
 	.set_sysclk	= dac33_set_dai_sysclk,
 	.set_fmt	= dac33_set_dai_fmt,
+	.auto_selectable_formats	= &dac33_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver dac33_dai = {
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index b70c9d9..e772dd3 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -3233,6 +3233,17 @@ static int tscs454_prepare(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 tscs454_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static struct snd_soc_dai_ops const tscs454_dai1_ops = {
 	.set_sysclk	= tscs454_set_sysclk,
 	.set_bclk_ratio = tscs454_set_bclk_ratio,
@@ -3241,6 +3252,8 @@ static struct snd_soc_dai_ops const tscs454_dai1_ops = {
 	.hw_params	= tscs454_hw_params,
 	.hw_free	= tscs454_hw_free,
 	.prepare	= tscs454_prepare,
+	.auto_selectable_formats	= &tscs454_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_ops const tscs454_dai23_ops = {
@@ -3251,6 +3264,8 @@ static struct snd_soc_dai_ops const tscs454_dai23_ops = {
 	.hw_params	= tscs454_hw_params,
 	.hw_free	= tscs454_hw_free,
 	.prepare	= tscs454_prepare,
+	.auto_selectable_formats	= &tscs454_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static int tscs454_probe(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 9476cdfd..b986ece 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -202,13 +202,10 @@ static void
 twl4030_get_board_param_values(struct twl4030_board_params *board_params,
 			       struct device_node *node)
 {
-	int value;
-
 	of_property_read_u32(node, "ti,digimic_delay", &board_params->digimic_delay);
 	of_property_read_u32(node, "ti,ramp_delay_value", &board_params->ramp_delay_value);
 	of_property_read_u32(node, "ti,offset_cncl_path", &board_params->offset_cncl_path);
-	if (!of_property_read_u32(node, "ti,hs_extmute", &value))
-		board_params->hs_extmute = value;
+	board_params->hs_extmute = of_property_read_bool(node, "ti,hs_extmute");
 
 	if (of_property_present(node, "ti,hs_extmute_gpio"))
 		board_params->hs_extmute = 1;
@@ -2097,6 +2094,10 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
 #define TWL4030_RATES	 (SNDRV_PCM_RATE_8000_48000)
 #define TWL4030_FORMATS	 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 twl4030_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
 static const struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
 	.startup	= twl4030_startup,
 	.shutdown	= twl4030_shutdown,
@@ -2104,8 +2105,14 @@ static const struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
 	.set_sysclk	= twl4030_set_dai_sysclk,
 	.set_fmt	= twl4030_set_dai_fmt,
 	.set_tristate	= twl4030_set_tristate,
+	.auto_selectable_formats	= &twl4030_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
+static const u64 twl4030_voice_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops twl4030_dai_voice_ops = {
 	.startup	= twl4030_voice_startup,
 	.shutdown	= twl4030_voice_shutdown,
@@ -2113,6 +2120,8 @@ static const struct snd_soc_dai_ops twl4030_dai_voice_ops = {
 	.set_sysclk	= twl4030_voice_set_dai_sysclk,
 	.set_fmt	= twl4030_voice_set_dai_fmt,
 	.set_tristate	= twl4030_voice_set_tristate,
+	.auto_selectable_formats	= &twl4030_voice_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver twl4030_dai[] = {
diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c
index 54c5cb5..7ae6afd 100644
--- a/sound/soc/codecs/uda1334.c
+++ b/sound/soc/codecs/uda1334.c
@@ -193,12 +193,18 @@ static int uda1334_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 
 #define UDA1334_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 uda1334_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops uda1334_dai_ops = {
 	.startup	= uda1334_startup,
 	.shutdown	= uda1334_shutdown,
 	.set_sysclk	= uda1334_set_dai_sysclk,
 	.set_fmt	= uda1334_set_fmt,
 	.mute_stream	= uda1334_mute_stream,
+	.auto_selectable_formats	= &uda1334_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver uda1334_dai = {
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
index 4e2d624..63d0875 100644
--- a/sound/soc/codecs/uda1342.c
+++ b/sound/soc/codecs/uda1342.c
@@ -223,6 +223,11 @@ static const struct snd_soc_dapm_route uda1342_dapm_routes[] = {
 	{ "VOUTR", NULL, "DAC" },
 };
 
+static const u64 uda1342_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops uda1342_dai_ops = {
 	.startup	= uda1342_startup,
 	.shutdown	= uda1342_shutdown,
@@ -230,6 +235,8 @@ static const struct snd_soc_dai_ops uda1342_dai_ops = {
 	.mute_stream	= uda1342_mute,
 	.set_sysclk	= uda1342_set_dai_sysclk,
 	.set_fmt	= uda1342_set_dai_fmt,
+	.auto_selectable_formats	= &uda1342_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver uda1342_dai = {
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 1dd09d1..02adc53 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -653,11 +653,18 @@ static int uda1380_set_bias_level(struct snd_soc_component *component,
 		       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
 		       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
+static const u64 uda1380_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops uda1380_dai_ops = {
 	.hw_params	= uda1380_pcm_hw_params,
 	.shutdown	= uda1380_pcm_shutdown,
 	.trigger	= uda1380_trigger,
 	.set_fmt	= uda1380_set_dai_fmt_both,
+	.auto_selectable_formats	= &uda1380_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops uda1380_dai_ops_playback = {
@@ -665,6 +672,8 @@ static const struct snd_soc_dai_ops uda1380_dai_ops_playback = {
 	.shutdown	= uda1380_pcm_shutdown,
 	.trigger	= uda1380_trigger,
 	.set_fmt	= uda1380_set_dai_fmt_playback,
+	.auto_selectable_formats	= &uda1380_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops uda1380_dai_ops_capture = {
@@ -672,6 +681,8 @@ static const struct snd_soc_dai_ops uda1380_dai_ops_capture = {
 	.shutdown	= uda1380_pcm_shutdown,
 	.trigger	= uda1380_trigger,
 	.set_fmt	= uda1380_set_dai_fmt_capture,
+	.auto_selectable_formats	= &uda1380_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver uda1380_dai[] = {
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index bb0c847..850be84 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -864,7 +864,7 @@ static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
 	u8 adc_en;
 
 	/* Pre-requisites for ADC continuous measurement */
-	/* Read legacy electircal detection and disable */
+	/* Read legacy electrical detection and disable */
 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
 	/* Set ADC to continuous measurement */
 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1);
@@ -965,7 +965,7 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
 	if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
 		return -EINVAL;
 
-	/* Read legacy electircal detection and disable */
+	/* Read legacy electrical detection and disable */
 	elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC);
 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
 
@@ -1470,14 +1470,14 @@ int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg)
 	ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
 				   &microvolt);
 	if (ret)
-		dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
+		dev_dbg(dev, "missing qcom,mbhc-headset-vthreshold-microvolt in dt node\n");
 	else
 		cfg->hs_thr = microvolt/1000;
 
 	ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
 				   &microvolt);
 	if (ret)
-		dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt	entry\n");
+		dev_dbg(dev, "missing qcom,mbhc-headphone-vthreshold-microvolt entry\n");
 	else
 		cfg->hph_thr = microvolt/1000;
 
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index caca5cc..0ed24cc 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -2130,9 +2130,9 @@ static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd)
 	struct device *dev = wcd->dev;
 	struct device_node *np = dev->parent->of_node;
 	const char *parent_clk_name = NULL;
+	struct clk_init_data init = {};
 	const char *clk_name = "mclk";
 	struct clk_hw *hw;
-	struct clk_init_data init;
 	int ret;
 
 	if (of_property_read_u32(np, "clock-frequency", &wcd->rate))
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index bc78b55..692e933 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2066,10 +2066,20 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 wm2200_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm2200_dai_ops = {
 	.probe = wm2200_dai_probe,
 	.set_fmt = wm2200_set_fmt,
 	.hw_params = wm2200_hw_params,
+	.auto_selectable_formats	= &wm2200_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define WM2200_RATES SNDRV_PCM_RATE_8000_48000
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 2fe937a..f7ecbac 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1501,9 +1501,19 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 wm5100_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm5100_dai_ops = {
 	.set_fmt = wm5100_set_fmt,
 	.hw_params = wm5100_hw_params,
+	.auto_selectable_formats	= &wm5100_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static int wm5100_set_sysclk(struct snd_soc_component *component, int clk_id,
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index ad68ff1..0e7c8a5 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1426,6 +1426,28 @@ EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
 			SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8350_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/*
+	 * 2nd priority
+	 *
+	 * iface of DSP_A/B are same, the diff is only LRCLK_INV.
+	 * It will be impossible to distinguish between DSP_A/B
+	 * if xB_IF are used. Allow xB_NF only.
+	 */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8350_dai_ops = {
 	 .hw_params	= wm8350_pcm_hw_params,
 	 .mute_stream	= wm8350_mute,
@@ -1434,6 +1456,8 @@ static const struct snd_soc_dai_ops wm8350_dai_ops = {
 	 .set_pll	= wm8350_set_fll,
 	 .set_clkdiv	= wm8350_set_clkdiv,
 	 .no_capture_mute = 1,
+	 .auto_selectable_formats	= wm8350_selectable_formats,
+	 .num_auto_selectable_formats	= ARRAY_SIZE(wm8350_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8350_dai = {
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 0eecc86..83e2d72a 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1222,6 +1222,13 @@ static int wm8400_set_bias_level(struct snd_soc_component *component,
 #define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8400_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops wm8400_dai_ops = {
 	.hw_params = wm8400_hw_params,
 	.mute_stream = wm8400_mute,
@@ -1230,6 +1237,8 @@ static const struct snd_soc_dai_ops wm8400_dai_ops = {
 	.set_sysclk = wm8400_set_dai_sysclk,
 	.set_pll = wm8400_set_dai_pll,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8400_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 /*
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 137dcd3..7d40ed2 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -545,6 +545,16 @@ static int wm8510_set_bias_level(struct snd_soc_component *component,
 #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8510_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8510_dai_ops = {
 	.hw_params	= wm8510_pcm_hw_params,
 	.mute_stream	= wm8510_mute,
@@ -552,6 +562,8 @@ static const struct snd_soc_dai_ops wm8510_dai_ops = {
 	.set_clkdiv	= wm8510_set_dai_clkdiv,
 	.set_pll	= wm8510_set_dai_pll,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8510_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8510_dai = {
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index b8832a1..9972d65 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -374,11 +374,24 @@ static int wm8523_set_bias_level(struct snd_soc_component *component,
 #define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8523_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8523_dai_ops = {
 	.startup	= wm8523_startup,
 	.hw_params	= wm8523_hw_params,
 	.set_sysclk	= wm8523_set_dai_sysclk,
 	.set_fmt	= wm8523_set_dai_fmt,
+	.auto_selectable_formats	= &wm8523_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8523_dai = {
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index 23daf15..8d0565b 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -190,6 +190,10 @@ static int wm8524_hw_params(struct snd_pcm_substream *substream,
 			SNDRV_PCM_FMTBIT_S24_LE |\
 			SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8525_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops wm8524_dai_ops = {
 	.startup	= wm8524_startup,
 	.shutdown	= wm8524_shutdown,
@@ -197,6 +201,8 @@ static const struct snd_soc_dai_ops wm8524_dai_ops = {
 	.set_fmt	= wm8524_set_fmt,
 	.mute_stream	= wm8524_mute_stream,
 	.hw_params	= wm8524_hw_params,
+	.auto_selectable_formats	= &wm8525_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8524_dai = {
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index eb374ba..9bc5d1e7 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -860,6 +860,22 @@ static int wm8580_playback_startup(struct snd_pcm_substream *substream,
 #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8580_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
 	.startup	= wm8580_playback_startup,
 	.set_sysclk	= wm8580_set_sysclk,
@@ -869,6 +885,8 @@ static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
 	.set_pll	= wm8580_set_dai_pll,
 	.mute_stream	= wm8580_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8580_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8580_selectable_formats),
 };
 
 static const struct snd_soc_dai_ops wm8580_dai_ops_capture = {
@@ -877,6 +895,8 @@ static const struct snd_soc_dai_ops wm8580_dai_ops_capture = {
 	.set_fmt	= wm8580_set_paif_dai_fmt,
 	.set_clkdiv	= wm8580_set_dai_clkdiv,
 	.set_pll	= wm8580_set_dai_pll,
+	.auto_selectable_formats	= wm8580_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8580_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8580_dai[] = {
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 2db8829..390af15 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -325,6 +325,17 @@ static int wm8711_set_bias_level(struct snd_soc_component *component,
 #define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8711_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8711_ops = {
 	.prepare = wm8711_pcm_prepare,
 	.hw_params = wm8711_hw_params,
@@ -333,6 +344,8 @@ static const struct snd_soc_dai_ops wm8711_ops = {
 	.set_sysclk = wm8711_set_dai_sysclk,
 	.set_fmt = wm8711_set_dai_fmt,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8711_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8711_dai = {
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 3109a6a..7af5ce0 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -190,11 +190,20 @@ static int wm8728_set_bias_level(struct snd_soc_component *component,
 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8728_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8728_dai_ops = {
 	.hw_params	= wm8728_hw_params,
 	.mute_stream	= wm8728_mute,
 	.set_fmt	= wm8728_set_dai_fmt,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8728_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8728_dai = {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index ce87280..f25b509 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -519,6 +519,17 @@ static int wm8731_startup(struct snd_pcm_substream *substream,
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8731_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8731_dai_ops = {
 	.startup	= wm8731_startup,
 	.hw_params	= wm8731_hw_params,
@@ -526,6 +537,8 @@ static const struct snd_soc_dai_ops wm8731_dai_ops = {
 	.set_sysclk	= wm8731_set_dai_sysclk,
 	.set_fmt	= wm8731_set_dai_fmt,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8731_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8731_dai = {
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 33a3f88..72b7d09 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -516,10 +516,21 @@ static int wm8737_set_bias_level(struct snd_soc_component *component,
 #define WM8737_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8737_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF;
+
 static const struct snd_soc_dai_ops wm8737_dai_ops = {
 	.hw_params	= wm8737_hw_params,
 	.set_sysclk	= wm8737_set_dai_sysclk,
 	.set_fmt	= wm8737_set_dai_fmt,
+	.auto_selectable_formats	= &wm8737_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8737_dai = {
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index ca56fdf..e49adc9 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -381,6 +381,17 @@ static int wm8741_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
 #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8741_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8741_dai_ops = {
 	.startup	= wm8741_startup,
 	.hw_params	= wm8741_hw_params,
@@ -388,6 +399,8 @@ static const struct snd_soc_dai_ops wm8741_dai_ops = {
 	.set_fmt	= wm8741_set_dai_fmt,
 	.mute_stream	= wm8741_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8741_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8741_dai = {
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index d3f1178..b0b4447 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -659,12 +659,25 @@ static int wm8750_set_bias_level(struct snd_soc_component *component,
 #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8750_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8750_dai_ops = {
 	.hw_params	= wm8750_pcm_hw_params,
 	.mute_stream	= wm8750_mute,
 	.set_fmt	= wm8750_set_dai_fmt,
 	.set_sysclk	= wm8750_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8750_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8750_dai = {
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index ac4008b..cbdf1e6 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1380,6 +1380,22 @@ static int wm8753_set_bias_level(struct snd_soc_component *component,
  * 3. Voice disabled - HIFI over HIFI
  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
  */
+static const u64 wm8753_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+};
+
 static const struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
 	.hw_params	= wm8753_i2s_hw_params,
 	.mute_stream	= wm8753_mute,
@@ -1388,6 +1404,8 @@ static const struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
 	.set_pll	= wm8753_set_dai_pll,
 	.set_sysclk	= wm8753_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8753_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8753_selectable_formats),
 };
 
 static const struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
@@ -1398,6 +1416,8 @@ static const struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
 	.set_pll	= wm8753_set_dai_pll,
 	.set_sysclk	= wm8753_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8753_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8753_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8753_dai[] = {
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index b8b4d1e..1e485d2 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -537,12 +537,23 @@ static int wm8770_set_bias_level(struct snd_soc_component *component,
 #define WM8770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8770_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8770_dai_ops = {
 	.mute_stream = wm8770_mute,
 	.hw_params = wm8770_hw_params,
 	.set_fmt = wm8770_set_fmt,
 	.set_sysclk = wm8770_set_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8770_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver wm8770_dai = {
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index a8e4f71..c633fe8 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -360,18 +360,31 @@ static int wm8776_set_bias_level(struct snd_soc_component *component,
 #define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8776_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8776_dac_ops = {
 	.mute_stream	= wm8776_mute,
 	.hw_params      = wm8776_hw_params,
 	.set_fmt        = wm8776_set_fmt,
 	.set_sysclk     = wm8776_set_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8776_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops wm8776_adc_ops = {
 	.hw_params      = wm8776_hw_params,
 	.set_fmt        = wm8776_set_fmt,
 	.set_sysclk     = wm8776_set_sysclk,
+	.auto_selectable_formats	= &wm8776_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8776_dai[] = {
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 94aa3c8..2fc9634 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -502,12 +502,25 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 wm8804_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8804_dai_ops = {
 	.hw_params = wm8804_hw_params,
 	.set_fmt = wm8804_set_fmt,
 	.set_sysclk = wm8804_set_sysclk,
 	.set_clkdiv = wm8804_set_clkdiv,
-	.set_pll = wm8804_set_pll
+	.set_pll = wm8804_set_pll,
+	.auto_selectable_formats = &wm8804_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index a9128cf..dcda7a7 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -992,6 +992,22 @@ static int wm8900_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	 SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8900_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8900_dai_ops = {
 	.hw_params	= wm8900_hw_params,
 	.set_clkdiv	= wm8900_set_dai_clkdiv,
@@ -999,6 +1015,8 @@ static const struct snd_soc_dai_ops wm8900_dai_ops = {
 	.set_fmt	= wm8900_set_dai_fmt,
 	.mute_stream	= wm8900_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8900_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8900_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8900_dai = {
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 156e1e2..68112cb 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1733,12 +1733,30 @@ static irqreturn_t wm8903_irq(int irq, void *data)
 			SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8903_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8903_dai_ops = {
 	.hw_params	= wm8903_hw_params,
 	.mute_stream	= wm8903_mute,
 	.set_fmt	= wm8903_set_dai_fmt,
 	.set_sysclk	= wm8903_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8903_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8903_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8903_dai = {
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 9e5782e..153ce2c 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -2026,6 +2026,22 @@ static int wm8904_set_bias_level(struct snd_soc_component *component,
 #define WM8904_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8904_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8904_dai_ops = {
 	.set_sysclk = wm8904_set_sysclk,
 	.set_fmt = wm8904_set_fmt,
@@ -2034,6 +2050,8 @@ static const struct snd_soc_dai_ops wm8904_dai_ops = {
 	.hw_params = wm8904_hw_params,
 	.mute_stream = wm8904_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8904_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8904_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8904_dai = {
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 2292523..0125562 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -730,6 +730,17 @@ static int wm8940_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 			SNDRV_PCM_FMTBIT_S24_LE |			\
 			SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8940_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8940_dai_ops = {
 	.hw_params = wm8940_i2s_hw_params,
 	.set_sysclk = wm8940_set_dai_sysclk,
@@ -738,6 +749,8 @@ static const struct snd_soc_dai_ops wm8940_dai_ops = {
 	.set_clkdiv = wm8940_set_dai_clkdiv,
 	.set_pll = wm8940_set_dai_pll,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8940_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver wm8940_dai = {
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index c897a9a..1d367a9 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -845,12 +845,30 @@ static int wm8955_set_bias_level(struct snd_soc_component *component,
 #define WM8955_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8955_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8955_dai_ops = {
 	.set_sysclk = wm8955_set_sysclk,
 	.set_fmt = wm8955_set_fmt,
 	.hw_params = wm8955_hw_params,
 	.mute_stream = wm8955_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8955_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8955_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8955_dai = {
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index a810732..093530a 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1340,6 +1340,17 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8960_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8960_dai_ops = {
 	.hw_params = wm8960_hw_params,
 	.hw_free = wm8960_hw_free,
@@ -1349,6 +1360,8 @@ static const struct snd_soc_dai_ops wm8960_dai_ops = {
 	.set_pll = wm8960_set_dai_pll,
 	.set_sysclk = wm8960_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8960_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver wm8960_dai = {
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 504fc59..55ccac7 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -803,6 +803,22 @@ static int wm8961_set_bias_level(struct snd_soc_component *component,
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8961_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8961_dai_ops = {
 	.hw_params = wm8961_hw_params,
 	.set_sysclk = wm8961_set_sysclk,
@@ -811,6 +827,8 @@ static const struct snd_soc_dai_ops wm8961_dai_ops = {
 	.set_tristate = wm8961_set_tristate,
 	.set_clkdiv = wm8961_set_clkdiv,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8961_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8961_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8961_dai = {
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 8a95981..db8b86d 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3056,6 +3056,22 @@ static int wm8962_mute(struct snd_soc_dai *dai, int mute, int direction)
 #define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8962_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8962_dai_ops = {
 	.hw_params = wm8962_hw_params,
 	.set_sysclk = wm8962_set_dai_sysclk,
@@ -3063,6 +3079,8 @@ static const struct snd_soc_dai_ops wm8962_dai_ops = {
 	.set_tdm_slot = wm8962_set_tdm_slot,
 	.mute_stream = wm8962_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8962_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8962_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8962_dai = {
@@ -3355,7 +3373,7 @@ static void wm8962_init_beep(struct snd_soc_component *component)
 	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	wm8962->beep = devm_input_allocate_device(component->dev);
+	wm8962->beep = input_allocate_device();
 	if (!wm8962->beep) {
 		dev_err(component->dev, "Failed to allocate beep device\n");
 		return;
@@ -3376,8 +3394,10 @@ static void wm8962_init_beep(struct snd_soc_component *component)
 
 	ret = input_register_device(wm8962->beep);
 	if (ret != 0) {
+		input_free_device(wm8962->beep);
 		wm8962->beep = NULL;
 		dev_err(component->dev, "Failed to register beep device\n");
+		return;
 	}
 
 	ret = device_create_file(component->dev, &dev_attr_beep);
@@ -3393,7 +3413,10 @@ static void wm8962_free_beep(struct snd_soc_component *component)
 
 	device_remove_file(component->dev, &dev_attr_beep);
 	cancel_work_sync(&wm8962->beep_work);
-	wm8962->beep = NULL;
+	if (wm8962->beep) {
+		input_unregister_device(wm8962->beep);
+		wm8962->beep = NULL;
+	}
 
 	snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
 }
@@ -3430,7 +3453,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
 
 	/* The WM8962 GPIOs aren't linearly numbered.  For simplicity
 	 * we export linear numbers and error out if the unsupported
-	 * ones are requsted.
+	 * ones are requested.
 	 */
 	switch (offset + 1) {
 	case 2:
@@ -3525,34 +3548,12 @@ static void wm8962_free_gpio(struct snd_soc_component *component)
 static int wm8962_probe(struct snd_soc_component *component)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
-	int ret;
 	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int i;
 	bool dmicclk, dmicdat;
 
 	wm8962->component = component;
 
-	wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
-	wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
-	wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
-	wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
-	wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
-	wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
-	wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
-	wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
-
-	/* This should really be moved into the regulator core */
-	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
-		ret = devm_regulator_register_notifier(
-						wm8962->supplies[i].consumer,
-						&wm8962->disable_nb[i]);
-		if (ret != 0) {
-			dev_err(component->dev,
-				"Failed to register regulator notifier: %d\n",
-				ret);
-		}
-	}
-
 	wm8962_add_widgets(component);
 
 	/* Save boards having to disable DMIC when not in use */
@@ -3742,6 +3743,27 @@ static int wm8962_i2c_probe(struct i2c_client *i2c)
 
 	regcache_cache_bypass(wm8962->regmap, false);
 
+	wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
+	wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
+	wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
+	wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
+	wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
+	wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
+	wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
+	wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
+		ret = devm_regulator_register_notifier(wm8962->supplies[i].consumer,
+						       &wm8962->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+			goto err_enable;
+		}
+	}
+
 	ret = wm8962_reset(wm8962);
 	if (ret < 0) {
 		dev_err(&i2c->dev, "Failed to issue reset\n");
@@ -3813,7 +3835,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c)
 	regmap_update_bits(wm8962->regmap, WM8962_EQ1,
 			   WM8962_EQ_SHARED_COEFF, 0);
 
-	/* Don't debouce interrupts so we don't need SYSCLK */
+	/* Don't debounce interrupts so we don't need SYSCLK */
 	regmap_update_bits(wm8962->regmap, WM8962_IRQ_DEBOUNCE,
 			   WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
 			   WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index a5d2e91..388ee05 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -601,12 +601,25 @@ static int wm8971_set_bias_level(struct snd_soc_component *component,
 #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8971_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8971_dai_ops = {
 	.hw_params	= wm8971_pcm_hw_params,
 	.mute_stream	= wm8971_mute,
 	.set_fmt	= wm8971_set_dai_fmt,
 	.set_sysclk	= wm8971_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8971_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8971_dai = {
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 4656652b..5e1737d 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -623,6 +623,21 @@ static int wm8974_set_bias_level(struct snd_soc_component *component,
 #define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8974_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8974_ops = {
 	.hw_params = wm8974_pcm_hw_params,
 	.mute_stream = wm8974_mute,
@@ -631,6 +646,8 @@ static const struct snd_soc_dai_ops wm8974_ops = {
 	.set_pll = wm8974_set_dai_pll,
 	.set_sysclk = wm8974_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8974_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8974_selectable_formats),
 };
 
 static struct snd_soc_dai_driver wm8974_dai = {
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index ad8064b..25cc433 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -892,6 +892,16 @@ static int wm8978_set_bias_level(struct snd_soc_component *component,
 #define WM8978_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8978_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8978_dai_ops = {
 	.hw_params	= wm8978_hw_params,
 	.mute_stream	= wm8978_mute,
@@ -899,6 +909,8 @@ static const struct snd_soc_dai_ops wm8978_dai_ops = {
 	.set_clkdiv	= wm8978_set_dai_clkdiv,
 	.set_sysclk	= wm8978_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8978_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 /* Also supports 12kHz */
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index fab25f3..3366166 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -943,6 +943,16 @@ static int wm8983_probe(struct snd_soc_component *component)
 	return 0;
 }
 
+/* FIXME: it doesn't support DSP A/B for now */
+static const u64 wm8983_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8983_dai_ops = {
 	.mute_stream = wm8983_dac_mute,
 	.hw_params = wm8983_hw_params,
@@ -950,6 +960,8 @@ static const struct snd_soc_dai_ops wm8983_dai_ops = {
 	.set_sysclk = wm8983_set_sysclk,
 	.set_pll = wm8983_set_pll,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8983_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define WM8983_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 2a64d5a..77ca9a0 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1072,6 +1072,22 @@ static int wm8985_probe(struct snd_soc_component *component)
 	return ret;
 }
 
+static const u64 wm8985_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8985_dai_ops = {
 	.mute_stream = wm8985_dac_mute,
 	.hw_params = wm8985_hw_params,
@@ -1079,6 +1095,8 @@ static const struct snd_soc_dai_ops wm8985_dai_ops = {
 	.set_sysclk = wm8985_set_sysclk,
 	.set_pll = wm8985_set_pll,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8985_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8985_selectable_formats),
 };
 
 #define WM8985_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 741aecc7..6f97c9a 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -762,6 +762,17 @@ static int wm8988_set_bias_level(struct snd_soc_component *component,
 #define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8988_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8988_ops = {
 	.startup = wm8988_pcm_startup,
 	.hw_params = wm8988_pcm_hw_params,
@@ -769,6 +780,8 @@ static const struct snd_soc_dai_ops wm8988_ops = {
 	.set_sysclk = wm8988_set_dai_sysclk,
 	.mute_stream = wm8988_mute,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8988_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver wm8988_dai = {
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 11dfbbb..c8fef18 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1151,6 +1151,13 @@ static int wm8990_set_bias_level(struct snd_soc_component *component,
  * 1. ADC/DAC on Primary Interface
  * 2. ADC on Primary Interface/DAC on secondary
  */
+static const u64 wm8990_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops wm8990_dai_ops = {
 	.hw_params	= wm8990_hw_params,
 	.mute_stream	= wm8990_mute,
@@ -1159,6 +1166,8 @@ static const struct snd_soc_dai_ops wm8990_dai_ops = {
 	.set_pll	= wm8990_set_dai_pll,
 	.set_sysclk	= wm8990_set_dai_sysclk,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= &wm8990_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm8990_dai = {
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 225c235..2cb7fb9 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1195,6 +1195,13 @@ static int wm8991_set_bias_level(struct snd_soc_component *component,
 #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm8991_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops wm8991_ops = {
 	.hw_params = wm8991_hw_params,
 	.mute_stream = wm8991_mute,
@@ -1202,6 +1209,8 @@ static const struct snd_soc_dai_ops wm8991_ops = {
 	.set_clkdiv = wm8991_set_dai_clkdiv,
 	.set_pll = wm8991_set_dai_pll,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = &wm8991_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 /*
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 2a94b23..934fa41 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1441,6 +1441,22 @@ static irqreturn_t wm8993_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static const u64 wm8993_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8993_ops = {
 	.set_sysclk = wm8993_set_sysclk,
 	.set_fmt = wm8993_set_dai_fmt,
@@ -1449,6 +1465,8 @@ static const struct snd_soc_dai_ops wm8993_ops = {
 	.set_pll = wm8993_set_fll,
 	.set_tdm_slot = wm8993_set_tdm_slot,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8993_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8993_selectable_formats),
 };
 
 #define WM8993_RATES SNDRV_PCM_RATE_8000_48000
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 8bf58a6..96d3aae 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -3202,6 +3202,22 @@ static int wm8994_aif2_probe(struct snd_soc_dai *dai)
 #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8994_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
 	.set_sysclk	= wm8994_set_dai_sysclk,
 	.set_fmt	= wm8994_set_dai_fmt,
@@ -3210,6 +3226,8 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
 	.set_pll	= wm8994_set_fll,
 	.set_tristate	= wm8994_set_tristate,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8994_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8994_selectable_formats),
 };
 
 static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
@@ -3221,6 +3239,8 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
 	.set_pll	= wm8994_set_fll,
 	.set_tristate	= wm8994_set_tristate,
 	.no_capture_mute = 1,
+	.auto_selectable_formats	= wm8994_selectable_formats,
+	.num_auto_selectable_formats	= ARRAY_SIZE(wm8994_selectable_formats),
 };
 
 static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
@@ -4340,6 +4360,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
 	ret = regmap_read(control->regmap, WM8994_GPIO_1, &reg);
 	if (ret < 0) {
 		dev_err(component->dev, "Failed to read GPIO1 state: %d\n", ret);
+		pm_runtime_put(component->dev);
 		goto err_irq;
 	}
 	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
@@ -4352,6 +4373,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
 	ret = regmap_read(control->regmap, WM8994_GPIO_6, &reg);
 	if (ret < 0) {
 		dev_err(component->dev, "Failed to read GPIO6 state: %d\n", ret);
+		pm_runtime_put(component->dev);
 		goto err_irq;
 	}
 	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 799989a..7f01d20 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -1993,23 +1993,17 @@ static int wm8995_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
-static int wm8995_probe(struct snd_soc_component *component)
+static int wm8995_hw_init(struct device *dev, struct wm8995_priv *wm8995)
 {
-	struct wm8995_priv *wm8995;
-	int i;
-	int ret;
-
-	wm8995 = snd_soc_component_get_drvdata(component);
-	wm8995->component = component;
+	int i, ret;
 
 	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)
 		wm8995->supplies[i].supply = wm8995_supply_names[i];
 
-	ret = devm_regulator_bulk_get(component->dev,
-				      ARRAY_SIZE(wm8995->supplies),
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8995->supplies),
 				      wm8995->supplies);
 	if (ret) {
-		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
+		dev_err(dev, "Failed to request supplies: %d\n", ret);
 		return ret;
 	}
 
@@ -2024,16 +2018,27 @@ static int wm8995_probe(struct snd_soc_component *component)
 
 	/* This should really be moved into the regulator core */
 	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) {
-		ret = devm_regulator_register_notifier(
-						wm8995->supplies[i].consumer,
-						&wm8995->disable_nb[i]);
+		ret = devm_regulator_register_notifier(wm8995->supplies[i].consumer,
+						       &wm8995->disable_nb[i]);
 		if (ret) {
-			dev_err(component->dev,
+			dev_err(dev,
 				"Failed to register regulator notifier: %d\n",
 				ret);
+			return ret;
 		}
 	}
 
+	return 0;
+}
+
+static int wm8995_probe(struct snd_soc_component *component)
+{
+	struct wm8995_priv *wm8995;
+	int ret;
+
+	wm8995 = snd_soc_component_get_drvdata(component);
+	wm8995->component = component;
+
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
 				    wm8995->supplies);
 	if (ret) {
@@ -2091,6 +2096,22 @@ static int wm8995_probe(struct snd_soc_component *component)
 #define WM8995_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8995_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm8995_aif1_dai_ops = {
 	.set_sysclk = wm8995_set_dai_sysclk,
 	.set_fmt = wm8995_set_dai_fmt,
@@ -2099,6 +2120,8 @@ static const struct snd_soc_dai_ops wm8995_aif1_dai_ops = {
 	.set_pll = wm8995_set_fll,
 	.set_tristate = wm8995_set_tristate,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8995_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8995_selectable_formats),
 };
 
 static const struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
@@ -2109,6 +2132,8 @@ static const struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
 	.set_pll = wm8995_set_fll,
 	.set_tristate = wm8995_set_tristate,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm8995_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm8995_selectable_formats),
 };
 
 static const struct snd_soc_dai_ops wm8995_aif3_dai_ops = {
@@ -2216,6 +2241,10 @@ static int wm8995_spi_probe(struct spi_device *spi)
 		return ret;
 	}
 
+	ret = wm8995_hw_init(&spi->dev, wm8995);
+	if (ret)
+		return ret;
+
 	ret = devm_snd_soc_register_component(&spi->dev,
 				     &soc_component_dev_wm8995, wm8995_dai,
 				     ARRAY_SIZE(wm8995_dai));
@@ -2249,6 +2278,10 @@ static int wm8995_i2c_probe(struct i2c_client *i2c)
 		return ret;
 	}
 
+	ret = wm8995_hw_init(&i2c->dev, wm8995);
+	if (ret)
+		return ret;
+
 	ret = devm_snd_soc_register_component(&i2c->dev,
 				     &soc_component_dev_wm8995, wm8995_dai,
 				     ARRAY_SIZE(wm8995_dai));
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index dface55..9d8fb4e 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2106,7 +2106,7 @@ static int wm8996_set_fll(struct snd_soc_component *component, int fll_id, int s
 	if (i2c->irq)
 		timeout *= 10;
 	else
-		/* ensure timeout of atleast 1 jiffies */
+		/* ensure timeout of at least 1 jiffies */
 		timeout = (timeout/2) ? : 1;
 
 	for (retry = 0; retry < 10; retry++) {
@@ -2703,10 +2703,22 @@ static const struct snd_soc_component_driver soc_component_dev_wm8996 = {
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
 			SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm8996_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm8996_dai_ops = {
 	.set_fmt = wm8996_set_fmt,
 	.hw_params = wm8996_hw_params,
 	.set_sysclk = wm8996_set_sysclk,
+	.auto_selectable_formats = &wm8996_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver wm8996_dai[] = {
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 2e4e0a7..824e9c6 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1230,12 +1230,30 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 wm9081_selectable_formats[] = {
+	/* 1st priority */
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+	/* 2nd priority */
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF,
+};
+
 static const struct snd_soc_dai_ops wm9081_dai_ops = {
 	.hw_params = wm9081_hw_params,
 	.set_fmt = wm9081_set_dai_fmt,
 	.mute_stream = wm9081_mute,
 	.set_tdm_slot = wm9081_set_tdm_slot,
 	.no_capture_mute = 1,
+	.auto_selectable_formats = wm9081_selectable_formats,
+	.num_auto_selectable_formats = ARRAY_SIZE(wm9081_selectable_formats),
 };
 
 /* We report two channels because the CODEC processes a stereo signal, even
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 3ba7ca3..3cffdfb 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1067,6 +1067,17 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	 SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 wm9713_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
 	.prepare	= ac97_hifi_prepare,
 	.set_clkdiv	= wm9713_set_dai_clkdiv,
@@ -1085,6 +1096,8 @@ static const struct snd_soc_dai_ops wm9713_dai_ops_voice = {
 	.set_pll	= wm9713_set_dai_pll,
 	.set_fmt	= wm9713_set_dai_fmt,
 	.set_tristate	= wm9713_set_dai_tristate,
+	.auto_selectable_formats	= &wm9713_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver wm9713_dai[] = {
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index f80dfc4..0199405 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -338,7 +338,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
 	/* If we're applying an offset correction then updating the
-	 * callibration would be likely to introduce further offsets. */
+	 * calibration would be likely to introduce further offsets. */
 	if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
 		return ret;
 
diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c
index 894b8eb..b706286 100644
--- a/sound/soc/codecs/zl38060.c
+++ b/sound/soc/codecs/zl38060.c
@@ -334,10 +334,16 @@ static const struct reg_sequence cp_config_stereo_bypass[] = {
 	{ 0x0202, 0x000F },	/* enable I2S1 + DAC   */
 };
 
+static const u64 zl38_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops zl38_dai_ops = {
 	.set_fmt = zl38_set_fmt,
 	.hw_params = zl38_hw_params,
 	.hw_free = zl38_hw_free,
+	.auto_selectable_formats = &zl38_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver zl38_dai = {
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 2e9fb79..ade89c1 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -464,6 +464,13 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 dw_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
 static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
 	.probe		= dw_i2s_dai_probe,
 	.startup	= dw_i2s_startup,
@@ -472,6 +479,8 @@ static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
 	.trigger	= dw_i2s_trigger,
 	.set_fmt	= dw_i2s_set_fmt,
 	.set_tdm_slot	= dw_i2s_set_tdm_slot,
+	.auto_selectable_formats	= &dw_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static int dw_i2s_runtime_suspend(struct device *dev)
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 04940879..101bc95 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -234,7 +234,7 @@
 
 config SND_SOC_MPC5200_AC97
 	tristate "Freescale MPC5200 PSC in AC97 mode driver"
-	depends on PPC_BESTCOMM
+	depends on PPC_BESTCOMM && PPC_MPC52xx
 	select SND_SOC_AC97_BUS
 	select SND_MPC52xx_DMA
 	select PPC_BESTCOMM_GEN_BD
diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c
index 901f840..5b00488 100644
--- a/sound/soc/fsl/fsl_mqs.c
+++ b/sound/soc/fsl/fsl_mqs.c
@@ -183,7 +183,21 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
 			   mqs_priv->soc->en_mask, 0);
 }
 
+static const struct snd_soc_dapm_widget fsl_mqs_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("MQS_L"),
+	SND_SOC_DAPM_OUTPUT("MQS_R"),
+};
+
+static const struct snd_soc_dapm_route fsl_mqs_dapm_routes[] = {
+	{ "MQS_L", NULL, "Playback" },
+	{ "MQS_R", NULL, "Playback" },
+};
+
 static const struct snd_soc_component_driver soc_codec_fsl_mqs = {
+	.dapm_widgets = fsl_mqs_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(fsl_mqs_dapm_widgets),
+	.dapm_routes = fsl_mqs_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(fsl_mqs_dapm_routes),
 	.idle_bias_on = 1,
 };
 
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 0a8a6d8..127c2e6 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -629,6 +629,7 @@ static int graph_probe(struct platform_device *pdev)
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
 	card->probe		= graph_util_card_probe;
+	card->remove		= graph_util_card_remove;
 
 	if (of_device_get_match_data(dev))
 		priv->dpcm_selectable = 1;
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 9fb3d3d..e11bc81 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -1310,6 +1310,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
 		goto end;
 
 	card->probe	= graph_util_card_probe;
+	card->remove	= graph_util_card_remove;
 	card->owner	= THIS_MODULE;
 	card->dev	= dev;
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 5f34231..de27163 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -825,6 +825,16 @@ int simple_util_init_jack(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(simple_util_init_jack);
 
+void simple_util_remove_jack(struct simple_util_jack *sjack)
+{
+	if (!sjack->gpio.desc)
+		return;
+
+	snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
+	sjack->gpio.desc = NULL;
+}
+EXPORT_SYMBOL_GPL(simple_util_remove_jack);
+
 int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix)
 {
 	struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
@@ -1018,6 +1028,17 @@ int graph_util_card_probe(struct snd_soc_card *card)
 }
 EXPORT_SYMBOL_GPL(graph_util_card_probe);
 
+int graph_util_card_remove(struct snd_soc_card *card)
+{
+	struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
+
+	simple_util_remove_jack(&priv->hp_jack);
+	simple_util_remove_jack(&priv->mic_jack);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(graph_util_card_remove);
+
 int graph_util_is_ports0(struct device_node *np)
 {
 	struct device_node *parent __free(device_node) = of_get_parent(np);
@@ -1116,7 +1137,7 @@ int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
 	args.np = ep;
 	dai = snd_soc_get_dai_via_args(&args);
 	if (dai) {
-		const char *dai_name = snd_soc_dai_name_get(dai);
+		const char *dai_name = snd_soc_dai_name(dai);
 		const struct of_phandle_args *dai_args = snd_soc_copy_dai_args(dev, &args);
 
 		ret = -ENOMEM;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index e7ad7af..b2fc91b 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -92,7 +92,7 @@ static int simple_parse_dai(struct simple_util_priv *priv,
 	dai = snd_soc_get_dai_via_args(&args);
 	if (dai) {
 		ret = -ENOMEM;
-		dlc->dai_name = snd_soc_dai_name_get(dai);
+		dlc->dai_name = snd_soc_dai_name(dai);
 		dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
 		if (!dlc->dai_args)
 			goto end;
@@ -666,6 +666,16 @@ static int simple_soc_probe(struct snd_soc_card *card)
 	return simple_ret(priv, ret);
 }
 
+static int simple_soc_remove(struct snd_soc_card *card)
+{
+	struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
+
+	simple_util_remove_jack(&priv->hp_jack);
+	simple_util_remove_jack(&priv->mic_jack);
+
+	return 0;
+}
+
 static int simple_parse_of(struct simple_util_priv *priv)
 {
 	struct snd_soc_card *card = simple_priv_to_card(priv);
@@ -754,6 +764,7 @@ static int simple_probe(struct platform_device *pdev)
 	card->owner		= THIS_MODULE;
 	card->dev		= dev;
 	card->probe		= simple_soc_probe;
+	card->remove		= simple_soc_remove;
 	card->driver_name       = "simple-card";
 
 	return simple_parse_of(priv);
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index 33b1daf..554356f 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -507,6 +507,11 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
 }
 
 
+static const u64 hi6210_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
 	.probe		= hi6210_i2s_dai_probe,
 	.trigger	= hi6210_i2s_trigger,
@@ -514,6 +519,8 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
 	.set_fmt	= hi6210_i2s_set_fmt,
 	.startup	= hi6210_i2s_startup,
 	.shutdown	= hi6210_i2s_shutdown,
+	.auto_selectable_formats	= &hi6210_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index 98d2ab6..a0c87e2 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -379,11 +379,21 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 img_i2s_in_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
 	.probe		= img_i2s_in_dai_probe,
 	.trigger	= img_i2s_in_trigger,
 	.hw_params	= img_i2s_in_hw_params,
-	.set_fmt	= img_i2s_in_set_fmt
+	.set_fmt	= img_i2s_in_set_fmt,
+	.auto_selectable_formats	= &img_i2s_in_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_component_driver img_i2s_in_component = {
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index aedcf56..caa7870 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -385,11 +385,22 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 img_i2s_out_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_CONT	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
 	.probe		= img_i2s_out_dai_probe,
 	.trigger	= img_i2s_out_trigger,
 	.hw_params	= img_i2s_out_hw_params,
-	.set_fmt	= img_i2s_out_set_fmt
+	.set_fmt	= img_i2s_out_set_fmt,
+	.auto_selectable_formats	= &img_i2s_out_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_component_driver img_i2s_out_component = {
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index 86b60e6..8927091 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -183,11 +183,17 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 img_prl_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF;
+
 static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
 	.probe		= img_prl_out_dai_probe,
 	.trigger	= img_prl_out_trigger,
 	.hw_params	= img_prl_out_hw_params,
-	.set_fmt	= img_prl_out_set_fmt
+	.set_fmt	= img_prl_out_set_fmt,
+	.auto_selectable_formats	= &img_prl_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver img_prl_out_dai = {
diff --git a/sound/soc/intel/atom/sst-mfld-dsp.h b/sound/soc/intel/atom/sst-mfld-dsp.h
index c8f0816..5960625 100644
--- a/sound/soc/intel/atom/sst-mfld-dsp.h
+++ b/sound/soc/intel/atom/sst-mfld-dsp.h
@@ -189,7 +189,7 @@ struct ipc_dsp_hdr {
 union ipc_header_high {
 	struct {
 		u32  msg_id:8;	    /* Message ID - Max 256 Message Types */
-		u32  task_id:4;	    /* Task ID associated with this comand */
+		u32  task_id:4;	    /* Task ID associated with this command */
 		u32  drv_id:4;    /* Identifier for the driver to track*/
 		u32  rsvd1:8;	    /* Reserved */
 		u32  result:4;	    /* Reserved */
diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h
index c43946c..e24d9da 100644
--- a/sound/soc/intel/atom/sst/sst.h
+++ b/sound/soc/intel/atom/sst/sst.h
@@ -182,7 +182,7 @@ struct sst_block {
  * @pcm_substream : PCM substream
  * @period_elapsed : PCM period elapsed callback
  * @sfreq : stream sampling freq
- * @cumm_bytes : cummulative bytes decoded
+ * @cumm_bytes : cumulative bytes decoded
  */
 struct stream_info {
 	unsigned int		status;
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index 2e15a29..c1d2d00 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -147,17 +147,15 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
 	struct snd_soc_dai_link *links = NULL;
 	struct snd_soc_card *card = rtm->card;
 	struct hda_codec *codec;
-	struct hda_pcm *pcm;
-	int ret, pcm_count = 0;
+	int ret, pcm_count;
 
 	mach = dev_get_platdata(card->dev);
 	pdata = mach->pdata;
 	codec = pdata->codec;
+	pcm_count = list_count_nodes(&codec->pcm_list_head);
 
-	if (list_empty(&codec->pcm_list_head))
+	if (!pcm_count)
 		return -EINVAL;
-	list_for_each_entry(pcm, &codec->pcm_list_head, list)
-		pcm_count++;
 
 	ret = avs_create_dai_links(card->dev, codec, pcm_count, &links);
 	if (ret < 0) {
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index ad25bd3..2d7ced9 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -1065,7 +1065,7 @@ static int avs_component_probe(struct snd_soc_component *component)
 	return 0;
 
 err_load_libs:
-	avs_remove_topology(component);
+	snd_soc_tplg_component_remove(component);
 	return ret;
 }
 
@@ -1083,7 +1083,7 @@ static void avs_component_remove(struct snd_soc_component *component)
 	mutex_unlock(&adev->comp_list_mutex);
 
 	if (mach->tplg_filename) {
-		ret = avs_remove_topology(component);
+		ret = snd_soc_tplg_component_remove(component);
 		if (ret < 0)
 			dev_err(component->dev, "unload topology failed: %d\n", ret);
 	}
@@ -1614,7 +1614,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
 	struct hda_codec *codec;
 	struct hda_pcm *pcm;
 	const char *cname;
-	int pcm_count = 0, ret, i;
+	int pcm_count, ret, i;
 
 	mach = dev_get_platdata(component->card->dev);
 	if (!mach)
@@ -1622,10 +1622,9 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
 
 	pdata = mach->pdata;
 	codec = pdata->codec;
-	if (list_empty(&codec->pcm_list_head))
+	pcm_count = list_count_nodes(&codec->pcm_list_head);
+	if (!pcm_count)
 		return -EINVAL;
-	list_for_each_entry(pcm, &codec->pcm_list_head, list)
-		pcm_count++;
 
 	dais = devm_kcalloc(component->dev, pcm_count, sizeof(*dais),
 			    GFP_KERNEL);
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 5d70be6..1085090 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -2226,28 +2226,3 @@ struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp)
 
 	return tplg;
 }
-
-int avs_load_topology(struct snd_soc_component *comp, const char *filename)
-{
-	const struct firmware *fw __free(firmware) = NULL;
-	int ret;
-
-	ret = request_firmware(&fw, filename, comp->dev);
-	if (ret < 0) {
-		dev_err(comp->dev, "request topology \"%s\" failed: %d\n", filename, ret);
-		return ret;
-	}
-
-	ret = snd_soc_tplg_component_load(comp, &avs_tplg_ops, fw);
-	if (ret < 0)
-		dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret);
-
-	return ret;
-}
-
-int avs_remove_topology(struct snd_soc_component *comp)
-{
-	snd_soc_tplg_component_remove(comp);
-
-	return 0;
-}
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 189984c..25f3888 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -233,7 +233,4 @@ struct avs_tplg_module {
 extern const struct snd_soc_tplg_ops avs_tplg_ops;
 struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp);
 
-int avs_load_topology(struct snd_soc_component *comp, const char *filename);
-int avs_remove_topology(struct snd_soc_component *comp);
-
 #endif
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index b795bca..919d3f5 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -536,6 +536,7 @@
 	imply SND_SOC_TAC5XX2_SDW
 	select SND_SOC_DMIC
 	select SND_SOC_INTEL_HDA_DSP_COMMON
+	select SND_SOC_SN624X_SDCA_SDW
 	imply SND_SOC_SDW_MOCKUP
 	help
 	  Add support for Intel SoundWire-based platforms connected to
diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c
index 88fc6cb..ec4bda4 100644
--- a/sound/soc/intel/boards/sof_cirrus_common.c
+++ b/sound/soc/intel/boards/sof_cirrus_common.c
@@ -151,7 +151,7 @@ static const char * const cs35l41_name_prefixes[] = { "WL", "WR", "TL", "TR" };
  * UID 0x2 -> TL
  * UID 0x3 -> TR
  * Note: If there are less than 4 Amps, UIDs still map to WL/WR/TL/TR. Dynamic code will only create
- * dai links for UIDs which exist, and ignore non-existant ones. Only 2 or 4 amps are expected.
+ * dai links for UIDs which exist, and ignore non-existent ones. Only 2 or 4 amps are expected.
  * Return number of codecs found.
  */
 static int cs35l41_compute_codec_conf(void)
diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
index 1033f2d..575889a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -531,6 +531,63 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = {
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines);
 
 /* this table is used when there is no I2S codec present */
+
+/*
+ * Senary SN624x on Arrow Lake: one multi-function device on link 0.
+ * Separate mach entries per part ID (adr_d[] is AND, not OR). Amp endpoint
+ * is aggregated like the generic SOC_SDW_DAI_TYPE_AMP shape from
+ * find_acpi_adr_device().
+ */
+static const struct snd_soc_acpi_endpoint sn624x_endpoints[] = {
+	/* Jack */
+	{
+		.num = 0,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	/* Amp */
+	{
+		.num = 1,
+		.aggregated = 1,
+		.group_position = 1,
+		.group_id = 1,
+	},
+	/* DMIC */
+	{
+		.num = 2,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+};
+
+#define SN624X_ARL_SINGLE_ADR(_sym, _adr)				\
+static const struct snd_soc_acpi_adr_device _sym[] = {			\
+	{								\
+		.adr = (_adr),						\
+		.num_endpoints = ARRAY_SIZE(sn624x_endpoints),		\
+		.endpoints = sn624x_endpoints,				\
+		.name_prefix = "sn624x",				\
+	},								\
+}
+
+#define SN624X_ARL_LINK(_sym, _adr_arr)					\
+static const struct snd_soc_acpi_link_adr _sym[] = {			\
+	{								\
+		.mask = BIT(0),						\
+		.num_adr = ARRAY_SIZE(_adr_arr),			\
+		.adr_d = _adr_arr,					\
+	},								\
+	{}								\
+}
+
+SN624X_ARL_SINGLE_ADR(sn6242_single_adr, 0x0000000496624201ull);
+SN624X_ARL_SINGLE_ADR(sn6244_single_adr, 0x0000000496624401ull);
+
+SN624X_ARL_LINK(arl_link_sn6242, sn6242_single_adr);
+SN624X_ARL_LINK(arl_link_sn6244, sn6244_single_adr);
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
 	{
 		.link_mask = BIT(0) | BIT(2) | BIT(3),
@@ -624,6 +681,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
 		.sof_tplg_filename = "sof-arl-es9356.tplg",
 		.get_function_tplg_files = sof_sdw_get_tplg_files,
 	},
+	{
+		.link_mask = BIT(0),
+		.links = arl_link_sn6242,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-arl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
+	{
+		.link_mask = BIT(0),
+		.links = arl_link_sn6244,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-arl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
index 3b9758f..f9c47cc 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -685,6 +685,63 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt712_vb_l2_rt1320_l1[] = {
 };
 
 /* this table is used when there is no I2S codec present */
+
+/*
+ * Senary SN624x on Lunar Lake: one multi-function device on link 0.
+ * Separate mach entries per part ID (adr_d[] is AND, not OR). Amp endpoint
+ * is aggregated like the generic SOC_SDW_DAI_TYPE_AMP shape from
+ * find_acpi_adr_device().
+ */
+static const struct snd_soc_acpi_endpoint sn624x_endpoints[] = {
+	/* Jack */
+	{
+		.num = 0,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	/* Amp */
+	{
+		.num = 1,
+		.aggregated = 1,
+		.group_position = 1,
+		.group_id = 1,
+	},
+	/* DMIC */
+	{
+		.num = 2,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+};
+
+#define SN624X_LNL_SINGLE_ADR(_sym, _adr)				\
+static const struct snd_soc_acpi_adr_device _sym[] = {			\
+	{								\
+		.adr = (_adr),						\
+		.num_endpoints = ARRAY_SIZE(sn624x_endpoints),		\
+		.endpoints = sn624x_endpoints,				\
+		.name_prefix = "sn624x",				\
+	},								\
+}
+
+#define SN624X_LNL_LINK(_sym, _adr_arr)					\
+static const struct snd_soc_acpi_link_adr _sym[] = {			\
+	{								\
+		.mask = BIT(0),						\
+		.num_adr = ARRAY_SIZE(_adr_arr),			\
+		.adr_d = _adr_arr,					\
+	},								\
+	{}								\
+}
+
+SN624X_LNL_SINGLE_ADR(sn6242_single_adr, 0x0000000496624201ull);
+SN624X_LNL_SINGLE_ADR(sn6244_single_adr, 0x0000000496624401ull);
+
+SN624X_LNL_LINK(lnl_link_sn6242, sn6242_single_adr);
+SN624X_LNL_LINK(lnl_link_sn6244, sn6244_single_adr);
+
 /* this table is used when there is no I2S codec present */
 struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
 	/* mockup tests need to be first */
@@ -805,6 +862,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
 		.sof_tplg_filename = "sof-lnl-rt713-l2-rt1320-l13.tplg",
 		.get_function_tplg_files = sof_sdw_get_tplg_files,
 	},
+	{
+		.link_mask = BIT(0),
+		.links = lnl_link_sn6242,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-lnl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
+	{
+		.link_mask = BIT(0),
+		.links = lnl_link_sn6244,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-lnl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index 5965820..e89c5cf 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -1296,6 +1296,63 @@ static const struct snd_soc_acpi_link_adr mtl_cs35l63_x2_link1_link3_fb[] = {
 };
 
 /* this table is used when there is no I2S codec present */
+
+/*
+ * Senary SN624x on Meteor Lake: one multi-function device on link 0.
+ * Separate mach entries per part ID (adr_d[] is AND, not OR). Amp endpoint
+ * is aggregated like the generic SOC_SDW_DAI_TYPE_AMP shape from
+ * find_acpi_adr_device().
+ */
+static const struct snd_soc_acpi_endpoint sn624x_endpoints[] = {
+	/* Jack */
+	{
+		.num = 0,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	/* Amp */
+	{
+		.num = 1,
+		.aggregated = 1,
+		.group_position = 1,
+		.group_id = 1,
+	},
+	/* DMIC */
+	{
+		.num = 2,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+};
+
+#define SN624X_MTL_SINGLE_ADR(_sym, _adr)				\
+static const struct snd_soc_acpi_adr_device _sym[] = {			\
+	{								\
+		.adr = (_adr),						\
+		.num_endpoints = ARRAY_SIZE(sn624x_endpoints),		\
+		.endpoints = sn624x_endpoints,				\
+		.name_prefix = "sn624x",				\
+	},								\
+}
+
+#define SN624X_MTL_LINK(_sym, _adr_arr)					\
+static const struct snd_soc_acpi_link_adr _sym[] = {			\
+	{								\
+		.mask = BIT(0),						\
+		.num_adr = ARRAY_SIZE(_adr_arr),			\
+		.adr_d = _adr_arr,					\
+	},								\
+	{}								\
+}
+
+SN624X_MTL_SINGLE_ADR(sn6242_single_adr, 0x0000000496624201ull);
+SN624X_MTL_SINGLE_ADR(sn6244_single_adr, 0x0000000496624401ull);
+
+SN624X_MTL_LINK(mtl_link_sn6242, sn6242_single_adr);
+SN624X_MTL_LINK(mtl_link_sn6244, sn6244_single_adr);
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
 	/* mockup tests need to be first */
 	{
@@ -1503,6 +1560,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
 		.sof_tplg_filename = "sof-mtl-sdw-cs42l42-l0-max98363-l2.tplg",
 		.get_function_tplg_files = sof_sdw_get_tplg_files,
 	},
+	{
+		.link_mask = BIT(0),
+		.links = mtl_link_sn6242,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-mtl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
+	{
+		.link_mask = BIT(0),
+		.links = mtl_link_sn6244,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-mtl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
index 756bbf8..dd84e97 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -438,6 +438,66 @@ static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l3[] = {
 };
 
 /* this table is used when there is no I2S codec present */
+
+/*
+ * Senary SN624x on Panther Lake: one multi-function device on link 3.
+ * Separate mach entries per part ID (adr_d[] is AND, not OR). ADR version
+ * nibble 0x3 matches the silicon SoundWire version. Amp endpoint is
+ * aggregated like the generic SOC_SDW_DAI_TYPE_AMP shape from
+ * find_acpi_adr_device().
+ */
+static const struct snd_soc_acpi_endpoint sn624x_endpoints[] = {
+	/* Jack */
+	{
+		.num = 0,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+	/* Amp */
+	{
+		.num = 1,
+		.aggregated = 1,
+		.group_position = 1,
+		.group_id = 1,
+	},
+	/* DMIC */
+	{
+		.num = 2,
+		.aggregated = 0,
+		.group_position = 0,
+		.group_id = 0,
+	},
+};
+
+#define SN624X_PTL_SINGLE_ADR(_sym, _adr)				\
+static const struct snd_soc_acpi_adr_device _sym[] = {			\
+	{								\
+		.adr = (_adr),						\
+		.num_endpoints = ARRAY_SIZE(sn624x_endpoints),		\
+		.endpoints = sn624x_endpoints,				\
+		.name_prefix = "sn624x",				\
+	},								\
+}
+
+#define SN624X_PTL_LINK(_sym, _adr_arr)					\
+static const struct snd_soc_acpi_link_adr _sym[] = {			\
+	{								\
+		.mask = BIT(3),						\
+		.num_adr = ARRAY_SIZE(_adr_arr),			\
+		.adr_d = _adr_arr,					\
+	},								\
+	{}								\
+}
+
+SN624X_PTL_SINGLE_ADR(sn6242_single_adr, 0x0003300496624201ull);
+SN624X_PTL_SINGLE_ADR(sn6244_single_adr, 0x0003300496624401ull);
+SN624X_PTL_SINGLE_ADR(sn6247_single_adr, 0x0003300496624701ull);
+
+SN624X_PTL_LINK(ptl_link_sn6242, sn6242_single_adr);
+SN624X_PTL_LINK(ptl_link_sn6244, sn6244_single_adr);
+SN624X_PTL_LINK(ptl_link_sn6247, sn6247_single_adr);
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
 /* Order Priority: mockup > most links > most bit link-mask > alphabetical */
 	{
@@ -531,6 +591,28 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
 		.machine_check = snd_soc_acpi_intel_rt712_vb_no_function_topology,
 		.sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg",
 	},
+
+	{
+		.link_mask = BIT(3),
+		.links = ptl_link_sn6242,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-ptl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
+	{
+		.link_mask = BIT(3),
+		.links = ptl_link_sn6244,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-ptl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
+	{
+		.link_mask = BIT(3),
+		.links = ptl_link_sn6247,
+		.drv_name = "sof_sdw",
+		.sof_tplg_filename = "sof-ptl-sn624x.tplg",
+		.get_function_tplg_files = sof_sdw_get_tplg_files,
+	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines);
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index d36bbc8..7a1589c 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -326,6 +326,11 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 jz4740_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
 	.probe = jz4740_i2s_dai_probe,
 	.startup = jz4740_i2s_startup,
@@ -333,6 +338,8 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
 	.trigger = jz4740_i2s_trigger,
 	.hw_params = jz4740_i2s_hw_params,
 	.set_fmt = jz4740_i2s_set_fmt,
+	.auto_selectable_formats = &jz4740_i2s_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 99bd066..739a819 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -544,11 +544,18 @@ static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
 
 }
 
+static const u64 kirkwood_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
 	.startup	= kirkwood_i2s_startup,
 	.trigger	= kirkwood_i2s_trigger,
 	.hw_params      = kirkwood_i2s_hw_params,
 	.set_fmt        = kirkwood_i2s_set_fmt,
+	.auto_selectable_formats	= &kirkwood_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c
index cfe102a..da0d029 100644
--- a/sound/soc/loongson/loongson_i2s.c
+++ b/sound/soc/loongson/loongson_i2s.c
@@ -220,12 +220,18 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
 	return 0;
 }
 
+static const u64 loongson_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
 static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
 	.probe		= loongson_i2s_dai_probe,
 	.trigger	= loongson_i2s_trigger,
 	.hw_params	= loongson_i2s_hw_params,
 	.set_sysclk	= loongson_i2s_set_dai_sysclk,
 	.set_fmt	= loongson_i2s_set_fmt,
+	.auto_selectable_formats	= &loongson_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 struct snd_soc_dai_driver loongson_i2s_dai = {
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
index d217f93..1cf66ca 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -30,10 +30,9 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 
 	for (i = 0; i < MT2701_BASE_CLK_NUM; i++) {
 		afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]);
-		if (IS_ERR(afe_priv->base_ck[i])) {
-			dev_err(afe->dev, "failed to get %s\n", base_clks[i]);
-			return PTR_ERR(afe_priv->base_ck[i]);
-		}
+		if (IS_ERR(afe_priv->base_ck[i]))
+			return dev_err_probe(afe->dev, PTR_ERR(afe_priv->base_ck[i]),
+					     "failed to get %s\n", base_clks[i]);
 	}
 
 	i2s_num = min(afe_priv->soc->i2s_num, MT2701_BASE_CLK_NUM);
@@ -45,57 +44,49 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 
 		snprintf(name, sizeof(name), "i2s%d_src_sel", i);
 		i2s_path->sel_ck = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_path->sel_ck)) {
-			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_path->sel_ck);
-		}
+		if (IS_ERR(i2s_path->sel_ck))
+			return dev_err_probe(afe->dev, PTR_ERR(i2s_path->sel_ck),
+					     "failed to get %s\n", name);
 
 		snprintf(name, sizeof(name), "i2s%d_src_div", i);
 		i2s_path->div_ck = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_path->div_ck)) {
-			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_path->div_ck);
-		}
+		if (IS_ERR(i2s_path->div_ck))
+			return dev_err_probe(afe->dev, PTR_ERR(i2s_path->div_ck),
+					     "failed to get %s\n", name);
 
 		snprintf(name, sizeof(name), "i2s%d_mclk_en", i);
 		i2s_path->mclk_ck = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_path->mclk_ck)) {
-			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_path->mclk_ck);
-		}
+		if (IS_ERR(i2s_path->mclk_ck))
+			return dev_err_probe(afe->dev, PTR_ERR(i2s_path->mclk_ck),
+				       "failed to get %s\n", name);
 
 		snprintf(name, sizeof(name), "i2so%d_hop_ck", i);
 		i2s_ck = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_ck)) {
-			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_ck);
-		}
+		if (IS_ERR(i2s_ck))
+			return dev_err_probe(afe->dev, PTR_ERR(i2s_ck),
+					     "failed to get %s\n", name);
+
 		i2s_path->hop_ck[SNDRV_PCM_STREAM_PLAYBACK] = i2s_ck;
 
 		snprintf(name, sizeof(name), "i2si%d_hop_ck", i);
 		i2s_ck = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_ck)) {
-			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_ck);
-		}
+		if (IS_ERR(i2s_ck))
+			return dev_err_probe(afe->dev, PTR_ERR(i2s_ck),
+					     "failed to get %s\n", name);
+
 		i2s_path->hop_ck[SNDRV_PCM_STREAM_CAPTURE] = i2s_ck;
 
 		snprintf(name, sizeof(name), "asrc%d_out_ck", i);
 		i2s_path->asrco_ck = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_path->asrco_ck)) {
-			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_path->asrco_ck);
-		}
+		if (IS_ERR(i2s_path->asrco_ck))
+			return dev_err_probe(afe->dev, PTR_ERR(i2s_path->asrco_ck),
+					     "failed to get %s\n", name);
 	}
 
 	/* Some platforms may support BT path */
-	afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd");
-	if (IS_ERR(afe_priv->mrgif_ck)) {
-		if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		afe_priv->mrgif_ck = NULL;
-	}
+	afe_priv->mrgif_ck = devm_clk_get_optional(afe->dev, "audio_mrgif_pd");
+	if (IS_ERR(afe_priv->mrgif_ck))
+		return PTR_ERR(afe_priv->mrgif_ck);
 
 	/*
 	 * Optional HDMI audio clocks. Platforms that do not wire up the
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index d56b498..3c5a765 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -1622,10 +1622,8 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
 			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
-	if (ret) {
-		dev_err(dev, "could not request_irq for asys-isr\n");
+	if (ret)
 		return ret;
-	}
 
 	afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
 	if (IS_ERR(afe->regmap)) {
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
index 778a9dc..af833a8 100644
--- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -366,10 +366,8 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
 							= codec_node_bt_mrg;
 
 	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
-	if (ret) {
-		dev_err(dev, "failed to parse audio-routing: %d\n", ret);
+	if (ret)
 		return ret;
-	}
 
 	priv->i2s1_in_mux_sel_1 = devm_gpiod_get_optional(dev, "i2s1-in-sel-gpio1",
 							  GPIOD_OUT_LOW);
diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
index 84b3d6c..25ea3e2 100644
--- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c
+++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
@@ -137,10 +137,8 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev)
 	}
 
 	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
-	if (ret) {
-		dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+	if (ret)
 		goto put_codec_node;
-	}
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-clk.c b/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
index 6f3e6ac..2326496 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
@@ -43,12 +43,9 @@ int mt6797_init_clock(struct mtk_base_afe *afe)
 
 	for (i = 0; i < CLK_NUM; i++) {
 		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
-		if (IS_ERR(afe_priv->clk[i])) {
-			dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
-				__func__, aud_clks[i],
-				PTR_ERR(afe_priv->clk[i]));
-			return PTR_ERR(afe_priv->clk[i]);
-		}
+		if (IS_ERR(afe_priv->clk[i]))
+			return dev_err_probe(afe->dev, PTR_ERR(afe_priv->clk[i]),
+					     "failed to get clock %s\n", aud_clks[i]);
 	}
 
 	return 0;
@@ -63,21 +60,21 @@ int mt6797_afe_enable_clock(struct mtk_base_afe *afe)
 	if (ret) {
 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
 			__func__, aud_clks[CLK_INFRA_SYS_AUD], ret);
-		goto CLK_INFRA_SYS_AUDIO_ERR;
+		return ret;
 	}
 
 	ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
 	if (ret) {
 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
 			__func__, aud_clks[CLK_INFRA_SYS_AUD_26M], ret);
-		goto CLK_INFRA_SYS_AUD_26M_ERR;
+		goto CLK_INFRA_SYS_AUDIO_ERR;
 	}
 
 	ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD]);
 	if (ret) {
 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
 			__func__, aud_clks[CLK_TOP_MUX_AUD], ret);
-		goto CLK_MUX_AUDIO_ERR;
+		goto CLK_INFRA_SYS_AUD_26M_ERR;
 	}
 
 	ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD],
@@ -93,13 +90,11 @@ int mt6797_afe_enable_clock(struct mtk_base_afe *afe)
 	if (ret) {
 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
 			__func__, aud_clks[CLK_TOP_MUX_AUD_BUS], ret);
-		goto CLK_MUX_AUDIO_INTBUS_ERR;
+		goto CLK_MUX_AUDIO_ERR;
 	}
 
-	return ret;
+	return 0;
 
-CLK_MUX_AUDIO_INTBUS_ERR:
-	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
 CLK_MUX_AUDIO_ERR:
 	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
 CLK_INFRA_SYS_AUD_26M_ERR:
@@ -107,7 +102,7 @@ int mt6797_afe_enable_clock(struct mtk_base_afe *afe)
 CLK_INFRA_SYS_AUDIO_ERR:
 	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
 
-	return 0;
+	return ret;
 }
 
 int mt6797_afe_disable_clock(struct mtk_base_afe *afe)
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index f62a32f2..dfe6772 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -754,10 +754,8 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	/* initial audio related clock */
 	ret = mt6797_init_clock(afe);
-	if (ret) {
-		dev_err(dev, "init clock error\n");
+	if (ret)
 		return ret;
-	}
 
 	/* regmap init */
 	afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
@@ -800,10 +798,8 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
 			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
-	if (ret) {
-		dev_err(dev, "could not request_irq for asys-isr\n");
+	if (ret)
 		return ret;
-	}
 
 	/* init sub_dais */
 	INIT_LIST_HEAD(&afe->sub_dais);
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
index 7a6ad91..e7ecb27 100644
--- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
@@ -334,7 +334,7 @@ static int mt7986_init_clock(struct mtk_base_afe *afe)
 
 	ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks);
 	if (ret)
-		return dev_err_probe(afe->dev, ret, "Failed to get clocks\n");
+		return ret;
 
 	return 0;
 }
@@ -414,7 +414,7 @@ static int mt7986_afe_runtime_resume(struct device *dev)
 
 	ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
 	if (ret)
-		return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+		return ret;
 
 	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
 		return 0;
@@ -484,7 +484,7 @@ static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
 	/* initial audio related clock */
 	ret = mt7986_init_clock(afe);
 	if (ret)
-		return dev_err_probe(dev, ret, "Cannot initialize clocks\n");
+		return ret;
 
 	ret = devm_pm_runtime_enable(dev);
 	if (ret)
@@ -535,7 +535,7 @@ static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
 	ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler,
 			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
 	if (ret)
-		return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n");
+		return ret;
 
 	/* init sub_dais */
 	INIT_LIST_HEAD(&afe->sub_dais);
diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
index fc55ff4..49f5b2b 100644
--- a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
@@ -124,7 +124,7 @@ static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
 
 	ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
 	if (ret)
-		return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+		return ret;
 
 	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
 	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
index f1dc182..4517af9 100644
--- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
@@ -135,10 +135,8 @@ static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
 	}
 
 	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
+	if (ret)
 		goto err_of_node_put;
-	}
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 69cadc9..c95699f 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -997,10 +997,10 @@ static int mt8173_afe_runtime_resume(struct device *dev)
 		goto err_bck0;
 	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S1_M]);
 	if (ret)
-		goto err_i2s1_m;
+		goto err_bck1;
 	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S2_M]);
 	if (ret)
-		goto err_i2s2_m;
+		goto err_i2s1_m;
 
 	/* enable AFE clk */
 	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, 0);
@@ -1018,8 +1018,8 @@ static int mt8173_afe_runtime_resume(struct device *dev)
 
 err_i2s1_m:
 	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]);
-err_i2s2_m:
-	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]);
+err_bck1:
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK1]);
 err_bck0:
 	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]);
 err_top_aud:
@@ -1038,11 +1038,9 @@ static int mt8173_afe_init_audio_clk(struct mtk_base_afe *afe)
 
 	for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
 		afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
-		if (IS_ERR(afe_priv->clocks[i])) {
-			dev_err(afe->dev, "%s devm_clk_get %s fail\n",
-				__func__, aud_clks[i]);
-			return PTR_ERR(afe_priv->clocks[i]);
-		}
+		if (IS_ERR(afe_priv->clocks[i]))
+			return dev_err_probe(afe->dev, PTR_ERR(afe_priv->clocks[i]),
+					     "failed to get clock %s\n", aud_clks[i]);
 	}
 	clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK0], 22579200); /* 22M */
 	clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK1], 24576000); /* 24M */
@@ -1072,7 +1070,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	afe->dev = dev;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret) {
 		dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
 		afe->preallocate_buffers = true;
@@ -1093,10 +1091,8 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	/* initial audio related clock */
 	ret = mt8173_afe_init_audio_clk(afe);
-	if (ret) {
-		dev_err(dev, "mt8173_afe_init_audio_clk fail\n");
+	if (ret)
 		return ret;
-	}
 
 	/* memif % irq initialize*/
 	afe->memif_size = MT8173_AFE_MEMIF_NUM;
@@ -1156,10 +1152,8 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	ret = devm_request_irq(dev, irq_id, mt8173_afe_irq_handler,
 			       0, "Afe_ISR_Handle", (void *)afe);
-	if (ret) {
-		dev_err(dev, "could not request_irq\n");
+	if (ret)
 		goto err_cleanup_components;
-	}
 
 	dev_info(dev, "MT8173 AFE driver initialized.\n");
 	return 0;
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
index 2634699..6ad396e 100644
--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
@@ -766,11 +766,6 @@ static const dai_register_cb dai_register_cbs[] = {
 	mt8183_dai_memif_register,
 };
 
-static void mt8183_afe_release_reserved_mem(void *data)
-{
-	of_reserved_mem_device_release(data);
-}
-
 static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct mtk_base_afe *afe;
@@ -795,16 +790,10 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
 	afe_priv = afe->platform_priv;
 	afe->dev = dev;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret) {
 		dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
 		afe->preallocate_buffers = true;
-	} else {
-		ret = devm_add_action_or_reset(dev,
-					       mt8183_afe_release_reserved_mem,
-					       dev);
-		if (ret)
-			return ret;
 	}
 
 	/* initial audio related clock */
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
index daaca36..62b008b 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
@@ -98,7 +98,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
 		if (ret) {
 			dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_1], ret);
-			return ret;
+			goto ERR_ENABLE_CLK_TOP_MUX_AUD_1;
 		}
 		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
 				     afe_priv->clk[CLK_TOP_APLL1_CK]);
@@ -106,7 +106,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_1],
 				aud_clks[CLK_TOP_APLL1_CK], ret);
-			return ret;
+			goto ERR_SELECT_CLK_TOP_MUX_AUD_1;
 		}
 
 		/* 180.6336 / 8 = 22.5792MHz */
@@ -114,7 +114,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
 		if (ret) {
 			dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret);
-			return ret;
+			goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1;
 		}
 		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
 				     afe_priv->clk[CLK_TOP_APLL1_D8]);
@@ -122,7 +122,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
 				aud_clks[CLK_TOP_APLL1_D8], ret);
-			return ret;
+			goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG1;
 		}
 	} else {
 		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
@@ -131,7 +131,6 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
 				aud_clks[CLK_CLK26M], ret);
-			return ret;
 		}
 		clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
 
@@ -141,12 +140,23 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_1],
 				aud_clks[CLK_CLK26M], ret);
-			return ret;
 		}
 		clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
 	}
 
 	return 0;
+
+ERR_SELECT_CLK_TOP_MUX_AUD_ENG1:
+	clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+		       afe_priv->clk[CLK_CLK26M]);
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1:
+ERR_SELECT_CLK_TOP_MUX_AUD_1:
+	clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+		       afe_priv->clk[CLK_CLK26M]);
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_1:
+	return ret;
 }
 
 static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
@@ -159,7 +169,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
 		if (ret) {
 			dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_2], ret);
-			return ret;
+			goto ERR_ENABLE_CLK_TOP_MUX_AUD_2;
 		}
 		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
 				     afe_priv->clk[CLK_TOP_APLL2_CK]);
@@ -167,7 +177,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_2],
 				aud_clks[CLK_TOP_APLL2_CK], ret);
-			return ret;
+			goto ERR_SELECT_CLK_TOP_MUX_AUD_2;
 		}
 
 		/* 196.608 / 8 = 24.576MHz */
@@ -175,7 +185,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
 		if (ret) {
 			dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret);
-			return ret;
+			goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2;
 		}
 		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
 				     afe_priv->clk[CLK_TOP_APLL2_D8]);
@@ -183,7 +193,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
 				aud_clks[CLK_TOP_APLL2_D8], ret);
-			return ret;
+			goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG2;
 		}
 	} else {
 		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
@@ -192,7 +202,6 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
 				aud_clks[CLK_CLK26M], ret);
-			return ret;
 		}
 		clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
 
@@ -202,12 +211,23 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
 			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[CLK_TOP_MUX_AUD_2],
 				aud_clks[CLK_CLK26M], ret);
-			return ret;
 		}
 		clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
 	}
 
 	return 0;
+
+ERR_SELECT_CLK_TOP_MUX_AUD_ENG2:
+	clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+		       afe_priv->clk[CLK_CLK26M]);
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2:
+ERR_SELECT_CLK_TOP_MUX_AUD_2:
+	clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+		       afe_priv->clk[CLK_CLK26M]);
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_2:
+	return ret;
 }
 
 int mt8186_afe_enable_cgs(struct mtk_base_afe *afe)
@@ -268,7 +288,7 @@ int mt8186_afe_enable_clock(struct mtk_base_afe *afe)
 		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
 			__func__, aud_clks[CLK_MUX_AUDIO],
 			aud_clks[CLK_CLK26M], ret);
-		goto clk_mux_audio_err;
+		goto clk_mux_audio_intbus_err;
 	}
 
 	ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
@@ -295,24 +315,22 @@ int mt8186_afe_enable_clock(struct mtk_base_afe *afe)
 	if (ret) {
 		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
 			__func__, aud_clks[CLK_AFE], ret);
-		goto clk_afe_err;
+		goto clk_mux_audio_h_parent_err;
 	}
 
 	return 0;
 
-clk_afe_err:
-	clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
 clk_mux_audio_h_parent_err:
-clk_mux_audio_intbus_parent_err:
 	mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
-clk_mux_audio_intbus_err:
+clk_mux_audio_intbus_parent_err:
 	clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
-clk_mux_audio_err:
+clk_mux_audio_intbus_err:
 	clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
-clk_infra_sys_audio_err:
-	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
-clk_infra_audio_26m_err:
+clk_mux_audio_err:
 	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+clk_infra_audio_26m_err:
+	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+clk_infra_sys_audio_err:
 
 	return ret;
 }
@@ -335,7 +353,9 @@ int mt8186_apll1_enable(struct mtk_base_afe *afe)
 	int ret;
 
 	/* setting for APLL */
-	apll1_mux_setting(afe, true);
+	ret = apll1_mux_setting(afe, true);
+	if (ret)
+		return ret;
 
 	ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]);
 	if (ret) {
@@ -360,9 +380,9 @@ int mt8186_apll1_enable(struct mtk_base_afe *afe)
 	return 0;
 
 err_clk_apll1_tuner:
-	clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
-err_clk_apll22m:
 	clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+err_clk_apll22m:
+	apll1_mux_setting(afe, false);
 
 	return ret;
 }
@@ -388,7 +408,9 @@ int mt8186_apll2_enable(struct mtk_base_afe *afe)
 	int ret;
 
 	/* setting for APLL */
-	apll2_mux_setting(afe, true);
+	ret = apll2_mux_setting(afe, true);
+	if (ret)
+		return ret;
 
 	ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]);
 	if (ret) {
@@ -413,9 +435,9 @@ int mt8186_apll2_enable(struct mtk_base_afe *afe)
 	return 0;
 
 err_clk_apll2_tuner:
-	clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
-err_clk_apll24m:
 	clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+err_clk_apll24m:
+	apll2_mux_setting(afe, false);
 
 	return ret;
 }
@@ -498,7 +520,7 @@ int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
 		if (ret) {
 			dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
 				__func__, aud_clks[m_sel_id], ret);
-			return ret;
+			goto ERR_ENABLE_MCLK;
 		}
 		ret = clk_set_parent(afe_priv->clk[m_sel_id],
 				     afe_priv->clk[apll_clk_id]);
@@ -506,7 +528,7 @@ int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
 			dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
 				__func__, aud_clks[m_sel_id],
 				aud_clks[apll_clk_id], ret);
-			return ret;
+			goto ERR_SELECT_MCLK;
 		}
 	}
 
@@ -515,16 +537,25 @@ int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
 	if (ret) {
 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
 			__func__, aud_clks[div_clk_id], ret);
-		return ret;
+		goto ERR_ENABLE_MCLK_DIV;
 	}
 	ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
 	if (ret) {
 		dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
 			__func__, aud_clks[div_clk_id], rate, ret);
-		return ret;
+		goto ERR_SET_MCLK_RATE;
 	}
 
 	return 0;
+
+ERR_SET_MCLK_RATE:
+	clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+ERR_ENABLE_MCLK_DIV:
+ERR_SELECT_MCLK:
+	if (m_sel_id >= 0)
+		clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+ERR_ENABLE_MCLK:
+	return ret;
 }
 
 void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id)
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
index aced8e7..1cff2a6 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
@@ -143,6 +143,7 @@ static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable)
 		ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON);
 		if (ret) {
 			dev_dbg(dev, "%s(), MOSI DAT ON select fail!\n", __func__);
+			mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF);
 			return ret;
 		}
 	} else {
@@ -154,7 +155,8 @@ static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable)
 
 		ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF);
 		if (ret) {
-			dev_dbg(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
+			dev_dbg(dev, "%s(), MOSI CLK OFF select fail!\n", __func__);
+			mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON);
 			return ret;
 		}
 	}
@@ -176,6 +178,7 @@ static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable)
 		ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON);
 		if (ret) {
 			dev_dbg(dev, "%s(), MISO DAT ON select fail!\n", __func__);
+			mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF);
 			return ret;
 		}
 	} else {
@@ -188,6 +191,7 @@ static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable)
 		ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF);
 		if (ret) {
 			dev_dbg(dev, "%s(), MISO CLK OFF select fail!\n", __func__);
+			mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON);
 			return ret;
 		}
 	}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
index 44a521c..2f50f78 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
@@ -2743,7 +2743,11 @@ static int mt8186_afe_runtime_resume(struct device *dev)
 		goto skip_regmap;
 
 	regcache_cache_only(afe->regmap, false);
-	regcache_sync(afe->regmap);
+	ret = regcache_sync(afe->regmap);
+	if (ret) {
+		regcache_cache_only(afe->regmap, true);
+		return ret;
+	}
 
 	/* enable audio sys DCM for power saving */
 	regmap_update_bits(afe_priv->infracfg, PERI_BUS_DCM_CTRL, BIT(29), BIT(29));
@@ -2836,7 +2840,7 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
 	afe_priv = afe->platform_priv;
 	afe->dev = &pdev->dev;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret) {
 		dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
 		afe->preallocate_buffers = true;
@@ -2848,10 +2852,8 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	/* init audio related clock */
 	ret = mt8186_init_clock(afe);
-	if (ret) {
-		dev_err(dev, "init clock error, ret %d\n", ret);
+	if (ret)
 		return ret;
-	}
 
 	/* init memif */
 	afe->memif_32bit_supported = 0;
@@ -2881,15 +2883,14 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	/* request irq */
 	irq_id = platform_get_irq(pdev, 0);
-	if (irq_id <= 0)
-		return dev_err_probe(dev, irq_id < 0 ? irq_id : -ENXIO,
-				     "no irq found");
+	if (irq_id < 0)
+		return irq_id;
 
 	ret = devm_request_irq(dev, irq_id, mt8186_afe_irq_handler,
 			       IRQF_TRIGGER_NONE,
 			       "Afe_ISR_Handle", (void *)afe);
 	if (ret)
-		return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+		return ret;
 
 	ret = enable_irq_wake(irq_id);
 	if (ret < 0)
@@ -2953,10 +2954,8 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
 					      &mt8186_afe_component,
 					      afe->dai_drivers,
 					      afe->num_dai_drivers);
-	if (ret) {
-		dev_err(dev, "err_dai_component\n");
+	if (ret)
 		goto err_pm_disable;
-	}
 
 	ret = pm_runtime_put_sync(dev);
 	if (ret) {
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index 7b1f5d0..ab4ce5e 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -3199,7 +3199,7 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
 	struct regmap *infra_ao;
 	int i, irq_id, ret;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret)
 		dev_dbg(dev, "failed to assign memory region: %d\n", ret);
 
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-clk.c b/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
index fc7a7a7..594c214 100644
--- a/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
@@ -454,30 +454,47 @@ int mt8189_apll1_enable(struct mtk_base_afe *afe)
 
 	ret = mt8189_afe_enable_top_cg(afe, MT8189_CG_APLL1_CK);
 	if (ret)
-		return ret;
+		goto err_clear_mux_setting;
 
 	ret = mt8189_afe_enable_top_cg(afe, MT8189_PDN_APLL_TUNER1);
 	if (ret)
-		return ret;
+		goto err_disable_apll1_ck;
 
 	/* sel 44.1kHz:1, apll_div:7, upper bound:3 */
-	regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
-			   XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT |
-			   UPPER_BOUND_MASK_SFT,
-			   (0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
-			   (3 << UPPER_BOUND_SFT));
+	ret = regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+				 XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT |
+				 UPPER_BOUND_MASK_SFT,
+				 (0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
+				 (3 << UPPER_BOUND_SFT));
+	if (ret)
+		goto err_disable_apll_tuner1;
 
 	/* apll1 freq tuner enable */
-	regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
-			   FREQ_TUNER_EN_MASK_SFT,
-			   0x1 << FREQ_TUNER_EN_SFT);
+	ret = regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+				 FREQ_TUNER_EN_MASK_SFT,
+				 0x1 << FREQ_TUNER_EN_SFT);
+	if (ret)
+		goto err_disable_apll_tuner1;
 
 	/* audio apll1 on */
 	ret = mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_APLL1_EN_ON);
 	if (ret)
-		return ret;
+		goto err_clear_freq_tuner_en;
 
 	return 0;
+
+err_clear_freq_tuner_en:
+	regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+			   FREQ_TUNER_EN_MASK_SFT,
+			   0x0);
+err_disable_apll_tuner1:
+	mt8189_afe_disable_top_cg(afe, MT8189_PDN_APLL_TUNER1);
+err_disable_apll1_ck:
+	mt8189_afe_disable_top_cg(afe, MT8189_CG_APLL1_CK);
+err_clear_mux_setting:
+	apll1_mux_setting(afe, false);
+
+	return ret;
 }
 
 void mt8189_apll1_disable(struct mtk_base_afe *afe)
@@ -506,30 +523,47 @@ int mt8189_apll2_enable(struct mtk_base_afe *afe)
 
 	ret = mt8189_afe_enable_top_cg(afe, MT8189_CG_APLL2_CK);
 	if (ret)
-		return ret;
+		goto err_clear_mux_setting;
 
 	ret = mt8189_afe_enable_top_cg(afe, MT8189_PDN_APLL_TUNER2);
 	if (ret)
-		return ret;
+		goto err_disable_apll2_ck;
 
 	/* sel 48kHz: 2, apll_div: 7, upper bound: 3*/
-	regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
-			   XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT |
-			   UPPER_BOUND_MASK_SFT,
-			   (0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
-			   (3 << UPPER_BOUND_SFT));
+	ret = regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+				 XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT |
+				 UPPER_BOUND_MASK_SFT,
+				 (0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
+				 (3 << UPPER_BOUND_SFT));
+	if (ret)
+		goto err_disable_apll_tuner2;
 
 	/* apll2 freq tuner enable */
-	regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
-			   FREQ_TUNER_EN_MASK_SFT,
-			   0x1 << FREQ_TUNER_EN_SFT);
+	ret = regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+				 FREQ_TUNER_EN_MASK_SFT,
+				 0x1 << FREQ_TUNER_EN_SFT);
+	if (ret)
+		goto err_disable_apll_tuner2;
 
 	/* audio apll2 on */
 	ret = mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_APLL2_EN_ON);
 	if (ret)
-		return ret;
+		goto err_clear_freq_tuner_en;
 
 	return 0;
+
+err_clear_freq_tuner_en:
+	regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+			   FREQ_TUNER_EN_MASK_SFT,
+			   0x0);
+err_disable_apll_tuner2:
+	mt8189_afe_disable_top_cg(afe, MT8189_PDN_APLL_TUNER2);
+err_disable_apll2_ck:
+	mt8189_afe_disable_top_cg(afe, MT8189_CG_APLL2_CK);
+err_clear_mux_setting:
+	apll2_mux_setting(afe, false);
+
+	return ret;
 }
 
 void mt8189_apll2_disable(struct mtk_base_afe *afe)
@@ -605,7 +639,7 @@ int mt8189_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
 		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[m_sel_id],
 						afe_priv->clk[apll_clk_id]);
 		if (ret)
-			return ret;
+			goto err_disable_m_sel_clk;
 	}
 
 	/* enable div, set rate */
@@ -616,13 +650,21 @@ int mt8189_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
 
 	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
 	if (ret)
-		return ret;
+		goto err_disable_m_sel_clk;
 
 	ret = mt8189_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
 	if (ret)
-		return ret;
+		goto err_disable_div_clk;
 
 	return 0;
+
+err_disable_div_clk:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
+err_disable_m_sel_clk:
+	if (m_sel_id >= 0)
+		mt8189_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
+
+	return ret;
 }
 
 int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id)
@@ -633,8 +675,8 @@ int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id)
 
 	dev_dbg(afe->dev, "mck_id: %d.\n", mck_id);
 
-	if (mck_id < 0) {
-		dev_err(afe->dev, "mck_id = %d < 0\n", mck_id);
+	if (mck_id >= MT8189_MCK_NUM || mck_id < 0) {
+		dev_err(afe->dev, "mck_id = %d\n", mck_id);
 		return -EINVAL;
 	}
 
@@ -658,17 +700,36 @@ int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id)
 int mt8189_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
 {
 	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int ret;
 
 	/* bus clock for AFE internal access, like AFE SRAM */
-	mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
-	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS],
-				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS],
+					afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	if (ret)
+		goto err_disable_audiointbus_clk;
+
 	/* enable audio clock source */
-	mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
-	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
-				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	if (ret)
+		goto err_disable_audiointbus_clk;
+
+	ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+					afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	if (ret)
+		goto err_disable_audio_h_clk;
 
 	return 0;
+
+err_disable_audio_h_clk:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+err_disable_audiointbus_clk:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
+
+	return ret;
 }
 
 int mt8189_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
@@ -732,10 +793,9 @@ int mt8189_init_clock(struct mtk_base_afe *afe)
 
 	for (i = 0; i < MT8189_CLK_NUM; i++) {
 		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
-		if (IS_ERR(afe_priv->clk[i])) {
-			dev_err(afe->dev, "devm_clk_get %s fail\n", aud_clks[i]);
-			return PTR_ERR(afe_priv->clk[i]);
-		}
+		if (IS_ERR(afe_priv->clk[i]))
+			return dev_err_probe(afe->dev, PTR_ERR(afe_priv->clk[i]),
+					     "failed to get clock %s\n", aud_clks[i]);
 	}
 
 	ret = mt8189_afe_disable_apll(afe);
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
index 77cf2b60..c0f340a 100644
--- a/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
@@ -2332,20 +2332,40 @@ static int mt8189_afe_runtime_resume(struct device *dev)
 	}
 
 	regcache_cache_only(afe->regmap, false);
-	regcache_sync(afe->regmap);
+	ret = regcache_sync(afe->regmap);
+	if (ret)
+		goto err_set_cache_only;
 
 	/* set audio 26M request */
-	regmap_update_bits(afe->regmap, AFE_SPM_CONTROL_REQ, 0x1, 0x1);
-	regmap_update_bits(afe->regmap, AFE_CBIP_CFG0, 0x1, 0x1);
+	ret = regmap_update_bits(afe->regmap, AFE_SPM_CONTROL_REQ, 0x1, 0x1);
+	if (ret)
+		goto err_set_cache_only;
+
+	ret = regmap_update_bits(afe->regmap, AFE_CBIP_CFG0, 0x1, 0x1);
+	if (ret)
+		goto err_clear_26m_req;
 
 	/* force cpu use 8_24 format when writing 32bit data */
-	regmap_update_bits(afe->regmap, AFE_MEMIF_CON0,
-			   CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
+	ret = regmap_update_bits(afe->regmap, AFE_MEMIF_CON0,
+				 CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
+	if (ret)
+		goto err_clear_26m_req;
 
 	/* enable AFE */
-	mt8189_afe_enable_main_clock(afe);
+	ret = mt8189_afe_enable_main_clock(afe);
+	if (ret)
+		goto err_clear_26m_req;
 
 	return 0;
+
+err_clear_26m_req:
+	regmap_update_bits(afe->regmap,
+			   AFE_SPM_CONTROL_REQ, 0x1, 0x0);
+err_set_cache_only:
+	regcache_cache_only(afe->regmap, true);
+	mt8189_afe_disable_reg_rw_clk(afe);
+
+	return ret;
 }
 
 static int mt8189_afe_component_probe(struct snd_soc_component *component)
@@ -2421,11 +2441,6 @@ static const struct reg_sequence mt8189_cg_patch[] = {
 	{ AUDIO_TOP_CON4, 0x361c },
 };
 
-static void mt8189_afe_release_reserved_mem(void *data)
-{
-	of_reserved_mem_device_release(data);
-}
-
 static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
 {
 	int ret, i;
@@ -2439,16 +2454,9 @@ static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = of_reserved_mem_device_init(dev);
-	if (ret) {
+	ret = devm_of_reserved_mem_device_init(dev);
+	if (ret)
 		dev_warn(dev, "failed to assign memory region: %d\n", ret);
-	} else {
-		ret = devm_add_action_or_reset(dev,
-					       mt8189_afe_release_reserved_mem,
-					       dev);
-		if (ret)
-			return ret;
-	}
 
 	afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
 	if (!afe)
@@ -2466,13 +2474,12 @@ static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(afe->base_addr))
-		return dev_err_probe(dev, PTR_ERR(afe->base_addr),
-				     "AFE base_addr not found\n");
+		return PTR_ERR(afe->base_addr);
 
 	/* init audio related clock */
 	ret = mt8189_init_clock(afe);
 	if (ret)
-		return dev_err_probe(dev, ret, "init clock error.\n");
+		return ret;
 
 	/* init memif */
 	/* IPM2.0 no need banding */
@@ -2506,13 +2513,13 @@ static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
 	/* request irq */
 	irq_id = platform_get_irq(pdev, 0);
 	if (irq_id < 0)
-		return dev_err_probe(dev, irq_id, "no irq found");
+		return irq_id;
 
 	ret = devm_request_irq(dev, irq_id, mt8189_afe_irq_handler,
 			       IRQF_TRIGGER_NONE,
 			       "Afe_ISR_Handle", afe);
 	if (ret)
-		return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+		return ret;
 
 	/* init sub_dais */
 	INIT_LIST_HEAD(&afe->sub_dais);
@@ -2581,10 +2588,8 @@ static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
 					      &mt8189_afe_component,
 					      afe->dai_drivers,
 					      afe->num_dai_drivers);
-	if (ret) {
-		dev_err(dev, "afe component err: %d\n", ret);
+	if (ret)
 		return ret;
-	}
 
 	return 0;
 
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c b/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
index 94c49a6..c9e80ef 100644
--- a/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
@@ -485,6 +485,7 @@ static int mtk_apll_event(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	int ret;
 
 	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
 		__func__, w->name, event);
@@ -492,9 +493,11 @@ static int mtk_apll_event(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (strcmp(w->name, APLL1_W_NAME) == 0)
-			mt8189_apll1_enable(afe);
+			ret = mt8189_apll1_enable(afe);
 		else
-			mt8189_apll2_enable(afe);
+			ret = mt8189_apll2_enable(afe);
+		if (ret)
+			return ret;
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		if (strcmp(w->name, APLL1_W_NAME) == 0)
@@ -516,6 +519,7 @@ static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
 	struct mtk_afe_i2s_priv *i2s_priv;
+	int ret;
 
 	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
 		__func__, w->name, event);
@@ -526,17 +530,18 @@ static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		mt8189_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+		ret = mt8189_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		i2s_priv->mclk_rate = 0;
-		mt8189_mck_disable(afe, i2s_priv->mclk_id);
+		ret = mt8189_mck_disable(afe, i2s_priv->mclk_id);
 		break;
 	default:
+		ret = 0;
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
 static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
@@ -1282,6 +1287,9 @@ static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
 	    dir != SND_SOC_CLOCK_OUT)
 		return -EINVAL;
 
+	if (!freq)
+		return -EINVAL;
+
 	i2s_priv = afe_priv->dai_priv[dai->id];
 	if (!i2s_priv)
 		return -EINVAL;
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c b/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
index 5d68a55..e113c52 100644
--- a/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
@@ -261,22 +261,24 @@ static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
 	struct mt8189_afe_private *afe_priv = afe->platform_priv;
 	int dai_id = get_tdm_id_by_name(w->name);
 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+	int ret;
 
 	dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, bck: %d\n",
 		w->name, event, dai_id, tdm_priv->bck_rate);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		mt8189_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+		ret = mt8189_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		mt8189_mck_disable(afe, tdm_priv->bck_id);
+		ret = mt8189_mck_disable(afe, tdm_priv->bck_id);
 		break;
 	default:
+		ret = 0;
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
 static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
@@ -288,23 +290,25 @@ static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
 	struct mt8189_afe_private *afe_priv = afe->platform_priv;
 	int dai_id = get_tdm_id_by_name(w->name);
 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+	int ret;
 
 	dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, mclk %d\n",
 		w->name, event, dai_id, tdm_priv->mclk_rate);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		mt8189_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+		ret = mt8189_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		tdm_priv->mclk_rate = 0;
-		mt8189_mck_disable(afe, tdm_priv->mclk_id);
+		ret = mt8189_mck_disable(afe, tdm_priv->mclk_id);
 		break;
 	default:
+		ret = 0;
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
 static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
@@ -379,6 +383,9 @@ static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
 	int apll;
 	int apll_rate;
 
+	if (freq <= 0)
+		return -EINVAL;
+
 	apll = mt8189_get_apll_by_rate(afe, freq);
 	apll_rate = mt8189_get_apll_rate(afe, apll);
 
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
index db0ae44..e4ecd23 100644
--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
@@ -2155,11 +2155,6 @@ static const dai_register_cb dai_register_cbs[] = {
 	mt8192_dai_memif_register,
 };
 
-static void mt8192_afe_release_reserved_mem(void *data)
-{
-	of_reserved_mem_device_release(data);
-}
-
 static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct mtk_base_afe *afe;
@@ -2185,14 +2180,10 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
 
 	afe->dev = dev;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret) {
 		dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
 		afe->preallocate_buffers = true;
-	} else {
-		ret = devm_add_action_or_reset(dev, mt8192_afe_release_reserved_mem, dev);
-		if (ret)
-			return ret;
 	}
 
 	/* init audio related clock */
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
index bc0a634..52c3381 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
@@ -3013,7 +3013,7 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
 	struct reset_control *rstc;
 	int i, irq_id, ret;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to assign memory region\n");
 
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
index a1ae832..dcee037 100644
--- a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
@@ -2309,11 +2309,6 @@ static const struct reg_sequence mt8196_cg_patch[] = {
 	{ AUDIO_TOP_CON4, 0x361c },
 };
 
-static void mt8196_afe_release_reserved_mem(void *data)
-{
-	of_reserved_mem_device_release(data);
-}
-
 static int mt8196_afe_pcm_dev_probe(struct platform_device *pdev)
 {
 	int ret, i;
@@ -2327,14 +2322,9 @@ static int mt8196_afe_pcm_dev_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = of_reserved_mem_device_init(dev);
-	if (ret) {
+	ret = devm_of_reserved_mem_device_init(dev);
+	if (ret)
 		dev_err(dev, "failed to assign memory region: %d\n", ret);
-	} else {
-		ret = devm_add_action_or_reset(dev, mt8196_afe_release_reserved_mem, dev);
-		if (ret)
-			return ret;
-	}
 
 	afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
 	if (!afe)
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index a77cd51..e46896a 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -691,6 +691,14 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE)
 
+static const u64 mxs_saif_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops mxs_saif_dai_ops = {
 	.startup = mxs_saif_startup,
 	.shutdown = mxs_saif_shutdown,
@@ -699,6 +707,8 @@ static const struct snd_soc_dai_ops mxs_saif_dai_ops = {
 	.hw_params = mxs_saif_hw_params,
 	.set_sysclk = mxs_saif_set_dai_sysclk,
 	.set_fmt = mxs_saif_set_dai_fmt,
+	.auto_selectable_formats = &mxs_saif_dai_selectable_formats,
+	.num_auto_selectable_formats = 1,
 };
 
 static struct snd_soc_dai_driver mxs_saif_dai = {
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index fbbce81..f9066fb 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -339,6 +339,10 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai)
 		SNDRV_PCM_FMTBIT_S24_3LE | \
 		SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 mmp_sspa_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
 	.probe		= mmp_sspa_probe,
 	.startup	= mmp_sspa_startup,
@@ -348,6 +352,8 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
 	.set_sysclk	= mmp_sspa_set_dai_sysclk,
 	.set_pll	= mmp_sspa_set_dai_pll,
 	.set_fmt	= mmp_sspa_set_dai_fmt,
+	.auto_selectable_formats	= &mmp_sspa_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver mmp_sspa_dai = {
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 3a0abcb..9a98246 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -809,6 +809,15 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
 
 #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const u64 pxa_ssp_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
 	.probe		= pxa_ssp_probe,
 	.remove		= pxa_ssp_remove,
@@ -820,6 +829,8 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
 	.set_fmt	= pxa_ssp_set_dai_fmt,
 	.set_tdm_slot	= pxa_ssp_set_dai_tdm_slot,
 	.set_tristate	= pxa_ssp_set_dai_tristate,
+	.auto_selectable_formats	= &pxa_ssp_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver pxa_ssp_dai = {
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index fe1df78..008cf5a 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -328,6 +328,10 @@ static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
 		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
 		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 
+static const u64 pxa_i2s_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
 	.probe		= pxa2xx_i2s_probe,
 	.remove		= pxa2xx_i2s_remove,
@@ -337,6 +341,8 @@ static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
 	.hw_params	= pxa2xx_i2s_hw_params,
 	.set_fmt	= pxa2xx_i2s_set_dai_fmt,
 	.set_sysclk	= pxa2xx_i2s_set_dai_sysclk,
+	.auto_selectable_formats	= &pxa_i2s_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver pxa_i2s_dai = {
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 4f09fdd..cd4f82b 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -551,7 +551,7 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
 						 prtd->stream_id,
 						 CMD_CLOSE);
 				/*
-				 * vaild stream ids start from 1, So we are
+				 * valid stream ids start from 1, So we are
 				 * toggling this between 1 and 2.
 				 */
 				prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
index 9fe8a63..b1587f4 100644
--- a/sound/soc/renesas/rz-ssi.c
+++ b/sound/soc/renesas/rz-ssi.c
@@ -900,6 +900,13 @@ static int rz_ssi_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 rz_ssi_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
 	.probe		= rz_ssi_dai_probe,
 	.startup	= rz_ssi_startup,
@@ -907,6 +914,8 @@ static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
 	.trigger	= rz_ssi_dai_trigger,
 	.set_fmt	= rz_ssi_dai_set_fmt,
 	.hw_params	= rz_ssi_dai_hw_params,
+	.auto_selectable_formats	= &rz_ssi_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_pcm_hardware rz_ssi_pcm_hardware = {
diff --git a/sound/soc/renesas/siu_dai.c b/sound/soc/renesas/siu_dai.c
index 85dee90..fff6ef8 100644
--- a/sound/soc/renesas/siu_dai.c
+++ b/sound/soc/renesas/siu_dai.c
@@ -688,12 +688,18 @@ static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	return ret;
 }
 
+static const u64 siu_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops siu_dai_ops = {
 	.startup	= siu_dai_startup,
 	.shutdown	= siu_dai_shutdown,
 	.prepare	= siu_dai_prepare,
 	.set_sysclk	= siu_dai_set_sysclk,
 	.set_fmt	= siu_dai_set_fmt,
+	.auto_selectable_formats	= &siu_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver siu_i2s_dai = {
diff --git a/sound/soc/renesas/ssi.c b/sound/soc/renesas/ssi.c
index 96cf523..f00067b 100644
--- a/sound/soc/renesas/ssi.c
+++ b/sound/soc/renesas/ssi.c
@@ -329,6 +329,17 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |	\
 	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
 
+static const u64 ssi_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_GATED	|
+	SND_SOC_POSSIBLE_DAIFMT_CONT	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops ssi_dai_ops = {
 	.startup	= ssi_startup,
 	.shutdown	= ssi_shutdown,
@@ -337,6 +348,8 @@ static const struct snd_soc_dai_ops ssi_dai_ops = {
 	.set_sysclk	= ssi_set_sysclk,
 	.set_clkdiv	= ssi_set_clkdiv,
 	.set_fmt	= ssi_set_fmt,
+	.auto_selectable_formats	= &ssi_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver sh4_ssi_dai[] = {
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 261f36d..ef3f658 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -537,13 +537,26 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 rockchip_i2s_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
-	.probe = rockchip_i2s_dai_probe,
-	.hw_params = rockchip_i2s_hw_params,
-	.set_bclk_ratio	= rockchip_i2s_set_bclk_ratio,
-	.set_sysclk = rockchip_i2s_set_sysclk,
-	.set_fmt = rockchip_i2s_set_fmt,
-	.trigger = rockchip_i2s_trigger,
+	.probe				= rockchip_i2s_dai_probe,
+	.hw_params			= rockchip_i2s_hw_params,
+	.set_bclk_ratio			= rockchip_i2s_set_bclk_ratio,
+	.set_sysclk			= rockchip_i2s_set_sysclk,
+	.set_fmt			= rockchip_i2s_set_fmt,
+	.trigger			= rockchip_i2s_trigger,
+	.auto_selectable_formats	= &rockchip_i2s_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver rockchip_i2s_dai = {
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index 5ef7f10..983319a 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -826,14 +826,27 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static const u64 rockchip_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
-	.probe = rockchip_i2s_tdm_dai_probe,
-	.hw_params = rockchip_i2s_tdm_hw_params,
-	.set_bclk_ratio	= rockchip_i2s_tdm_set_bclk_ratio,
-	.set_fmt = rockchip_i2s_tdm_set_fmt,
-	.set_sysclk = rockchip_i2s_tdm_set_sysclk,
-	.set_tdm_slot = rockchip_dai_tdm_slot,
-	.trigger = rockchip_i2s_tdm_trigger,
+	.probe				= rockchip_i2s_tdm_dai_probe,
+	.hw_params			= rockchip_i2s_tdm_hw_params,
+	.set_bclk_ratio			= rockchip_i2s_tdm_set_bclk_ratio,
+	.set_fmt			= rockchip_i2s_tdm_set_fmt,
+	.set_sysclk			= rockchip_i2s_tdm_set_sysclk,
+	.set_tdm_slot			= rockchip_dai_tdm_slot,
+	.trigger			= rockchip_i2s_tdm_trigger,
+	.auto_selectable_formats	= &rockchip_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_component_driver rockchip_i2s_tdm_component = {
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index 343fda4..0720748 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -381,11 +381,17 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 rockchip_pdm_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF;
+
 static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
-	.probe = rockchip_pdm_dai_probe,
-	.set_fmt = rockchip_pdm_set_fmt,
-	.trigger = rockchip_pdm_trigger,
-	.hw_params = rockchip_pdm_hw_params,
+	.probe				= rockchip_pdm_dai_probe,
+	.set_fmt			= rockchip_pdm_set_fmt,
+	.trigger			= rockchip_pdm_trigger,
+	.hw_params			= rockchip_pdm_hw_params,
+	.auto_selectable_formats	= &rockchip_pdm_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define ROCKCHIP_PDM_RATES SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index 30b5e71..9dfe46f 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -957,16 +957,29 @@ static int rockchip_sai_set_sysclk(struct snd_soc_dai *dai, int stream,
 	return 0;
 }
 
+static const u64 rockchip_sai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops rockchip_sai_dai_ops = {
-	.probe = rockchip_sai_dai_probe,
-	.startup = rockchip_sai_startup,
-	.shutdown = rockchip_sai_shutdown,
-	.hw_params = rockchip_sai_hw_params,
-	.set_fmt = rockchip_sai_set_fmt,
-	.set_sysclk = rockchip_sai_set_sysclk,
-	.prepare = rockchip_sai_prepare,
-	.trigger = rockchip_sai_trigger,
-	.set_tdm_slot = rockchip_sai_set_tdm_slot,
+	.probe				= rockchip_sai_dai_probe,
+	.startup			= rockchip_sai_startup,
+	.shutdown			= rockchip_sai_shutdown,
+	.hw_params			= rockchip_sai_hw_params,
+	.set_fmt			= rockchip_sai_set_fmt,
+	.set_sysclk			= rockchip_sai_set_sysclk,
+	.prepare			= rockchip_sai_prepare,
+	.trigger			= rockchip_sai_trigger,
+	.set_tdm_slot			= rockchip_sai_set_tdm_slot,
+	.auto_selectable_formats	= &rockchip_sai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_driver rockchip_sai_dai = {
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index d865997..1a5b53f 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -374,17 +374,15 @@ static int aries_late_probe(struct snd_soc_card *card)
 	irq = gpiod_to_irq(priv->gpio_headset_detect);
 	if (irq < 0) {
 		dev_err(card->dev, "Failed to map headset detect gpio to irq");
-		return -EINVAL;
+		return irq;
 	}
 
 	ret = devm_request_threaded_irq(card->dev, irq, NULL,
 			headset_det_irq_thread,
 			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
 			IRQF_ONESHOT, "headset_detect", priv);
-	if (ret) {
-		dev_err(card->dev, "Failed to request headset detect irq");
+	if (ret)
 		return ret;
-	}
 
 	headset_button_gpio[0].data = priv;
 	headset_button_gpio[0].desc = priv->gpio_headset_key;
@@ -623,10 +621,8 @@ static int aries_audio_probe(struct platform_device *pdev)
 	if (ret < 0) {
 		/* Backwards compatible way */
 		ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
-		if (ret < 0) {
-			dev_err(dev, "Audio routing invalid/unspecified\n");
+		if (ret < 0)
 			return ret;
-		}
 	}
 
 	aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt;
@@ -671,10 +667,8 @@ static int aries_audio_probe(struct platform_device *pdev)
 
 	ret = devm_snd_soc_register_component(dev, &aries_component,
 				aries_ext_dai, ARRAY_SIZE(aries_ext_dai));
-	if (ret < 0) {
-		dev_err(dev, "Failed to register component: %d\n", ret);
+	if (ret < 0)
 		goto out;
-	}
 
 	ret = devm_snd_soc_register_card(dev, card);
 	if (ret)
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 309f024..8430686 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -499,10 +499,9 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 		return PTR_ERR(pcm->regs);
 
 	pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus");
-	if (IS_ERR(pcm->cclk)) {
-		dev_err(&pdev->dev, "failed to get audio-bus clock\n");
-		return PTR_ERR(pcm->cclk);
-	}
+	if (IS_ERR(pcm->cclk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(pcm->cclk),
+				     "failed to get audio-bus clock\n");
 	ret = clk_prepare_enable(pcm->cclk);
 	if (ret)
 		return ret;
@@ -512,8 +511,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 
 	pcm->pclk = devm_clk_get(&pdev->dev, "pcm");
 	if (IS_ERR(pcm->pclk)) {
-		dev_err(&pdev->dev, "failed to get pcm clock\n");
-		ret = PTR_ERR(pcm->pclk);
+		ret = dev_err_probe(&pdev->dev, PTR_ERR(pcm->pclk),
+				    "failed to get pcm clock\n");
 		goto err_dis_cclk;
 	}
 	ret = clk_prepare_enable(pcm->pclk);
@@ -535,19 +534,15 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 
 	ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
 						 NULL, NULL, NULL);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
+	if (ret)
 		goto err_dis_pclk;
-	}
 
 	pm_runtime_enable(&pdev->dev);
 
 	ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
 					 &s3c_pcm_dai[pdev->id], 1);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
+	if (ret != 0)
 		goto err_dis_pm;
-	}
 
 	return 0;
 
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 53eaaba..719083e 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -415,19 +415,15 @@ static int spdif_probe(struct platform_device *pdev)
 
 	ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
 						 NULL, NULL, NULL);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
+	if (ret)
 		goto err2;
-	}
 
 	dev_set_drvdata(&pdev->dev, spdif);
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
 			&samsung_spdif_component, &samsung_spdif_dai, 1);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "fail to register dai\n");
+	if (ret != 0)
 		goto err2;
-	}
 
 	return 0;
 err2:
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index f1f59e0..f491282 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -518,19 +518,15 @@ static int tm2_probe(struct platform_device *pdev)
 	}
 
 	ret = snd_soc_of_parse_card_name(card, "model");
-	if (ret < 0) {
-		dev_err(dev, "Card name is not specified\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
 	if (ret < 0) {
 		/* Backwards compatible way */
 		ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
-		if (ret < 0) {
-			dev_err(dev, "Audio routing is not specified or invalid\n");
+		if (ret < 0)
 			return ret;
-		}
 	}
 
 	card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node,
@@ -609,10 +605,8 @@ static int tm2_probe(struct platform_device *pdev)
 
 	ret = devm_snd_soc_register_component(dev, &tm2_component,
 				tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
-	if (ret < 0) {
-		dev_err(dev, "Failed to register component: %d\n", ret);
+	if (ret < 0)
 		goto dai_node_put;
-	}
 
 	ret = devm_snd_soc_register_card(dev, card);
 	if (ret < 0) {
diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c
index cc7045d..1d7fd66 100644
--- a/sound/soc/sdca/sdca_class_function.c
+++ b/sound/soc/sdca/sdca_class_function.c
@@ -367,6 +367,7 @@ static int class_function_probe(struct auxiliary_device *auxdev,
 	switch (drv->function->desc->type) {
 	case SDCA_FUNCTION_TYPE_UAJ:
 	case SDCA_FUNCTION_TYPE_RJ:
+	case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
 		cmp_drv->set_jack = class_function_set_jack;
 		break;
 	default:
@@ -552,6 +553,10 @@ static const struct auxiliary_device_id class_function_id_table[] = {
 		.name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_RJ_NAME,
 		.driver_data = SDCA_FUNCTION_TYPE_RJ,
 	},
+	{
+		.name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_SIMPLE_NAME,
+		.driver_data = SDCA_FUNCTION_TYPE_SIMPLE_JACK,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(auxiliary, class_function_id_table);
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 32d9b7f3..f39008a 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -78,6 +78,8 @@ static const char *get_sdca_function_name(u32 function_type)
 		return SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME;
 	case SDCA_FUNCTION_TYPE_RJ:
 		return SDCA_FUNCTION_TYPE_RJ_NAME;
+	case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
+		return SDCA_FUNCTION_TYPE_SIMPLE_NAME;
 	case SDCA_FUNCTION_TYPE_COMPANION_AMP:
 		return SDCA_FUNCTION_TYPE_COMPANION_AMP_NAME;
 	case SDCA_FUNCTION_TYPE_IMP_DEF:
@@ -918,8 +920,8 @@ static int find_sdca_control_value(struct device *dev, struct sdca_entity *entit
 	return 0;
 }
 
-static int find_sdca_control_reset(const struct sdca_entity *entity,
-				   struct sdca_control *control)
+static void find_sdca_control_reset(const struct sdca_entity *entity,
+				    struct sdca_control *control)
 {
 	switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
 	case SDCA_CTL_TYPE_S(FU, AGC):
@@ -946,8 +948,6 @@ static int find_sdca_control_reset(const struct sdca_entity *entity,
 	default:
 		break;
 	}
-
-	return 0;
 }
 
 static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity,
@@ -1028,9 +1028,7 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
 
 	control->is_volatile = find_sdca_control_volatile(entity, control);
 
-	ret = find_sdca_control_reset(entity, control);
-	if (ret)
-		return ret;
+	find_sdca_control_reset(entity, control);
 
 	ret = find_sdca_control_range(dev, control_node, &control->range);
 	if (ret) {
@@ -1985,7 +1983,6 @@ static int find_sdca_cluster_channels(struct device *dev,
 		char channel_property[SDCA_PROPERTY_LENGTH];
 		struct fwnode_handle *channel_node;
 
-		/* DisCo uses upper-case for hex numbers */
 		snprintf(channel_property, sizeof(channel_property),
 			 "mipi-sdca-channel-%d-subproperties", i + 1);
 
diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile
index 5ae8c69..1dbc00a 100644
--- a/sound/soc/sdw_utils/Makefile
+++ b/sound/soc/sdw_utils/Makefile
@@ -10,5 +10,7 @@
 		       soc_sdw_cs_amp.o					\
 		       soc_sdw_es9356.o					\
 		       soc_sdw_maxim.o \
-		       soc_sdw_ti_amp.o
+		       soc_sdw_ti_amp.o \
+		       soc_sdw_senary_sdca.o soc_sdw_senary_sdca_jack_common.o \
+		       soc_sdw_senary_amp.o soc_sdw_senary_dmic.o
 obj-$(CONFIG_SND_SOC_SDW_UTILS) += snd-soc-sdw-utils.o
diff --git a/sound/soc/sdw_utils/soc_sdw_senary_amp.c b/sound/soc/sdw_utils/soc_sdw_senary_amp.c
new file mode 100644
index 0000000..9370402
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_senary_amp.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2022 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc_sdw_utils.h>
+
+static int senary_amp_add_device_props(struct device *sdw_dev)
+{
+	return 0;
+}
+
+int asoc_sdw_senary_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+	if (ctx->amp_dev1) {
+		device_remove_software_node(ctx->amp_dev1);
+		put_device(ctx->amp_dev1);
+	}
+
+	if (ctx->amp_dev2) {
+		device_remove_software_node(ctx->amp_dev2);
+		put_device(ctx->amp_dev2);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_amp_exit, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_senary_amp_init(struct snd_soc_card *card,
+			     struct snd_soc_dai_link *dai_links,
+			     struct asoc_sdw_codec_info *info,
+			     bool playback)
+{
+	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+	struct device *sdw_dev1, *sdw_dev2;
+	int ret;
+
+	/* Count amp number and do init on playback link only. */
+	if (!playback)
+		return 0;
+
+	info->amp_num++;
+
+	if (info->amp_num == 2) {
+		sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+		if (!sdw_dev1)
+			return -EPROBE_DEFER;
+
+		ret = senary_amp_add_device_props(sdw_dev1);
+		if (ret < 0) {
+			put_device(sdw_dev1);
+			return ret;
+		}
+		ctx->amp_dev1 = sdw_dev1;
+
+		sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
+		if (!sdw_dev2)
+			return -EPROBE_DEFER;
+
+		ret = senary_amp_add_device_props(sdw_dev2);
+		if (ret < 0) {
+			put_device(sdw_dev2);
+			return ret;
+		}
+		ctx->amp_dev2 = sdw_dev2;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_amp_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_senary_dmic.c b/sound/soc/sdw_utils/soc_sdw_senary_dmic.c
new file mode 100644
index 0000000..7481706
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_senary_dmic.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2024 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc_sdw_utils.h>
+
+/* Card pin "Dmic" → codec input (name_prefix + " DMIC") */
+static const struct snd_soc_dapm_route senary_dmic_map[] = {
+	{ "sn624x DMIC", NULL, "Dmic" },
+};
+
+int asoc_sdw_senary_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+	struct snd_soc_component *component;
+	char *mic_name;
+	int ret;
+
+	component = dai->component;
+
+	ret = snd_soc_dapm_add_routes(dapm, senary_dmic_map,
+				      ARRAY_SIZE(senary_dmic_map));
+	if (ret) {
+		dev_err(card->dev, "senary dmic map addition failed: %d\n", ret);
+		return ret;
+	}
+
+	mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s", component->name_prefix);
+	if (!mic_name)
+		return -ENOMEM;
+
+	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+					  "%s mic:%s-dmic", card->components,
+					  mic_name);
+	if (!card->components)
+		return -ENOMEM;
+
+	dev_dbg(card->dev, "card->components: %s\n", card->components);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_dmic_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_senary_sdca.c b/sound/soc/sdw_utils/soc_sdw_senary_sdca.c
new file mode 100644
index 0000000..5c2cd75
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_senary_sdca.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2024 Intel Corporation.
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc_sdw_utils.h>
+
+/* dapm routes for SPK will be registered dynamically */
+static const struct snd_soc_dapm_route sn624x_spk_map[] = {
+	{ "Speaker", NULL, "sn624x SPK" },
+};
+
+/* Structure to map codec names to respective route arrays and sizes */
+struct codec_route_map {
+	const char *codec_name;
+	const struct snd_soc_dapm_route *route_map;
+	size_t route_size;
+};
+
+/* Codec route maps array */
+static const struct codec_route_map codec_routes[] = {
+	{ "sn624x", sn624x_spk_map, ARRAY_SIZE(sn624x_spk_map) },
+};
+
+static const struct codec_route_map *get_codec_route_map(const char *dai_name)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(codec_routes); i++) {
+		if (str_has_prefix(dai_name, codec_routes[i].codec_name))
+			return &codec_routes[i];
+	}
+	return NULL;
+}
+
+int asoc_sdw_senary_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+	int ret;
+
+	/* Match by DAI name prefix (e.g. sn624x-sdca-aif2). */
+	const struct codec_route_map *route_map = get_codec_route_map(dai->name);
+
+	if (!route_map) {
+		dev_err(rtd->dev, "failed to get codec name and route map\n");
+		return -EINVAL;
+	}
+
+	/* Add routes */
+	ret = snd_soc_dapm_add_routes(dapm, route_map->route_map, route_map->route_size);
+	if (ret)
+		dev_err(rtd->dev, "failed to add rt sdca spk map: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_sdca_spk_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_senary_sdca_jack_common.c b/sound/soc/sdw_utils/soc_sdw_senary_sdca_jack_common.c
new file mode 100644
index 0000000..1dab6f9
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_senary_sdca_jack_common.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <sound/soc_sdw_utils.h>
+
+/*
+ * jack_init / jack_exit / most of rtd_init follow soc_sdw_rt_sdca_jack_common.c
+ * (same SDCA headset machine-helper pattern). Vendor-specific pieces here are
+ * mainly the "senarytech,jd-src" property name and senary_sdca_jack_map[].
+ *
+ * Keep a Senary-local file for now to mirror the existing RT layout. Sharing
+ * parameterised SDCA jack helpers in snd-soc-sdw-utils (jd-src key + common
+ * init/exit/rtd_init boilerplate) is intentional follow-up work, out of scope
+ * for the sn624x codec series.
+ */
+
+/*
+ * Note this MUST be called before snd_soc_register_card(), so that the props
+ * are in place before the codec component driver's probe function parses them.
+ */
+static int senary_sdca_jack_add_codec_device_props(struct device *sdw_dev, unsigned long quirk)
+{
+	struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {};
+	struct fwnode_handle *fwnode;
+	int ret;
+
+	if (!SOC_SDW_JACK_JDSRC(quirk))
+		return 0;
+
+	props[0] = PROPERTY_ENTRY_U32("senarytech,jd-src", SOC_SDW_JACK_JDSRC(quirk));
+
+	fwnode = fwnode_create_software_node(props, NULL);
+	if (IS_ERR(fwnode))
+		return PTR_ERR(fwnode);
+
+	ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
+
+	fwnode_handle_put(fwnode);
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_route senary_sdca_jack_map[] = {
+	{ "Headphone", NULL, "sn624x HP" },
+	{ "sn624x MIC2", NULL, "Headset Mic" },
+};
+
+static struct snd_soc_jack_pin senary_sdca_jack_pins[] = {
+	{
+		.pin    = "Headphone",
+		.mask   = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin    = "Headset Mic",
+		.mask   = SND_JACK_MICROPHONE,
+	},
+};
+
+static const char * const need_sdca_suffix[] = {
+	"sn624x"
+};
+
+int asoc_sdw_senary_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+	struct snd_soc_component *component;
+	struct snd_soc_jack *jack;
+	int ret;
+	int i;
+
+	component = dai->component;
+	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+					  "%s hs:%s",
+					  card->components, component->name_prefix);
+	if (!card->components)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(need_sdca_suffix); i++) {
+		if (!strstr(component->name_prefix, need_sdca_suffix[i]))
+			continue;
+
+		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+						  "%s-sdca", card->components);
+		if (!card->components)
+			return -ENOMEM;
+
+		ret = snd_soc_dapm_add_routes(dapm, senary_sdca_jack_map,
+					      ARRAY_SIZE(senary_sdca_jack_map));
+		if (ret) {
+			dev_err(card->dev,
+				"senary sdca jack map addition failed: %d\n", ret);
+			return ret;
+		}
+		break;
+	}
+
+	if (i == ARRAY_SIZE(need_sdca_suffix)) {
+		dev_err(card->dev, "%s is not supported\n", component->name_prefix);
+		return -EINVAL;
+	}
+
+	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+					 SND_JACK_HEADSET | SND_JACK_BTN_0 |
+					 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+					 SND_JACK_BTN_3,
+					 &ctx->sdw_headset,
+					 senary_sdca_jack_pins,
+					 ARRAY_SIZE(senary_sdca_jack_pins));
+	if (ret) {
+		dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n",
+			ret);
+		return ret;
+	}
+
+	jack = &ctx->sdw_headset;
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	ret = snd_soc_component_set_jack(component, jack, NULL);
+
+	if (ret)
+		dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n",
+			ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_sdca_jack_rtd_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_senary_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+	if (!ctx->headset_codec_dev)
+		return 0;
+
+	if (!SOC_SDW_JACK_JDSRC(ctx->mc_quirk))
+		return 0;
+
+	device_remove_software_node(ctx->headset_codec_dev);
+	put_device(ctx->headset_codec_dev);
+	ctx->headset_codec_dev = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_sdca_jack_exit, "SND_SOC_SDW_UTILS");
+
+/*
+ * Same control flow as asoc_sdw_rt_sdca_jack_init(); see file comment above
+ * about deferred helper sharing in snd-soc-sdw-utils.
+ */
+int asoc_sdw_senary_sdca_jack_init(struct snd_soc_card *card,
+				   struct snd_soc_dai_link *dai_links,
+				   struct asoc_sdw_codec_info *info,
+				   bool playback)
+{
+	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+	struct device *sdw_dev;
+	int ret;
+
+	/*
+	 * Jack detection should be only initialized once for headsets since
+	 * the playback/capture is sharing the same jack
+	 */
+	if (ctx->headset_codec_dev)
+		return 0;
+
+	sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+	if (!sdw_dev)
+		return -EPROBE_DEFER;
+
+	ret = senary_sdca_jack_add_codec_device_props(sdw_dev, ctx->mc_quirk);
+	if (ret < 0) {
+		put_device(sdw_dev);
+		return ret;
+	}
+	ctx->headset_codec_dev = sdw_dev;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_senary_sdca_jack_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index d2eeef4..0d7182b 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -17,6 +17,15 @@ static const struct snd_soc_dapm_widget generic_dmic_widgets[] = {
 	SND_SOC_DAPM_MIC("DMIC", NULL),
 };
 
+/* Senary SN624x UCM uses CaptureMixerElem "Dmic"; keep separate from generic DMIC. */
+static const struct snd_soc_dapm_widget sn624x_dmic_widgets[] = {
+	SND_SOC_DAPM_MIC("Dmic", NULL),
+};
+
+static const struct snd_kcontrol_new sn624x_dmic_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Dmic"),
+};
+
 static const struct snd_soc_dapm_widget generic_jack_widgets[] = {
 	SND_SOC_DAPM_HP("Headphone", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -1264,6 +1273,163 @@ struct asoc_sdw_codec_info codec_info_list[] = {
 		},
 		.dai_num = 1,
 	},
+	/*
+	 * Senary SN6242/6244/6247: same SDCA jack/amp/mic topology; only part_id
+	 * differs. name_prefix stays "sn624x" for UCM/DAI naming.
+	 */
+	{
+		.vendor_id = 0x0496,
+		.part_id = 0x6244,
+		.name_prefix = "sn624x",
+		.ignore_internal_dmic = true,
+		.dais = {
+			{
+				.direction = {true, true},
+				.dai_name = "sn624x-sdca-aif",
+				.dai_type = SOC_SDW_DAI_TYPE_JACK,
+				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+				.init = asoc_sdw_senary_sdca_jack_init,
+				.exit = asoc_sdw_senary_sdca_jack_exit,
+				.rtd_init = asoc_sdw_senary_sdca_jack_rtd_init,
+				.controls = generic_jack_controls,
+				.num_controls = ARRAY_SIZE(generic_jack_controls),
+				.widgets = generic_jack_widgets,
+				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
+			},
+			{
+				.direction = {true, false},
+				.dai_name = "sn624x-sdca-aif2",
+				.component_name = "sn624x",
+				.dai_type = SOC_SDW_DAI_TYPE_AMP,
+				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+				.init = asoc_sdw_senary_amp_init,
+				.exit = asoc_sdw_senary_amp_exit,
+				.rtd_init = asoc_sdw_senary_sdca_spk_rtd_init,
+				.controls = generic_spk_controls,
+				.num_controls = ARRAY_SIZE(generic_spk_controls),
+				.widgets = generic_spk_widgets,
+				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
+				.quirk = SOC_SDW_CODEC_SPKR,
+				.quirk_exclude = true,
+			},
+			{
+				.direction = {false, true},
+				.dai_name = "sn624x-sdca-aif3",
+				.dai_type = SOC_SDW_DAI_TYPE_MIC,
+				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+				.rtd_init = asoc_sdw_senary_dmic_rtd_init,
+				.widgets = sn624x_dmic_widgets,
+				.num_widgets = ARRAY_SIZE(sn624x_dmic_widgets),
+				.controls = sn624x_dmic_controls,
+				.num_controls = ARRAY_SIZE(sn624x_dmic_controls),
+				.quirk = SOC_SDW_CODEC_MIC,
+				.quirk_exclude = true,
+			},
+		},
+		.dai_num = 3,
+	},
+	{
+		.vendor_id = 0x0496,
+		.part_id = 0x6247,
+		.name_prefix = "sn624x",
+		.ignore_internal_dmic = true,
+		.dais = {
+			{
+				.direction = {true, true},
+				.dai_name = "sn624x-sdca-aif",
+				.dai_type = SOC_SDW_DAI_TYPE_JACK,
+				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+				.init = asoc_sdw_senary_sdca_jack_init,
+				.exit = asoc_sdw_senary_sdca_jack_exit,
+				.rtd_init = asoc_sdw_senary_sdca_jack_rtd_init,
+				.controls = generic_jack_controls,
+				.num_controls = ARRAY_SIZE(generic_jack_controls),
+				.widgets = generic_jack_widgets,
+				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
+			},
+			{
+				.direction = {true, false},
+				.dai_name = "sn624x-sdca-aif2",
+				.component_name = "sn624x",
+				.dai_type = SOC_SDW_DAI_TYPE_AMP,
+				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+				.init = asoc_sdw_senary_amp_init,
+				.exit = asoc_sdw_senary_amp_exit,
+				.rtd_init = asoc_sdw_senary_sdca_spk_rtd_init,
+				.controls = generic_spk_controls,
+				.num_controls = ARRAY_SIZE(generic_spk_controls),
+				.widgets = generic_spk_widgets,
+				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
+				.quirk = SOC_SDW_CODEC_SPKR,
+				.quirk_exclude = true,
+			},
+			{
+				.direction = {false, true},
+				.dai_name = "sn624x-sdca-aif3",
+				.dai_type = SOC_SDW_DAI_TYPE_MIC,
+				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+				.rtd_init = asoc_sdw_senary_dmic_rtd_init,
+				.widgets = sn624x_dmic_widgets,
+				.num_widgets = ARRAY_SIZE(sn624x_dmic_widgets),
+				.controls = sn624x_dmic_controls,
+				.num_controls = ARRAY_SIZE(sn624x_dmic_controls),
+				.quirk = SOC_SDW_CODEC_MIC,
+				.quirk_exclude = true,
+			},
+		},
+		.dai_num = 3,
+	},
+	{
+		.vendor_id = 0x0496,
+		.part_id = 0x6242,
+		.name_prefix = "sn624x",
+		.ignore_internal_dmic = true,
+		.dais = {
+			{
+				.direction = {true, true},
+				.dai_name = "sn624x-sdca-aif",
+				.dai_type = SOC_SDW_DAI_TYPE_JACK,
+				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+				.init = asoc_sdw_senary_sdca_jack_init,
+				.exit = asoc_sdw_senary_sdca_jack_exit,
+				.rtd_init = asoc_sdw_senary_sdca_jack_rtd_init,
+				.controls = generic_jack_controls,
+				.num_controls = ARRAY_SIZE(generic_jack_controls),
+				.widgets = generic_jack_widgets,
+				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
+			},
+			{
+				.direction = {true, false},
+				.dai_name = "sn624x-sdca-aif2",
+				.component_name = "sn624x",
+				.dai_type = SOC_SDW_DAI_TYPE_AMP,
+				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+				.init = asoc_sdw_senary_amp_init,
+				.exit = asoc_sdw_senary_amp_exit,
+				.rtd_init = asoc_sdw_senary_sdca_spk_rtd_init,
+				.controls = generic_spk_controls,
+				.num_controls = ARRAY_SIZE(generic_spk_controls),
+				.widgets = generic_spk_widgets,
+				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
+				.quirk = SOC_SDW_CODEC_SPKR,
+				.quirk_exclude = true,
+			},
+			{
+				.direction = {false, true},
+				.dai_name = "sn624x-sdca-aif3",
+				.dai_type = SOC_SDW_DAI_TYPE_MIC,
+				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+				.rtd_init = asoc_sdw_senary_dmic_rtd_init,
+				.widgets = sn624x_dmic_widgets,
+				.num_widgets = ARRAY_SIZE(sn624x_dmic_widgets),
+				.controls = sn624x_dmic_controls,
+				.num_controls = ARRAY_SIZE(sn624x_dmic_controls),
+				.quirk = SOC_SDW_CODEC_MIC,
+				.quirk_exclude = true,
+			},
+		},
+		.dai_num = 3,
+	},
 };
 EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS");
 
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index dc7d203..463ea22 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -315,8 +315,12 @@ void snd_soc_component_suspend(struct snd_soc_component *component)
 
 void snd_soc_component_resume(struct snd_soc_component *component)
 {
-	if (component->driver->resume)
-		component->driver->resume(component);
+	int ret;
+
+	if (component->driver->resume) {
+		ret = component->driver->resume(component);
+		soc_component_ret(component, ret);
+	}
 	component->suspended = 0;
 }
 
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index b840280..093a70a 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -20,6 +20,7 @@
 #include <sound/initval.h>
 #include <sound/soc-dpcm.h>
 #include <sound/soc-link.h>
+#include "soc-internal.h"
 
 static int snd_soc_compr_components_open(struct snd_compr_stream *cstream)
 {
@@ -69,10 +70,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
 	snd_soc_dai_digital_mute(codec_dai, 1, stream);
 
 	if (!snd_soc_dai_active(cpu_dai))
-		soc_pcm_set_dai_params(cpu_dai, NULL);
+		snd_soc_dai_symmetric_set_params(cpu_dai, NULL);
 
 	if (!snd_soc_dai_active(codec_dai))
-		soc_pcm_set_dai_params(codec_dai, NULL);
+		snd_soc_dai_symmetric_set_params(codec_dai, NULL);
 
 	snd_soc_link_compr_shutdown(cstream, rollback);
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b9c7026..06167a1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -41,11 +41,13 @@
 #include <sound/soc-topology.h>
 #include <sound/soc-link.h>
 #include <sound/initval.h>
+#include "soc-internal.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/asoc.h>
 
-static DEFINE_MUTEX(client_mutex);
+DEFINE_MUTEX(client_mutex);
+
 static LIST_HEAD(component_list);
 static LIST_HEAD(unbind_card_list);
 
@@ -232,22 +234,6 @@ static inline void snd_soc_debugfs_exit(void) { }
 
 #endif
 
-static int snd_soc_is_match_dai_args(const struct of_phandle_args *args1,
-				     const struct of_phandle_args *args2)
-{
-	if (!args1 || !args2)
-		return 0;
-
-	if (args1->np != args2->np)
-		return 0;
-
-	for (int i = 0; i < args1->args_count; i++)
-		if (args1->args[i] != args2->args[i])
-			return 0;
-
-	return 1;
-}
-
 static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
 {
 	return !(dlc->dai_args || dlc->name || dlc->of_node);
@@ -263,50 +249,6 @@ static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dl
 	return !(dlc->dai_args || dlc->dai_name);
 }
 
-static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
-				   struct snd_soc_dai *dai)
-{
-	if (!dlc)
-		return 0;
-
-	if (dlc->dai_args)
-		return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args);
-
-	if (!dlc->dai_name)
-		return 1;
-
-	/* see snd_soc_dai_name_get() */
-
-	if (dai->driver->name &&
-	    strcmp(dlc->dai_name, dai->driver->name) == 0)
-		return 1;
-
-	if (strcmp(dlc->dai_name, dai->name) == 0)
-		return 1;
-
-	if (dai->component->name &&
-	    strcmp(dlc->dai_name, dai->component->name) == 0)
-		return 1;
-
-	return 0;
-}
-
-const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai)
-{
-	/* see snd_soc_is_matching_dai() */
-	if (dai->driver->name)
-		return dai->driver->name;
-
-	if (dai->name)
-		return dai->name;
-
-	if (dai->component->name)
-		return dai->component->name;
-
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dai_name_get);
-
 static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
 				     struct snd_soc_component *component)
 {
@@ -868,7 +810,7 @@ static int snd_soc_is_matching_component(
 		struct snd_soc_dai *dai;
 
 		for_each_component_dais(component, dai)
-			if (snd_soc_is_matching_dai(dlc, dai))
+			if (snd_soc_dai_matches_dlc(dai, dlc))
 				return 1;
 		return 0;
 	}
@@ -928,7 +870,7 @@ struct snd_soc_dai *snd_soc_find_dai(
 	for_each_component(component)
 		if (snd_soc_is_matching_component(dlc, component))
 			for_each_component_dais(component, dai)
-				if (snd_soc_is_matching_dai(dlc, dai))
+				if (snd_soc_dai_matches_dlc(dai, dlc))
 					return dai;
 
 	return NULL;
@@ -1859,7 +1801,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card)
 			}
 
 			dev_dbg(card->dev, "info: override BE DAI link %s\n",
-				card->dai_link[i].name);
+				dai_link->name);
 
 			/* override platform component */
 			if (!dai_link->platforms) {
@@ -2343,9 +2285,9 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
 }
 EXPORT_SYMBOL_GPL(snd_soc_cnew);
 
-static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
-	const struct snd_kcontrol_new *controls, int num_controls,
-	const char *prefix, void *data)
+int snd_soc_add_controls(struct snd_card *card, struct device *dev,
+			 const struct snd_kcontrol_new *controls, int num_controls,
+			 const char *prefix, void *data)
 {
 	int i;
 
@@ -2403,26 +2345,6 @@ int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
 EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
 
 /**
- * snd_soc_add_dai_controls - add an array of controls to a DAI.
- * Convenience function to add a list of controls.
- *
- * @dai: DAI to add controls to
- * @controls: array of controls to add
- * @num_controls: number of elements in the array
- *
- * Return 0 for success, else error.
- */
-int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
-	const struct snd_kcontrol_new *controls, int num_controls)
-{
-	struct snd_card *card = dai->component->card->snd_card;
-
-	return snd_soc_add_controls(card, dai->dev, controls, num_controls,
-			NULL, dai);
-}
-EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
-
-/**
  * snd_soc_register_card - Register a card with the ASoC core
  *
  * @card: Card to register
@@ -2480,7 +2402,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
  * Simplify DAI link configuration by removing ".-1" from device names
  * and sanitizing names.
  */
-static char *fmt_single_name(struct device *dev, int *id)
+char *snd_soc_fmt_single_name(struct device *dev, int *id)
 {
 	const char *devname = dev_name(dev);
 	char *found, *name;
@@ -2529,8 +2451,7 @@ static char *fmt_single_name(struct device *dev, int *id)
  * Simplify DAI link naming for single devices with multiple DAIs by removing
  * any ".-1" and using the DAI name (instead of device name).
  */
-static inline char *fmt_multiple_name(struct device *dev,
-		struct snd_soc_dai_driver *dai_drv)
+char *snd_soc_fmt_multiple_name(struct device *dev, struct snd_soc_dai_driver *dai_drv)
 {
 	if (dai_drv->name == NULL) {
 		dev_err(dev,
@@ -2542,74 +2463,6 @@ static inline char *fmt_multiple_name(struct device *dev,
 	return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL);
 }
 
-void snd_soc_unregister_dai(struct snd_soc_dai *dai)
-{
-	lockdep_assert_held(&client_mutex);
-
-	dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
-	list_del(&dai->list);
-}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
-
-/**
- * snd_soc_register_dai - Register a DAI dynamically & create its widgets
- *
- * @component: The component the DAIs are registered for
- * @dai_drv: DAI driver to use for the DAI
- * @legacy_dai_naming: if %true, use legacy single-name format;
- * 	if %false, use multiple-name format;
- *
- * Topology can use this API to register DAIs when probing a component.
- * These DAIs's widgets will be freed in the card cleanup and the DAIs
- * will be freed in the component cleanup.
- */
-struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
-					 struct snd_soc_dai_driver *dai_drv,
-					 bool legacy_dai_naming)
-{
-	struct device *dev = component->dev;
-	struct snd_soc_dai *dai;
-
-	lockdep_assert_held(&client_mutex);
-
-	dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
-	if (dai == NULL)
-		return NULL;
-
-	/*
-	 * Back in the old days when we still had component-less DAIs,
-	 * instead of having a static name, component-less DAIs would
-	 * inherit the name of the parent device so it is possible to
-	 * register multiple instances of the DAI. We still need to keep
-	 * the same naming style even though those DAIs are not
-	 * component-less anymore.
-	 */
-	if (legacy_dai_naming &&
-	    (dai_drv->id == 0 || dai_drv->name == NULL)) {
-		dai->name = fmt_single_name(dev, &dai->id);
-	} else {
-		dai->name = fmt_multiple_name(dev, dai_drv);
-		if (dai_drv->id)
-			dai->id = dai_drv->id;
-		else
-			dai->id = component->num_dai;
-	}
-	if (!dai->name)
-		return NULL;
-
-	dai->component = component;
-	dai->dev = dev;
-	dai->driver = dai_drv;
-
-	/* see for_each_component_dais */
-	list_add_tail(&dai->list, &component->dai_list);
-	component->num_dai++;
-
-	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
-	return dai;
-}
-EXPORT_SYMBOL_GPL(snd_soc_register_dai);
-
 /**
  * snd_soc_unregister_dais - Unregister DAIs from the ASoC core
  *
@@ -2724,7 +2577,7 @@ static int soc_component_initialize(struct snd_soc_component *component,
 	mutex_init(&component->io_mutex);
 
 	if (!component->name) {
-		component->name = fmt_single_name(dev, NULL);
+		component->name = snd_soc_fmt_single_name(dev, NULL);
 		if (!component->name) {
 			dev_err(dev, "ASoC: Failed to allocate name\n");
 			return -ENOMEM;
@@ -3477,7 +3330,7 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
 				id--;
 			}
 
-			dlc->dai_name	= snd_soc_dai_name_get(dai);
+			dlc->dai_name	= snd_soc_dai_name(dai);
 		} else if (ret) {
 			/*
 			 * if another error than ENOTSUPP is returned go on and
@@ -3552,7 +3405,7 @@ struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_a
 
 	for_each_component(component) {
 		for_each_component_dais(component, dai)
-			if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args))
+			if (snd_soc_dai_matches_args(dai, dai_args))
 				return dai;
 	}
 	return NULL;
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index b098d110..83d030e 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -6,9 +6,11 @@
 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 //
 
+#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 #include <sound/soc-link.h>
+#include "soc-internal.h"
 
 #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
 static inline int _soc_dai_ret(const struct snd_soc_dai *dai,
@@ -989,3 +991,343 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
 	return soc_dai_ret(dai, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
+
+/**
+ * snd_soc_dai_add_controls - add an array of controls to a DAI.
+ * Convenience function to add a list of controls.
+ *
+ * @dai: DAI to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_dai_add_controls(struct snd_soc_dai *dai,
+			     const struct snd_kcontrol_new *controls, int num_controls)
+{
+	struct snd_card *card = dai->component->card->snd_card;
+
+	return snd_soc_add_controls(card, dai->dev, controls, num_controls, NULL, dai);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_add_controls);
+
+int snd_soc_dai_matches_args(const struct snd_soc_dai *dai,
+			     const struct of_phandle_args *args2)
+{
+	const struct of_phandle_args *args1 = dai->driver->dai_args;
+
+	if (!args1 || !args2)
+		return 0;
+
+	if (args1->np != args2->np)
+		return 0;
+
+	for (int i = 0; i < args1->args_count; i++)
+		if (args1->args[i] != args2->args[i])
+			return 0;
+
+	return 1;
+}
+
+int snd_soc_dai_matches_dlc(struct snd_soc_dai *dai,
+			    const struct snd_soc_dai_link_component *dlc)
+{
+	if (!dlc)
+		return 0;
+
+	if (dlc->dai_args)
+		return snd_soc_dai_matches_args(dai, dlc->dai_args);
+
+	if (!dlc->dai_name)
+		return 1;
+
+	/* see snd_soc_dai_name() */
+
+	if (dai->driver->name &&
+	    strcmp(dlc->dai_name, dai->driver->name) == 0)
+		return 1;
+
+	if (strcmp(dlc->dai_name, dai->name) == 0)
+		return 1;
+
+	if (dai->component->name &&
+	    strcmp(dlc->dai_name, dai->component->name) == 0)
+		return 1;
+
+	return 0;
+}
+
+const char *snd_soc_dai_name(const struct snd_soc_dai *dai)
+{
+	/* see snd_soc_dai_matches_dlc() */
+	if (dai->driver->name)
+		return dai->driver->name;
+
+	if (dai->name)
+		return dai->name;
+
+	if (dai->component->name)
+		return dai->component->name;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_name);
+
+const struct snd_soc_pcm_stream *
+snd_soc_dai_pcm_stream_get_i(const struct snd_soc_dai *dai, int stream)
+{
+	return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		&dai->driver->playback : &dai->driver->capture;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_pcm_stream_get_i);
+
+struct snd_soc_dapm_widget *snd_soc_dai_stream_widget_get(struct snd_soc_dai *dai, int stream)
+{
+	return dai->stream[stream].widget;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_widget_get);
+
+void snd_soc_dai_stream_widget_set(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget *widget)
+{
+	dai->stream[stream].widget = widget;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_widget_set);
+
+void *snd_soc_dai_stream_dma_data_get_i(const struct snd_soc_dai *dai, int stream)
+{
+	return dai->stream[stream].dma_data;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_dma_data_get_i);
+
+void snd_soc_dai_stream_dma_data_set_i(struct snd_soc_dai *dai, int stream, void *data)
+{
+	dai->stream[stream].dma_data = data;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_dma_data_set_i);
+
+unsigned int snd_soc_dai_stream_tdm_mask_get(const struct snd_soc_dai *dai, int stream)
+{
+	return dai->stream[stream].tdm_mask;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_tdm_mask_get);
+
+void snd_soc_dai_stream_tdm_mask_set(struct snd_soc_dai *dai, int stream, unsigned int tdm_mask)
+{
+	dai->stream[stream].tdm_mask = tdm_mask;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_tdm_mask_set);
+
+unsigned int snd_soc_dai_stream_active(const struct snd_soc_dai *dai, int stream)
+{
+	/* see snd_soc_dai_action() for setup */
+	return dai->stream[stream].active;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_active);
+
+/**
+ * snd_soc_dai_set_stream() - Configures a DAI for stream operation
+ * @dai: DAI
+ * @stream: STREAM (opaque structure depending on DAI type)
+ * @direction: Stream direction(Playback/Capture)
+ * Some subsystems, such as SoundWire, don't have a notion of direction and we reuse
+ * the ASoC stream direction to configure sink/source ports.
+ * Playback maps to source ports and Capture for sink ports.
+ *
+ * This should be invoked with NULL to clear the stream set previously.
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int snd_soc_dai_set_stream(struct snd_soc_dai *dai, void *stream, int direction)
+{
+	if (dai->driver->ops->set_stream)
+		return dai->driver->ops->set_stream(dai, stream, direction);
+	else
+		return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_stream);
+
+/**
+ * snd_soc_dai_get_stream() - Retrieves stream from DAI
+ * @dai: DAI
+ * @direction: Stream direction(Playback/Capture)
+ *
+ * This routine only retrieves that was previously configured
+ * with snd_soc_dai_get_stream()
+ *
+ * Returns pointer to stream or an ERR_PTR value, e.g.
+ * ERR_PTR(-ENOTSUPP) if callback is not supported;
+ */
+void *snd_soc_dai_get_stream(struct snd_soc_dai *dai, int direction)
+{
+	if (dai->driver->ops->get_stream)
+		return dai->driver->ops->get_stream(dai, direction);
+	else
+		return ERR_PTR(-ENOTSUPP);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_get_stream);
+
+void snd_soc_dai_unregister(struct snd_soc_dai *dai)
+{
+	lockdep_assert_held(&client_mutex);
+
+	dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
+	list_del(&dai->list);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_unregister);
+
+/**
+ * snd_soc_dai_register - Register a DAI dynamically & create its widgets
+ *
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAI
+ * @legacy_dai_naming: if %true, use legacy single-name format;
+ * 	if %false, use multiple-name format;
+ *
+ * Topology can use this API to register DAIs when probing a component.
+ * These DAIs's widgets will be freed in the card cleanup and the DAIs
+ * will be freed in the component cleanup.
+ */
+struct snd_soc_dai *snd_soc_dai_register(struct snd_soc_component *component,
+					 struct snd_soc_dai_driver *dai_drv,
+					 bool legacy_dai_naming)
+{
+	struct device *dev = component->dev;
+	struct snd_soc_dai *dai;
+
+	lockdep_assert_held(&client_mutex);
+
+	dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
+	if (dai == NULL)
+		return NULL;
+
+	/*
+	 * Back in the old days when we still had component-less DAIs,
+	 * instead of having a static name, component-less DAIs would
+	 * inherit the name of the parent device so it is possible to
+	 * register multiple instances of the DAI. We still need to keep
+	 * the same naming style even though those DAIs are not
+	 * component-less anymore.
+	 */
+	if (legacy_dai_naming &&
+	    (dai_drv->id == 0 || dai_drv->name == NULL)) {
+		dai->name = snd_soc_fmt_single_name(dev, &dai->id);
+	} else {
+		dai->name = snd_soc_fmt_multiple_name(dev, dai_drv);
+		if (dai_drv->id)
+			dai->id = dai_drv->id;
+		else
+			dai->id = component->num_dai;
+	}
+	if (!dai->name)
+		return NULL;
+
+	dai->component = component;
+	dai->dev = dev;
+	dai->driver = dai_drv;
+
+	/* see for_each_component_dais */
+	list_add_tail(&dai->list, &component->dai_list);
+	component->num_dai++;
+
+	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
+	return dai;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_register);
+
+void snd_soc_dai_symmetric_set_params(struct snd_soc_dai *dai,
+				      struct snd_pcm_hw_params *params)
+{
+	if (params) {
+		dai->symmetric_rate	   = params_rate(params);
+		dai->symmetric_channels	   = params_channels(params);
+		dai->symmetric_sample_bits = snd_pcm_format_physical_width(params_format(params));
+	} else {
+		dai->symmetric_rate	   = 0;
+		dai->symmetric_channels	   = 0;
+		dai->symmetric_sample_bits = 0;
+	}
+}
+
+int snd_soc_dai_symmetric_apply(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	int ret;
+
+	if (!snd_soc_dai_active(dai))
+		return 0;
+
+#define __symmetric_apply(name, NAME)							\
+	if (dai->symmetric_##name &&							\
+	    (dai->driver->symmetric_##name || rtd->dai_link->symmetric_##name)) {	\
+		dev_dbg(dai->dev, "ASoC: Symmetry forces %s to %d\n",			\
+			#name, dai->symmetric_##name);					\
+											\
+		ret = snd_pcm_hw_constraint_single(substream->runtime,			\
+						   SNDRV_PCM_HW_PARAM_##NAME,		\
+						   dai->symmetric_##name);		\
+		if (ret < 0)								\
+			return snd_soc_ret(dai->dev, ret,				\
+					   "Unable to apply %s constraint\n", #name);	\
+	}
+
+	__symmetric_apply(rate,		RATE);
+	__symmetric_apply(channels,	CHANNELS);
+	__symmetric_apply(sample_bits,	SAMPLE_BITS);
+
+	return 0;
+}
+
+int snd_soc_dai_symmetric_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_dai d;
+	struct snd_soc_dai *dai;
+	struct snd_soc_dai *cpu_dai;
+	unsigned int symmetry, i;
+
+	d.name = __func__;
+	snd_soc_dai_symmetric_set_params(&d, params);
+
+#define __symmetric_params(xxx)						\
+	symmetry = rtd->dai_link->symmetric_##xxx;			\
+	for_each_rtd_dais(rtd, i, dai)					\
+		symmetry |= dai->driver->symmetric_##xxx;		\
+									\
+	if (symmetry)							\
+		for_each_rtd_cpu_dais(rtd, i, cpu_dai)			\
+			if (!snd_soc_dai_is_dummy(cpu_dai) &&		\
+			    cpu_dai->symmetric_##xxx &&			\
+			    cpu_dai->symmetric_##xxx != d.symmetric_##xxx) \
+				return snd_soc_ret(rtd->dev, -EINVAL,	\
+						   "unmatched %s symmetry: %s:%d - %s:%d\n", \
+						   #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \
+						   d.name, d.symmetric_##xxx);
+
+	/* reject unmatched parameters when applying symmetry */
+	__symmetric_params(rate);
+	__symmetric_params(channels);
+	__symmetric_params(sample_bits);
+
+	return 0;
+}
+
+void snd_soc_dai_symmetric_update(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_dai_link *link = rtd->dai_link;
+	struct snd_soc_dai *dai;
+	unsigned int symmetry, i;
+
+	symmetry = link->symmetric_rate		||
+		   link->symmetric_channels	||
+		   link->symmetric_sample_bits;
+
+	for_each_rtd_dais(rtd, i, dai)
+		symmetry = symmetry				||
+			   dai->driver->symmetric_rate		||
+			   dai->driver->symmetric_channels	||
+			   dai->driver->symmetric_sample_bits;
+
+	if (symmetry)
+		substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+}
diff --git a/sound/soc/soc-internal.h b/sound/soc/soc-internal.h
new file mode 100644
index 0000000..3afc50d
--- /dev/null
+++ b/sound/soc/soc-internal.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * soc-internal.h
+ *
+ * Copyright (c) 2026 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ */
+#ifndef __SOC_INTERNAL_H
+#define __SOC_INTERNAL_H
+
+/*
+ * This header is for ALSA SoC Framework internal, not for Vender drivers.
+ * The ALSA SoC functions for Vender drivers are defined in linux/include/sound/xxx.h
+ * as snd_soc_xxx();
+ */
+
+/*
+ * In soc-core
+ */
+extern struct mutex client_mutex;
+
+char *snd_soc_fmt_single_name(struct device *dev, int *id);
+char *snd_soc_fmt_multiple_name(struct device *dev, struct snd_soc_dai_driver *dai_drv);
+int snd_soc_add_controls(struct snd_card *card, struct device *dev,
+			 const struct snd_kcontrol_new *controls, int num_controls,
+			 const char *prefix, void *data);
+
+/*
+ * In soc-dai
+ */
+void snd_soc_dai_symmetric_set_params(struct snd_soc_dai *dai,
+				      struct snd_pcm_hw_params *params);
+int snd_soc_dai_symmetric_apply(struct snd_pcm_substream *substream, struct snd_soc_dai *dai);
+int snd_soc_dai_symmetric_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
+void snd_soc_dai_symmetric_update(struct snd_pcm_substream *substream);
+
+#endif /* __SOC_INTERNAL_H */
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index c935571..142f407 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -305,8 +305,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
  * Callback to provide information about a single mixer control, or a double
  * mixer control that spans 2 registers of the SX TLV type. SX TLV controls
  * have a range that represents both positive and negative values either side
- * of zero but without a sign bit. min is the minimum register value, max is
- * the number of steps.
+ * of zero but without a sign bit. min is the register value representing the
+ * minimum volume, max is the number of volume steps.
  *
  * Returns 0 for success.
  */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 3137c09..2742a70 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -26,6 +26,7 @@
 #include <sound/soc-dpcm.h>
 #include <sound/soc-link.h>
 #include <sound/initval.h>
+#include "soc-internal.h"
 
 
 DEFINE_GUARD(snd_soc_card_mutex, struct snd_soc_card *,
@@ -427,50 +428,6 @@ void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event)
 	snd_soc_dapm_stream_event(fe, dir, event);
 }
 
-void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
-			    struct snd_pcm_hw_params *params)
-{
-	if (params) {
-		dai->symmetric_rate	   = params_rate(params);
-		dai->symmetric_channels	   = params_channels(params);
-		dai->symmetric_sample_bits = snd_pcm_format_physical_width(params_format(params));
-	} else {
-		dai->symmetric_rate	   = 0;
-		dai->symmetric_channels	   = 0;
-		dai->symmetric_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 = snd_soc_substream_to_rtd(substream);
-	int ret;
-
-	if (!snd_soc_dai_active(soc_dai))
-		return 0;
-
-#define __soc_pcm_apply_symmetry(name, NAME)				\
-	if (soc_dai->symmetric_##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->symmetric_##name);		\
-									\
-		ret = snd_pcm_hw_constraint_single(substream->runtime,	\
-						   SNDRV_PCM_HW_PARAM_##NAME,\
-						   soc_dai->symmetric_##name);	\
-		if (ret < 0)							\
-			return snd_soc_ret(soc_dai->dev, ret,			\
-				"Unable to apply %s constraint\n", #name);	\
-	}
-
-	__soc_pcm_apply_symmetry(rate,		RATE);
-	__soc_pcm_apply_symmetry(channels,	CHANNELS);
-	__soc_pcm_apply_symmetry(sample_bits,	SAMPLE_BITS);
-
-	return 0;
-}
-
 /*
  * Shared BCLK constraint: when multiple DAIs share the same physical BCLK,
  * constrain hw_params so that the BCLK rate (rate * channels * sample_bits,
@@ -579,62 +536,6 @@ static int soc_pcm_apply_shared_bclk(struct snd_pcm_substream *substream,
 		-1);
 }
 
-static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-	struct snd_soc_dai d;
-	struct snd_soc_dai *dai;
-	struct snd_soc_dai *cpu_dai;
-	unsigned int symmetry, i;
-
-	d.name = __func__;
-	soc_pcm_set_dai_params(&d, params);
-
-#define __soc_pcm_params_symmetry(xxx)					\
-	symmetry = rtd->dai_link->symmetric_##xxx;			\
-	for_each_rtd_dais(rtd, i, dai)					\
-		symmetry |= dai->driver->symmetric_##xxx;		\
-									\
-	if (symmetry)							\
-		for_each_rtd_cpu_dais(rtd, i, cpu_dai)			\
-			if (!snd_soc_dai_is_dummy(cpu_dai) &&		\
-			    cpu_dai->symmetric_##xxx &&			\
-			    cpu_dai->symmetric_##xxx != d.symmetric_##xxx) \
-				return snd_soc_ret(rtd->dev, -EINVAL,	\
-						   "unmatched %s symmetry: %s:%d - %s:%d\n", \
-						   #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \
-						   d.name, d.symmetric_##xxx);
-
-	/* reject unmatched parameters when applying symmetry */
-	__soc_pcm_params_symmetry(rate);
-	__soc_pcm_params_symmetry(channels);
-	__soc_pcm_params_symmetry(sample_bits);
-
-	return 0;
-}
-
-static void soc_pcm_update_symmetry(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-	struct snd_soc_dai_link *link = rtd->dai_link;
-	struct snd_soc_dai *dai;
-	unsigned int symmetry, i;
-
-	symmetry = link->symmetric_rate ||
-		link->symmetric_channels ||
-		link->symmetric_sample_bits;
-
-	for_each_rtd_dais(rtd, i, dai)
-		symmetry = symmetry ||
-			dai->driver->symmetric_rate ||
-			dai->driver->symmetric_channels ||
-			dai->driver->symmetric_sample_bits;
-
-	if (symmetry)
-		substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
-}
-
 static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
 {
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
@@ -879,7 +780,7 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
 		/* Make sure DAI parameters cleared if the DAI becomes inactive */
 		for_each_rtd_dais(rtd, i, dai) {
 			if (snd_soc_dai_active(dai) == 0)
-				soc_pcm_set_dai_params(dai, NULL);
+				snd_soc_dai_symmetric_set_params(dai, NULL);
 		}
 	}
 
@@ -1001,7 +902,7 @@ static int __soc_pcm_open(struct snd_soc_pcm_runtime *rtd,
 	/* Check that the codec and cpu DAIs are compatible */
 	soc_pcm_init_runtime_hw(substream);
 
-	soc_pcm_update_symmetry(substream);
+	snd_soc_dai_symmetric_update(substream);
 
 	ret = soc_hw_sanity_check(substream);
 	if (ret < 0)
@@ -1011,7 +912,7 @@ static int __soc_pcm_open(struct snd_soc_pcm_runtime *rtd,
 
 	/* Symmetry only applies if we've already got an active stream. */
 	for_each_rtd_dais(rtd, i, dai) {
-		ret = soc_pcm_apply_symmetry(substream, dai);
+		ret = snd_soc_dai_symmetric_apply(substream, dai);
 		if (ret != 0)
 			goto err;
 	}
@@ -1135,7 +1036,7 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
 	/* clear the corresponding DAIs parameters when going to be inactive */
 	for_each_rtd_dais(rtd, i, dai) {
 		if (snd_soc_dai_active(dai) == 1)
-			soc_pcm_set_dai_params(dai, NULL);
+			snd_soc_dai_symmetric_set_params(dai, NULL);
 
 		if (snd_soc_dai_stream_active(dai, substream->stream) == 1) {
 			if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai))
@@ -1197,7 +1098,7 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	snd_soc_dpcm_mutex_assert_held(rtd);
 
-	ret = soc_pcm_params_symmetry(substream, params);
+	ret = snd_soc_dai_symmetric_params(substream, params);
 	if (ret)
 		goto out;
 
@@ -1245,7 +1146,7 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		if(ret < 0)
 			goto out;
 
-		soc_pcm_set_dai_params(codec_dai, &tmp_params);
+		snd_soc_dai_symmetric_set_params(codec_dai, &tmp_params);
 		snd_soc_dapm_update_dai(substream, &tmp_params, codec_dai);
 	}
 
@@ -1283,7 +1184,7 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
 			goto out;
 
 		/* store the parameters for each DAI */
-		soc_pcm_set_dai_params(cpu_dai, &tmp_params);
+		snd_soc_dai_symmetric_set_params(cpu_dai, &tmp_params);
 		snd_soc_dapm_update_dai(substream, &tmp_params, cpu_dai);
 	}
 
@@ -2032,11 +1933,11 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
 	int i;
 
 	/* apply symmetry for FE */
-	soc_pcm_update_symmetry(fe_substream);
+	snd_soc_dai_symmetric_update(fe_substream);
 
 	for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
 		/* Symmetry only applies if we've got an active stream. */
-		err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
+		err = snd_soc_dai_symmetric_apply(fe_substream, fe_cpu_dai);
 		if (err < 0)
 			goto error;
 	}
@@ -2057,11 +1958,11 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
 		if (rtd->dai_link->be_hw_params_fixup)
 			continue;
 
-		soc_pcm_update_symmetry(be_substream);
+		snd_soc_dai_symmetric_update(be_substream);
 
 		/* Symmetry only applies if we've got an active stream. */
 		for_each_rtd_dais(rtd, i, dai) {
-			err = soc_pcm_apply_symmetry(fe_substream, dai);
+			err = snd_soc_dai_symmetric_apply(fe_substream, dai);
 			if (err < 0)
 				goto error;
 		}
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 903e7ec..d64f682 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -109,6 +109,7 @@
 	depends on SND_SOC_SOF_PCI
 	depends on AMD_NODE
 	select SND_SOC_SOF_AMD_COMMON
+	select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
 	help
 	  Select this option for SOF support on AMD ACP7.B and ACP7.F PCI
 	  revision based platforms.
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index df656cd..33540f7 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -16,6 +16,7 @@
 #include "acp.h"
 #include "acp-dsp-offset.h"
 #include <sound/sof/xtensa.h>
+#include "../../amd/acp/soc_amd_sdw_common.h"
 
 /**
  * amd_sof_ipc_dump() - This function is called when IPC tx times out.
@@ -177,6 +178,7 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
 	struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
 	const struct sof_dev_desc *desc = sof_pdata->desc;
 	struct snd_soc_acpi_mach *mach = NULL;
+	struct amd_pdm_pdata *pdm_pdata;
 
 	if (desc->machines)
 		mach = snd_soc_acpi_find_machine(desc->machines);
@@ -188,7 +190,22 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
 		}
 	}
 
+	mach = devm_kmemdup(sdev->dev, mach, sizeof(*mach), GFP_KERNEL);
+	if (!mach) {
+		dev_err(sdev->dev, "failed to allocate machine entry copy\n");
+		return NULL;
+	}
+
 	mach->mach_params.subsystem_rev = acp_data->pci_rev;
+
+	if (acp_data->pdm_sel) {
+		pdm_pdata = devm_kzalloc(sdev->dev, sizeof(*pdm_pdata), GFP_KERNEL);
+		if (!pdm_pdata)
+			return NULL;
+		pdm_pdata->pdm_sel = acp_data->pdm_sel;
+		mach->pdata = pdm_pdata;
+	}
+
 	sof_pdata->tplg_filename = mach->sof_tplg_filename;
 	sof_pdata->fw_filename = mach->fw_filename;
 
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index bea1bd3..3984cd6 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -156,5 +156,22 @@
 #define ACP7X_IDMA_ERROR_MASK			0x1FF9FF
 #define ACP7X_ZSC_DSP_CTRL			0x001014
 #define ACP7X_PME_EN				ACP70_PME_EN
+/* SW enable base for SDW0; manager N uses ACP7X_SW_EN + (N * 0x2000) */
+#define ACP7X_SW_EN				0x5200
+
+/* ACP7X SoundWire IO registers (non-gsync, up to 4 managers SW0-SW3) */
+#define ACP7X_EXTERNAL_SW_INTR_STAT		0x001A24
+#define ACP7X_SW_WAKE_EN			0x001458
+#define ACP7X_SW_PME_STS			0x001474
+#define ACP7X_SDW_STAT				BIT(23)
+#define ACP7X_ERROR_IRQ				BIT(29)
+#define ACP7X_SW_WAKE_EN_MASK			BIT(0)
+#define ACP7X_SW_HOST_WAKE_MASK			BIT(22)
+#define ACP7X_SDW_HOST_WAKE_STAT		BIT(24)
+#define ACP7X_SW_FIFO_ERROR_REASON		0x50C4
+#define ACP7X_SW_ERROR_REASON1			0x50CC
+#define ACP7X_SW_ERROR_REASON2			0x50D4
+#define ACP7X_EXTERNAL_SDW_STAT			BIT(16)
+#define ACP7X_SW_ERR_STAT_MASK			BIT(11)
 
 #endif
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index f89ad86..b059039 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -22,11 +22,20 @@
 #include "../ops.h"
 #include "acp.h"
 #include "acp-dsp-offset.h"
+#include "../../amd/acp/soc_amd_sdw_common.h"
+#include "acp7x.h"
 
 static bool enable_fw_debug;
 module_param(enable_fw_debug, bool, 0444);
 MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
 
+static const u32 acp7x_sof_sdw_ext_stat[ACP7X_SDW_MAX_MANAGER_COUNT] = {
+	ACP7X_SDW_STAT << 0,
+	ACP7X_SDW_STAT << 1,
+	ACP7X_SDW_STAT << 2,
+	ACP7X_SDW_STAT << 3,
+};
+
 static struct acp_quirk_entry quirk_valve_galileo = {
 	.signed_fw_image = true,
 	.skip_iram_dram_size_mod = true,
@@ -581,30 +590,196 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
 		return IRQ_NONE;
 }
 
+/* ACP7X SoundWire IO data tables */
+
+const struct sof_amd_acp7x_sdw_err_regs acp7x_sdw_err_regs[ACP7X_SDW_MAX_MANAGER_COUNT] = {
+	{ ACP7X_SW_ERR_STAT_MASK << 0,
+	  ACP7X_SW_FIFO_ERROR_REASON + (0 * 0x2000),
+	  ACP7X_SW_ERROR_REASON1 + (0 * 0x2000),
+	  ACP7X_SW_ERROR_REASON2 + (0 * 0x2000) },
+	{ ACP7X_SW_ERR_STAT_MASK << 1,
+	  ACP7X_SW_FIFO_ERROR_REASON + (1 * 0x2000),
+	  ACP7X_SW_ERROR_REASON1 + (1 * 0x2000),
+	  ACP7X_SW_ERROR_REASON2 + (1 * 0x2000) },
+	{ ACP7X_SW_ERR_STAT_MASK << 2,
+	  ACP7X_SW_FIFO_ERROR_REASON + (2 * 0x2000),
+	  ACP7X_SW_ERROR_REASON1 + (2 * 0x2000),
+	  ACP7X_SW_ERROR_REASON2 + (2 * 0x2000) },
+	{ ACP7X_SW_ERR_STAT_MASK << 3,
+	  ACP7X_SW_FIFO_ERROR_REASON + (3 * 0x2000),
+	  ACP7X_SW_ERROR_REASON1 + (3 * 0x2000),
+	  ACP7X_SW_ERROR_REASON2 + (3 * 0x2000) },
+};
+
+const struct acp7x_sdw_wake_src acp7x_sdw_wake_sources[] = {
+	{ ACP7X_SDW_HOST_WAKE_STAT << 0, ACP7X_SW_PME_STS + (0 * 4),
+	  ACP7X_SW_WAKE_EN_MASK << 0, 0 },
+	{ ACP7X_SDW_HOST_WAKE_STAT << 1, ACP7X_SW_PME_STS + (1 * 4),
+	  ACP7X_SW_WAKE_EN_MASK << 1, 1 },
+	{ ACP7X_SDW_HOST_WAKE_STAT << 2, ACP7X_SW_PME_STS + (2 * 4),
+	  ACP7X_SW_WAKE_EN_MASK << 2, 2 },
+	{ ACP7X_SDW_HOST_WAKE_STAT << 3, ACP7X_SW_PME_STS + (3 * 4),
+	  ACP7X_SW_WAKE_EN_MASK << 3, 3 },
+};
+
+/* ACP7X SoundWire IO interrupt and wake helpers */
+
+static void sof_amd_acp7x_handle_one_sdw_err(struct snd_sof_dev *sdev, u32 *err_stat,
+					     u32 acp_error_stat_reg,
+					     const struct sof_amd_acp7x_sdw_err_regs *regs)
+{
+	if (!(*err_stat & regs->err_stat_mask))
+		return;
+
+	*err_stat &= ~regs->err_stat_mask;
+	snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_error_stat_reg, *err_stat);
+	snd_sof_dsp_write(sdev, ACP_DSP_BAR, regs->fifo_err_reason, 0);
+	snd_sof_dsp_write(sdev, ACP_DSP_BAR, regs->err_reason1, 0);
+	snd_sof_dsp_write(sdev, ACP_DSP_BAR, regs->err_reason2, 0);
+}
+
+/* Clears SoundWire error registers for all managers; runs in hard IRQ context. */
+static void sof_amd_acp7x_clear_sdw_err_regs(struct snd_sof_dev *sdev)
+{
+	const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+	u32 err_stat;
+	unsigned int instance;
+
+	err_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->acp_error_stat);
+
+	for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++)
+		sof_amd_acp7x_handle_one_sdw_err(sdev, &err_stat, desc->acp_error_stat,
+						 &acp7x_sdw_err_regs[instance]);
+}
+
+static void sof_amd_handle_acp7x_sdw_wake_event(struct acp_dev_data *adata)
+{
+	struct amd_sdw_manager *amd_manager;
+	unsigned int instance;
+
+	for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) {
+		if (!adata->acp7x_sdw_wake_event[instance])
+			continue;
+		if (!adata->sdw->pdev[instance])
+			continue;
+
+		amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev);
+		if (amd_manager)
+			pm_request_resume(amd_manager->dev);
+		adata->acp7x_sdw_wake_event[instance] = false;
+	}
+}
+
+static int sof_amd_check_and_handle_acp7x_sdw_wake_irq(struct snd_sof_dev *sdev)
+{
+	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
+	const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+	unsigned int ext_intr_stat1;
+	unsigned int sdw_pme_stat, sdw_wake_en;
+	unsigned int i;
+	bool sdw_wake_irq = false;
+
+	ext_intr_stat1 = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
+
+	for (i = 0; i < ARRAY_SIZE(acp7x_sdw_wake_sources); i++) {
+		const struct acp7x_sdw_wake_src *src = &acp7x_sdw_wake_sources[i];
+
+		bool woke = false;
+
+		if (ext_intr_stat1 & src->host_stat_mask) {
+			snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
+					  src->host_stat_mask);
+			woke = true;
+		}
+
+		sdw_pme_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, src->pme_sts_reg);
+		if (sdw_pme_stat) {
+			sdw_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN);
+			sdw_wake_en &= ~src->wake_en_mask;
+			snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN, sdw_wake_en);
+			snd_sof_dsp_write(sdev, ACP_DSP_BAR, src->pme_sts_reg, sdw_pme_stat);
+			woke = true;
+		}
+
+		if (woke) {
+			adata->acp7x_sdw_wake_event[src->instance] = true;
+			sdw_wake_irq = true;
+		}
+	}
+
+	if (sdw_wake_irq) {
+		sof_amd_handle_acp7x_sdw_wake_event(adata);
+		return WAKE_IRQ_HANDLED;
+	}
+	return WAKE_IRQ_NONE;
+}
+
+static void sof_acp7x_handle_sdw_manager_irq(struct snd_sof_dev *sdev,
+					     struct acp_dev_data *adata,
+					     const struct sof_amd_acp_desc *desc,
+					     unsigned int instance,
+					     u32 ext_stat_mask)
+{
+	struct amd_sdw_manager *amd_manager;
+	unsigned int sdw_intr_stat;
+	u32 sw_intr_reg = ACP7X_EXTERNAL_SW_INTR_STAT + (instance * 4);
+
+	snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ext_stat_mask);
+	sdw_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, sw_intr_reg);
+	if (sdw_intr_stat & ACP7X_EXTERNAL_SDW_STAT) {
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, sw_intr_reg, ACP7X_EXTERNAL_SDW_STAT);
+		if (!adata->sdw->pdev[instance])
+			return;
+		amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev);
+		if (amd_manager)
+			schedule_work(&amd_manager->amd_sdw_irq_thread);
+	}
+}
+
 static irqreturn_t acp7x_irq_handler(int irq, void *dev_id)
 {
 	struct snd_sof_dev *sdev = dev_id;
+	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
 	const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
 	unsigned int base = desc->dsp_intr_base;
 	unsigned int val;
 	unsigned int ext_intr_stat;
-	int irq_flag = 0;
+	unsigned int instance;
+	int irq_flag = 0, wake_irq_flag = 0;
+	bool dsp_irq = false;
 
 	val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
 	if (val & ACP_DSP_TO_HOST_IRQ) {
 		snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
 				  ACP_DSP_TO_HOST_IRQ);
-		return IRQ_WAKE_THREAD;
+		dsp_irq = true;
 	}
 
 	ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
-	if (ext_intr_stat & ACP_ERROR_IRQ_MASK) {
-		snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
-		snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
+
+	if (adata->sdw) {
+		for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) {
+			if (ext_intr_stat & acp7x_sof_sdw_ext_stat[instance]) {
+				sof_acp7x_handle_sdw_manager_irq(sdev, adata, desc, instance,
+								 acp7x_sof_sdw_ext_stat[instance]);
+				irq_flag = 1;
+			}
+		}
+	}
+
+	if (adata->sdw)
+		wake_irq_flag = sof_amd_check_and_handle_acp7x_sdw_wake_irq(sdev);
+
+	if (ext_intr_stat & ACP7X_ERROR_IRQ) {
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP7X_ERROR_IRQ);
+		sof_amd_acp7x_clear_sdw_err_regs(sdev);
 		irq_flag = 1;
 	}
 
-	if (irq_flag)
+	if (dsp_irq)
+		return IRQ_WAKE_THREAD;
+
+	if (irq_flag || wake_irq_flag)
 		return IRQ_HANDLED;
 
 	return IRQ_NONE;
@@ -728,6 +903,8 @@ static int acp_init(struct snd_sof_dev *sdev)
 	const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
 	struct acp_dev_data *acp_data;
 	unsigned int sdw0_wake_en, sdw1_wake_en;
+	u32 sdw_wake_en, intr_mask;
+	unsigned int i;
 	int ret;
 
 	/* power on */
@@ -771,6 +948,20 @@ static int acp_init(struct snd_sof_dev *sdev)
 		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
 		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK,
 				  ACP7X_IDMA_ERROR_MASK);
+		/*
+		 * Enable host-wake interrupt per manager based on SW_WAKE_EN:
+		 * SW_WAKE_EN bit i enables ACP7X_SW_HOST_WAKE_MASK << i in INTR_CNTL1.
+		 */
+		sdw_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN);
+		intr_mask = 0;
+		for (i = 0; i < ACP7X_SDW_MAX_MANAGER_COUNT; i++) {
+			if (sdw_wake_en & BIT(i))
+				intr_mask |= ACP7X_SW_HOST_WAKE_MASK << i;
+		}
+		if (intr_mask)
+			snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR,
+						ACP7X_EXTERNAL_INTR_CNTL1,
+						intr_mask, intr_mask);
 		break;
 	}
 	return 0;
@@ -779,15 +970,30 @@ static int acp_init(struct snd_sof_dev *sdev)
 static bool check_acp_sdw_enable_status(struct snd_sof_dev *sdev)
 {
 	struct acp_dev_data *acp_data;
-	u32 sdw0_en, sdw1_en;
+	u32 sdw0_en, sdw1_en, sdw2_en, sdw3_en;
 
 	acp_data = sdev->pdata->hw_pdata;
 	if (!acp_data->sdw)
 		return false;
 
-	sdw0_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW0_EN);
-	sdw1_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW1_EN);
-	acp_data->sdw_en_stat = sdw0_en || sdw1_en;
+	switch (acp_data->pci_rev) {
+	case ACP63_PCI_ID:
+	case ACP70_PCI_ID:
+	case ACP71_PCI_ID:
+	case ACP72_PCI_ID:
+		sdw0_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW0_EN);
+		sdw1_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW1_EN);
+		acp_data->sdw_en_stat = sdw0_en || sdw1_en;
+		break;
+	case ACP7B_PCI_ID:
+	case ACP7F_PCI_ID:
+		sdw0_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (0 * 0x2000));
+		sdw1_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (1 * 0x2000));
+		sdw2_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (2 * 0x2000));
+		sdw3_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (3 * 0x2000));
+		acp_data->sdw_en_stat = sdw0_en || sdw1_en || sdw2_en || sdw3_en;
+		break;
+	}
 	return acp_data->sdw_en_stat;
 }
 
@@ -853,6 +1059,31 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev)
 }
 EXPORT_SYMBOL_NS(amd_sof_acp_resume, "SND_SOC_SOF_AMD_COMMON");
 
+static void acp_sof_scan_pdm_devices(struct snd_sof_dev *sdev,
+				     struct acpi_device *pdm_dev)
+{
+	struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
+	struct fwnode_handle *fwnode, *child;
+	u32 ep_port_val;
+
+	fwnode = acpi_fwnode_handle(pdm_dev);
+	child = fwnode_get_next_child_node(fwnode, NULL);
+	if (!child)
+		return;
+
+	if (!fwnode_property_read_u32(child, "acp-audio-ep-port", &ep_port_val)) {
+		if (ep_port_val == ACP_DEV_PORT_PDM)
+			acp_data->pdm_sel = ACP7X_PDM_DMIC0;
+		else if (ep_port_val == ACP_DEV_PORT_PDM2)
+			acp_data->pdm_sel = ACP7X_PDM_DMIC1;
+		else
+			dev_warn(sdev->dev,
+				 "acp-audio-ep-port: unrecognized value %u\n",
+				 ep_port_val);
+	}
+	fwnode_handle_put(child);
+}
+
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE)
 static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr)
 {
@@ -1038,6 +1269,8 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
 
 free_ipc_irq:
 	free_irq(sdev->ipc_irq, sdev);
+	if (adata->sdw)
+		amd_sof_sdw_exit(sdev);
 unregister_dev:
 	platform_device_unregister(adata->dmic_dev);
 	return ret;
@@ -1048,12 +1281,12 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
 {
 	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
 
-	if (adata->sdw)
-		amd_sof_sdw_exit(sdev);
-
 	if (sdev->ipc_irq)
 		free_irq(sdev->ipc_irq, sdev);
 
+	if (adata->sdw)
+		amd_sof_sdw_exit(sdev);
+
 	if (adata->dmic_dev)
 		platform_device_unregister(adata->dmic_dev);
 
@@ -1068,6 +1301,7 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev)
 	const struct sof_amd_acp_desc *chip;
 	const union acpi_object *obj;
 	struct acpi_device *adev;
+	struct acpi_device *pdm_dev;
 	unsigned int addr;
 	unsigned int irqflags;
 	int ret;
@@ -1120,7 +1354,27 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev)
 		goto unregister_dev;
 	}
 
+	/* scan SoundWire capabilities exposed by DSDT */
+	ret = acp_sof_scan_sdw_devices(sdev, chip->sdw_acpi_dev_addr);
+	if (ret < 0) {
+		dev_dbg(sdev->dev, "skipping SoundWire, not detected with ACPI scan\n");
+		goto skip_soundwire;
+	}
+	ret = amd_sof_sdw_probe(sdev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: SoundWire probe error\n");
+		goto free_ipc_irq;
+	}
+	if (adata->info.link_mask)
+		adata->is_sdw_dev = true;
+
+skip_soundwire:
 	if (adev) {
+		/* DMIC ACPI child address is 2 on ACP7x platforms */
+		pdm_dev = acpi_find_child_device(adev, ACP7X_DMIC_ADDR, 0);
+		if (pdm_dev)
+			acp_sof_scan_pdm_devices(sdev, pdm_dev);
+
 		if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image",
 					   ACPI_TYPE_INTEGER, &obj))
 			adata->acp_sof_signed_firmware_image = obj->integer.value;
@@ -1158,6 +1412,8 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev)
 
 free_ipc_irq:
 	free_irq(sdev->ipc_irq, sdev);
+	if (adata->sdw)
+		amd_sof_sdw_exit(sdev);
 unregister_dev:
 	platform_device_unregister(adata->dmic_dev);
 	return ret;
@@ -1171,6 +1427,9 @@ void amd_sof_acp7x_remove(struct snd_sof_dev *sdev)
 	if (sdev->ipc_irq)
 		free_irq(sdev->ipc_irq, sdev);
 
+	if (adata->sdw)
+		amd_sof_sdw_exit(sdev);
+
 	if (adata->dmic_dev)
 		platform_device_unregister(adata->dmic_dev);
 
@@ -1178,6 +1437,44 @@ void amd_sof_acp7x_remove(struct snd_sof_dev *sdev)
 }
 EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON");
 
+static void handle_amd_sof_acp7x_sdw_pme_event(struct snd_sof_dev *sdev)
+{
+	struct acp_dev_data *adata;
+	struct amd_sdw_manager *amd_manager;
+	u32 sdw_pme_stat;
+	u32 sdw_wake_en;
+	u32 pme_reg;
+	u32 wake_mask;
+	unsigned int instance;
+
+	adata = sdev->pdata->hw_pdata;
+	if (!adata->sdw)
+		return;
+
+	for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) {
+		pme_reg = ACP7X_SW_PME_STS + (instance * 4);
+		wake_mask = ACP7X_SW_WAKE_EN_MASK << instance;
+
+		sdw_pme_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, pme_reg);
+		if (!sdw_pme_stat)
+			continue;
+
+		mutex_lock(&adata->acp_lock);
+		sdw_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN);
+		sdw_wake_en &= ~wake_mask;
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN, sdw_wake_en);
+		mutex_unlock(&adata->acp_lock);
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, pme_reg, sdw_pme_stat);
+
+		if (!adata->sdw->pdev[instance])
+			continue;
+
+		amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev);
+		if (amd_manager)
+			pm_request_resume(amd_manager->dev);
+	}
+}
+
 int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state)
 {
 	struct acp_dev_data *acp_data;
@@ -1186,6 +1483,11 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state)
 
 	acp_data = sdev->pdata->hw_pdata;
 
+	if (acp_data->is_sdw_dev && check_acp_sdw_enable_status(sdev)) {
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1);
+		return acp_dsp_reset(sdev);
+	}
+
 	ret = acp_reset(sdev);
 	if (ret) {
 		dev_err(sdev->dev, "ACP Reset failed\n");
@@ -1197,7 +1499,8 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state)
 		enable = true;
 		break;
 	default:
-		break;
+		dev_err(sdev->dev, "Unexpected PCI revision: 0x%x\n", acp_data->pci_rev);
+		return -EINVAL;
 	}
 	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);
 	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1);
@@ -1206,13 +1509,25 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state)
 }
 EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON");
 
-int amd_sof_acp7x_resume(struct snd_sof_dev *sdev)
+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev)
+{
+	return amd_sof_acp7x_suspend(sdev, 0);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev)
 {
 	struct acp_dev_data *acp_data;
 	int ret;
 
 	acp_data = sdev->pdata->hw_pdata;
 
+	if (acp_data->sdw_en_stat) {
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0);
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
+		return acp_dsp_reset(sdev);
+	}
+
 	ret = acp_init(sdev);
 	if (ret) {
 		dev_err(sdev->dev, "ACP Init failed\n");
@@ -1224,31 +1539,41 @@ int amd_sof_acp7x_resume(struct snd_sof_dev *sdev)
 		return ret;
 	}
 
-	switch (acp_data->pci_rev) {
-	case ACP7B_PCI_ID:
-	case ACP7F_PCI_ID:
+	if (acp_data->is_sdw_dev)
+		handle_amd_sof_acp7x_sdw_pme_event(sdev);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev)
+{
+	struct acp_dev_data *acp_data;
+	int ret;
+
+	acp_data = sdev->pdata->hw_pdata;
+
+	if (acp_data->sdw_en_stat) {
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0);
 		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
-		break;
-	default:
-		break;
+		return acp_dsp_reset(sdev);
+	}
+
+	ret = acp_init(sdev);
+	if (ret) {
+		dev_err(sdev->dev, "ACP Init failed\n");
+		return ret;
+	}
+	ret = acp_memory_init(sdev);
+	if (ret) {
+		dev_err(sdev->dev, "ACP Memory init failed\n");
+		return ret;
 	}
 
 	return 0;
 }
 EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON");
 
-int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev)
-{
-	return amd_sof_acp7x_suspend(sdev, 0);
-}
-EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON");
-
-int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev)
-{
-	return amd_sof_acp7x_resume(sdev);
-}
-EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON");
-
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("AMD ACP sof driver");
 MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 16d66b2..1bc6b57 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -125,6 +125,17 @@
 #define ACP_SRAM_PAGE_COUNT			128
 #define ACP6X_SDW_MAX_MANAGER_COUNT		2
 #define ACP70_SDW_MAX_MANAGER_COUNT		ACP6X_SDW_MAX_MANAGER_COUNT
+/* ACPI _DSD acp-audio-ep-port values for PDM controller selection */
+#define ACP_DEV_PORT_PDM			4
+#define ACP_DEV_PORT_PDM2			5
+#define SDW_ACPI_ADDR_ACP7X			SDW_ACPI_ADDR_ACP63
+#define ACP7X_SDW_MAX_MANAGER_COUNT		4
+
+/* ACPI child device address for the ACP7x PDM/DMIC device */
+#define ACP7X_DMIC_ADDR				2
+/* ACP7X PDM controller selection values for acp_dev_data.pdm_sel; 0 = not set */
+#define ACP7X_PDM_DMIC0				1
+#define ACP7X_PDM_DMIC1				2
 #define ACP_DSP_MSG_SET				1
 #define ACP_DSP_ACK_SET				1
 
@@ -279,6 +290,11 @@ struct acp_dev_data {
 	bool acp70_sdw0_wake_event;
 	/* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */
 	bool acp70_sdw1_wake_event;
+	/* per-manager wake event flags; indexed by SoundWire manager instance (0-3) */
+	bool acp7x_sdw_wake_event[ACP7X_SDW_MAX_MANAGER_COUNT];
+	/* PDM controller index selected from ACPI acp-audio-ep-port; passed to machine driver */
+	unsigned int pdm_sel;
+	bool is_sdw_dev;
 	unsigned int pci_rev;
 	int acp_sof_signed_firmware_image;
 };
diff --git a/sound/soc/sof/amd/acp7x.h b/sound/soc/sof/amd/acp7x.h
new file mode 100644
index 0000000..5151d87
--- /dev/null
+++ b/sound/soc/sof/amd/acp7x.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * Author: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+ */
+
+#ifndef __SOF_AMD_ACP7X_H
+#define __SOF_AMD_ACP7X_H
+
+/* Return values for sof_amd_check_and_handle_acp7x_sdw_wake_irq() */
+#define WAKE_IRQ_HANDLED			1
+#define WAKE_IRQ_NONE				0
+
+/* ACP7X SoundWire IO structures */
+
+struct sof_amd_acp7x_sdw_err_regs {
+	u32 err_stat_mask;
+	u32 fifo_err_reason;
+	u32 err_reason1;
+	u32 err_reason2;
+};
+
+struct acp7x_sdw_wake_src {
+	u32 host_stat_mask;
+	u32 pme_sts_reg;
+	u32 wake_en_mask;
+	u8  instance;
+};
+
+extern const struct sof_amd_acp7x_sdw_err_regs acp7x_sdw_err_regs[ACP7X_SDW_MAX_MANAGER_COUNT];
+extern const struct acp7x_sdw_wake_src acp7x_sdw_wake_sources[];
+
+#endif /* __SOF_AMD_ACP7X_H */
diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c
index 532e153..0594c1f 100644
--- a/sound/soc/sof/amd/pci-acp7x.c
+++ b/sound/soc/sof/amd/pci-acp7x.c
@@ -40,6 +40,8 @@ static const struct sof_amd_acp_desc acp7x_chip_info = {
 	.fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL,
 	.probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0,
 	.reg_start_addr	= ACP7X_REG_START,
+	.sdw_max_link_count = ACP7X_SDW_MAX_MANAGER_COUNT,
+	.sdw_acpi_dev_addr = SDW_ACPI_ADDR_ACP7X,
 	.reg_end_addr	= ACP7X_REG_END,
 };
 
diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c
index 7a03c8c..436fe49 100644
--- a/sound/soc/sof/imx/imx-common.c
+++ b/sound/soc/sof/imx/imx-common.c
@@ -34,6 +34,7 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
 
 	/* first read registers */
 	sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
+	xoops->plat_hdr.numaregs = 0;
 
 	/* then get panic info */
 	if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c
index 7e9eab2..0820724 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -36,19 +36,23 @@
 
 struct imx8m_chip_data {
 	void __iomem *dap;
-	struct regmap *regmap;
 	struct reset_control *run_stall;
 };
 
 static int imx8_shutdown(struct snd_sof_dev *sdev)
 {
+	int ret;
 	/*
 	 * Force the DSP to stall. After the firmware image is loaded,
 	 * the stall will be removed during run() by a matching
 	 * imx_sc_pm_cpu_start() call.
 	 */
-	imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, false,
-			    RESET_VECTOR_VADDR);
+	ret = imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, false,
+				  RESET_VECTOR_VADDR);
+	if (ret < 0) {
+		dev_err(sdev->dev, "Error stalling DSP core %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
@@ -89,8 +93,12 @@ static int imx8x_run(struct snd_sof_dev *sdev)
 		return ret;
 	}
 
-	imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
-			    RESET_VECTOR_VADDR);
+	ret = imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
+				  RESET_VECTOR_VADDR);
+	if (ret < 0) {
+		dev_err(sdev->dev, "Error starting DSP %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
@@ -106,8 +114,12 @@ static int imx8_run(struct snd_sof_dev *sdev)
 		return ret;
 	}
 
-	imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
-			    RESET_VECTOR_VADDR);
+	ret = imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
+				  RESET_VECTOR_VADDR);
+	if (ret < 0) {
+		dev_err(sdev->dev, "Error starting DSP %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index c1bea96..a5ccee8 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -49,7 +49,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
 	struct mtk_adsp_chip_info *adsp = data;
 	int ret;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret) {
 		dev_err(dev, "of_reserved_mem_device_init failed\n");
 		return ret;
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index 4d6e930..e4b6b6c 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -49,7 +49,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
 	struct mtk_adsp_chip_info *adsp = data;
 	int ret;
 
-	ret = of_reserved_mem_device_init(dev);
+	ret = devm_of_reserved_mem_device_init(dev);
 	if (ret) {
 		dev_err(dev, "of_reserved_mem_device_init failed\n");
 		return ret;
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index f509a46..2d5ffbe 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -459,10 +459,9 @@ static const struct snd_soc_component_driver sprd_soc_component = {
 
 static int sprd_soc_platform_probe(struct platform_device *pdev)
 {
-	struct device_node *np = pdev->dev.of_node;
 	int ret;
 
-	ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
+	ret = devm_of_reserved_mem_device_init(&pdev->dev);
 	if (ret)
 		dev_warn(&pdev->dev,
 			 "no reserved DMA memory for audio platform device\n");
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index e4b9799..844ddcf 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -1028,16 +1028,27 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev,
 	return 0;
 }
 
+static const u64 uni_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops uni_player_dai_ops = {
-		.startup = uni_player_startup,
-		.shutdown = uni_player_shutdown,
-		.prepare = uni_player_prepare,
-		.probe = sti_uniperiph_dai_probe,
-		.trigger = uni_player_trigger,
-		.hw_params = sti_uniperiph_dai_hw_params,
-		.set_fmt = sti_uniperiph_dai_set_fmt,
-		.set_sysclk = uni_player_set_sysclk,
-		.set_tdm_slot = sti_uniperiph_set_tdm_slot
+	.startup			= uni_player_startup,
+	.shutdown			= uni_player_shutdown,
+	.prepare			= uni_player_prepare,
+	.probe				= sti_uniperiph_dai_probe,
+	.trigger			= uni_player_trigger,
+	.hw_params			= sti_uniperiph_dai_hw_params,
+	.set_fmt			= sti_uniperiph_dai_set_fmt,
+	.set_sysclk			= uni_player_set_sysclk,
+	.set_tdm_slot			= sti_uniperiph_set_tdm_slot,
+	.auto_selectable_formats	= &uni_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 int uni_player_init(struct platform_device *pdev,
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
index 5347f96..acdd520 100644
--- a/sound/soc/sti/uniperif_reader.c
+++ b/sound/soc/sti/uniperif_reader.c
@@ -391,15 +391,26 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream,
 	reader->substream = NULL;
 }
 
+static const u64 uni_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops uni_reader_dai_ops = {
-		.startup = uni_reader_startup,
-		.shutdown = uni_reader_shutdown,
-		.prepare = uni_reader_prepare,
-		.probe = sti_uniperiph_dai_probe,
-		.trigger = uni_reader_trigger,
-		.hw_params = sti_uniperiph_dai_hw_params,
-		.set_fmt = sti_uniperiph_dai_set_fmt,
-		.set_tdm_slot = sti_uniperiph_set_tdm_slot
+	.startup			= uni_reader_startup,
+	.shutdown			= uni_reader_shutdown,
+	.prepare			= uni_reader_prepare,
+	.probe				= sti_uniperiph_dai_probe,
+	.trigger			= uni_reader_trigger,
+	.hw_params			= sti_uniperiph_dai_hw_params,
+	.set_fmt			= sti_uniperiph_dai_set_fmt,
+	.set_tdm_slot			= sti_uniperiph_set_tdm_slot,
+	.auto_selectable_formats	= &uni_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 int uni_reader_init(struct platform_device *pdev,
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 83b5189..a59ad944 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -1089,6 +1089,16 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = {
 	.cache_type = REGCACHE_FLAT,
 };
 
+static const u64 stm32_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = {
 	.probe		= stm32_i2s_dai_probe,
 	.set_sysclk	= stm32_i2s_set_sysclk,
@@ -1097,6 +1107,8 @@ static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = {
 	.hw_params	= stm32_i2s_hw_params,
 	.trigger	= stm32_i2s_trigger,
 	.shutdown	= stm32_i2s_shutdown,
+	.auto_selectable_formats	= &stm32_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_pcm_hardware stm32_i2s_pcm_hw = {
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 9a201bd..d00377e 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1358,6 +1358,17 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
+static const u64 stm32_sai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
 	.probe		= stm32_sai_dai_probe,
 	.set_sysclk	= stm32_sai_set_sysclk,
@@ -1368,6 +1379,8 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
 	.trigger	= stm32_sai_trigger,
 	.shutdown	= stm32_sai_shutdown,
 	.pcm_new	= stm32_sai_pcm_new,
+	.auto_selectable_formats	= &stm32_sai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = {
@@ -1379,6 +1392,8 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = {
 	.hw_params	= stm32_sai_hw_params,
 	.trigger	= stm32_sai_trigger,
 	.shutdown	= stm32_sai_shutdown,
+	.auto_selectable_formats	= &stm32_sai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream,
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 716fa4d..43e6ea2 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1106,6 +1106,17 @@ static int sun4i_i2s_dai_startup(struct snd_pcm_substream *sub, struct snd_soc_d
 					    i2s->variant->pcm_formats);
 }
 
+static const u64 sun4i_i2s_selectable_format =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
 	.probe		= sun4i_i2s_dai_probe,
 	.startup	= sun4i_i2s_dai_startup,
@@ -1114,6 +1125,8 @@ static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
 	.set_sysclk	= sun4i_i2s_set_sysclk,
 	.set_tdm_slot	= sun4i_i2s_set_tdm_slot,
 	.trigger	= sun4i_i2s_trigger,
+	.auto_selectable_formats	= &sun4i_i2s_selectable_format,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define SUN4I_FORMATS_ALL (SNDRV_PCM_FMTBIT_S16_LE | \
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 6bd42da..2e4a205 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -688,12 +688,25 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const u64 sun8i_codec_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 	.set_fmt	= sun8i_codec_set_fmt,
 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
 	.startup	= sun8i_codec_startup,
 	.hw_params	= sun8i_codec_hw_params,
 	.hw_free	= sun8i_codec_hw_free,
+	.auto_selectable_formats	= &sun8i_codec_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index d9ab210..b31f947 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -309,12 +309,22 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream,
 				   SNDRV_PCM_HW_PARAM_RATE, -1);
 }
 
+static const u64 tegra20_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
 	.probe		= tegra20_i2s_probe,
 	.set_fmt	= tegra20_i2s_set_fmt,
 	.hw_params	= tegra20_i2s_hw_params,
 	.trigger	= tegra20_i2s_trigger,
 	.startup	= tegra20_i2s_startup,
+	.auto_selectable_formats	= &tegra20_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c
index e75bf50..f2adf1c 100644
--- a/sound/soc/tegra/tegra210_adx.c
+++ b/sound/soc/tegra/tegra210_adx.c
@@ -676,11 +676,13 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev)
 	void __iomem *regs;
 	int err, i;
 
-	adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL);
+	soc_data = of_device_get_match_data(dev);
+	adx = devm_kzalloc(dev,
+			   struct_size(adx, map, soc_data->ram_depth * TEGRA_ADX_SLOTS_PER_WORD),
+			   GFP_KERNEL);
 	if (!adx)
 		return -ENOMEM;
 
-	soc_data = of_device_get_match_data(dev);
 	adx->soc_data = soc_data;
 
 	dev_set_drvdata(dev, adx);
@@ -697,12 +699,6 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev)
 
 	regcache_cache_only(adx->regmap, true);
 
-	adx->map = devm_kcalloc(dev,
-				soc_data->ram_depth * TEGRA_ADX_SLOTS_PER_WORD,
-				sizeof(*adx->map), GFP_KERNEL);
-	if (!adx->map)
-		return -ENOMEM;
-
 	adx->byte_mask = devm_kcalloc(dev, soc_data->byte_mask_size,
 				      sizeof(*adx->byte_mask), GFP_KERNEL);
 	if (!adx->byte_mask)
diff --git a/sound/soc/tegra/tegra210_adx.h b/sound/soc/tegra/tegra210_adx.h
index a6298c3..e5f1b44 100644
--- a/sound/soc/tegra/tegra210_adx.h
+++ b/sound/soc/tegra/tegra210_adx.h
@@ -92,8 +92,8 @@ struct tegra210_adx_soc_data {
 struct tegra210_adx {
 	struct regmap *regmap;
 	unsigned int *byte_mask;
-	u16 *map;
 	const struct tegra210_adx_soc_data *soc_data;
+	u16 map[];
 };
 
 #endif
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index 79a2f89..f2cfe3b 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -739,11 +739,24 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
 					      cif_conf.client_ch);
 }
 
+static const u64 tegra210_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
 	.set_fmt	= tegra210_i2s_set_fmt,
 	.hw_params	= tegra210_i2s_hw_params,
 	.set_bclk_ratio	= tegra210_i2s_set_dai_bclk_ratio,
 	.set_tdm_slot	= tegra210_i2s_set_tdm_slot,
+	.auto_selectable_formats	= &tegra210_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 1d7b3aed..69acff7 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -302,12 +302,22 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 tegra30_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
 	.probe		= tegra30_i2s_probe,
 	.set_fmt	= tegra30_i2s_set_fmt,
 	.hw_params	= tegra30_i2s_hw_params,
 	.trigger	= tegra30_i2s_trigger,
 	.set_tdm_slot	= tegra30_i2s_set_tdm,
+	.auto_selectable_formats	= &tegra30_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index 059967f..3614f61 100644
--- a/sound/soc/ti/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
@@ -49,7 +49,7 @@
  *    incompatible with ASP and with either McBSP.
  *
  * In short:  this uses ASP to implement I2S, not McBSP.
- * And it won't be the only DaVinci implemention of I2S.
+ * And it won't be the only DaVinci implementation of I2S.
  */
 #define DAVINCI_MCBSP_DRR_REG	0x00
 #define DAVINCI_MCBSP_DXR_REG	0x04
@@ -743,6 +743,17 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 davinci_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_CONT	|
+	SND_SOC_POSSIBLE_DAIFMT_GATED	|
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
 	.probe		= davinci_i2s_dai_probe,
 	.shutdown	= davinci_i2s_shutdown,
@@ -752,7 +763,8 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
 	.set_fmt	= davinci_i2s_set_dai_fmt,
 	.set_clkdiv	= davinci_i2s_dai_set_clkdiv,
 	.set_tdm_slot   = davinci_i2s_set_tdm_slot,
-
+	.auto_selectable_formats	= &davinci_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver davinci_i2s_dai = {
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 7923913..d461ab4 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -1818,7 +1818,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
 	    !mcasp->async_mode)
 		max_channels = mcasp->channels;
 	/*
-	 * But we can always allow channels upto the amount of
+	 * But we can always allow channels up to the amount of
 	 * the available tdm_slots.
 	 */
 	if (max_channels < tdm_slots)
@@ -1993,6 +1993,18 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 davinci_mcasp_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_AC97	|
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF;
+
 static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 	.probe		= davinci_mcasp_dai_probe,
 	.startup	= davinci_mcasp_startup,
@@ -2004,6 +2016,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 	.set_clkdiv	= davinci_mcasp_set_clkdiv,
 	.set_sysclk	= davinci_mcasp_set_sysclk,
 	.set_tdm_slot	= davinci_mcasp_set_tdm_slot,
+	.auto_selectable_formats	= &davinci_mcasp_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 #define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index 26af616..889e357 100644
--- a/sound/soc/ti/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -1237,7 +1237,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 		break;
 	case OMAP_MCBSP_SYSCLK_CLKR_EXT:
 		regs->pcr0	|= SCLKME;
-		/* Disable ouput on CLKR pin in master mode */
+		/* Disable output on CLKR pin in master mode */
 		regs->pcr0	&= ~CLKRM;
 		break;
 	default:
@@ -1269,6 +1269,16 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 mcbsp_mcbsp_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
 static const struct snd_soc_dai_ops mcbsp_dai_ops = {
 	.probe		= omap_mcbsp_probe,
 	.remove		= omap_mcbsp_remove,
@@ -1281,6 +1291,8 @@ static const struct snd_soc_dai_ops mcbsp_dai_ops = {
 	.set_fmt	= omap_mcbsp_dai_set_dai_fmt,
 	.set_clkdiv	= omap_mcbsp_dai_set_clkdiv,
 	.set_sysclk	= omap_mcbsp_dai_set_dai_sysclk,
+	.auto_selectable_formats	= &mcbsp_mcbsp_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver omap_mcbsp_dai = {
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 78c82bf..b263526 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -440,6 +440,11 @@ static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static const u64 uniphier_aio_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
+	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
 const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
 	.probe		= uniphier_aio_ld11_probe,
 	.remove		= uniphier_aio_dai_remove,
@@ -451,6 +456,8 @@ const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
 	.hw_params	= uniphier_aio_hw_params,
 	.hw_free	= uniphier_aio_hw_free,
 	.prepare	= uniphier_aio_prepare,
+	.auto_selectable_formats	= &uniphier_aio_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops);
 
@@ -492,6 +499,8 @@ const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = {
 	.hw_params	= uniphier_aio_hw_params,
 	.hw_free	= uniphier_aio_hw_free,
 	.prepare	= uniphier_aio_prepare,
+	.auto_selectable_formats	= &uniphier_aio_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops);
 
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
index c01eae5..389a453 100644
--- a/sound/soc/uniphier/aio-dma.c
+++ b/sound/soc/uniphier/aio-dma.c
@@ -66,8 +66,7 @@ static void aiodma_compr_irq(struct uniphier_aio_sub *sub)
 
 static irqreturn_t aiodma_irq(int irq, void *p)
 {
-	struct platform_device *pdev = p;
-	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
+	struct uniphier_aio_chip *chip = p;
 	irqreturn_t ret = IRQ_NONE;
 	int i, j;
 
@@ -263,7 +262,7 @@ int uniphier_aiodma_soc_register_platform(struct platform_device *pdev)
 		return irq;
 
 	ret = devm_request_irq(dev, irq, aiodma_irq,
-			       IRQF_SHARED, dev_name(dev), pdev);
+			       IRQF_SHARED, dev_name(dev), chip);
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index 1900ea0..87b2725 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -183,7 +183,7 @@ struct uniphier_aio_selector {
  *
  * These are examples for sound data paths:
  *
- * For caputure device:
+ * For capture device:
  *   (outer of AIO) -> iport -> iif -> ch -> rb -> (CPU)
  * For playback device:
  *   (CPU) -> rb -> ch -> oif -> oport -> (outer of AIO)
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 37c48cc..c135a77 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -644,18 +644,25 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
-static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
-	{
-		.probe = ux500_msp_dai_of_probe,
-		.set_sysclk = ux500_msp_dai_set_dai_sysclk,
-		.set_fmt = ux500_msp_dai_set_dai_fmt,
-		.set_tdm_slot = ux500_msp_dai_set_tdm_slot,
-		.startup = ux500_msp_dai_startup,
-		.shutdown = ux500_msp_dai_shutdown,
-		.prepare = ux500_msp_dai_prepare,
-		.trigger = ux500_msp_dai_trigger,
-		.hw_params = ux500_msp_dai_hw_params,
-	}
+static const u64 ux500_msp_dai_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_IF	|
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
+	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
+static const struct snd_soc_dai_ops ux500_msp_dai_ops = {
+	.probe		= ux500_msp_dai_of_probe,
+	.set_sysclk	= ux500_msp_dai_set_dai_sysclk,
+	.set_fmt	= ux500_msp_dai_set_dai_fmt,
+	.set_tdm_slot	= ux500_msp_dai_set_tdm_slot,
+	.startup	= ux500_msp_dai_startup,
+	.shutdown	= ux500_msp_dai_shutdown,
+	.prepare	= ux500_msp_dai_prepare,
+	.trigger	= ux500_msp_dai_trigger,
+	.hw_params	= ux500_msp_dai_hw_params,
+	.auto_selectable_formats	= &ux500_msp_dai_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver ux500_msp_dai_drv = {
@@ -667,7 +674,7 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv = {
 	.capture.channels_max  = UX500_MSP_MAX_CHANNELS,
 	.capture.rates         = UX500_I2S_RATES,
 	.capture.formats       = UX500_I2S_FORMATS,
-	.ops                   = ux500_msp_dai_ops,
+	.ops                   = &ux500_msp_dai_ops,
 };
 
 static const struct snd_soc_component_driver ux500_msp_component = {
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index 683b485..bd2cfc6 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -19,7 +19,7 @@
 
 #include "ux500_msp_i2s.h"
 
- /* Protocol desciptors */
+ /* Protocol descriptors */
 static const struct msp_protdesc prot_descs[] = {
 	{ /* I2S */
 		MSP_SINGLE_PHASE,
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 95312b4..304220d 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -81,7 +81,6 @@ struct xlnx_pcm_drv_data {
 	int mm2s_irq;
 	struct snd_pcm_substream *play_stream;
 	struct snd_pcm_substream *capture_stream;
-	struct clk *axi_clk;
 	unsigned int sysclk;
 };
 
@@ -595,100 +594,68 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
 	u32 val;
 	struct xlnx_pcm_drv_data *aud_drv_data;
 	struct device *dev = &pdev->dev;
+	struct clk *axi_clk;
+
+	axi_clk = devm_clk_get_enabled(dev, "s_axi_lite_aclk");
+	if (IS_ERR(axi_clk))
+		return dev_err_probe(dev, PTR_ERR(axi_clk), "failed to get s_axi_lite_aclk");
 
 	aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL);
 	if (!aud_drv_data)
 		return -ENOMEM;
 
-	aud_drv_data->axi_clk = devm_clk_get(dev, "s_axi_lite_aclk");
-	if (IS_ERR(aud_drv_data->axi_clk)) {
-		ret = PTR_ERR(aud_drv_data->axi_clk);
-		dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret);
-		return ret;
-	}
-	ret = clk_prepare_enable(aud_drv_data->axi_clk);
-	if (ret) {
-		dev_err(dev,
-			"failed to enable s_axi_lite_aclk(%d)\n", ret);
-		return ret;
-	}
-
 	aud_drv_data->mmio = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(aud_drv_data->mmio)) {
-		dev_err(dev, "audio formatter ioremap failed\n");
-		ret = PTR_ERR(aud_drv_data->mmio);
-		goto clk_err;
-	}
+	if (IS_ERR(aud_drv_data->mmio))
+		return PTR_ERR(aud_drv_data->mmio);
 
 	val = readl(aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG);
 	if (val & AUD_CFG_MM2S_MASK) {
 		aud_drv_data->mm2s_presence = true;
 		ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +
 					       XLNX_MM2S_OFFSET);
-		if (ret) {
-			dev_err(dev, "audio formatter reset failed\n");
-			goto clk_err;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "audio formatter reset failed\n");
 		xlnx_formatter_disable_irqs(aud_drv_data->mmio +
 					    XLNX_MM2S_OFFSET,
 					    SNDRV_PCM_STREAM_PLAYBACK);
 
 		aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev,
 								 "irq_mm2s");
-		if (aud_drv_data->mm2s_irq < 0) {
-			ret = aud_drv_data->mm2s_irq;
-			goto clk_err;
-		}
+		if (aud_drv_data->mm2s_irq < 0)
+			return aud_drv_data->mm2s_irq;
+
 		ret = devm_request_irq(dev, aud_drv_data->mm2s_irq,
 				       xlnx_mm2s_irq_handler, 0,
 				       "xlnx_formatter_pcm_mm2s_irq", aud_drv_data);
-		if (ret) {
-			dev_err(dev, "xlnx audio mm2s irq request failed\n");
-			goto clk_err;
-		}
+		if (ret)
+			return ret;
 	}
 	if (val & AUD_CFG_S2MM_MASK) {
 		aud_drv_data->s2mm_presence = true;
 		ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +
 					       XLNX_S2MM_OFFSET);
-		if (ret) {
-			dev_err(dev, "audio formatter reset failed\n");
-			goto clk_err;
-		}
+		if (ret)
+			return dev_err_probe(dev, ret, "audio formatter reset failed\n");
 		xlnx_formatter_disable_irqs(aud_drv_data->mmio +
 					    XLNX_S2MM_OFFSET,
 					    SNDRV_PCM_STREAM_CAPTURE);
 
 		aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev,
 								 "irq_s2mm");
-		if (aud_drv_data->s2mm_irq < 0) {
-			ret = aud_drv_data->s2mm_irq;
-			goto clk_err;
-		}
+		if (aud_drv_data->s2mm_irq < 0)
+			return aud_drv_data->s2mm_irq;
+
 		ret = devm_request_irq(dev, aud_drv_data->s2mm_irq,
 				       xlnx_s2mm_irq_handler, 0,
 				       "xlnx_formatter_pcm_s2mm_irq",
 				       aud_drv_data);
-		if (ret) {
-			dev_err(dev, "xlnx audio s2mm irq request failed\n");
-			goto clk_err;
-		}
+		if (ret)
+			return ret;
 	}
 
 	dev_set_drvdata(dev, aud_drv_data);
 
-	ret = devm_snd_soc_register_component(dev, &xlnx_asoc_component,
-					      NULL, 0);
-	if (ret) {
-		dev_err(dev, "pcm platform device register failed\n");
-		goto clk_err;
-	}
-
-	return 0;
-
-clk_err:
-	clk_disable_unprepare(aud_drv_data->axi_clk);
-	return ret;
+	return devm_snd_soc_register_component(dev, &xlnx_asoc_component, NULL, 0);
 }
 
 static void xlnx_formatter_pcm_remove(struct platform_device *pdev)
@@ -705,8 +672,6 @@ static void xlnx_formatter_pcm_remove(struct platform_device *pdev)
 
 	if (ret)
 		dev_err(&pdev->dev, "audio formatter reset failed\n");
-
-	clk_disable_unprepare(adata->axi_clk);
 }
 
 static const struct of_device_id xlnx_formatter_pcm_of_match[] = {
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index fd09902..e5e8b72 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -485,10 +485,16 @@ static const struct snd_soc_component_driver xtfpga_i2s_component = {
 	.legacy_dai_naming	= 1,
 };
 
+static const u64 xtfpga_i2s_selectable_formats =
+	SND_SOC_POSSIBLE_DAIFMT_I2S	|
+	SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
 static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = {
-	.startup	= xtfpga_i2s_startup,
-	.hw_params      = xtfpga_i2s_hw_params,
-	.set_fmt	= xtfpga_i2s_set_fmt,
+	.startup			= xtfpga_i2s_startup,
+	.hw_params			= xtfpga_i2s_hw_params,
+	.set_fmt			= xtfpga_i2s_set_fmt,
+	.auto_selectable_formats	= &xtfpga_i2s_selectable_formats,
+	.num_auto_selectable_formats	= 1,
 };
 
 static struct snd_soc_dai_driver xtfpga_i2s_dai[] = {