diff --git a/Documentation/devicetree/bindings/sound/fsl,sai.yaml b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
index 5b28d2d513277477e6ef3393032a0e6cbb43c38c..7e56337d8edc1604f16f0e45f1c4e93c7503af89 100644
--- a/Documentation/devicetree/bindings/sound/fsl,sai.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
@@ -38,6 +38,7 @@ properties:
               - fsl,imx8mq-sai
               - fsl,imx8qm-sai
               - fsl,imx8ulp-sai
+              - fsl,imx93-sai
               - fsl,vf610-sai
 
   reg:
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index 68ab89211de28308476670269ee532f899153cb3..511211f4a2b66fa94f97f91c5223387789d286ad 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -75,6 +75,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
 					   struct snd_pcm_substream *substream,
 					   int type);
 void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type);
+struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
+						    struct snd_compr_stream *cstream);
 void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
 					 struct hdac_ext_stream *hext_stream, bool decouple);
 void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 2a071a09224debce702abb59e6b592962cc18e4a..11b7119cc47e631892cec7bb8ed8c0958908266a 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -14,6 +14,7 @@
 #include <sound/pcm.h>
 #include <sound/hda_register.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/compress_driver.h>
 
 /**
  * snd_hdac_ext_stream_init - initialize each stream (aka device)
@@ -367,3 +368,43 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
 
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
+
+/**
+ * snd_hdac_ext_cstream_assign - assign a host stream for compress
+ * @bus: HD-audio core bus
+ * @cstream: Compress stream to assign
+ *
+ * Assign an unused host stream for the given compress stream.
+ * If no stream is free, NULL is returned. Stream is decoupled
+ * before assignment.
+ */
+struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
+						    struct snd_compr_stream *cstream)
+{
+	struct hdac_ext_stream *res = NULL;
+	struct hdac_stream *hstream;
+
+	spin_lock_irq(&bus->reg_lock);
+	list_for_each_entry(hstream, &bus->stream_list, list) {
+		struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+
+		if (hstream->direction != cstream->direction)
+			continue;
+
+		if (!hstream->opened) {
+			res = hext_stream;
+			break;
+		}
+	}
+
+	if (res) {
+		snd_hdac_ext_stream_decouple_locked(bus, res, true);
+		res->hstream.opened = 1;
+		res->hstream.running = 0;
+		res->hstream.cstream = cstream;
+	}
+	spin_unlock_irq(&bus->reg_lock);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_cstream_assign);
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index 9a60bfdb39bac564b07a6e2a19206d224b1160a8..3c7af655824914fdfa1e9ea105346c2f61708558 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -578,8 +578,8 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
 			sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
 			snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
 			handled |= 1 << azx_dev->index;
-			if (!azx_dev->substream || !azx_dev->running ||
-			    !(sd_status & SD_INT_COMPLETE))
+			if ((!azx_dev->substream && !azx_dev->cstream) ||
+			    !azx_dev->running || !(sd_status & SD_INT_COMPLETE))
 				continue;
 			if (ack)
 				ack(bus, azx_dev);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index 3b250ee7f6a7b6c2b18f932d41873febb101030e..8f625402505f8709b7af4bc92806926de3dcad75 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -7,6 +7,7 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/clocksource.h>
+#include <sound/compress_driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/hdaudio.h>
@@ -487,11 +488,20 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
 {
 	struct hdac_bus *bus = azx_dev->bus;
 	struct snd_pcm_substream *substream = azx_dev->substream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_compr_stream *cstream = azx_dev->cstream;
+	struct snd_pcm_runtime *runtime = NULL;
+	struct snd_dma_buffer *dmab;
 	__le32 *bdl;
 	int i, ofs, periods, period_bytes;
 	int pos_adj, pos_align;
 
+	if (substream) {
+		runtime = substream->runtime;
+		dmab = snd_pcm_get_dma_buf(substream);
+	} else if (cstream) {
+		dmab = snd_pcm_get_dma_buf(cstream);
+	}
+
 	/* reset BDL address */
 	snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
 	snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
@@ -505,7 +515,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
 	azx_dev->frags = 0;
 
 	pos_adj = bus->bdl_pos_adj;
-	if (!azx_dev->no_period_wakeup && pos_adj > 0) {
+	if (runtime && !azx_dev->no_period_wakeup && pos_adj > 0) {
 		pos_align = pos_adj;
 		pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000);
 		if (!pos_adj)
@@ -518,8 +528,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
 				 pos_adj);
 			pos_adj = 0;
 		} else {
-			ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
-					 azx_dev,
+			ofs = setup_bdle(bus, dmab, azx_dev,
 					 &bdl, ofs, pos_adj, true);
 			if (ofs < 0)
 				goto error;
@@ -529,13 +538,11 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
 
 	for (i = 0; i < periods; i++) {
 		if (i == periods - 1 && pos_adj)
-			ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
-					 azx_dev, &bdl, ofs,
-					 period_bytes - pos_adj, 0);
+			ofs = setup_bdle(bus, dmab, azx_dev,
+					 &bdl, ofs, period_bytes - pos_adj, 0);
 		else
-			ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
-					 azx_dev, &bdl, ofs,
-					 period_bytes,
+			ofs = setup_bdle(bus, dmab, azx_dev,
+					 &bdl, ofs, period_bytes,
 					 !azx_dev->no_period_wakeup);
 		if (ofs < 0)
 			goto error;
@@ -560,26 +567,32 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods);
 int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
 				 unsigned int format_val)
 {
-
-	unsigned int bufsize, period_bytes;
 	struct snd_pcm_substream *substream = azx_dev->substream;
-	struct snd_pcm_runtime *runtime;
+	struct snd_compr_stream *cstream = azx_dev->cstream;
+	unsigned int bufsize, period_bytes;
+	unsigned int no_period_wakeup;
 	int err;
 
-	if (!substream)
+	if (substream) {
+		bufsize = snd_pcm_lib_buffer_bytes(substream);
+		period_bytes = snd_pcm_lib_period_bytes(substream);
+		no_period_wakeup = substream->runtime->no_period_wakeup;
+	} else if (cstream) {
+		bufsize = cstream->runtime->buffer_size;
+		period_bytes = cstream->runtime->fragment_size;
+		no_period_wakeup = 0;
+	} else {
 		return -EINVAL;
-	runtime = substream->runtime;
-	bufsize = snd_pcm_lib_buffer_bytes(substream);
-	period_bytes = snd_pcm_lib_period_bytes(substream);
+	}
 
 	if (bufsize != azx_dev->bufsize ||
 	    period_bytes != azx_dev->period_bytes ||
 	    format_val != azx_dev->format_val ||
-	    runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
+	    no_period_wakeup != azx_dev->no_period_wakeup) {
 		azx_dev->bufsize = bufsize;
 		azx_dev->period_bytes = period_bytes;
 		azx_dev->format_val = format_val;
-		azx_dev->no_period_wakeup = runtime->no_period_wakeup;
+		azx_dev->no_period_wakeup = no_period_wakeup;
 		err = snd_hdac_stream_setup_periods(azx_dev);
 		if (err < 0)
 			return err;
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index 4c7ebc7fb400131756e909fb932d3bc07cf448b6..a75db27e52055c45b031450bd4dce0857d5836f4 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -130,12 +130,6 @@ static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
 		ctrl->clsh_users = 0;
 }
 
-static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
-{
-	return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) &
-					WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
-}
-
 static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
 					  int mode)
 {
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 50b71e5d45897c128ee478f79ec233acb0d99b02..582f1e2431eee3b4db2c238715732c48644139a2 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -75,8 +75,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
 	if (!buf)
 		return -ENOMEM;
 
-	ret = scnprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
-		       pdcr, ptcr);
+	ret = sysfs_emit(buf, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr);
 
 	if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR)
 		ret += scnprintf(buf + ret, PAGE_SIZE - ret,
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index fe7cf972d44ce61e550e206174f0b5bc98eb4b13..5daa824a4ffcf8925cd18b9406e4353413dd038b 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -485,8 +485,10 @@ static int __graph_for_each_link(struct asoc_simple_priv *priv,
 			of_node_put(codec_ep);
 			of_node_put(codec_port);
 
-			if (ret < 0)
+			if (ret < 0) {
+				of_node_put(cpu_ep);
 				return ret;
+			}
 
 			codec_port_old = codec_port;
 		}
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index ac799de4f7fdae0f8c096abd5d475af32e79d971..4b9e498e330373be1903fa38dee092729da20f2b 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS
 	select SND_SOC_ACPI if ACPI
 	select SND_SOC_TOPOLOGY
 	select SND_SOC_HDA
+	select SND_SOC_COMPRESS if DEBUG_FS
 	select SND_HDA_EXT_CORE
 	select SND_HDA_DSP_LOADER
 	select SND_INTEL_DSP_CONFIG
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 919212825f21645c29b4baed97d1ae4b2e3adadf..1c6924a1ebca3af4f29db3773b2e5a3cd85985a6 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o
 # tell define_trace.h where to find the trace header
 CFLAGS_trace.o := -I$(src)
 
+ifneq ($(CONFIG_DEBUG_FS),)
+snd-soc-avs-objs += probes.o debugfs.o
+endif
+
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
 
 # Machine support
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index 7c8ce98eda9dd2fa386babea540ff0b8cc7cd8e8..02683dce277aff11cfcb09795209beebfd6196a5 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -13,8 +13,9 @@
 #include "path.h"
 #include "topology.h"
 
-static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
-			   u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+static int __maybe_unused
+apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+		u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
 {
 	struct apl_log_state_info *info;
 	u32 size, num_cores = adev->hw_cfg.dsp_cores;
@@ -50,7 +51,6 @@ static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
 static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
 {
 	struct apl_log_buffer_layout layout;
-	unsigned long flags;
 	void __iomem *addr, *buf;
 
 	addr = avs_log_buffer_addr(adev, msg->log.core);
@@ -59,26 +59,20 @@ static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg
 
 	memcpy_fromio(&layout, addr, sizeof(layout));
 
-	spin_lock_irqsave(&adev->dbg.trace_lock, flags);
-	if (!kfifo_initialized(&adev->dbg.trace_fifo))
+	if (!avs_logging_fw(adev))
 		/* consume the logs regardless of consumer presence */
 		goto update_read_ptr;
 
 	buf = apl_log_payload_addr(addr);
 
 	if (layout.read_ptr > layout.write_ptr) {
-		__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
-				      apl_log_payload_size(adev) - layout.read_ptr,
-				      &adev->dbg.fifo_lock);
+		avs_dump_fw_log(adev, buf + layout.read_ptr,
+				apl_log_payload_size(adev) - layout.read_ptr);
 		layout.read_ptr = 0;
 	}
-	__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
-			      layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
-
-	wake_up(&adev->dbg.trace_waitq);
+	avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr);
 
 update_read_ptr:
-	spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
 	writel(layout.write_ptr, addr);
 	return 0;
 }
@@ -140,7 +134,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
 		 * gathered before dumping stack
 		 */
 		lbs_msg.log.core = msg->ext.coredump.core_id;
-		avs_dsp_op(adev, log_buffer_status, &lbs_msg);
+		avs_log_buffer_status_locked(adev, &lbs_msg);
 	}
 
 	pos = dump + AVS_FW_REGS_SIZE;
@@ -243,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = {
 	.load_basefw = avs_hda_load_basefw,
 	.load_lib = avs_hda_load_library,
 	.transfer_mods = avs_hda_transfer_modules,
-	.enable_logs = apl_enable_logs,
 	.log_buffer_offset = skl_log_buffer_offset,
 	.log_buffer_status = apl_log_buffer_status,
 	.coredump = apl_coredump,
 	.d0ix_toggle = apl_d0ix_toggle,
 	.set_d0ix = apl_set_d0ix,
+	AVS_SET_ENABLE_LOGS_OP(apl)
 };
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 8d05b27608fe58ce0c3217b21e35232d55d3ecd5..d7fccdcb9c167f819bbc265cbc8fd440f907460a 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -9,6 +9,7 @@
 #ifndef __SOUND_SOC_INTEL_AVS_H
 #define __SOUND_SOC_INTEL_AVS_H
 
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/kfifo.h>
@@ -93,16 +94,6 @@ struct avs_fw_entry {
 	struct list_head node;
 };
 
-struct avs_debug {
-	struct kfifo trace_fifo;
-	spinlock_t fifo_lock;	/* serialize I/O for trace_fifo */
-	spinlock_t trace_lock;	/* serialize debug window I/O between each LOG_BUFFER_STATUS */
-	wait_queue_head_t trace_waitq;
-	u32 aging_timer_period;
-	u32 fifo_full_timer_period;
-	u32 logged_resources;	/* context dependent: core or library */
-};
-
 /*
  * struct avs_dev - Intel HD-Audio driver data
  *
@@ -146,7 +137,18 @@ struct avs_dev {
 	spinlock_t path_list_lock;
 	struct mutex path_mutex;
 
-	struct avs_debug dbg;
+	spinlock_t trace_lock;	/* serialize debug window I/O between each LOG_BUFFER_STATUS */
+#ifdef CONFIG_DEBUG_FS
+	struct kfifo trace_fifo;
+	wait_queue_head_t trace_waitq;
+	u32 aging_timer_period;
+	u32 fifo_full_timer_period;
+	u32 logged_resources;	/* context dependent: core or library */
+	struct dentry *debugfs_root;
+	/* probes */
+	struct hdac_ext_stream *extractor;
+	unsigned int num_probe_streams;
+#endif
 };
 
 /* from hda_bus to avs_dev */
@@ -321,6 +323,9 @@ struct avs_soc_component {
 
 extern const struct snd_soc_dai_ops avs_dai_fe_ops;
 
+int avs_soc_component_register(struct device *dev, const char *name,
+			       const struct snd_soc_component_driver *drv,
+			       struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
 int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
 int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
 			      unsigned long *tdms);
@@ -331,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev);
 
 /* Firmware tracing helpers */
 
-unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
-				   spinlock_t *lock);
-
 #define avs_log_buffer_size(adev) \
 	((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
 
@@ -344,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src,
 			 (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
 })
 
+static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&adev->trace_lock, flags);
+	ret = avs_dsp_op(adev, log_buffer_status, msg);
+	spin_unlock_irqrestore(&adev->trace_lock, flags);
+
+	return ret;
+}
+
 struct apl_log_buffer_layout {
 	u32 read_ptr;
 	u32 write_ptr;
@@ -356,4 +370,42 @@ struct apl_log_buffer_layout {
 #define apl_log_payload_addr(addr) \
 	(addr + sizeof(struct apl_log_buffer_layout))
 
+#ifdef CONFIG_DEBUG_FS
+#define AVS_SET_ENABLE_LOGS_OP(name) \
+	.enable_logs = name##_enable_logs
+
+bool avs_logging_fw(struct avs_dev *adev);
+void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len);
+void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len);
+
+int avs_probe_platform_register(struct avs_dev *adev, const char *name);
+
+void avs_debugfs_init(struct avs_dev *adev);
+void avs_debugfs_exit(struct avs_dev *adev);
+#else
+#define AVS_SET_ENABLE_LOGS_OP(name)
+
+static inline bool avs_logging_fw(struct avs_dev *adev)
+{
+	return false;
+}
+
+static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+}
+
+static inline void
+avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+}
+
+static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name)
+{
+	return 0;
+}
+
+static inline void avs_debugfs_init(struct avs_dev *adev) { }
+static inline void avs_debugfs_exit(struct avs_dev *adev) { }
+#endif
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 02cc1ce8f5f58eda82f04f92798e671b1088d38f..b2823c2107f77306b360239167dca62d7bdb05a1 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -291,6 +291,33 @@ static void board_pdev_unregister(void *data)
 	platform_device_unregister(data);
 }
 
+static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
+{
+	struct platform_device *board;
+	struct snd_soc_acpi_mach mach = {{0}};
+	int ret;
+
+	ret = avs_probe_platform_register(adev, "probe-platform");
+	if (ret < 0)
+		return ret;
+
+	mach.mach_params.platform = "probe-platform";
+
+	board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,
+					      (const void *)&mach, sizeof(mach));
+	if (IS_ERR(board)) {
+		dev_err(adev->dev, "probe board register failed\n");
+		return PTR_ERR(board);
+	}
+
+	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
+	if (ret < 0) {
+		platform_device_unregister(board);
+		return ret;
+	}
+	return 0;
+}
+
 static int avs_register_dmic_board(struct avs_dev *adev)
 {
 	struct platform_device *codec, *board;
@@ -500,6 +527,12 @@ int avs_register_all_boards(struct avs_dev *adev)
 {
 	int ret;
 
+#ifdef CONFIG_DEBUG_FS
+	ret = avs_register_probe_board(adev);
+	if (ret < 0)
+		dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
+#endif
+
 	ret = avs_register_dmic_board(adev);
 	if (ret < 0)
 		dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 9bd40fdd902809ac709588d6953670cbf82da2ac..e4c230efe8d792278ea860ede96d644a214c32e9 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -77,6 +77,14 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825
 	   Say Y or m if you have such a device. This is a recommended option.
 	   If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_PROBE
+	tristate "Probing (data) board"
+	depends on DEBUG_FS
+	select SND_HWDEP
+	help
+	   This adds support for data probing board which can be used to
+	   gather data from runtime stream over compress operations.
+
 config SND_SOC_INTEL_AVS_MACH_RT274
 	tristate "rt274 in I2S mode"
 	depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 4d70b8d09ce558b38a283330d10a032056925b78..b81343420370fddfc93844df6a077d6c71957653 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -8,6 +8,7 @@ snd-soc-avs-max98927-objs := max98927.o
 snd-soc-avs-max98357a-objs := max98357a.o
 snd-soc-avs-max98373-objs := max98373.o
 snd-soc-avs-nau8825-objs := nau8825.o
+snd-soc-avs-probe-objs := probe.o
 snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
 snd-soc-avs-rt298-objs := rt298.o
@@ -22,6 +23,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c
new file mode 100644
index 0000000000000000000000000000000000000000..411acaee74f901e7d699cbc74cc8b847dc6e314c
--- /dev/null
+++ b/sound/soc/intel/avs/boards/probe.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI")));
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform")));
+
+static struct snd_soc_dai_link probe_mb_dai_links[] = {
+	{
+		.name = "Compress Probe Capture",
+		.nonatomic = 1,
+		SND_SOC_DAILINK_REG(probe_cp, dummy, platform),
+	},
+};
+
+static int avs_probe_mb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	int ret;
+
+	mach = dev_get_platdata(dev);
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = "avs_probe_mb";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = probe_mb_dai_links;
+	card->num_links = ARRAY_SIZE(probe_mb_dai_links);
+	card->fully_routed = true;
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_probe_mb_driver = {
+	.probe = avs_probe_mb_probe,
+	.driver = {
+		.name = "avs_probe_mb",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_probe_mb_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_probe_mb");
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index f7bc06404dbce3f289d96f18374f91403cb4657f..2ca24273c4910ae840e40292258ab571f0b5099b 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -214,6 +214,7 @@ static void avs_hda_probe_work(struct work_struct *work)
 	adev->nhlt = intel_nhlt_init(adev->dev);
 	if (!adev->nhlt)
 		dev_info(bus->dev, "platform has no NHLT\n");
+	avs_debugfs_init(adev);
 
 	avs_register_all_boards(adev);
 
@@ -491,6 +492,7 @@ static void avs_pci_remove(struct pci_dev *pci)
 
 	avs_unregister_all_boards(adev);
 
+	avs_debugfs_exit(adev);
 	if (adev->nhlt)
 		intel_nhlt_free(adev->nhlt);
 
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
new file mode 100644
index 0000000000000000000000000000000000000000..bdd388ec01eaf76609ca9d979f9d83980406242f
--- /dev/null
+++ b/sound/soc/intel/avs/debugfs.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/debugfs.h>
+#include <linux/kfifo.h>
+#include <linux/wait.h>
+#include <linux/sched/signal.h>
+#include <sound/soc.h>
+#include "avs.h"
+#include "messages.h"
+
+static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len)
+{
+	struct __kfifo *__fifo = &fifo->kfifo;
+	unsigned int l, off;
+
+	len = min(len, kfifo_avail(fifo));
+	off = __fifo->in & __fifo->mask;
+	l = min(len, kfifo_size(fifo) - off);
+
+	memcpy_fromio(__fifo->data + off, src, l);
+	memcpy_fromio(__fifo->data, src + l, len - l);
+	/* Make sure data copied from SRAM is visible to all CPUs. */
+	smp_mb();
+	__fifo->in += len;
+
+	return len;
+}
+
+bool avs_logging_fw(struct avs_dev *adev)
+{
+	return kfifo_initialized(&adev->trace_fifo);
+}
+
+void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+	__kfifo_fromio(&adev->trace_fifo, src, len);
+}
+
+void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+	avs_dump_fw_log(adev, src, len);
+	wake_up(&adev->trace_waitq);
+}
+
+static ssize_t fw_regs_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	char *buf;
+	int ret;
+
+	buf = kzalloc(AVS_FW_REGS_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy_fromio(buf, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
+
+	ret = simple_read_from_buffer(to, count, ppos, buf, AVS_FW_REGS_SIZE);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations fw_regs_fops = {
+	.open = simple_open,
+	.read = fw_regs_read,
+	.llseek = no_llseek,
+};
+
+static ssize_t debug_window_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	size_t size;
+	char *buf;
+	int ret;
+
+	size = adev->hw_cfg.dsp_cores * AVS_WINDOW_CHUNK_SIZE;
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy_fromio(buf, avs_sram_addr(adev, AVS_DEBUG_WINDOW), size);
+
+	ret = simple_read_from_buffer(to, count, ppos, buf, size);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debug_window_fops = {
+	.open = simple_open,
+	.read = debug_window_read,
+	.llseek = no_llseek,
+};
+
+static ssize_t probe_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	struct avs_probe_point_desc *desc;
+	size_t num_desc, len = 0;
+	char *buf;
+	int i, ret;
+
+	/* Prevent chaining, send and dump IPC value just once. */
+	if (*ppos)
+		return 0;
+
+	buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
+	if (ret) {
+		ret = AVS_IPC_RET(ret);
+		goto exit;
+	}
+
+	for (i = 0; i < num_desc; i++) {
+		ret = snprintf(buf + len, PAGE_SIZE - len,
+			       "Id: %#010x  Purpose: %d  Node id: %#x\n",
+			       desc[i].id.value, desc[i].purpose, desc[i].node_id.val);
+		if (ret < 0)
+			goto free_desc;
+		len += ret;
+	}
+
+	ret = simple_read_from_buffer(to, count, ppos, buf, len);
+free_desc:
+	kfree(desc);
+exit:
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t probe_points_write(struct file *file, const char __user *from, size_t count,
+				  loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	struct avs_probe_point_desc *desc;
+	u32 *array, num_elems;
+	size_t bytes;
+	int ret;
+
+	ret = parse_int_array_user(from, count, (int **)&array);
+	if (ret < 0)
+		return ret;
+
+	num_elems = *array;
+	bytes = sizeof(*array) * num_elems;
+	if (bytes % sizeof(*desc)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	desc = (struct avs_probe_point_desc *)&array[1];
+	ret = avs_ipc_probe_connect_points(adev, desc, bytes / sizeof(*desc));
+	if (ret)
+		ret = AVS_IPC_RET(ret);
+	else
+		ret = count;
+exit:
+	kfree(array);
+	return ret;
+}
+
+static const struct file_operations probe_points_fops = {
+	.open = simple_open,
+	.read = probe_points_read,
+	.write = probe_points_write,
+	.llseek = no_llseek,
+};
+
+static ssize_t probe_points_disconnect_write(struct file *file, const char __user *from,
+					     size_t count, loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	union avs_probe_point_id *id;
+	u32 *array, num_elems;
+	size_t bytes;
+	int ret;
+
+	ret = parse_int_array_user(from, count, (int **)&array);
+	if (ret < 0)
+		return ret;
+
+	num_elems = *array;
+	bytes = sizeof(*array) * num_elems;
+	if (bytes % sizeof(*id)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	id = (union avs_probe_point_id *)&array[1];
+	ret = avs_ipc_probe_disconnect_points(adev, id, bytes / sizeof(*id));
+	if (ret)
+		ret = AVS_IPC_RET(ret);
+	else
+		ret = count;
+exit:
+	kfree(array);
+	return ret;
+}
+
+static const struct file_operations probe_points_disconnect_fops = {
+	.open = simple_open,
+	.write = probe_points_disconnect_write,
+	.llseek = default_llseek,
+};
+
+static ssize_t strace_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	struct kfifo *fifo = &adev->trace_fifo;
+	unsigned int copied;
+
+	if (kfifo_is_empty(fifo)) {
+		DEFINE_WAIT(wait);
+
+		prepare_to_wait(&adev->trace_waitq, &wait, TASK_INTERRUPTIBLE);
+		if (!signal_pending(current))
+			schedule();
+		finish_wait(&adev->trace_waitq, &wait);
+	}
+
+	if (kfifo_to_user(fifo, to, count, &copied))
+		return -EFAULT;
+	*ppos += copied;
+	return copied;
+}
+
+static int strace_open(struct inode *inode, struct file *file)
+{
+	struct avs_dev *adev = inode->i_private;
+	int ret;
+
+	if (kfifo_initialized(&adev->trace_fifo))
+		return -EBUSY;
+
+	ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL);
+	if (ret < 0)
+		return ret;
+
+	file->private_data = adev;
+	return 0;
+}
+
+static int strace_release(struct inode *inode, struct file *file)
+{
+	union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
+	struct avs_dev *adev = file->private_data;
+	unsigned long resource_mask;
+	unsigned long flags, i;
+	u32 num_cores;
+
+	resource_mask = adev->logged_resources;
+	num_cores = adev->hw_cfg.dsp_cores;
+
+	spin_lock_irqsave(&adev->trace_lock, flags);
+
+	/* Gather any remaining logs. */
+	for_each_set_bit(i, &resource_mask, num_cores) {
+		msg.log.core = i;
+		avs_dsp_op(adev, log_buffer_status, &msg);
+	}
+
+	kfifo_free(&adev->trace_fifo);
+
+	spin_unlock_irqrestore(&adev->trace_lock, flags);
+
+	return 0;
+}
+
+static const struct file_operations strace_fops = {
+	.llseek = default_llseek,
+	.read = strace_read,
+	.open = strace_open,
+	.release = strace_release,
+};
+
+#define DISABLE_TIMERS	UINT_MAX
+
+static int enable_logs(struct avs_dev *adev, u32 resource_mask, u32 *priorities)
+{
+	int ret;
+
+	/* Logging demands D0i0 state from DSP. */
+	if (!adev->logged_resources) {
+		pm_runtime_get_sync(adev->dev);
+
+		ret = avs_dsp_disable_d0ix(adev);
+		if (ret)
+			goto err_d0ix;
+	}
+
+	ret = avs_ipc_set_system_time(adev);
+	if (ret && ret != AVS_IPC_NOT_SUPPORTED) {
+		ret = AVS_IPC_RET(ret);
+		goto err_ipc;
+	}
+
+	ret = avs_dsp_op(adev, enable_logs, AVS_LOG_ENABLE, adev->aging_timer_period,
+			 adev->fifo_full_timer_period, resource_mask, priorities);
+	if (ret)
+		goto err_ipc;
+
+	adev->logged_resources |= resource_mask;
+	return 0;
+
+err_ipc:
+	if (!adev->logged_resources) {
+		avs_dsp_enable_d0ix(adev);
+err_d0ix:
+		pm_runtime_mark_last_busy(adev->dev);
+		pm_runtime_put_autosuspend(adev->dev);
+	}
+
+	return ret;
+}
+
+static int disable_logs(struct avs_dev *adev, u32 resource_mask)
+{
+	int ret;
+
+	/* Check if there's anything to do. */
+	if (!adev->logged_resources)
+		return 0;
+
+	ret = avs_dsp_op(adev, enable_logs, AVS_LOG_DISABLE, DISABLE_TIMERS, DISABLE_TIMERS,
+			 resource_mask, NULL);
+
+	/*
+	 * If IPC fails causing recovery, logged_resources is already zero
+	 * so unsetting bits is still safe.
+	 */
+	adev->logged_resources &= ~resource_mask;
+
+	/* If that's the last resource, allow for D3. */
+	if (!adev->logged_resources) {
+		avs_dsp_enable_d0ix(adev);
+		pm_runtime_mark_last_busy(adev->dev);
+		pm_runtime_put_autosuspend(adev->dev);
+	}
+
+	return ret;
+}
+
+static ssize_t trace_control_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	char buf[64];
+	int len;
+
+	len = snprintf(buf, sizeof(buf), "0x%08x\n", adev->logged_resources);
+
+	return simple_read_from_buffer(to, count, ppos, buf, len);
+}
+
+static ssize_t trace_control_write(struct file *file, const char __user *from, size_t count,
+				   loff_t *ppos)
+{
+	struct avs_dev *adev = file->private_data;
+	u32 *array, num_elems;
+	u32 resource_mask;
+	int ret;
+
+	ret = parse_int_array_user(from, count, (int **)&array);
+	if (ret < 0)
+		return ret;
+
+	num_elems = *array;
+	resource_mask = array[1];
+
+	/*
+	 * Disable if just resource mask is provided - no log priority flags.
+	 *
+	 * Enable input format:   mask, prio1, .., prioN
+	 * Where 'N' equals number of bits set in the 'mask'.
+	 */
+	if (num_elems == 1) {
+		ret = disable_logs(adev, resource_mask);
+	} else {
+		if (num_elems != (hweight_long(resource_mask) + 1)) {
+			ret = -EINVAL;
+			goto free_array;
+		}
+
+		ret = enable_logs(adev, resource_mask, &array[2]);
+	}
+
+	if (!ret)
+		ret = count;
+free_array:
+	kfree(array);
+	return ret;
+}
+
+static const struct file_operations trace_control_fops = {
+	.llseek = default_llseek,
+	.read = trace_control_read,
+	.write = trace_control_write,
+	.open = simple_open,
+};
+
+void avs_debugfs_init(struct avs_dev *adev)
+{
+	init_waitqueue_head(&adev->trace_waitq);
+	spin_lock_init(&adev->trace_lock);
+
+	adev->debugfs_root = debugfs_create_dir("avs", snd_soc_debugfs_root);
+
+	/* Initialize timer periods with recommended defaults. */
+	adev->aging_timer_period = 10;
+	adev->fifo_full_timer_period = 10;
+
+	debugfs_create_file("strace", 0444, adev->debugfs_root, adev, &strace_fops);
+	debugfs_create_file("trace_control", 0644, adev->debugfs_root, adev, &trace_control_fops);
+	debugfs_create_file("fw_regs", 0444, adev->debugfs_root, adev, &fw_regs_fops);
+	debugfs_create_file("debug_window", 0444, adev->debugfs_root, adev, &debug_window_fops);
+
+	debugfs_create_u32("trace_aging_period", 0644, adev->debugfs_root,
+			   &adev->aging_timer_period);
+	debugfs_create_u32("trace_fifo_full_period", 0644, adev->debugfs_root,
+			   &adev->fifo_full_timer_period);
+
+	debugfs_create_file("probe_points", 0644, adev->debugfs_root, adev, &probe_points_fops);
+	debugfs_create_file("probe_points_disconnect", 0200, adev->debugfs_root, adev,
+			    &probe_points_disconnect_fops);
+}
+
+void avs_debugfs_exit(struct avs_dev *adev)
+{
+	debugfs_remove_recursive(adev->debugfs_root);
+}
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index af8a260093f4c67cc483594126be2260fccb0133..bdf013c3dd12e2b701e8b17d53470afdbd1f8399 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -266,7 +266,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
 		break;
 
 	case AVS_NOTIFY_LOG_BUFFER_STATUS:
-		avs_dsp_op(adev, log_buffer_status, &msg);
+		avs_log_buffer_status_locked(adev, &msg);
 		break;
 
 	case AVS_NOTIFY_EXCEPTION_CAUGHT:
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 6b0fecbf07c3cf64aea08f556d23b1195c7ebc6f..e11ae4246416cfe90917e2605730e5e7340a56f6 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -685,6 +685,24 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
 	return 0;
 }
 
+int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
+				   u8 instance_id, u32 sink_id,
+				   const struct avs_audio_format *src_fmt,
+				   const struct avs_audio_format *sink_fmt)
+{
+	struct avs_copier_sink_format cpr_fmt;
+
+	cpr_fmt.sink_id = sink_id;
+	/* Firmware expects driver to resend copier's input format. */
+	cpr_fmt.src_fmt = *src_fmt;
+	cpr_fmt.sink_fmt = *sink_fmt;
+
+	return avs_ipc_set_large_config(adev, module_id, instance_id,
+					AVS_COPIER_SET_SINK_FORMAT,
+					(u8 *)&cpr_fmt, sizeof(cpr_fmt));
+}
+
+#ifdef CONFIG_DEBUG_FS
 int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
 {
 	return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
@@ -705,19 +723,81 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
 					AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
 }
 
-int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
-				   u8 instance_id, u32 sink_id,
-				   const struct avs_audio_format *src_fmt,
-				   const struct avs_audio_format *sink_fmt)
+int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas)
 {
-	struct avs_copier_sink_format cpr_fmt;
+	size_t payload_size;
+	u32 module_id;
+	u8 *payload;
+	int ret;
 
-	cpr_fmt.sink_id = sink_id;
-	/* Firmware expects driver to resend copier's input format. */
-	cpr_fmt.src_fmt = *src_fmt;
-	cpr_fmt.sink_fmt = *sink_fmt;
+	module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
 
-	return avs_ipc_set_large_config(adev, module_id, instance_id,
-					AVS_COPIER_SET_SINK_FORMAT,
-					(u8 *)&cpr_fmt, sizeof(cpr_fmt));
+	ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
+				       NULL, 0, &payload, &payload_size);
+	if (ret)
+		return ret;
+
+	*dmas = (struct avs_probe_dma *)payload;
+	*num_dmas = payload_size / sizeof(**dmas);
+
+	return 0;
+}
+
+int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas)
+{
+	u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+	return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
+					(u8 *)dmas, array_size(sizeof(*dmas), num_dmas));
+}
+
+int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
+			     size_t num_node_ids)
+{
+	u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+	return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
+					AVS_PROBE_INJECTION_DMA_DETACH, (u8 *)node_ids,
+					array_size(sizeof(*node_ids), num_node_ids));
+}
+
+int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
+			     size_t *num_descs)
+{
+	size_t payload_size;
+	u32 module_id;
+	u8 *payload;
+	int ret;
+
+	module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+	ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS, NULL,
+				       0, &payload, &payload_size);
+	if (ret)
+		return ret;
+
+	*descs = (struct avs_probe_point_desc *)payload;
+	*num_descs = payload_size / sizeof(**descs);
+
+	return 0;
+}
+
+int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
+				 size_t num_descs)
+{
+	u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+	return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS,
+					(u8 *)descs, array_size(sizeof(*descs), num_descs));
+}
+
+int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
+				    size_t num_ids)
+{
+	u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+	return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
+					AVS_PROBE_POINTS_DISCONNECT, (u8 *)ids,
+					array_size(sizeof(*ids), num_ids));
 }
+#endif
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 02b3b7a74783a0c7574bffc337228d76da016694..9dd835527e02c3ad8ac09bbadb70a3d587a17fd7 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -802,4 +802,57 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
 				   const struct avs_audio_format *src_fmt,
 				   const struct avs_audio_format *sink_fmt);
 
+#define AVS_PROBE_INST_ID	0
+
+enum avs_probe_runtime_param {
+	AVS_PROBE_INJECTION_DMA = 1,
+	AVS_PROBE_INJECTION_DMA_DETACH,
+	AVS_PROBE_POINTS,
+	AVS_PROBE_POINTS_DISCONNECT,
+};
+
+struct avs_probe_dma {
+	union avs_connector_node_id node_id;
+	u32 dma_buffer_size;
+} __packed;
+
+enum avs_probe_type {
+	AVS_PROBE_TYPE_INPUT = 0,
+	AVS_PROBE_TYPE_OUTPUT,
+	AVS_PROBE_TYPE_INTERNAL
+};
+
+union avs_probe_point_id {
+	u32 value;
+	struct {
+		u32 module_id:16;
+		u32 instance_id:8;
+		u32 type:2;
+		u32 index:6;
+	} id;
+} __packed;
+
+enum avs_connection_purpose {
+	AVS_CONNECTION_PURPOSE_EXTRACT = 0,
+	AVS_CONNECTION_PURPOSE_INJECT,
+	AVS_CONNECTION_PURPOSE_INJECT_REEXTRACT,
+};
+
+struct avs_probe_point_desc {
+	union avs_probe_point_id id;
+	u32 purpose;
+	union avs_connector_node_id node_id;
+} __packed;
+
+int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas);
+int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas);
+int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
+			     size_t num_node_ids);
+int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
+			     size_t *num_descs);
+int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
+				 size_t num_descs);
+int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
+				    size_t num_ids);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 70d687fa9923e46fe04b05bb2bc75eef6bbbbf2e..f930c5e86a84ad24b4a2fcad4b46f8e3e189fef1 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -1126,9 +1126,9 @@ static const struct snd_soc_component_driver avs_component_driver = {
 	.topology_name_prefix	= "intel/avs",
 };
 
-static int avs_soc_component_register(struct device *dev, const char *name,
-				      const struct snd_soc_component_driver *drv,
-				      struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
+int avs_soc_component_register(struct device *dev, const char *name,
+			       const struct snd_soc_component_driver *drv,
+			       struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
 {
 	struct avs_soc_component *acomp;
 	int ret;
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
new file mode 100644
index 0000000000000000000000000000000000000000..29d63f2a9616cc9055504d2d18b9b03444bcf363
--- /dev/null
+++ b/sound/soc/intel/avs/probes.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <sound/compress_driver.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hdaudio.h>
+#include <sound/soc.h>
+#include "avs.h"
+#include "messages.h"
+
+static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
+			      size_t buffer_size)
+{
+	struct avs_probe_cfg cfg = {{0}};
+	struct avs_module_entry mentry;
+	u16 dummy;
+
+	avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+
+	/*
+	 * Probe module uses no cycles, audio data format and input and output
+	 * frame sizes are unused. It is also not owned by any pipeline.
+	 */
+	cfg.base.ibs = 1;
+	/* BSS module descriptor is always segment of index=2. */
+	cfg.base.is_pages = mentry.segments[2].flags.length;
+	cfg.gtw_cfg.node_id = node_id;
+	cfg.gtw_cfg.dma_buffer_size = buffer_size;
+
+	return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg,
+				   sizeof(cfg), &dummy);
+}
+
+static void avs_dsp_delete_probe(struct avs_dev *adev)
+{
+	struct avs_module_entry mentry;
+
+	avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+
+	/* There is only ever one probe module instance. */
+	avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
+}
+
+static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream)
+{
+	return cstream->runtime->private_data;
+}
+
+static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
+{
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	struct hdac_bus *bus = &adev->base.core;
+	struct hdac_ext_stream *host_stream;
+
+	if (adev->extractor) {
+		dev_err(dai->dev, "Cannot open more than one extractor stream\n");
+		return -EEXIST;
+	}
+
+	host_stream = snd_hdac_ext_cstream_assign(bus, cstream);
+	if (!host_stream) {
+		dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n");
+		return -EBUSY;
+	}
+
+	adev->extractor = host_stream;
+	hdac_stream(host_stream)->curr_pos = 0;
+	cstream->runtime->private_data = host_stream;
+
+	return 0;
+}
+
+static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
+{
+	struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	struct avs_probe_point_desc *desc;
+	/* Extractor node identifier. */
+	unsigned int vindex = INVALID_NODE_ID.vindex;
+	size_t num_desc;
+	int i, ret;
+
+	/* Disconnect all probe points. */
+	ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
+	if (ret) {
+		dev_err(dai->dev, "get probe points failed: %d\n", ret);
+		ret = AVS_IPC_RET(ret);
+		goto exit;
+	}
+
+	for (i = 0; i < num_desc; i++)
+		if (desc[i].node_id.vindex == vindex)
+			avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1);
+	kfree(desc);
+
+exit:
+	if (adev->num_probe_streams) {
+		adev->num_probe_streams--;
+		if (!adev->num_probe_streams) {
+			avs_dsp_delete_probe(adev);
+			avs_dsp_enable_d0ix(adev);
+		}
+	}
+
+	snd_hdac_stream_cleanup(hdac_stream(host_stream));
+	hdac_stream(host_stream)->prepared = 0;
+	snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST);
+
+	snd_compr_free_pages(cstream);
+	adev->extractor = NULL;
+
+	return ret;
+}
+
+static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
+				      struct snd_compr_params *params, struct snd_soc_dai *dai)
+{
+	struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+	struct snd_compr_runtime *rtd = cstream->runtime;
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	/* compr params do not store bit depth, default to S32_LE. */
+	snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
+	unsigned int format_val;
+	int bps, ret;
+
+	hdac_stream(host_stream)->bufsize = 0;
+	hdac_stream(host_stream)->period_bytes = 0;
+	hdac_stream(host_stream)->format_val = 0;
+	cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
+	cstream->dma_buffer.dev.dev = adev->dev;
+
+	ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
+	if (ret < 0)
+		return ret;
+	bps = snd_pcm_format_physical_width(format);
+	if (bps < 0)
+		return bps;
+	format_val = snd_hdac_calc_stream_format(params->codec.sample_rate, params->codec.ch_out,
+						 format, bps, 0);
+	ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
+	if (ret < 0)
+		return ret;
+	ret = snd_hdac_stream_setup(hdac_stream(host_stream));
+	if (ret < 0)
+		return ret;
+
+	hdac_stream(host_stream)->prepared = 1;
+
+	if (!adev->num_probe_streams) {
+		union avs_connector_node_id node_id;
+
+		/* D0ix not allowed during probing. */
+		ret = avs_dsp_disable_d0ix(adev);
+		if (ret)
+			return ret;
+
+		node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
+		node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
+
+		ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
+		if (ret < 0) {
+			dev_err(dai->dev, "probe init failed: %d\n", ret);
+			avs_dsp_enable_d0ix(adev);
+			return ret;
+		}
+	}
+
+	adev->num_probe_streams++;
+	return 0;
+}
+
+static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
+				   struct snd_soc_dai *dai)
+{
+	struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+	struct avs_dev *adev = to_avs_dev(dai->dev);
+	struct hdac_bus *bus = &adev->base.core;
+	unsigned long cookie;
+
+	if (!hdac_stream(host_stream)->prepared)
+		return -EPIPE;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		spin_lock_irqsave(&bus->reg_lock, cookie);
+		snd_hdac_stream_start(hdac_stream(host_stream), true);
+		spin_unlock_irqrestore(&bus->reg_lock, cookie);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+		spin_lock_irqsave(&bus->reg_lock, cookie);
+		snd_hdac_stream_stop(hdac_stream(host_stream));
+		spin_unlock_irqrestore(&bus->reg_lock, cookie);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int avs_probe_compr_pointer(struct snd_compr_stream *cstream,
+				   struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
+{
+	struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+	struct snd_soc_pcm_stream *pstream;
+
+	pstream = &dai->driver->capture;
+	tstamp->copied_total = hdac_stream(host_stream)->curr_pos;
+	tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
+
+	return 0;
+}
+
+static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream,
+				char __user *buf, size_t count)
+{
+	struct snd_compr_runtime *rtd = cstream->runtime;
+	unsigned int offset, n;
+	void *ptr;
+	int ret;
+
+	if (count > rtd->buffer_size)
+		count = rtd->buffer_size;
+
+	div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
+	ptr = rtd->dma_area + offset;
+	n = rtd->buffer_size - offset;
+
+	if (count < n) {
+		ret = copy_to_user(buf, ptr, count);
+	} else {
+		ret = copy_to_user(buf, ptr, n);
+		ret += copy_to_user(buf + n, rtd->dma_area, count - n);
+	}
+
+	if (ret)
+		return count - ret;
+	return count;
+}
+
+static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
+	.startup = avs_probe_compr_open,
+	.shutdown = avs_probe_compr_free,
+	.set_params = avs_probe_compr_set_params,
+	.trigger = avs_probe_compr_trigger,
+	.pointer = avs_probe_compr_pointer,
+};
+
+static const struct snd_compress_ops avs_probe_compress_ops = {
+	.copy = avs_probe_compr_copy,
+};
+
+static struct snd_soc_dai_driver probe_cpu_dais[] = {
+{
+	.name = "Probe Extraction CPU DAI",
+	.compress_new = snd_soc_new_compress,
+	.cops = &avs_probe_dai_ops,
+	.capture = {
+		.stream_name = "Probe Extraction",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_48000,
+		.rate_min = 48000,
+		.rate_max = 48000,
+	},
+},
+};
+
+static int avs_probe_component_probe(struct snd_soc_component *component)
+{
+	struct avs_soc_component *acomp = to_avs_soc_component(component);
+	struct avs_dev *adev = to_avs_dev(component->dev);
+
+	mutex_lock(&adev->comp_list_mutex);
+	list_add_tail(&acomp->node, &adev->comp_list);
+	mutex_unlock(&adev->comp_list_mutex);
+	return 0;
+}
+
+static void avs_probe_component_remove(struct snd_soc_component *component)
+{
+	struct avs_soc_component *acomp = to_avs_soc_component(component);
+	struct avs_dev *adev = to_avs_dev(component->dev);
+
+	mutex_lock(&adev->comp_list_mutex);
+	list_del(&acomp->node);
+	mutex_unlock(&adev->comp_list_mutex);
+}
+
+static const struct snd_soc_component_driver avs_probe_component_driver = {
+	.name			= "avs-probe-compr",
+	.probe			= avs_probe_component_probe,
+	.remove			= avs_probe_component_remove,
+	.compress_ops		= &avs_probe_compress_ops,
+	.module_get_upon_open	= 1, /* increment refcount when a stream is opened */
+};
+
+int avs_probe_platform_register(struct avs_dev *adev, const char *name)
+{
+	return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver,
+					  probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
+}
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 95be86148cf3a25db7c0ab24d339599fa559ba9e..2b464e466ed5206a92748140273a40db3d041d73 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -59,7 +59,8 @@
 #define AVS_FW_REG_STATUS(adev)		(AVS_FW_REG_BASE(adev) + 0x0)
 #define AVS_FW_REG_ERROR_CODE(adev)	(AVS_FW_REG_BASE(adev) + 0x4)
 
-#define AVS_FW_REGS_SIZE		PAGE_SIZE
+#define AVS_WINDOW_CHUNK_SIZE		PAGE_SIZE
+#define AVS_FW_REGS_SIZE		AVS_WINDOW_CHUNK_SIZE
 #define AVS_FW_REGS_WINDOW		0
 /* DSP -> HOST communication window */
 #define AVS_UPLINK_WINDOW		AVS_FW_REGS_WINDOW
diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c
index dc98b5cf900f25250803e8b9d9da35ea2880bdfc..6bb8bbc70442bdf380c28c80b512c0e95f5a4728 100644
--- a/sound/soc/intel/avs/skl.c
+++ b/sound/soc/intel/avs/skl.c
@@ -12,8 +12,9 @@
 #include "avs.h"
 #include "messages.h"
 
-static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
-			   u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+static int __maybe_unused
+skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+		u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
 {
 	struct skl_log_state_info *info;
 	u32 size, num_cores = adev->hw_cfg.dsp_cores;
@@ -55,15 +56,11 @@ int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
 static int
 skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
 {
-	unsigned long flags;
 	void __iomem *buf;
 	u16 size, write, offset;
 
-	spin_lock_irqsave(&adev->dbg.trace_lock, flags);
-	if (!kfifo_initialized(&adev->dbg.trace_fifo)) {
-		spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+	if (!avs_logging_fw(adev))
 		return 0;
-	}
 
 	size = avs_log_buffer_size(adev) / 2;
 	write = readl(avs_sram_addr(adev, AVS_FW_REGS_WINDOW) + FW_REGS_DBG_LOG_WP(msg->log.core));
@@ -72,9 +69,7 @@ skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
 
 	/* Address is guaranteed to exist in SRAM2. */
 	buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
-	__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf, size, &adev->dbg.fifo_lock);
-	wake_up(&adev->dbg.trace_waitq);
-	spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+	avs_dump_fw_log_wakeup(adev, buf, size);
 
 	return 0;
 }
@@ -116,10 +111,10 @@ const struct avs_dsp_ops skl_dsp_ops = {
 	.load_basefw = avs_cldma_load_basefw,
 	.load_lib = avs_cldma_load_library,
 	.transfer_mods = avs_cldma_transfer_modules,
-	.enable_logs = skl_enable_logs,
 	.log_buffer_offset = skl_log_buffer_offset,
 	.log_buffer_status = skl_log_buffer_status,
 	.coredump = skl_coredump,
 	.d0ix_toggle = skl_d0ix_toggle,
 	.set_d0ix = skl_set_d0ix,
+	AVS_SET_ENABLE_LOGS_OP(skl)
 };
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index 13611dee9787796230b2e187f20f5c61b1100d58..82416b86662d86696b8fa78ca794e8c919c90f89 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -300,25 +300,3 @@ void avs_release_firmwares(struct avs_dev *adev)
 		kfree(entry);
 	}
 }
-
-unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
-				   spinlock_t *lock)
-{
-	struct __kfifo *__fifo = &fifo->kfifo;
-	unsigned long flags;
-	unsigned int l, off;
-
-	spin_lock_irqsave(lock, flags);
-	len = min(len, kfifo_avail(fifo));
-	off = __fifo->in & __fifo->mask;
-	l = min(len, kfifo_size(fifo) - off);
-
-	memcpy_fromio(__fifo->data + off, src, l);
-	memcpy_fromio(__fifo->data, src + l, len - l);
-	/* Make sure data copied from SRAM is visible to all CPUs. */
-	smp_mb();
-	__fifo->in += len;
-	spin_unlock_irqrestore(lock, flags);
-
-	return len;
-}
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 7e1a4ff77ac32b346ddf98eb7f267f6d07d3139c..d1fd7a2b32dbca27df868dbc1e3a61ca1735930d 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -37,8 +37,7 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
 snd-soc-ehl-rt5660-objs := ehl_rt5660.o
 snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
 snd-soc-sof-sdw-objs += sof_sdw.o				\
-			sof_sdw_max98373.o sof_sdw_rt1308.o	\
-			sof_sdw_rt1316.o sof_sdw_rt1318.o	\
+			sof_sdw_max98373.o sof_sdw_rt_amp.o	\
 			sof_sdw_rt5682.o sof_sdw_rt700.o	\
 			sof_sdw_rt711.o sof_sdw_rt711_sdca.o 	\
 			sof_sdw_rt715.o	sof_sdw_rt715_sdca.o 	\
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index 70713e4b07dc108572ec53a721adbf8ffe1d20bb..773e5d1d87d460362bb7d440544fe764cac2ad08 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -783,7 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
 
-	cancel_delayed_work(&priv->pcm_pop_work);
+	cancel_delayed_work_sync(&priv->pcm_pop_work);
 	gpiod_put(priv->gpio_speakers);
 	device_remove_software_node(priv->codec_dev);
 	put_device(priv->codec_dev);
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
index ff2851fc8930a2126d8e6976bb8c14706ab864b7..6c12ca92f3713df087f8a7af82404b7af03f2e09 100644
--- a/sound/soc/intel/boards/sof_realtek_common.c
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -267,7 +267,8 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
 	struct snd_soc_dai *codec_dai;
-	int i, clk_freq, ret;
+	int i, clk_freq;
+	int ret = 0;
 
 	clk_freq = sof_dai_get_bclk(rtd);
 
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 4a2f91249b10c94e9c2910e0acc7a840fba9bd01..2eabc4b0fafa499a6dd5e867380812dc63acd004 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -1104,6 +1104,12 @@ static const struct platform_device_id board_ids[] = {
 					SOF_RT5682_SSP_AMP(1) |
 					SOF_RT5682_NUM_HDMIDEV(4)),
 	},
+	{
+		.name = "jsl_rt5682",
+		.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+					SOF_RT5682_MCLK_24MHZ |
+					SOF_RT5682_SSP_CODEC(0)),
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index b58c7b35599d20fd4d3d826a12d9533adddc6e8c..d2ed807abde9590b1968aaf9d1b2c90803ae5b3c 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -550,23 +550,23 @@ static struct sof_sdw_codec_info codec_info_list[] = {
 		.direction = {true, false},
 		.dai_name = "rt1308-aif",
 		.ops = &sof_sdw_rt1308_i2s_ops,
-		.init = sof_sdw_rt1308_init,
-		.exit = sof_sdw_rt1308_exit,
+		.init = sof_sdw_rt_amp_init,
+		.exit = sof_sdw_rt_amp_exit,
 		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 	},
 	{
 		.part_id = 0x1316,
 		.direction = {true, true},
 		.dai_name = "rt1316-aif",
-		.init = sof_sdw_rt1316_init,
-		.exit = sof_sdw_rt1316_exit,
+		.init = sof_sdw_rt_amp_init,
+		.exit = sof_sdw_rt_amp_exit,
 		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 	},
 	{
 		.part_id = 0x1318,
 		.direction = {true, true},
 		.dai_name = "rt1318-aif",
-		.init = sof_sdw_rt1318_init,
+		.init = sof_sdw_rt_amp_init,
 		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 	},
 	{
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index 54a50f7da4da7beb285dba0755cf781b678e34a0..350010b0e5f4f1d9d999c42c1bfdd00fd8181ced 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -125,30 +125,18 @@ int sof_sdw_rt700_init(struct snd_soc_card *card,
 		       struct sof_sdw_codec_info *info,
 		       bool playback);
 
-/* RT1308 support */
+/* RT1308 I2S support */
 extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
 
-int sof_sdw_rt1308_init(struct snd_soc_card *card,
+/* generic amp support */
+int sof_sdw_rt_amp_init(struct snd_soc_card *card,
 			const struct snd_soc_acpi_link_adr *link,
 			struct snd_soc_dai_link *dai_links,
 			struct sof_sdw_codec_info *info,
 			bool playback);
-int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
+int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
 
 /* RT1316 support */
-int sof_sdw_rt1316_init(struct snd_soc_card *card,
-			const struct snd_soc_acpi_link_adr *link,
-			struct snd_soc_dai_link *dai_links,
-			struct sof_sdw_codec_info *info,
-			bool playback);
-int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-
-/* RT1318 support */
-int sof_sdw_rt1318_init(struct snd_soc_card *card,
-			const struct snd_soc_acpi_link_adr *link,
-			struct snd_soc_dai_link *dai_links,
-			struct sof_sdw_codec_info *info,
-			bool playback);
 
 /* RT715 support */
 int sof_sdw_rt715_init(struct snd_soc_card *card,
diff --git a/sound/soc/intel/boards/sof_sdw_rt1316.c b/sound/soc/intel/boards/sof_sdw_rt1316.c
deleted file mode 100644
index f6bbea0d38105fd46074827e9377eadc78af0b94..0000000000000000000000000000000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt1316.c
+++ /dev/null
@@ -1,239 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- *  sof_sdw_rt1316 - Helpers to handle RT1316 from generic machine driver
- */
-
-#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 <linux/dmi.h>
-#include "sof_sdw_common.h"
-#include "sof_sdw_amp_coeff_tables.h"
-
-struct rt1316_platform_data {
-	const unsigned char *bq_params;
-	const unsigned int bq_params_cnt;
-};
-
-static const struct rt1316_platform_data dell_0b00_platform_data = {
-	.bq_params = dell_0b00_bq_params,
-	.bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
-};
-
-static const struct dmi_system_id dmi_platform_data[] = {
-	/* AlderLake devices */
-	{
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
-		},
-		.driver_data = (void *)&dell_0b00_platform_data,
-	},
-	{
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
-		},
-		.driver_data = (void *)&dell_0b00_platform_data,
-	},
-	{
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
-		},
-		.driver_data = (void *)&dell_0b00_platform_data,
-	},
-	{
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
-		},
-		.driver_data = (void *)&dell_0b00_platform_data,
-	},
-};
-
-static int rt1316_add_device_props(struct device *sdw_dev)
-{
-	struct property_entry props[3] = {};
-	struct fwnode_handle *fwnode;
-	const struct dmi_system_id *dmi_data;
-	const struct rt1316_platform_data *pdata;
-	unsigned char params[RT1316_MAX_BQ_REG];
-	int ret;
-
-	dmi_data = dmi_first_match(dmi_platform_data);
-	if (!dmi_data)
-		return 0;
-
-	pdata = dmi_data->driver_data;
-	memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
-
-	props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
-	props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
-
-	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_widget rt1316_widgets[] = {
-	SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-/*
- * dapm routes for rt1316 will be registered dynamically according
- * to the number of rt1316 used. The first two entries will be registered
- * for one codec case, and the last two entries are also registered
- * if two 1316s are used.
- */
-static const struct snd_soc_dapm_route rt1316_map[] = {
-	{ "Speaker", NULL, "rt1316-1 SPOL" },
-	{ "Speaker", NULL, "rt1316-1 SPOR" },
-	{ "Speaker", NULL, "rt1316-2 SPOL" },
-	{ "Speaker", NULL, "rt1316-2 SPOR" },
-};
-
-static const struct snd_kcontrol_new rt1316_controls[] = {
-	SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_card *card = rtd->card;
-	int ret;
-
-	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
-					  "%s spk:rt1316",
-					  card->components);
-	if (!card->components)
-		return -ENOMEM;
-
-	ret = snd_soc_add_card_controls(card, rt1316_controls,
-					ARRAY_SIZE(rt1316_controls));
-	if (ret) {
-		dev_err(card->dev, "rt1316 controls addition failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = snd_soc_dapm_new_controls(&card->dapm, rt1316_widgets,
-					ARRAY_SIZE(rt1316_widgets));
-	if (ret) {
-		dev_err(card->dev, "rt1316 widgets addition failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map, 2);
-	if (ret)
-		dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
-
-	return ret;
-}
-
-static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_card *card = rtd->card;
-	int ret;
-
-	ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map + 2, 2);
-	if (ret)
-		dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
-
-	return ret;
-}
-
-static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
-	int ret;
-
-	ret = first_spk_init(rtd);
-	if (ret)
-		return ret;
-
-	return second_spk_init(rtd);
-}
-
-int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
-{
-	struct 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;
-}
-
-int sof_sdw_rt1316_init(struct snd_soc_card *card,
-			const struct snd_soc_acpi_link_adr *link,
-			struct snd_soc_dai_link *dai_links,
-			struct sof_sdw_codec_info *info,
-			bool playback)
-{
-	struct 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 == 1)
-		dai_links->init = first_spk_init;
-
-	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 = rt1316_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 = rt1316_add_device_props(sdw_dev2);
-		if (ret < 0) {
-			put_device(sdw_dev2);
-			return ret;
-		}
-		ctx->amp_dev2 = sdw_dev2;
-
-		/*
-		 * if two 1316s are in one dai link, the init function
-		 * in this dai link will be first set for the first speaker,
-		 * and it should be reset to initialize all speakers when
-		 * the second speaker is found.
-		 */
-		if (dai_links->init)
-			dai_links->init = all_spk_init;
-		else
-			dai_links->init = second_spk_init;
-	}
-
-	return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt1318.c b/sound/soc/intel/boards/sof_sdw_rt1318.c
deleted file mode 100644
index dbee4bf5c8149611f452392f4b3d9909f4274e56..0000000000000000000000000000000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt1318.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2022 Intel Corporation
-
-/*
- *  sof_sdw_rt1318 - Helpers to handle RT1318 from generic machine driver
- */
-
-#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 "sof_sdw_common.h"
-
-static const struct snd_soc_dapm_widget rt1318_widgets[] = {
-	SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-/*
- * dapm routes for rt1318 will be registered dynamically according
- * to the number of rt1318 used. The first two entries will be registered
- * for one codec case, and the last two entries are also registered
- * if two 1318s are used.
- */
-static const struct snd_soc_dapm_route rt1318_map[] = {
-	{ "Speaker", NULL, "rt1318-1 SPOL" },
-	{ "Speaker", NULL, "rt1318-1 SPOR" },
-	{ "Speaker", NULL, "rt1318-2 SPOL" },
-	{ "Speaker", NULL, "rt1318-2 SPOR" },
-};
-
-static const struct snd_kcontrol_new rt1318_controls[] = {
-	SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_card *card = rtd->card;
-	int ret;
-
-	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
-					  "%s spk:rt1318",
-					  card->components);
-	if (!card->components)
-		return -ENOMEM;
-
-	ret = snd_soc_add_card_controls(card, rt1318_controls,
-					ARRAY_SIZE(rt1318_controls));
-	if (ret) {
-		dev_err(card->dev, "rt1318 controls addition failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = snd_soc_dapm_new_controls(&card->dapm, rt1318_widgets,
-					ARRAY_SIZE(rt1318_widgets));
-	if (ret) {
-		dev_err(card->dev, "rt1318 widgets addition failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map, 2);
-	if (ret)
-		dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
-
-	return ret;
-}
-
-static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_card *card = rtd->card;
-	int ret;
-
-	ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map + 2, 2);
-	if (ret)
-		dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
-
-	return ret;
-}
-
-static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
-	int ret;
-
-	ret = first_spk_init(rtd);
-	if (ret)
-		return ret;
-
-	return second_spk_init(rtd);
-}
-
-int sof_sdw_rt1318_init(struct snd_soc_card *card,
-			const struct snd_soc_acpi_link_adr *link,
-			struct snd_soc_dai_link *dai_links,
-			struct sof_sdw_codec_info *info,
-			bool playback)
-{
-	/* Count amp number and do init on playback link only. */
-	if (!playback)
-		return 0;
-
-	info->amp_num++;
-	if (info->amp_num == 1)
-		dai_links->init = first_spk_init;
-
-	if (info->amp_num == 2) {
-		/*
-		 * if two 1318s are in one dai link, the init function
-		 * in this dai link will be first set for the first speaker,
-		 * and it should be reset to initialize all speakers when
-		 * the second speaker is found.
-		 */
-		if (dai_links->init)
-			dai_links->init = all_spk_init;
-		else
-			dai_links->init = second_spk_init;
-	}
-
-	return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c
similarity index 59%
rename from sound/soc/intel/boards/sof_sdw_rt1308.c
rename to sound/soc/intel/boards/sof_sdw_rt_amp.c
index a19b055b9c6f8ef928d6ea5afd11b77184327555..26bf9e0dd3d24c57ac9779419394d19486b3f572 100644
--- a/sound/soc/intel/boards/sof_sdw_rt1308.c
+++ b/sound/soc/intel/boards/sof_sdw_rt_amp.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2022 Intel Corporation
 
 /*
- *  sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver
+ *  sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
  */
 
 #include <linux/device.h>
@@ -18,16 +18,26 @@
 #include "sof_sdw_amp_coeff_tables.h"
 #include "../../codecs/rt1308.h"
 
-struct rt1308_platform_data {
+#define CODEC_NAME_SIZE	7
+
+/* choose a larger value to resolve compatibility issues */
+#define RT_AMP_MAX_BQ_REG RT1316_MAX_BQ_REG
+
+struct rt_amp_platform_data {
 	const unsigned char *bq_params;
 	const unsigned int bq_params_cnt;
 };
 
-static const struct rt1308_platform_data dell_0a5d_platform_data = {
+static const struct rt_amp_platform_data dell_0a5d_platform_data = {
 	.bq_params = dell_0a5d_bq_params,
 	.bq_params_cnt = ARRAY_SIZE(dell_0a5d_bq_params),
 };
 
+static const struct rt_amp_platform_data dell_0b00_platform_data = {
+	.bq_params = dell_0b00_bq_params,
+	.bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
+};
+
 static const struct dmi_system_id dmi_platform_data[] = {
 	/* CometLake devices */
 	{
@@ -59,15 +69,45 @@ static const struct dmi_system_id dmi_platform_data[] = {
 		},
 		.driver_data = (void *)&dell_0a5d_platform_data,
 	},
+	/* AlderLake devices */
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
+		},
+		.driver_data = (void *)&dell_0b00_platform_data,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
+		},
+		.driver_data = (void *)&dell_0b00_platform_data,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
+		},
+		.driver_data = (void *)&dell_0b00_platform_data,
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+		},
+		.driver_data = (void *)&dell_0b00_platform_data,
+	},
+	{},
 };
 
-static int rt1308_add_device_props(struct device *sdw_dev)
+static int rt_amp_add_device_props(struct device *sdw_dev)
 {
 	struct property_entry props[3] = {};
 	struct fwnode_handle *fwnode;
 	const struct dmi_system_id *dmi_data;
-	const struct rt1308_platform_data *pdata;
-	unsigned char params[RT1308_MAX_BQ_REG];
+	const struct rt_amp_platform_data *pdata;
+	unsigned char params[RT_AMP_MAX_BQ_REG];
 	int ret;
 
 	dmi_data = dmi_first_match(dmi_platform_data);
@@ -91,15 +131,19 @@ static int rt1308_add_device_props(struct device *sdw_dev)
 	return ret;
 }
 
-static const struct snd_soc_dapm_widget rt1308_widgets[] = {
+static const struct snd_kcontrol_new rt_amp_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget rt_amp_widgets[] = {
 	SND_SOC_DAPM_SPK("Speaker", NULL),
 };
 
 /*
- * dapm routes for rt1308 will be registered dynamically according
- * to the number of rt1308 used. The first two entries will be registered
- * for one codec case, and the last two entries are also registered
- * if two 1308s are used.
+ * dapm routes for rt1308/rt1316/rt1318 will be registered dynamically
+ * according to the number of rt1308/rt1316/rt1318 used. The first two
+ * entries will be registered for one codec case, and the last two entries
+ * are also registered if two 1308s/1316s/1318s are used.
  */
 static const struct snd_soc_dapm_route rt1308_map[] = {
 	{ "Speaker", NULL, "rt1308-1 SPOL" },
@@ -108,36 +152,69 @@ static const struct snd_soc_dapm_route rt1308_map[] = {
 	{ "Speaker", NULL, "rt1308-2 SPOR" },
 };
 
-static const struct snd_kcontrol_new rt1308_controls[] = {
-	SOC_DAPM_PIN_SWITCH("Speaker"),
+static const struct snd_soc_dapm_route rt1316_map[] = {
+	{ "Speaker", NULL, "rt1316-1 SPOL" },
+	{ "Speaker", NULL, "rt1316-1 SPOR" },
+	{ "Speaker", NULL, "rt1316-2 SPOL" },
+	{ "Speaker", NULL, "rt1316-2 SPOR" },
 };
 
+static const struct snd_soc_dapm_route rt1318_map[] = {
+	{ "Speaker", NULL, "rt1318-1 SPOL" },
+	{ "Speaker", NULL, "rt1318-1 SPOR" },
+	{ "Speaker", NULL, "rt1318-2 SPOL" },
+	{ "Speaker", NULL, "rt1318-2 SPOR" },
+};
+
+static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_pcm_runtime *rtd,
+								 char *codec_name)
+{
+	const char *dai_name;
+
+	dai_name = rtd->dai_link->codecs->dai_name;
+
+	/* get the codec name */
+	snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name);
+
+	/* choose the right codec's map  */
+	if (strcmp(codec_name, "rt1308") == 0)
+		return rt1308_map;
+	else if (strcmp(codec_name, "rt1316") == 0)
+		return rt1316_map;
+	else
+		return rt1318_map;
+}
+
 static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_card *card = rtd->card;
+	const struct snd_soc_dapm_route *rt_amp_map;
+	char codec_name[CODEC_NAME_SIZE];
 	int ret;
 
+	rt_amp_map = get_codec_name_and_route(rtd, codec_name);
+
 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
-					  "%s spk:rt1308",
-					  card->components);
+					  "%s spk:%s",
+					  card->components, codec_name);
 	if (!card->components)
 		return -ENOMEM;
 
-	ret = snd_soc_add_card_controls(card, rt1308_controls,
-					ARRAY_SIZE(rt1308_controls));
+	ret = snd_soc_add_card_controls(card, rt_amp_controls,
+					ARRAY_SIZE(rt_amp_controls));
 	if (ret) {
-		dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret);
+		dev_err(card->dev, "%s controls addition failed: %d\n", codec_name, ret);
 		return ret;
 	}
 
-	ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets,
-					ARRAY_SIZE(rt1308_widgets));
+	ret = snd_soc_dapm_new_controls(&card->dapm, rt_amp_widgets,
+					ARRAY_SIZE(rt_amp_widgets));
 	if (ret) {
-		dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret);
+		dev_err(card->dev, "%s widgets addition failed: %d\n", codec_name, ret);
 		return ret;
 	}
 
-	ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2);
+	ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2);
 	if (ret)
 		dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
 
@@ -147,9 +224,13 @@ static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
 static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_card *card = rtd->card;
+	const struct snd_soc_dapm_route *rt_amp_map;
+	char codec_name[CODEC_NAME_SIZE];
 	int ret;
 
-	ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2);
+	rt_amp_map = get_codec_name_and_route(rtd, codec_name);
+
+	ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map + 2, 2);
 	if (ret)
 		dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
 
@@ -204,7 +285,7 @@ struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
 	.hw_params = rt1308_i2s_hw_params,
 };
 
-int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
 {
 	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 
@@ -221,7 +302,7 @@ int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_
 	return 0;
 }
 
-int sof_sdw_rt1308_init(struct snd_soc_card *card,
+int sof_sdw_rt_amp_init(struct snd_soc_card *card,
 			const struct snd_soc_acpi_link_adr *link,
 			struct snd_soc_dai_link *dai_links,
 			struct sof_sdw_codec_info *info,
@@ -244,7 +325,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
 		if (!sdw_dev1)
 			return -EPROBE_DEFER;
 
-		ret = rt1308_add_device_props(sdw_dev1);
+		ret = rt_amp_add_device_props(sdw_dev1);
 		if (ret < 0) {
 			put_device(sdw_dev1);
 			return ret;
@@ -255,7 +336,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
 		if (!sdw_dev2)
 			return -EPROBE_DEFER;
 
-		ret = rt1308_add_device_props(sdw_dev2);
+		ret = rt_amp_add_device_props(sdw_dev2);
 		if (ret < 0) {
 			put_device(sdw_dev2);
 			return ret;
@@ -263,7 +344,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
 		ctx->amp_dev2 = sdw_dev2;
 
 		/*
-		 * if two 1308s are in one dai link, the init function
+		 * if two amps are in one dai link, the init function
 		 * in this dai link will be first set for the first speaker,
 		 * and it should be reset to initialize all speakers when
 		 * the second speaker is found.
diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
index b95c4b2cda947f413debaeeea730efec7a705d7a..f5c7e1bbded0623b9264c65500095772e317d425 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -78,6 +78,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
 		.quirk_data = &mx98360a_spk,
 		.sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg",
 	},
+	{
+		.comp_ids = &rt5682_rt5682s_hp,
+		.drv_name = "jsl_rt5682",
+		.sof_tplg_filename = "sof-jsl-rt5682.tplg",
+	},
 	{
 		.id = "10134242",
 		.drv_name = "jsl_cs4242_mx98360a",
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index b91f7a652a2b14037bde5cf5f9fcebf3f6bfe099..b0204ea00f07f84ef637e4f5181dbdb3f5554ccf 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <sound/hda_register.h>
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 
@@ -79,21 +80,25 @@ static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
 		__le32 **bdlp, int size, int with_ioc)
 {
 	__le32 *bdl = *bdlp;
+	int remaining = ctx->cl_dev.bufsize;
+	int offset = 0;
 
 	ctx->cl_dev.frags = 0;
-	while (size > 0) {
-		phys_addr_t addr = virt_to_phys(dmab_data->area +
-				(ctx->cl_dev.frags * ctx->cl_dev.bufsize));
+	while (remaining > 0) {
+		phys_addr_t addr;
+		int chunk;
 
+		addr = snd_sgbuf_get_addr(dmab_data, offset);
 		bdl[0] = cpu_to_le32(lower_32_bits(addr));
 		bdl[1] = cpu_to_le32(upper_32_bits(addr));
+		chunk = snd_sgbuf_get_chunk_size(dmab_data, offset, size);
+		bdl[2] = cpu_to_le32(chunk);
 
-		bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize);
-
-		size -= ctx->cl_dev.bufsize;
-		bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+		remaining -= chunk;
+		bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01);
 
 		bdl += 4;
+		offset += chunk;
 		ctx->cl_dev.frags++;
 	}
 }
@@ -338,15 +343,15 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
 	ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
 
 	/* Allocate buffer*/
-	ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
-			&ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize);
+	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize,
+				  &ctx->cl_dev.dmab_data);
 	if (ret < 0) {
 		dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret);
 		return ret;
 	}
+
 	/* Setup Code loader BDL */
-	ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
-			&ctx->cl_dev.dmab_bdl, PAGE_SIZE);
+	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl);
 	if (ret < 0) {
 		dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret);
 		ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index e06eac592da128a831577d05a34f215ef58ca2a5..b20643b83401256ba2fa55ba5ec83222dacda086 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -582,36 +582,10 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
 	return ret;
 }
 
-static bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe)
+static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx)
 {
-	struct skl_pipe_fmt *cur_fmt;
-	struct skl_pipe_fmt *next_fmt;
-	int i;
-
-	if (pipe->nr_cfgs <= 1)
-		return false;
-
-	if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
-		return true;
-
-	for (i = 0; i < pipe->nr_cfgs - 1; i++) {
-		if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
-			cur_fmt = &pipe->configs[i].out_fmt;
-			next_fmt = &pipe->configs[i + 1].out_fmt;
-		} else {
-			cur_fmt = &pipe->configs[i].in_fmt;
-			next_fmt = &pipe->configs[i + 1].in_fmt;
-		}
-
-		if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
-				     cur_fmt->bps,
-				     next_fmt->channels,
-				     next_fmt->freq,
-				     next_fmt->bps))
-			return true;
-	}
-
-	return false;
+	pipe->cur_config_idx = idx;
+	pipe->memory_pages = pipe->configs[idx].mem_pages;
 }
 
 /*
@@ -632,24 +606,14 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
 	int i;
 
 	if (pipe->nr_cfgs == 0) {
-		pipe->cur_config_idx = 0;
-		return 0;
-	}
-
-	if (skl_tplg_is_multi_fmt(skl, pipe)) {
-		pipe->cur_config_idx = pipe->pipe_config_idx;
-		pipe->memory_pages = pconfig->mem_pages;
-		dev_dbg(skl->dev, "found pipe config idx:%d\n",
-			pipe->cur_config_idx);
+		skl_tplg_set_pipe_config_idx(pipe, 0);
 		return 0;
 	}
 
 	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) {
 		dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
 			pipe->ppl_id);
-		pipe->cur_config_idx = 0;
-		pipe->memory_pages = pconfig->mem_pages;
-
+		skl_tplg_set_pipe_config_idx(pipe, 0);
 		return 0;
 	}
 
@@ -668,10 +632,8 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
 
 		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
 				    fmt->channels, fmt->freq, fmt->bps)) {
-			pipe->cur_config_idx = i;
-			pipe->memory_pages = pconfig->mem_pages;
+			skl_tplg_set_pipe_config_idx(pipe, i);
 			dev_dbg(skl->dev, "Using pipe config: %d\n", i);
-
 			return 0;
 		}
 	}
@@ -1391,9 +1353,9 @@ static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
 		return -EIO;
 
 	if (is_set)
-		pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
+		skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]);
 	else
-		ucontrol->value.enumerated.item[0]  =  pipe->pipe_config_idx;
+		ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
 
 	return 0;
 }
@@ -1837,20 +1799,28 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
 {
 	struct nhlt_specific_cfg *cfg;
 	struct skl_pipe *pipe = mconfig->pipe;
+	struct skl_pipe_params save = *pipe->p_params;
 	struct skl_pipe_fmt *pipe_fmt;
 	struct skl_dev *skl = get_skl_ctx(dai->dev);
 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
+	int ret;
 
 	skl_tplg_fill_dma_id(mconfig, params);
 
 	if (link_type == NHLT_LINK_HDA)
 		return 0;
 
+	*pipe->p_params = *params;
+	ret = skl_tplg_get_pipe_config(skl, mconfig);
+	if (ret)
+		goto err;
+
+	dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx);
 	if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
-		pipe_fmt = &pipe->configs[pipe->pipe_config_idx].out_fmt;
+		pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt;
 	else
-		pipe_fmt = &pipe->configs[pipe->pipe_config_idx].in_fmt;
+		pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt;
 
 	/* update the blob based on virtual bus_id*/
 	cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt,
@@ -1865,10 +1835,15 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
 		dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
 			mconfig->vbus_id, link_type, params->stream,
 			params->ch, params->s_freq, params->s_fmt);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	return 0;
+
+err:
+	*pipe->p_params = save;
+	return ret;
 }
 
 static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 017ac0ef324ddd65a20e4c3436485cdac1c57b99..6db0fd7bad49cdda8409f2333e79ff36b6fbd5f9 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -324,7 +324,6 @@ struct skl_pipe {
 	struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
 	struct list_head w_list;
 	bool passthru;
-	u32 pipe_config_idx;
 };
 
 enum skl_module_state {
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 9bd9f986689884ab000adbcc31d1359bb2e4559b..998bd0232cf1d4b66020bfeb8d8fc5bb6604e301 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -1107,7 +1107,10 @@ static void skl_shutdown(struct pci_dev *pci)
 	if (!skl->init_done)
 		return;
 
-	snd_hdac_stop_streams_and_chip(bus);
+	snd_hdac_stop_streams(bus);
+	snd_hdac_ext_bus_link_power_down_all(bus);
+	skl_dsp_sleep(skl->dsp);
+
 	list_for_each_entry(s, &bus->stream_list, list) {
 		stream = stream_to_hdac_ext_stream(s);
 		snd_hdac_ext_stream_decouple(bus, stream, false);
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 12f40c81b101e8bd0b4bcd6d151155774ffa251b..f803f121659de30850e4fa644a0924015863f301 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -200,14 +200,16 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
 	if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
 		dev_err(&pdev->dev,
 			"Property 'audio-codec' missing or invalid\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
 		of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
 	if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
 		dev_err(&pdev->dev,
 			"Property 'audio-codec' missing or invalid\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	mt8173_rt5650_rt5514_codec_conf[0].dlc.of_node =
 		mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
@@ -216,6 +218,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 
+out:
 	of_node_put(platform_node);
 	return ret;
 }
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index 8fb473543cf9f0b117611431f99ed47740f0d003..ce9aedde7e1eff1e8f8d935d881e87a427bbc59f 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -677,8 +677,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
 	}
 
 	card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
-	if (!card)
+	if (!card) {
+		of_node_put(platform_node);
 		return -EINVAL;
+	}
 	card->dev = &pdev->dev;
 
 	ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0);
@@ -767,8 +769,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
 	}
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	snd_soc_card_set_drvdata(card, priv);
 
@@ -776,7 +780,8 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
 	if (IS_ERR(priv->pinctrl)) {
 		dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n",
 			__func__);
-		return PTR_ERR(priv->pinctrl);
+		ret = PTR_ERR(priv->pinctrl);
+		goto out;
 	}
 
 	for (i = 0; i < PIN_STATE_MAX; i++) {
@@ -809,6 +814,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 
+out:
 	of_node_put(platform_node);
 	of_node_put(ec_codec);
 	of_node_put(hdmi_codec);
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index a7549f8272359fcc920d9459b302d01d78008d4b..5b1e47bdc376bce0f205d1893ac9230b36607cdc 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -431,6 +431,7 @@ static int rockchip_pdm_runtime_resume(struct device *dev)
 
 	ret = clk_prepare_enable(pdm->hclk);
 	if (ret) {
+		clk_disable_unprepare(pdm->clk);
 		dev_err(pdm->dev, "hclock enable failed %d\n", ret);
 		return ret;
 	}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index a7810c78ffa18aba42ba5c527eba8afc4232d10f..579a44d81d9a315876e64c4c2286889e7deb302c 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -709,8 +709,17 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
 
 	snd_soc_dpcm_mutex_assert_held(rtd);
 
-	if (!rollback)
+	if (!rollback) {
 		snd_soc_runtime_deactivate(rtd, substream->stream);
+		/* clear the corresponding DAIs parameters when going to be inactive */
+		for_each_rtd_dais(rtd, i, dai) {
+			if (snd_soc_dai_active(dai) == 0)
+				soc_pcm_set_dai_params(dai, NULL);
+
+			if (snd_soc_dai_stream_active(dai, substream->stream) == 0)
+				snd_soc_dai_digital_mute(dai, 1, substream->stream);
+		}
+	}
 
 	for_each_rtd_dais(rtd, i, dai)
 		snd_soc_dai_shutdown(dai, substream, rollback);
@@ -940,15 +949,6 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
 
 	snd_soc_dpcm_mutex_assert_held(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);
-
-		if (snd_soc_dai_stream_active(dai, substream->stream) == 1)
-			snd_soc_dai_digital_mute(dai, 1, substream->stream);
-	}
-
 	/* run the stream event */
 	snd_soc_dapm_stream_stop(rtd, substream->stream);