Merge "asoc: codecs: bolero: Update mixing path and channel mask for RX path"
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 6f81dab..76c9d40 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -504,6 +504,8 @@
 	if (macro_id == TX_MACRO) {
 		priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq;
 		priv->macro_params[macro_id].clk_switch = ops->clk_switch;
+		priv->macro_params[macro_id].reg_evt_listener =
+							ops->reg_evt_listener;
 	}
 
 	priv->num_dais += ops->num_dais;
@@ -567,6 +569,7 @@
 	if (macro_id == TX_MACRO) {
 		priv->macro_params[macro_id].reg_wake_irq = NULL;
 		priv->macro_params[macro_id].clk_switch = NULL;
+		priv->macro_params[macro_id].reg_evt_listener = NULL;
 	}
 
 	priv->num_dais -= priv->macro_params[macro_id].num_dais;
@@ -578,6 +581,29 @@
 }
 EXPORT_SYMBOL(bolero_unregister_macro);
 
+void bolero_wsa_pa_on(struct device *dev)
+{
+	struct bolero_priv *priv;
+
+	if (!dev) {
+		pr_err("%s: dev is null\n", __func__);
+		return;
+	}
+	if (!bolero_is_valid_child_dev(dev)) {
+		dev_err(dev, "%s: not a valid child dev\n",
+			__func__);
+		return;
+	}
+	priv = dev_get_drvdata(dev->parent);
+	if (!priv) {
+		dev_err(dev, "%s: priv is null\n", __func__);
+		return;
+	}
+
+	bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_PA_ON_POST_FSCLK);
+}
+EXPORT_SYMBOL(bolero_wsa_pa_on);
+
 static ssize_t bolero_version_read(struct snd_info_entry *entry,
 				   void *file_private_data,
 				   struct file *file,
@@ -803,6 +829,41 @@
 }
 EXPORT_SYMBOL(bolero_tx_clk_switch);
 
+/**
+ * bolero_register_event_listener - Register/Deregister to event listener
+ *
+ * @component: pointer to codec component instance.
+ * @enable: when set to 1 registers to event listener otherwise, derigisters
+ *          from the event listener
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int bolero_register_event_listener(struct snd_soc_component *component,
+				   bool enable)
+{
+	struct bolero_priv *priv = NULL;
+	int ret = 0;
+
+	if (!component)
+		return -EINVAL;
+
+	priv = snd_soc_component_get_drvdata(component);
+	if (!priv)
+		return -EINVAL;
+
+	if (!bolero_is_valid_codec_dev(priv->dev)) {
+		dev_err(component->dev, "%s: invalid codec\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->macro_params[TX_MACRO].reg_evt_listener)
+		ret = priv->macro_params[TX_MACRO].reg_evt_listener(component,
+								    enable);
+
+	return ret;
+}
+EXPORT_SYMBOL(bolero_register_event_listener);
+
 static int bolero_soc_codec_probe(struct snd_soc_component *component)
 {
 	struct bolero_priv *priv = dev_get_drvdata(component->dev);
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 7e8ec83..957389c 100644
--- a/asoc/codecs/bolero/bolero-cdc.h
+++ b/asoc/codecs/bolero/bolero-cdc.h
@@ -56,6 +56,7 @@
 	int (*set_port_map)(struct snd_soc_component *component, u32 uc,
 			    u32 size, void *data);
 	int (*clk_switch)(struct snd_soc_component *component);
+	int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
 	char __iomem *io_base;
 	u16 clk_id_req;
 	u16 default_clk_id;
@@ -80,6 +81,9 @@
 int bolero_runtime_suspend(struct device *dev);
 int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data);
 int bolero_tx_clk_switch(struct snd_soc_component *component);
+int bolero_register_event_listener(struct snd_soc_component *component,
+				   bool enable);
+void bolero_wsa_pa_on(struct device *dev);
 #else
 static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
 {
@@ -144,5 +148,15 @@
 	return 0;
 }
 
+static inline int bolero_register_event_listener(
+					struct snd_soc_component *component,
+					bool enable)
+{
+	return 0;
+}
+
+static void bolero_wsa_pa_on(struct device *dev)
+{
+}
 #endif /* CONFIG_SND_SOC_BOLERO */
 #endif /* BOLERO_CDC_H */
diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h
index d353a2d..d3f6894 100644
--- a/asoc/codecs/bolero/internal.h
+++ b/asoc/codecs/bolero/internal.h
@@ -15,6 +15,7 @@
 	BOLERO_WCD_EVT_PA_OFF_PRE_SSR,
 	BOLERO_WCD_EVT_SSR_DOWN,
 	BOLERO_WCD_EVT_SSR_UP,
+	BOLERO_WCD_EVT_PA_ON_POST_FSCLK,
 };
 
 enum {
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index d3370f0..9af1522 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -77,6 +77,8 @@
 #define RX_MACRO_EC_MIX_TX1_MASK 0x0f
 #define RX_MACRO_EC_MIX_TX2_MASK 0x0f
 
+#define COMP_MAX_COEFF 25
+
 struct wcd_imped_val {
 	u32 imped_val;
 	u8 index;
@@ -95,6 +97,75 @@
 	{13, 9},
 };
 
+struct comp_coeff_val {
+	u8 lsb;
+	u8 msb;
+};
+
+enum {
+	HPH_ULP,
+	HPH_LOHIFI,
+	HPH_MODE_MAX,
+};
+
+static const struct comp_coeff_val
+			comp_coeff_table [HPH_MODE_MAX][COMP_MAX_COEFF] = {
+	{
+		{0x40, 0x00},
+		{0x4C, 0x00},
+		{0x5A, 0x00},
+		{0x6B, 0x00},
+		{0x7F, 0x00},
+		{0x97, 0x00},
+		{0xB3, 0x00},
+		{0xD5, 0x00},
+		{0xFD, 0x00},
+		{0x2D, 0x01},
+		{0x66, 0x01},
+		{0xA7, 0x01},
+		{0xF8, 0x01},
+		{0x57, 0x02},
+		{0xC7, 0x02},
+		{0x4B, 0x03},
+		{0xE9, 0x03},
+		{0xA3, 0x04},
+		{0x7D, 0x05},
+		{0x90, 0x06},
+		{0xD1, 0x07},
+		{0x49, 0x09},
+		{0x00, 0x0B},
+		{0x01, 0x0D},
+		{0x59, 0x0F},
+	},
+	{
+		{0x40, 0x00},
+		{0x4C, 0x00},
+		{0x5A, 0x00},
+		{0x6B, 0x00},
+		{0x80, 0x00},
+		{0x98, 0x00},
+		{0xB4, 0x00},
+		{0xD5, 0x00},
+		{0xFE, 0x00},
+		{0x2E, 0x01},
+		{0x66, 0x01},
+		{0xA9, 0x01},
+		{0xF8, 0x01},
+		{0x56, 0x02},
+		{0xC4, 0x02},
+		{0x4F, 0x03},
+		{0xF0, 0x03},
+		{0xAE, 0x04},
+		{0x8B, 0x05},
+		{0x8E, 0x06},
+		{0xBC, 0x07},
+		{0x56, 0x09},
+		{0x0F, 0x0B},
+		{0x13, 0x0D},
+		{0x6F, 0x0F},
+	},
+};
+
 struct rx_macro_reg_mask_val {
 	u16 reg;
 	u8 mask;
@@ -301,6 +372,7 @@
 	int (*write)(void *handle, int reg, int val);
 	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
 	int (*clk)(void *handle, bool enable);
+	int (*core_vote)(void *handle, bool enable);
 	int (*handle_irq)(void *handle,
 			  irqreturn_t (*swrm_irq_handler)(int irq,
 							  void *data),
@@ -1638,6 +1710,47 @@
 	return 0;
 }
 
+static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
+					 struct rx_macro_priv *rx_priv,
+					 int interp_n, int event)
+{
+	int comp = 0;
+	u16 comp_coeff_lsb_reg = 0, comp_coeff_msb_reg = 0;
+	int i = 0;
+	int hph_pwr_mode = HPH_LOHIFI;
+
+	if (!rx_priv->comp_enabled[comp])
+		return 0;
+
+	if (interp_n == INTERP_HPHL) {
+		comp_coeff_lsb_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB;
+		comp_coeff_msb_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB;
+	} else if (interp_n == INTERP_HPHR) {
+		comp_coeff_lsb_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB;
+		comp_coeff_msb_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB;
+	} else {
+		/* compander coefficients are loaded only for hph path */
+		return 0;
+	}
+
+	comp = interp_n;
+	hph_pwr_mode = rx_priv->hph_pwr_mode;
+	dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n",
+		__func__, event, comp + 1, rx_priv->comp_enabled[comp]);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Load Compander Coeff */
+		for (i = 0; i < COMP_MAX_COEFF; i++) {
+			snd_soc_component_write(component, comp_coeff_lsb_reg,
+					comp_coeff_table[hph_pwr_mode][i].lsb);
+			snd_soc_component_write(component, comp_coeff_msb_reg,
+					comp_coeff_table[hph_pwr_mode][i].msb);
+		}
+	}
+
+	return 0;
+}
+
 static void rx_macro_enable_softclip_clk(struct snd_soc_component *component,
 					 struct rx_macro_priv *rx_priv,
 					 bool enable)
@@ -2354,6 +2467,8 @@
 					0x01, 0x01);
 			snd_soc_component_update_bits(component, rx_cfg2_reg,
 					0x03, 0x03);
+			rx_macro_load_compander_coeff(component, rx_priv,
+						      interp_idx, event);
 			rx_macro_idle_detect_control(component, rx_priv,
 					interp_idx, event);
 			if (rx_priv->hph_hd2_mode)
@@ -3370,6 +3485,23 @@
 	{"RX INT2 MIX2 INP", "SRC1", "SRC1"},
 };
 
+static int rx_macro_core_vote(void *handle, bool enable)
+{
+	struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle;
+
+	if (rx_priv == NULL) {
+		pr_err("%s: rx priv data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (enable) {
+		pm_runtime_get_sync(rx_priv->dev);
+		pm_runtime_put_autosuspend(rx_priv->dev);
+		pm_runtime_mark_last_busy(rx_priv->dev);
+	}
+
+	return 0;
+}
+
 static int rx_swrm_clock(void *handle, bool enable)
 {
 	struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle;
@@ -3388,8 +3520,16 @@
 	if (enable) {
 		pm_runtime_get_sync(rx_priv->dev);
 		if (rx_priv->swr_clk_users == 0) {
-			msm_cdc_pinctrl_select_active_state(
+			ret = msm_cdc_pinctrl_select_active_state(
 						rx_priv->rx_swr_gpio_p);
+			if (ret < 0) {
+				dev_err(rx_priv->dev,
+					"%s: rx swr pinctrl enable failed\n",
+					__func__);
+				pm_runtime_mark_last_busy(rx_priv->dev);
+				pm_runtime_put_autosuspend(rx_priv->dev);
+				goto exit;
+			}
 			ret = rx_macro_mclk_enable(rx_priv, 1, true);
 			if (ret < 0) {
 				msm_cdc_pinctrl_select_sleep_state(
@@ -3397,6 +3537,8 @@
 				dev_err(rx_priv->dev,
 					"%s: rx request clock enable failed\n",
 					__func__);
+				pm_runtime_mark_last_busy(rx_priv->dev);
+				pm_runtime_put_autosuspend(rx_priv->dev);
 				goto exit;
 			}
 			if (rx_priv->reset_swr)
@@ -3429,8 +3571,14 @@
 				BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
 				0x01, 0x00);
 			rx_macro_mclk_enable(rx_priv, 0, true);
-			msm_cdc_pinctrl_select_sleep_state(
+			ret = msm_cdc_pinctrl_select_sleep_state(
 						rx_priv->rx_swr_gpio_p);
+			if (ret < 0) {
+				dev_err(rx_priv->dev,
+					"%s: rx swr pinctrl disable failed\n",
+					__func__);
+				goto exit;
+			}
 		}
 	}
 	dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n",
@@ -3440,6 +3588,15 @@
 	return ret;
 }
 
+static const struct rx_macro_reg_mask_val rx_macro_reg_init[] = {
+	{BOLERO_CDC_RX_RX0_RX_PATH_SEC7, 0x07, 0x02},
+	{BOLERO_CDC_RX_RX1_RX_PATH_SEC7, 0x07, 0x02},
+	{BOLERO_CDC_RX_RX2_RX_PATH_SEC7, 0x07, 0x02},
+	{BOLERO_CDC_RX_RX0_RX_PATH_CFG3, 0x03, 0x02},
+	{BOLERO_CDC_RX_RX1_RX_PATH_CFG3, 0x03, 0x02},
+	{BOLERO_CDC_RX_RX2_RX_PATH_CFG3, 0x03, 0x02},
+};
+
 static void rx_macro_init_bcl_pmic_reg(struct snd_soc_component *component)
 {
 	struct device *rx_dev = NULL;
@@ -3494,6 +3651,7 @@
 	int ret = 0;
 	struct device *rx_dev = NULL;
 	struct rx_macro_priv *rx_priv = NULL;
+	int i;
 
 	rx_dev = bolero_get_device_ptr(component->dev, RX_MACRO);
 	if (!rx_dev) {
@@ -3545,18 +3703,11 @@
 	snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC3_INP");
 	snd_soc_dapm_sync(dapm);
 
-	snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_SEC7,
-				0x07, 0x02);
-	snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_SEC7,
-				0x07, 0x02);
-	snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX2_RX_PATH_SEC7,
-				0x07, 0x02);
-	snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_CFG3,
-				0x03, 0x02);
-	snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_CFG3,
-				0x03, 0x02);
-	snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX2_RX_PATH_CFG3,
-				0x03, 0x02);
+	for (i = 0; i < ARRAY_SIZE(rx_macro_reg_init); i++)
+		snd_soc_component_update_bits(component,
+				rx_macro_reg_init[i].reg,
+				rx_macro_reg_init[i].mask,
+				rx_macro_reg_init[i].val);
 
 	rx_priv->component = component;
 	rx_macro_init_bcl_pmic_reg(component);
@@ -3781,6 +3932,7 @@
 	rx_priv->swr_plat_data.write = NULL;
 	rx_priv->swr_plat_data.bulk_write = NULL;
 	rx_priv->swr_plat_data.clk = rx_swrm_clock;
+	rx_priv->swr_plat_data.core_vote = rx_macro_core_vote;
 	rx_priv->swr_plat_data.handle_irq = NULL;
 
 	ret = of_property_read_u8_array(pdev->dev.of_node,
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index fda01e1..45e0a80 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -41,6 +41,7 @@
 #define TX_MACRO_TX_PATH_OFFSET 0x80
 #define TX_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
 #define TX_MACRO_ADC_MUX_CFG_OFFSET 0x2
+#define TX_MACRO_ADC_MODE_CFG0_SHIFT 1
 
 #define TX_MACRO_TX_UNMUTE_DELAY_MS	40
 
@@ -71,6 +72,7 @@
 	int (*write)(void *handle, int reg, int val);
 	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
 	int (*clk)(void *handle, bool enable);
+	int (*core_vote)(void *handle, bool enable);
 	int (*handle_irq)(void *handle,
 			  irqreturn_t (*swrm_irq_handler)(int irq,
 							  void *data),
@@ -118,6 +120,12 @@
 	VA_MCLK,
 };
 
+struct tx_macro_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
 struct tx_mute_work {
 	struct tx_macro_priv *tx_priv;
 	u32 decimator;
@@ -163,6 +171,7 @@
 	int va_clk_status;
 	int tx_clk_status;
 	bool bcs_enable;
+	int dec_mode[NUM_DECIMATORS];
 };
 
 static bool tx_macro_get_data(struct snd_soc_component *component,
@@ -609,6 +618,91 @@
 
 	return 0;
 }
+
+static inline int tx_macro_path_get(const char *wname,
+				    unsigned int *path_num)
+{
+	int ret = 0;
+	char *widget_name = NULL;
+	char *w_name = NULL;
+	char *path_num_char = NULL;
+	char *path_name = NULL;
+
+	widget_name = kstrndup(wname, 10, GFP_KERNEL);
+	if (!widget_name)
+		return -EINVAL;
+
+	w_name = widget_name;
+
+	path_name = strsep(&widget_name, " ");
+	if (!path_name) {
+		pr_err("%s: Invalid widget name = %s\n",
+			__func__, widget_name);
+		ret = -EINVAL;
+		goto err;
+	}
+	path_num_char = strpbrk(path_name, "01234567");
+	if (!path_num_char) {
+		pr_err("%s: tx path index not found\n",
+			__func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	ret = kstrtouint(path_num_char, 10, path_num);
+	if (ret < 0)
+		pr_err("%s: Invalid tx path = %s\n",
+			__func__, w_name);
+
+err:
+	kfree(w_name);
+	return ret;
+}
+
+static int tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct tx_macro_priv *tx_priv = NULL;
+	struct device *tx_dev = NULL;
+	int ret = 0;
+	int path = 0;
+
+	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+		return -EINVAL;
+
+	ret = tx_macro_path_get(kcontrol->id.name, &path);
+	if (ret)
+		return ret;
+
+	ucontrol->value.integer.value[0] = tx_priv->dec_mode[path];
+
+	return 0;
+}
+
+static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct tx_macro_priv *tx_priv = NULL;
+	struct device *tx_dev = NULL;
+	int value = ucontrol->value.integer.value[0];
+	int ret = 0;
+	int path = 0;
+
+	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+		return -EINVAL;
+
+	ret = tx_macro_path_get(kcontrol->id.name, &path);
+	if (ret)
+		return ret;
+
+	tx_priv->dec_mode[path] = value;
+
+	return 0;
+}
+
 static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
@@ -759,6 +853,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+			dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] <<
+			TX_MACRO_ADC_MODE_CFG0_SHIFT);
 		/* Enable TX PGA Mute */
 		snd_soc_component_update_bits(component,
 			tx_vol_ctl_reg, 0x10, 0x10);
@@ -840,6 +937,8 @@
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 						0x20, 0x00);
+		snd_soc_component_update_bits(component,
+			dec_cfg_reg, 0x06, 0x00);
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 						0x10, 0x00);
 		if (tx_priv->bcs_enable) {
@@ -1111,6 +1210,14 @@
 			0, smic_mux_text, snd_soc_dapm_get_enum_double,
 			tx_macro_put_dec_enum);
 
+static const char * const dec_mode_mux_text[] = {
+	"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text),
+			    dec_mode_mux_text);
+
 static const struct snd_kcontrol_new tx_aif1_cap_mixer[] = {
 	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
 			tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
@@ -1586,10 +1693,75 @@
 			  BOLERO_CDC_TX7_TX_VOL_CTL,
 			  0, -84, 40, digital_gain),
 
+	SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+	SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum,
+			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
 	SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0,
 		       tx_macro_get_bcs, tx_macro_set_bcs),
 };
 
+static int tx_macro_register_event_listener(struct snd_soc_component *component,
+					    bool enable)
+{
+	struct device *tx_dev = NULL;
+	struct tx_macro_priv *tx_priv = NULL;
+	int ret = 0;
+
+	if (!component)
+		return -EINVAL;
+
+	tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO);
+	if (!tx_dev) {
+		dev_err(component->dev,
+			"%s: null device for macro!\n", __func__);
+		return -EINVAL;
+	}
+	tx_priv = dev_get_drvdata(tx_dev);
+	if (!tx_priv) {
+		dev_err(component->dev,
+			"%s: priv is null for macro!\n", __func__);
+		return -EINVAL;
+	}
+	if (tx_priv->swr_ctrl_data) {
+		if (enable) {
+			ret = swrm_wcd_notify(
+				tx_priv->swr_ctrl_data[0].tx_swr_pdev,
+				SWR_REGISTER_WAKEUP, NULL);
+			msm_cdc_pinctrl_set_wakeup_capable(
+					tx_priv->tx_swr_gpio_p, false);
+		} else {
+			msm_cdc_pinctrl_set_wakeup_capable(
+					tx_priv->tx_swr_gpio_p, true);
+			ret = swrm_wcd_notify(
+				tx_priv->swr_ctrl_data[0].tx_swr_pdev,
+				SWR_DEREGISTER_WAKEUP, NULL);
+		}
+	}
+
+	return ret;
+}
+
 static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv,
 				      struct regmap *regmap, int clk_type,
 				      bool enable)
@@ -1602,9 +1774,16 @@
 		(enable ? "enable" : "disable"), tx_priv->tx_mclk_users);
 
 	if (enable) {
-		if (tx_priv->swr_clk_users == 0)
-			msm_cdc_pinctrl_select_active_state(
+		if (tx_priv->swr_clk_users == 0) {
+			ret = msm_cdc_pinctrl_select_active_state(
 						tx_priv->tx_swr_gpio_p);
+			if (ret < 0) {
+				dev_err_ratelimited(tx_priv->dev,
+					"%s: tx swr pinctrl enable failed\n",
+					__func__);
+				goto exit;
+			}
+		}
 
 		clk_tx_ret = bolero_clk_rsc_request_clock(tx_priv->dev,
 						   TX_CORE_CLK,
@@ -1717,9 +1896,16 @@
 						   TX_CORE_CLK,
 						   TX_CORE_CLK,
 						   false);
-		if (tx_priv->swr_clk_users == 0)
-			msm_cdc_pinctrl_select_sleep_state(
+		if (tx_priv->swr_clk_users == 0) {
+			ret = msm_cdc_pinctrl_select_sleep_state(
 						tx_priv->tx_swr_gpio_p);
+			if (ret < 0) {
+				dev_err_ratelimited(tx_priv->dev,
+					"%s: tx swr pinctrl disable failed\n",
+					__func__);
+				goto exit;
+			}
+		}
 	}
 	return 0;
 
@@ -1729,6 +1915,7 @@
 				TX_CORE_CLK,
 				TX_CORE_CLK,
 				false);
+exit:
 	return ret;
 }
 
@@ -1762,6 +1949,24 @@
 	return ret;
 }
 
+static int tx_macro_core_vote(void *handle, bool enable)
+{
+	struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
+	int ret = 0;
+
+	if (tx_priv == NULL) {
+		pr_err("%s: tx priv data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (enable) {
+		pm_runtime_get_sync(tx_priv->dev);
+		pm_runtime_put_autosuspend(tx_priv->dev);
+		pm_runtime_mark_last_busy(tx_priv->dev);
+	}
+
+	return ret;
+}
+
 static int tx_macro_swrm_clock(void *handle, bool enable)
 {
 	struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
@@ -1784,14 +1989,20 @@
 		if (tx_priv->va_swr_clk_cnt && !tx_priv->tx_swr_clk_cnt) {
 			ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
 							VA_MCLK, enable);
-			if (ret)
+			if (ret) {
+				pm_runtime_mark_last_busy(tx_priv->dev);
+				pm_runtime_put_autosuspend(tx_priv->dev);
 				goto done;
+			}
 			tx_priv->va_clk_status++;
 		} else {
 			ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
 							TX_MCLK, enable);
-			if (ret)
+			if (ret) {
+				pm_runtime_mark_last_busy(tx_priv->dev);
+				pm_runtime_put_autosuspend(tx_priv->dev);
 				goto done;
+			}
 			tx_priv->tx_clk_status++;
 		}
 		pm_runtime_mark_last_busy(tx_priv->dev);
@@ -1889,6 +2100,10 @@
 	return dmic_sample_rate;
 }
 
+static const struct tx_macro_reg_mask_val tx_macro_reg_init[] = {
+	{BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x02},
+};
+
 static int tx_macro_init(struct snd_soc_component *component)
 {
 	struct snd_soc_dapm_context *dapm =
@@ -1968,8 +2183,12 @@
 	}
 	tx_priv->component = component;
 
-	snd_soc_component_update_bits(component,
-		BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x0E);
+	for (i = 0; i < ARRAY_SIZE(tx_macro_reg_init); i++)
+		snd_soc_component_update_bits(component,
+				tx_macro_reg_init[i].reg,
+				tx_macro_reg_init[i].mask,
+				tx_macro_reg_init[i].val);
+
 	return 0;
 }
 
@@ -2129,6 +2348,7 @@
 	ops->reg_wake_irq = tx_macro_reg_wake_irq;
 	ops->set_port_map = tx_macro_set_port_map;
 	ops->clk_switch = tx_macro_clk_switch;
+	ops->reg_evt_listener = tx_macro_register_event_listener;
 }
 
 static int tx_macro_probe(struct platform_device *pdev)
@@ -2208,6 +2428,7 @@
 	tx_priv->swr_plat_data.write = NULL;
 	tx_priv->swr_plat_data.bulk_write = NULL;
 	tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
+	tx_priv->swr_plat_data.core_vote = tx_macro_core_vote;
 	tx_priv->swr_plat_data.handle_irq = NULL;
 
 	mutex_init(&tx_priv->mclk_lock);
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index 4c16319..b7d6fe0 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -124,6 +124,7 @@
 	int micb_users;
 	u16 default_clk_id;
 	u16 clk_id;
+	int tx_clk_status;
 };
 
 static bool va_macro_get_data(struct snd_soc_component *component,
@@ -294,8 +295,10 @@
 			if (bolero_tx_clk_switch(component))
 				dev_dbg(va_dev, "%s: clock switch failed\n",
 					__func__);
+		bolero_register_event_listener(component, true);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		bolero_register_event_listener(component, false);
 		if (bolero_tx_clk_switch(component))
 			dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
 		if (va_priv->lpass_audio_hw_vote)
@@ -328,14 +331,19 @@
 						   va_priv->default_clk_id,
 						   TX_CORE_CLK,
 						   true);
+		if (!ret)
+			va_priv->tx_clk_status++;
 		ret = va_macro_mclk_enable(va_priv, 1, true);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		va_macro_mclk_enable(va_priv, 0, true);
-		bolero_clk_rsc_request_clock(va_priv->dev,
+		if (va_priv->tx_clk_status > 0) {
+			bolero_clk_rsc_request_clock(va_priv->dev,
 					   va_priv->default_clk_id,
 					   TX_CORE_CLK,
 					   false);
+			va_priv->tx_clk_status--;
+		}
 		break;
 	default:
 		dev_err(va_priv->dev,
@@ -767,16 +775,21 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		ret = bolero_clk_rsc_request_clock(va_priv->dev,
+		if (va_priv->tx_clk_status > 0) {
+			ret = bolero_clk_rsc_request_clock(va_priv->dev,
 						   va_priv->default_clk_id,
 						   TX_CORE_CLK,
 						   false);
+			va_priv->tx_clk_status--;
+		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		ret = bolero_clk_rsc_request_clock(va_priv->dev,
 						   va_priv->default_clk_id,
 						   TX_CORE_CLK,
 						   true);
+		if (!ret)
+			va_priv->tx_clk_status++;
 		break;
 	default:
 		dev_err(va_priv->dev,
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 39f331b..dfca968 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -160,6 +160,7 @@
 	int (*write)(void *handle, int reg, int val);
 	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
 	int (*clk)(void *handle, bool enable);
+	int (*core_vote)(void *handle, bool enable);
 	int (*handle_irq)(void *handle,
 			  irqreturn_t (*swrm_irq_handler)(int irq,
 							  void *data),
@@ -868,6 +869,7 @@
 			}
 		}
 	}
+	bolero_wsa_pa_on(wsa_dev);
 		break;
 	default:
 		break;
@@ -1442,14 +1444,22 @@
 	struct snd_soc_component *component =
 				snd_soc_dapm_to_component(w->dapm);
 	u16 reg = 0;
+	struct device *wsa_dev = NULL;
+	struct wsa_macro_priv *wsa_priv = NULL;
+
+	if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
+		return -EINVAL;
+
 
 	reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL +
 			WSA_MACRO_RX_PATH_OFFSET * w->shift;
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		if (wsa_macro_adie_lb(component, w->shift))
+		if (wsa_macro_adie_lb(component, w->shift)) {
 			snd_soc_component_update_bits(component,
 						reg, 0x20, 0x20);
+			bolero_wsa_pa_on(wsa_dev);
+		}
 		break;
 	default:
 		break;
@@ -2789,6 +2799,24 @@
 	wsa_macro_init_bcl_pmic_reg(component);
 }
 
+static int wsa_macro_core_vote(void *handle, bool enable)
+{
+	struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
+	int ret = 0;
+
+	if (wsa_priv == NULL) {
+		pr_err("%s: wsa priv data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (enable) {
+		pm_runtime_get_sync(wsa_priv->dev);
+		pm_runtime_put_autosuspend(wsa_priv->dev);
+		pm_runtime_mark_last_busy(wsa_priv->dev);
+	}
+
+	return ret;
+}
+
 static int wsa_swrm_clock(void *handle, bool enable)
 {
 	struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
@@ -2807,8 +2835,16 @@
 	if (enable) {
 		pm_runtime_get_sync(wsa_priv->dev);
 		if (wsa_priv->swr_clk_users == 0) {
-			msm_cdc_pinctrl_select_active_state(
+			ret = msm_cdc_pinctrl_select_active_state(
 						wsa_priv->wsa_swr_gpio_p);
+			if (ret < 0) {
+				dev_err_ratelimited(wsa_priv->dev,
+					"%s: wsa swr pinctrl enable failed\n",
+					__func__);
+				pm_runtime_mark_last_busy(wsa_priv->dev);
+				pm_runtime_put_autosuspend(wsa_priv->dev);
+				goto exit;
+			}
 			ret = wsa_macro_mclk_enable(wsa_priv, 1, true);
 			if (ret < 0) {
 				msm_cdc_pinctrl_select_sleep_state(
@@ -2816,6 +2852,8 @@
 				dev_err_ratelimited(wsa_priv->dev,
 					"%s: wsa request clock enable failed\n",
 					__func__);
+				pm_runtime_mark_last_busy(wsa_priv->dev);
+				pm_runtime_put_autosuspend(wsa_priv->dev);
 				goto exit;
 			}
 			if (wsa_priv->reset_swr)
@@ -2831,9 +2869,9 @@
 					0x02, 0x00);
 			wsa_priv->reset_swr = false;
 		}
+		wsa_priv->swr_clk_users++;
 		pm_runtime_mark_last_busy(wsa_priv->dev);
 		pm_runtime_put_autosuspend(wsa_priv->dev);
-		wsa_priv->swr_clk_users++;
 	} else {
 		if (wsa_priv->swr_clk_users <= 0) {
 			dev_err(wsa_priv->dev, "%s: clock already disabled\n",
@@ -2847,8 +2885,14 @@
 				BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
 				0x01, 0x00);
 			wsa_macro_mclk_enable(wsa_priv, 0, true);
-			msm_cdc_pinctrl_select_sleep_state(
+			ret = msm_cdc_pinctrl_select_sleep_state(
 						wsa_priv->wsa_swr_gpio_p);
+			if (ret < 0) {
+				dev_err_ratelimited(wsa_priv->dev,
+					"%s: wsa swr pinctrl disable failed\n",
+					__func__);
+				goto exit;
+			}
 		}
 	}
 	dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n",
@@ -3115,6 +3159,7 @@
 	wsa_priv->swr_plat_data.write = NULL;
 	wsa_priv->swr_plat_data.bulk_write = NULL;
 	wsa_priv->swr_plat_data.clk = wsa_swrm_clock;
+	wsa_priv->swr_plat_data.core_vote = wsa_macro_core_vote;
 	wsa_priv->swr_plat_data.handle_irq = NULL;
 
 	ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
diff --git a/asoc/codecs/ep92/ep92.c b/asoc/codecs/ep92/ep92.c
index 06d29ff..6077070 100644
--- a/asoc/codecs/ep92/ep92.c
+++ b/asoc/codecs/ep92/ep92.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -25,6 +25,7 @@
 
 #define EP92_POLL_INTERVAL_OFF_MSEC 200
 #define EP92_POLL_INTERVAL_ON_MSEC  20
+#define EP92_POLL_RUNOUT_MSEC       5000
 #define EP92_SYSFS_ENTRY_MAX_LEN 64
 #define EP92_HYST_CNT 5
 
@@ -68,6 +69,9 @@
 	struct timer_list    timer;
 	struct work_struct   read_status_worker;
 	int                  irq;
+	int                  poll_trig;
+	int                  poll_rem;
+	int                  force_inactive;
 
 	int                  hyst_tx_plug;
 	int                  hyst_link_on0;
@@ -560,15 +564,23 @@
 		send_uevent = true;
 	}
 
+	old = ep92->ai.cs[0];
+	ep92->ai.cs[0] = snd_soc_component_read32(component,
+		EP92_AUDIO_INFO_CHANNEL_STATUS_0);
+	if (ep92->ai.cs[0] == 0xff) {
+		dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_CHANNEL_STATUS_0 read 0xff\n");
+		ep92->ai.cs[0] = old;
+	}
+	change = ep92->ai.cs[0] ^ old;
+	if (change & EP92_AI_PREEMPH_MASK) {
+		dev_dbg(component->dev, "ep92 preemph changed to %d\n",
+			(ep92->ai.cs[0] & EP92_AI_PREEMPH_MASK) >>
+			EP92_AI_PREEMPH_SHIFT);
+		send_uevent = true;
+	}
+
 	new_mode = ep92->old_mode;
 	if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) {
-		old = ep92->ai.cs[0];
-		ep92->ai.cs[0] = snd_soc_component_read32(component,
-			EP92_AUDIO_INFO_CHANNEL_STATUS_0);
-		if (ep92->ai.cs[0] == 0xff) {
-			dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_CHANNEL_STATUS_0 read 0xff\n");
-			ep92->ai.cs[0] = old;
-		}
 		if (ep92->ai.cs[0] & EP92_AI_NPCM_MASK)
 			new_mode = 1; /* Compr */
 		else
@@ -648,10 +660,8 @@
 	ep92_init(component, ep92);
 
 	/* start polling when codec is registered */
-	if (ep92->irq == 0) {
-		mod_timer(&ep92->timer, jiffies +
-			msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
-	}
+	mod_timer(&ep92->timer, jiffies +
+		msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
 
 	return 0;
 }
@@ -690,6 +700,9 @@
 	if (component == NULL)
 		return;
 
+	if (ep92->force_inactive)
+		return;
+
 	/* check ADO_CHF that is set when audio format has changed */
 	val = snd_soc_component_read32(component, EP92_BI_GENERAL_INFO_1);
 	if (val == 0xff) {
@@ -724,6 +737,10 @@
 
 	dev_dbg(component->dev, "ep92_interrupt\n");
 
+	ep92->poll_trig = 1;
+	mod_timer(&ep92->timer, jiffies +
+		msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+
 	schedule_work(&ep92->read_status_worker);
 
 	return IRQ_HANDLED;
@@ -732,14 +749,45 @@
 void ep92_poll_status(struct timer_list *t)
 {
 	struct ep92_pdata *ep92 = from_timer(ep92, t, timer);
-	u32 poll_msec;
+	struct snd_soc_component *component = ep92->component;
 
-	if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0)
-		poll_msec = EP92_POLL_INTERVAL_OFF_MSEC;
-	else
-		poll_msec = EP92_POLL_INTERVAL_ON_MSEC;
+	if (ep92->force_inactive)
+		return;
 
-	mod_timer(&ep92->timer, jiffies + msecs_to_jiffies(poll_msec));
+	/* if no IRQ is configured, always keep on polling */
+	if (ep92->irq == 0)
+		ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
+
+	/* on interrupt, start polling for some time */
+	if (ep92->poll_trig) {
+		if (ep92->poll_rem == 0)
+			dev_info(component->dev, "status checking activated\n");
+
+		ep92->poll_trig = 0;
+		ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
+	}
+
+	/*
+	 * If power_on == 0, poll only until poll_rem reaches zero and stop.
+	 * This allows to system to go to low power sleep mode.
+	 * Otherwise (power_on == 1) always re-arm timer to keep on polling.
+	 */
+	if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0) {
+		if (ep92->poll_rem) {
+			mod_timer(&ep92->timer, jiffies +
+				msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
+			if (ep92->poll_rem > EP92_POLL_INTERVAL_OFF_MSEC) {
+				ep92->poll_rem -= EP92_POLL_INTERVAL_OFF_MSEC;
+			} else {
+				dev_info(component->dev, "status checking stopped\n");
+				ep92->poll_rem = 0;
+			}
+		}
+	} else {
+		ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
+		mod_timer(&ep92->timer, jiffies +
+			msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+	}
 
 	schedule_work(&ep92->read_status_worker);
 }
@@ -933,7 +981,7 @@
 	return ret;
 }
 
-static ssize_t ep92_sysfs_rda_avmute(struct device *dev,
+static ssize_t ep92_sysfs_rda_audio_preemph(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	ssize_t ret;
@@ -945,6 +993,26 @@
 		return -ENODEV;
 	}
 
+	val = (ep92->ai.cs[0] & EP92_AI_PREEMPH_MASK) >>
+		EP92_AI_PREEMPH_SHIFT;
+
+	ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+	dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+	return ret;
+}
+
+static ssize_t ep92_sysfs_rda_avmute(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	int val;
+	struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+	if (!ep92 || !ep92->component) {
+		dev_err(dev, "%s: device error\n", __func__);
+		return -ENODEV;
+	}
 
 	val = (ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) &
 		EP92_2CHOICE_MASK;
@@ -1162,6 +1230,11 @@
 	ep92->gc.ctl &= ~EP92_GC_POWER_MASK;
 	ep92->gc.ctl |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK;
 
+	if (val == 1) {
+		ep92->poll_trig = 1;
+		mod_timer(&ep92->timer, jiffies +
+			msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+	}
 	rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
 end:
 	return rc;
@@ -1321,12 +1394,12 @@
 	}
 
 	reg = snd_soc_component_read32(ep92->component, EP92_GENERAL_CONTROL_0);
-	reg &= ~EP92_GC_AUDIO_PATH_MASK;
-	reg |= (val << EP92_GC_AUDIO_PATH_SHIFT) & EP92_GC_AUDIO_PATH_MASK;
+	reg &= ~EP92_GC_ARC_EN_MASK;
+	reg |= (val << EP92_GC_ARC_EN_SHIFT) & EP92_GC_ARC_EN_MASK;
 	snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg);
-	ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK;
-	ep92->gc.ctl |= (val << EP92_GC_AUDIO_PATH_SHIFT) &
-		EP92_GC_AUDIO_PATH_MASK;
+	ep92->gc.ctl &= ~EP92_GC_ARC_EN_MASK;
+	ep92->gc.ctl |= (val << EP92_GC_ARC_EN_SHIFT) &
+		EP92_GC_ARC_EN_MASK;
 
 	rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
 end:
@@ -1440,6 +1513,83 @@
 	return rc;
 }
 
+static ssize_t ep92_sysfs_rda_runout(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	int val;
+	struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+	if (!ep92 || !ep92->component) {
+		dev_err(dev, "%s: device error\n", __func__);
+		return -ENODEV;
+	}
+
+	val = ep92->poll_rem;
+
+	ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+	dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+	return ret;
+}
+
+static ssize_t ep92_sysfs_rda_force_inactive(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	int val;
+	struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+	if (!ep92 || !ep92->component) {
+		dev_err(dev, "%s: device error\n", __func__);
+		return -ENODEV;
+	}
+
+	val = ep92->force_inactive;
+
+	ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+	dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+	return ret;
+}
+
+static ssize_t ep92_sysfs_wta_force_inactive(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int val, rc;
+	struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+	if (!ep92 || !ep92->component) {
+		dev_err(dev, "%s: device error\n", __func__);
+		return -ENODEV;
+	}
+
+	rc = kstrtoint(buf, 10, &val);
+	if (rc) {
+		dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		goto end;
+	}
+	if ((val < 0) || (val > 1)) {
+		dev_err(dev, "%s: value out of range.\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (val == 0) {
+		ep92->force_inactive = 0;
+		ep92->poll_trig = 1;
+		mod_timer(&ep92->timer, jiffies +
+			msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
+	} else {
+		ep92->force_inactive = 1;
+		ep92->poll_rem = 0;
+	}
+
+	rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
+end:
+	return rc;
+}
+
 static DEVICE_ATTR(chipid, 0444, ep92_sysfs_rda_chipid, NULL);
 static DEVICE_ATTR(version, 0444, ep92_sysfs_rda_version, NULL);
 static DEVICE_ATTR(audio_state, 0444, ep92_sysfs_rda_audio_state, NULL);
@@ -1448,6 +1598,7 @@
 static DEVICE_ATTR(audio_layout, 0444, ep92_sysfs_rda_audio_layout, NULL);
 static DEVICE_ATTR(audio_ch_count, 0444, ep92_sysfs_rda_audio_ch_count, NULL);
 static DEVICE_ATTR(audio_ch_alloc, 0444, ep92_sysfs_rda_audio_ch_alloc, NULL);
+static DEVICE_ATTR(audio_preemph, 0444, ep92_sysfs_rda_audio_preemph, NULL);
 static DEVICE_ATTR(audio_avmute, 0444, ep92_sysfs_rda_avmute, NULL);
 static DEVICE_ATTR(link_on0, 0444, ep92_sysfs_rda_link_on0, NULL);
 static DEVICE_ATTR(link_on1, 0444, ep92_sysfs_rda_link_on1, NULL);
@@ -1467,6 +1618,9 @@
 	ep92_sysfs_wta_cec_mute);
 static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume,
 	ep92_sysfs_wta_cec_volume);
+static DEVICE_ATTR(runout, 0444, ep92_sysfs_rda_runout, NULL);
+static DEVICE_ATTR(force_inactive, 0644, ep92_sysfs_rda_force_inactive,
+	ep92_sysfs_wta_force_inactive);
 
 static struct attribute *ep92_fs_attrs[] = {
 	&dev_attr_chipid.attr,
@@ -1477,6 +1631,7 @@
 	&dev_attr_audio_layout.attr,
 	&dev_attr_audio_ch_count.attr,
 	&dev_attr_audio_ch_alloc.attr,
+	&dev_attr_audio_preemph.attr,
 	&dev_attr_audio_avmute.attr,
 	&dev_attr_link_on0.attr,
 	&dev_attr_link_on1.attr,
@@ -1490,6 +1645,8 @@
 	&dev_attr_arc_enable.attr,
 	&dev_attr_cec_mute.attr,
 	&dev_attr_cec_volume.attr,
+	&dev_attr_runout.attr,
+	&dev_attr_force_inactive.attr,
 	NULL,
 };
 
@@ -1552,9 +1709,9 @@
 			ep92->irq = 0;
 		}
 	}
-	/* poll status if IRQ is not configured */
-	if (ep92->irq == 0)
-		timer_setup(&ep92->timer, ep92_poll_status, 0);
+	/* prepare timer */
+	timer_setup(&ep92->timer, ep92_poll_status, 0);
+	ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
 
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 	/* debugfs interface */
@@ -1610,8 +1767,7 @@
 err_sysfs:
 	snd_soc_unregister_component(&client->dev);
 err_reg:
-	if (ep92->irq == 0)
-		del_timer(&ep92->timer);
+	del_timer(&ep92->timer);
 
 	return ret;
 }
@@ -1622,8 +1778,7 @@
 
 	ep92 = i2c_get_clientdata(client);
 	if (ep92) {
-		if (ep92->irq == 0)
-			del_timer(&ep92->timer);
+		del_timer(&ep92->timer);
 
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 		debugfs_remove_recursive(ep92->debugfs_dir);
diff --git a/asoc/codecs/ep92/ep92.h b/asoc/codecs/ep92/ep92.h
index bfc8d80..18cb010 100644
--- a/asoc/codecs/ep92/ep92.h
+++ b/asoc/codecs/ep92/ep92.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __EP92_H__
@@ -171,6 +171,8 @@
 #define EP92_AI_STD_ADO_MASK     0x08
 #define EP92_AI_RATE_MASK        0x07
 #define EP92_AI_NPCM_MASK        0x02
+#define EP92_AI_PREEMPH_SHIFT    3
+#define EP92_AI_PREEMPH_MASK     0x38
 #define EP92_AI_CH_COUNT_MASK    0x07
 #define EP92_AI_CH_ALLOC_MASK    0xff
 
diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c
index c611345..a10a681 100644
--- a/asoc/codecs/msm-cdc-pinctrl.c
+++ b/asoc/codecs/msm-cdc-pinctrl.c
@@ -14,13 +14,16 @@
 #include <linux/pinctrl/qcom-pinctrl.h>
 #include <asoc/msm-cdc-pinctrl.h>
 
+#define MAX_GPIOS 16
+
 struct msm_cdc_pinctrl_info {
 	struct pinctrl *pinctrl;
 	struct pinctrl_state *pinctrl_active;
 	struct pinctrl_state *pinctrl_sleep;
 	int gpio;
 	bool state;
-	u32 tlmm_gpio;
+	u32 tlmm_gpio[MAX_GPIOS];
+	u32 count;
 	bool wakeup_capable;
 };
 
@@ -151,14 +154,21 @@
 {
 	struct msm_cdc_pinctrl_info *gpio_data;
 	int ret = 0;
+	u32 i = 0;
 
 	gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
 	if (!gpio_data)
 		return -EINVAL;
 
-	if (gpio_data->wakeup_capable)
-		ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio, enable);
-
+	if (gpio_data->wakeup_capable) {
+		for (i = 0; i < gpio_data->count; i++) {
+			ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio[i],
+						    enable);
+			if (ret < 0)
+				goto exit;
+		}
+	}
+exit:
 	return ret;
 }
 EXPORT_SYMBOL(msm_cdc_pinctrl_set_wakeup_capable);
@@ -167,7 +177,9 @@
 {
 	int ret = 0;
 	struct msm_cdc_pinctrl_info *gpio_data;
-	u32 tlmm_gpio = 0;
+	u32 tlmm_gpio[MAX_GPIOS] = {0};
+	u32 i = 0;
+	int count = 0;
 
 	gpio_data = devm_kzalloc(&pdev->dev,
 				 sizeof(struct msm_cdc_pinctrl_info),
@@ -210,12 +222,19 @@
 				__func__, ret);
 	}
 
-	if (!of_property_read_u32(pdev->dev.of_node, "qcom,tlmm-gpio",
-				&tlmm_gpio)) {
+
+	count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-gpio");
+	if (count <= 0)
+		goto cdc_rst;
+	if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,tlmm-gpio",
+				tlmm_gpio, count)) {
 		gpio_data->wakeup_capable = true;
-		gpio_data->tlmm_gpio = tlmm_gpio;
+		for (i = 0; i < count; i++)
+			gpio_data->tlmm_gpio[i] = tlmm_gpio[i];
+		gpio_data->count = count;
 	}
 
+cdc_rst:
 	gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
 					    "qcom,cdc-rst-n-gpio", 0);
 	if (gpio_is_valid(gpio_data->gpio)) {
diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c
index 8d2507e..5144b92 100644
--- a/asoc/codecs/msm_hdmi_codec_rx.c
+++ b/asoc/codecs/msm_hdmi_codec_rx.c
@@ -100,7 +100,7 @@
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 		uinfo->count = 0;
 		mutex_unlock(&codec_data->dp_ops_lock);
-		return -EINVAL;
+		return 0;
 	}
 
 	rc = codec_data->ext_disp_ops.get_audio_edid_blk(
diff --git a/asoc/codecs/wcd-irq.c b/asoc/codecs/wcd-irq.c
index 3c8e777..d4890a6 100644
--- a/asoc/codecs/wcd-irq.c
+++ b/asoc/codecs/wcd-irq.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/kernel.h>
@@ -178,7 +178,8 @@
 		return -EINVAL;
 	}
 
-	regmap_del_irq_chip(irq_find_mapping(virq, 0), irq_info->irq_chip);
+	devm_regmap_del_irq_chip(irq_info->dev, irq_find_mapping(virq, 0),
+				 irq_info->irq_chip);
 
 	return 0;
 }
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 624b59a..01544aa 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -691,10 +691,8 @@
 					&mbhc->zl, &mbhc->zr);
 			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN,
 						 fsm_en);
-			if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
-				mbhc->zl < MAX_IMPED) &&
-				(mbhc->zr > mbhc->mbhc_cfg->linein_th &&
-				 mbhc->zr < MAX_IMPED) &&
+			if ((mbhc->zl > mbhc->mbhc_cfg->linein_th) &&
+				(mbhc->zr > mbhc->mbhc_cfg->linein_th) &&
 				(jack_type == SND_JACK_HEADPHONE)) {
 				jack_type = SND_JACK_LINEOUT;
 				mbhc->force_linein = true;
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index fe0c65c..7a618c5 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -1349,13 +1349,17 @@
 		snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH2, 0x40, 0x40);
 		snd_soc_component_update_bits(component,
-				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x30, 0x30);
+				WCD937X_ANA_TX_CH3_HPF, 0x40, 0x40);
+		snd_soc_component_update_bits(component,
+				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70);
 		snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH1, 0x80, 0x80);
 		snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH2, 0x40, 0x00);
 		snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH2, 0x80, 0x80);
+		snd_soc_component_update_bits(component,
+				WCD937X_ANA_TX_CH3, 0x80, 0x80);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_component_update_bits(component,
@@ -1363,6 +1367,8 @@
 		snd_soc_component_update_bits(component,
 				WCD937X_ANA_TX_CH2, 0x80, 0x00);
 		snd_soc_component_update_bits(component,
+				WCD937X_ANA_TX_CH3, 0x80, 0x00);
+		snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00);
 		mutex_lock(&wcd937x->ana_tx_clk_lock);
 		wcd937x->ana_clk_count--;
@@ -2316,7 +2322,8 @@
 						   "variant",
 						   priv->entry);
 	if (!variant_entry) {
-		dev_dbg(codec->dev, "%s: failed to create wcd937x variant entry\n",
+		dev_dbg(component->dev,
+			"%s: failed to create wcd937x variant entry\n",
 			__func__);
 		return -ENOMEM;
 	}
diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h
index 2c67ff8..098a60d 100644
--- a/asoc/codecs/wcd938x/internal.h
+++ b/asoc/codecs/wcd938x/internal.h
@@ -11,6 +11,8 @@
 #include <asoc/wcd-clsh.h>
 #include "wcd938x-mbhc.h"
 
+#define SWR_SCP_CONTROL    0x44
+#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0
 #define WCD938X_MAX_MICBIAS 4
 
 /* Convert from vout ctl to micbias voltage in mV */
@@ -97,6 +99,7 @@
 	struct snd_info_entry *variant_entry;
 	int flyback_cur_det_disable;
 	int ear_rx_path;
+	bool dev_up;
 };
 
 struct wcd938x_micbias_setting {
diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c
index ec42b0d..d56cebb 100644
--- a/asoc/codecs/wcd938x/wcd938x-slave.c
+++ b/asoc/codecs/wcd938x/wcd938x-slave.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -11,10 +11,267 @@
 #include <linux/component.h>
 #include <soc/soundwire.h>
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_SLV_MAX_REG_ADDR    0x2009
+#define SWR_SLV_START_REG_ADDR  0x40
+#define SWR_SLV_MAX_BUF_LEN     20
+#define BYTES_PER_LINE          12
+#define SWR_SLV_RD_BUF_LEN      8
+#define SWR_SLV_WR_BUF_LEN      32
+#define SWR_SLV_MAX_DEVICES     2
+#endif /* CONFIG_DEBUG_FS */
+
 struct wcd938x_slave_priv {
 	struct swr_device *swr_slave;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_wcd938x_dent;
+	struct dentry *debugfs_peek;
+	struct dentry *debugfs_poke;
+	struct dentry *debugfs_reg_dump;
+	unsigned int read_data;
+#endif
 };
 
+#ifdef CONFIG_DEBUG_FS
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+	char *token = NULL;
+	int base = 0, cnt = 0;
+
+	token = strsep(&buf, " ");
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (kstrtou32(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else {
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static bool is_swr_slv_reg_readable(int reg)
+{
+	int ret = true;
+
+	if (((reg > 0x46) && (reg < 0x4A)) ||
+	    ((reg > 0x4A) && (reg < 0x50)) ||
+	    ((reg > 0x55) && (reg < 0xD0)) ||
+	    ((reg > 0xD0) && (reg < 0xE0)) ||
+	    ((reg > 0xE0) && (reg < 0xF0)) ||
+	    ((reg > 0xF0) && (reg < 0x100)) ||
+	    ((reg > 0x105) && (reg < 0x120)) ||
+	    ((reg > 0x205) && (reg < 0x220)) ||
+	    ((reg > 0x305) && (reg < 0x320)) ||
+	    ((reg > 0x405) && (reg < 0x420)) ||
+	    ((reg > 0x128) && (reg < 0x130)) ||
+	    ((reg > 0x228) && (reg < 0x230)) ||
+	    ((reg > 0x328) && (reg < 0x330)) ||
+	    ((reg > 0x428) && (reg < 0x430)) ||
+	    ((reg > 0x138) && (reg < 0x205)) ||
+	    ((reg > 0x238) && (reg < 0x305)) ||
+	    ((reg > 0x338) && (reg < 0x405)) ||
+	    ((reg > 0x405) && (reg < 0xF00)) ||
+	    ((reg > 0xF05) && (reg < 0xF20)) ||
+	    ((reg > 0xF25) && (reg < 0xF30)) ||
+	    ((reg > 0xF35) && (reg < 0x2000)))
+		ret = false;
+
+	return ret;
+}
+
+static ssize_t wcd938x_swrslave_reg_show(struct swr_device *pdev,
+					char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	int i, reg_val, len;
+	ssize_t total = 0;
+	char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+	if (!ubuf || !ppos)
+		return 0;
+
+	for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+		i <= SWR_SLV_MAX_REG_ADDR; i++) {
+		if (!is_swr_slv_reg_readable(i))
+			continue;
+		swr_read(pdev, pdev->dev_num, i, &reg_val, 1);
+		len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
+			       (reg_val & 0xFF));
+		if ((total + len) >= count - 1)
+			break;
+		if (copy_to_user((ubuf + total), tmp_buf, len)) {
+			pr_err("%s: fail to copy reg dump\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		total += len;
+		*ppos += len;
+	}
+
+copy_err:
+	*ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
+	return total;
+}
+
+static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct swr_device *pdev;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	return wcd938x_swrslave_reg_show(pdev, ubuf, count, ppos);
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_RD_BUF_LEN];
+	struct swr_device *pdev = NULL;
+	struct wcd938x_slave_priv *wcd938x_slave = NULL;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	wcd938x_slave = swr_get_dev_data(pdev);
+	if (!wcd938x_slave)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	snprintf(lbuf, sizeof(lbuf), "0x%x\n",
+			(wcd938x_slave->read_data & 0xFF));
+
+	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+					       strnlen(lbuf, 7));
+}
+
+static ssize_t codec_debug_peek_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc = 0;
+	u32 param[5];
+	struct swr_device *pdev = NULL;
+	struct wcd938x_slave_priv *wcd938x_slave = NULL;
+
+	if (!cnt || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	wcd938x_slave = swr_get_dev_data(pdev);
+	if (!wcd938x_slave)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	rc = get_parameters(lbuf, param, 1);
+	if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
+		return -EINVAL;
+	swr_read(pdev, pdev->dev_num, param[0], &wcd938x_slave->read_data, 1);
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static ssize_t codec_debug_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc = 0;
+	u32 param[5];
+	struct swr_device *pdev;
+
+	if (!file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	rc = get_parameters(lbuf, param, 2);
+	if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
+		(param[1] <= 0xFF) && (rc == 0)))
+		return -EINVAL;
+	swr_write(pdev, pdev->dev_num, param[0], &param[1]);
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_write_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+};
+
+static const struct file_operations codec_debug_read_ops = {
+	.open = codec_debug_open,
+	.read = codec_debug_read,
+	.write = codec_debug_peek_write,
+};
+
+static const struct file_operations codec_debug_dump_ops = {
+	.open = codec_debug_open,
+	.read = codec_debug_dump,
+};
+#endif
+
 static int wcd938x_slave_bind(struct device *dev,
 				struct device *master, void *data)
 {
@@ -82,11 +339,49 @@
 
 	wcd938x_slave->swr_slave = pdev;
 
+#ifdef CONFIG_DEBUG_FS
+	if (!wcd938x_slave->debugfs_wcd938x_dent) {
+		wcd938x_slave->debugfs_wcd938x_dent = debugfs_create_dir(
+						dev_name(&pdev->dev), 0);
+		if (!IS_ERR(wcd938x_slave->debugfs_wcd938x_dent)) {
+			wcd938x_slave->debugfs_peek =
+					debugfs_create_file("swrslave_peek",
+					S_IFREG | 0444,
+					wcd938x_slave->debugfs_wcd938x_dent,
+					(void *) pdev,
+					&codec_debug_read_ops);
+
+			wcd938x_slave->debugfs_poke =
+					debugfs_create_file("swrslave_poke",
+					S_IFREG | 0444,
+					wcd938x_slave->debugfs_wcd938x_dent,
+					(void *) pdev,
+					&codec_debug_write_ops);
+
+			wcd938x_slave->debugfs_reg_dump =
+					debugfs_create_file(
+					"swrslave_reg_dump",
+					S_IFREG | 0444,
+					wcd938x_slave->debugfs_wcd938x_dent,
+					(void *) pdev,
+					&codec_debug_dump_ops);
+                }
+        }
+#endif
+
 	return component_add(&pdev->dev, &wcd938x_slave_comp_ops);
 }
 
 static int wcd938x_swr_remove(struct swr_device *pdev)
 {
+#ifdef CONFIG_DEBUG_FS
+	struct wcd938x_slave_priv *wcd938x_slave = swr_get_dev_data(pdev);
+
+	if (wcd938x_slave) {
+		debugfs_remove_recursive(wcd938x_slave->debugfs_wcd938x_dent);
+		wcd938x_slave->debugfs_wcd938x_dent = NULL;
+	}
+#endif
 	component_del(&pdev->dev, &wcd938x_slave_comp_ops);
 	swr_set_dev_data(pdev, NULL);
 	swr_remove_device(pdev);
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index f89a2aa..2980c37 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -25,6 +25,7 @@
 #include "wcd938x-registers.h"
 #include "wcd938x.h"
 
+
 #define WCD938X_DRV_NAME "wcd938x_codec"
 #define NUM_SWRS_DT_PARAMS 5
 #define WCD938X_VARIANT_ENTRY_SIZE 32
@@ -126,6 +127,45 @@
 	return IRQ_HANDLED;
 }
 
+static int wcd938x_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum)
+{
+	int ret = 0;
+	int bank = 0;
+
+	ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1);
+	if (ret)
+		return -EINVAL;
+
+	return ((bank & 0x40) ? 1: 0);
+}
+
+static int wcd938x_swr_slv_set_host_clk_div2(struct swr_device *dev,
+						u8 devnum, int bank)
+{
+	u8 val = (bank ? 1 : 0);
+
+	return (swr_write(dev, devnum,
+		(SWR_SCP_HOST_CLK_DIV2_CTL_BANK + (0x10 * bank)), &val));
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component,
+					int mode, int bank)
+{
+	u8 mask = (bank ? 0xF0 : 0x0F);
+	u8 val = 0;
+
+	if ((mode == ADC_MODE_ULP1) || (mode == ADC_MODE_ULP2))
+		val = (bank ? 0x60 : 0x06);
+	else
+		val = 0x00;
+
+	snd_soc_component_update_bits(component,
+				      WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+				      mask, val);
+
+	return 0;
+}
+
 static int wcd938x_init_reg(struct snd_soc_component *component)
 {
 	snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E, 0x0E);
@@ -181,6 +221,8 @@
 				WCD938X_MICB3_TEST_CTL_1, 0xE0, 0xE0);
 	snd_soc_component_update_bits(component,
 				WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0);
+	snd_soc_component_update_bits(component,
+				WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00);
 
 	return 0;
 }
@@ -548,12 +590,26 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		wcd938x_rx_clk_enable(component);
-		snd_soc_component_update_bits(component,
+		wcd938x->ear_rx_path =
+			snd_soc_component_read32(
+				component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL);
+		if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+			snd_soc_component_update_bits(component,
+				WCD938X_EAR_EAR_DAC_CON, 0x80, 0x00);
+			snd_soc_component_update_bits(component,
+				WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x01);
+			snd_soc_component_update_bits(component,
+				WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x04);
+			snd_soc_component_update_bits(component,
+				WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80);
+		} else {
+			snd_soc_component_update_bits(component,
 				WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x04);
-		snd_soc_component_update_bits(component,
+			snd_soc_component_update_bits(component,
 				WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
-		snd_soc_component_update_bits(component,
+			snd_soc_component_update_bits(component,
 				WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x02);
+		}
 		/* 5 msec delay as per HW requirement */
 		usleep_range(5000, 5010);
 		if (wcd938x->flyback_cur_det_disable == 0)
@@ -567,6 +623,14 @@
 			     wcd938x->hph_mode);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+			snd_soc_component_update_bits(component,
+				WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x00);
+		}
+		snd_soc_component_update_bits(component,
+				WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00);
+		snd_soc_component_update_bits(component,
+				WCD938X_EAR_EAR_DAC_CON, 0x80, 0x80);
 		break;
 	};
 	return 0;
@@ -967,16 +1031,21 @@
 			snd_soc_component_update_bits(component,
 					WCD938X_ANA_RX_SUPPLIES,
 					0x02, 0x02);
-		if (wcd938x->update_wcd_event)
-			wcd938x->update_wcd_event(wcd938x->handle,
+		if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
+			if (wcd938x->update_wcd_event)
+				wcd938x->update_wcd_event(wcd938x->handle,
 						WCD_BOLERO_EVT_RX_MUTE,
-						(WCD_RX1 << 0x10));
-		if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
+						(WCD_RX3 << 0x10));
 			wcd_enable_irq(&wcd938x->irq_info,
 					WCD938X_IRQ_AUX_PDM_WD_INT);
-		else
+		} else {
+			if (wcd938x->update_wcd_event)
+				wcd938x->update_wcd_event(wcd938x->handle,
+						WCD_BOLERO_EVT_RX_MUTE,
+						(WCD_RX1 << 0x10));
 			wcd_enable_irq(&wcd938x->irq_info,
 					WCD938X_IRQ_HPHL_PDM_WD_INT);
+		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
@@ -1335,17 +1404,33 @@
 					snd_soc_dapm_to_component(w->dapm);
 	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 	int ret = 0;
+	int bank = 0;
+	int mode = 0;
 
+	bank = wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev,
+						wcd938x->tx_swr_dev->dev_num);
+	wcd938x_swr_slv_set_host_clk_div2(wcd938x->tx_swr_dev,
+					  wcd938x->tx_swr_dev->dev_num, bank);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
 		    wcd938x->tx_swr_dev->dev_num,
 		    true);
+		if (test_bit(WCD_ADC1, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC1];
+		if (test_bit(WCD_ADC2, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC2];
+		if (test_bit(WCD_ADC3, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC3];
+		if (test_bit(WCD_ADC4, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC4];
+		wcd938x_set_swr_clk_rate(component, mode, bank);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
 		    wcd938x->tx_swr_dev->dev_num,
 		    false);
+		wcd938x_set_swr_clk_rate(component, ADC_MODE_INVALID, bank);
 		break;
 	};
 
@@ -1565,6 +1650,7 @@
 	int pre_off_event = 0, post_off_event = 0;
 	int post_on_event = 0, post_dapm_off = 0;
 	int post_dapm_on = 0;
+	int ret = 0;
 
 	if ((micb_index < 0) || (micb_index > WCD938X_MAX_MICBIAS - 1)) {
 		dev_err(component->dev,
@@ -1606,6 +1692,12 @@
 
 	switch (req) {
 	case MICB_PULLUP_ENABLE:
+		if (!wcd938x->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		wcd938x->pullup_ref[micb_index]++;
 		if ((wcd938x->pullup_ref[micb_index] == 1) &&
 		    (wcd938x->micb_ref[micb_index] == 0))
@@ -1615,12 +1707,24 @@
 	case MICB_PULLUP_DISABLE:
 		if (wcd938x->pullup_ref[micb_index] > 0)
 			wcd938x->pullup_ref[micb_index]--;
+		if (!wcd938x->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		if ((wcd938x->pullup_ref[micb_index] == 0) &&
 		    (wcd938x->micb_ref[micb_index] == 0))
 			snd_soc_component_update_bits(component, micb_reg,
 							0xC0, 0x00);
 		break;
 	case MICB_ENABLE:
+		if (!wcd938x->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		wcd938x->micb_ref[micb_index]++;
 		if (wcd938x->micb_ref[micb_index] == 1) {
 			snd_soc_component_update_bits(component,
@@ -1653,6 +1757,12 @@
 	case MICB_DISABLE:
 		if (wcd938x->micb_ref[micb_index] > 0)
 			wcd938x->micb_ref[micb_index]--;
+		if (!wcd938x->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		if ((wcd938x->micb_ref[micb_index] == 0) &&
 		    (wcd938x->pullup_ref[micb_index] > 0))
 			snd_soc_component_update_bits(component, micb_reg,
@@ -1683,9 +1793,10 @@
 		"%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
 		__func__, micb_num, wcd938x->micb_ref[micb_index],
 		wcd938x->pullup_ref[micb_index]);
-	mutex_unlock(&wcd938x->micb_lock);
 
-	return 0;
+done:
+	mutex_unlock(&wcd938x->micb_lock);
+	return ret;
 }
 EXPORT_SYMBOL(wcd938x_micbias_control);
 
@@ -1748,6 +1859,7 @@
 					0x80, 0x00);
 		break;
 	case BOLERO_WCD_EVT_SSR_DOWN:
+		wcd938x->dev_up = false;
 		mbhc = &wcd938x->mbhc->wcd_mbhc;
 		wcd938x_mbhc_ssr_down(wcd938x->mbhc, component);
 		wcd938x_reset_low(wcd938x->dev);
@@ -1768,6 +1880,7 @@
 		} else {
 			wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg);
 		}
+		wcd938x->dev_up = true;
 		break;
 	case BOLERO_WCD_EVT_CLK_NOTIFY:
 		snd_soc_component_update_bits(component,
@@ -2779,6 +2892,40 @@
 }
 EXPORT_SYMBOL(wcd938x_info_create_codec_entry);
 
+static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x,
+			      struct wcd938x_pdata *pdata)
+{
+	int vout_ctl_1 = 0, vout_ctl_2 = 0, vout_ctl_3 = 0, vout_ctl_4 = 0;
+	int rc = 0;
+
+	if (!pdata) {
+		dev_err(wcd938x->dev, "%s: NULL pdata\n", __func__);
+		return -ENODEV;
+	}
+
+	/* set micbias voltage */
+	vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv);
+	vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv);
+	vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv);
+	vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv);
+	if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 ||
+	    vout_ctl_4 < 0) {
+		rc = -EINVAL;
+		goto done;
+	}
+	regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB1, 0x3F,
+			   vout_ctl_1);
+	regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB2, 0x3F,
+			   vout_ctl_2);
+	regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB3, 0x3F,
+			   vout_ctl_3);
+	regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB4, 0x3F,
+			   vout_ctl_4);
+
+done:
+	return rc;
+}
+
 static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
 {
 	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
@@ -2889,6 +3036,7 @@
 			return ret;
 		}
 	}
+	wcd938x->dev_up = true;
 	return ret;
 
 err_hwdep:
@@ -3026,6 +3174,19 @@
 		dev_info(dev, "%s: Micbias3 DT property not found\n",
 			__func__);
 	}
+
+	/* MB4 */
+	if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv",
+				    NULL)) {
+		rc = wcd938x_read_of_property_u32(dev,
+						  "qcom,cdc-micbias4-mv",
+						  &prop_val);
+		if (!rc)
+			mb->micb4_mv = prop_val;
+	} else {
+		dev_info(dev, "%s: Micbias4 DT property not found\n",
+			__func__);
+	}
 }
 
 static int wcd938x_reset_low(struct device *dev)
@@ -3164,6 +3325,12 @@
 	}
 	wcd938x->tx_swr_dev->slave_irq = wcd938x->virq;
 
+	ret = wcd938x_set_micbias_data(wcd938x, pdata);
+	if (ret < 0) {
+		dev_err(dev, "%s: bad micbias pdata\n", __func__);
+		goto err_irq;
+	}
+
 	/* Request for watchdog interrupt */
 	wcd_request_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT,
 			"HPHR PDM WD INT", wcd938x_wd_handle_irq, NULL);
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index 2871ad3..966fa8a 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
+#include <linux/of_platform.h>
 #include <linux/regmap.h>
 #include <linux/debugfs.h>
 #include <soc/soundwire.h>
@@ -101,6 +102,30 @@
 	struct delayed_work ocp_ctl_work;
 	struct device_node *wsa_rst_np;
 	int pa_mute;
+	struct device_node *bolero_np;
+	struct platform_device* bolero_dev;
+	struct notifier_block bolero_nblock;
+	void *handle;
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+/* from bolero to WSA events */
+enum {
+	BOLERO_WSA_EVT_TX_CH_HOLD_CLEAR = 1,
+	BOLERO_WSA_EVT_PA_OFF_PRE_SSR,
+	BOLERO_WSA_EVT_SSR_DOWN,
+	BOLERO_WSA_EVT_SSR_UP,
+	BOLERO_WSA_EVT_PA_ON_POST_FSCLK,
+};
+
+struct wsa_ctrl_platform_data {
+	void *handle;
+	int (*update_wsa_event)(void *handle, u16 event, u32 data);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
 };
 
 #define SWR_SLV_MAX_REG_ADDR	0x390
@@ -1006,6 +1031,10 @@
 
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+		if (!wsa881x->bolero_dev)
+			snd_soc_component_update_bits(component,
+					      WSA881X_SPKR_DRV_EN,
+					      0x80, 0x80);
 		if (!wsa881x->comp_enable) {
 			max_gain = wsa881x->pa_gain;
 			/*
@@ -1039,6 +1068,9 @@
 				      wsa881x->swr_slave->dev_num);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+					      WSA881X_SPKR_DRV_EN,
+					      0x80, 0x00);
 		if (wsa881x->visense_enable) {
 			wsa881x_visense_adc_ctrl(component, DISABLE);
 			wsa881x_visense_txfe_ctrl(component, DISABLE,
@@ -1064,7 +1096,7 @@
 		wsa881x_rdac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_PGA_E("SPKR PGA", WSA881X_SPKR_DRV_EN, 7, 0, NULL, 0,
+	SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
 			wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
 			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -1338,12 +1370,45 @@
 	return ret;
 }
 
+static int wsa881x_event_notify(struct notifier_block *nb,
+				unsigned long val, void *ptr)
+{
+	u16 event = (val & 0xffff);
+	struct wsa881x_priv *wsa881x = container_of(nb, struct wsa881x_priv,
+						    bolero_nblock);
+
+	if (!wsa881x)
+		return -EINVAL;
+
+	switch (event) {
+	case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
+		snd_soc_component_update_bits(wsa881x->component,
+					      WSA881X_SPKR_DRV_GAIN,
+					      0xF0, 0xC0);
+		snd_soc_component_update_bits(wsa881x->component,
+					      WSA881X_SPKR_DRV_EN,
+					      0x80, 0x00);
+		break;
+	case BOLERO_WSA_EVT_PA_ON_POST_FSCLK:
+		if ((snd_soc_component_read32(wsa881x->component,
+				WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80)
+			snd_soc_component_update_bits(wsa881x->component,
+					      WSA881X_SPKR_DRV_EN,
+					      0x80, 0x80);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int wsa881x_swr_probe(struct swr_device *pdev)
 {
 	int ret = 0;
 	struct wsa881x_priv *wsa881x;
 	u8 devnum = 0;
 	bool pin_state_current = false;
+	struct wsa_ctrl_platform_data *plat_data = NULL;
 
 	wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
 			    GFP_KERNEL);
@@ -1435,6 +1500,37 @@
 			__func__);
 		goto dev_err;
 	}
+
+	wsa881x->bolero_np = of_parse_phandle(pdev->dev.of_node,
+					      "qcom,bolero-handle", 0);
+	if (wsa881x->bolero_np) {
+		wsa881x->bolero_dev =
+				of_find_device_by_node(wsa881x->bolero_np);
+		if (wsa881x->bolero_dev) {
+			plat_data = dev_get_platdata(&wsa881x->bolero_dev->dev);
+			if (plat_data) {
+				wsa881x->bolero_nblock.notifier_call =
+							wsa881x_event_notify;
+				if (plat_data->register_notifier)
+					plat_data->register_notifier(
+						plat_data->handle,
+						&wsa881x->bolero_nblock,
+						true);
+				wsa881x->register_notifier =
+						plat_data->register_notifier;
+				wsa881x->handle = plat_data->handle;
+			} else {
+				dev_err(&pdev->dev, "%s: plat data not found\n",
+					__func__);
+			}
+		} else {
+			dev_err(&pdev->dev, "%s: bolero dev not found\n",
+				__func__);
+		}
+	} else {
+		dev_info(&pdev->dev, "%s: bolero node not found\n", __func__);
+	}
+
 	mutex_init(&wsa881x->res_lock);
 	mutex_init(&wsa881x->temp_lock);
 
@@ -1457,6 +1553,10 @@
 		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
 		return -EINVAL;
 	}
+
+	if (wsa881x->register_notifier)
+		wsa881x->register_notifier(wsa881x->handle,
+					   &wsa881x->bolero_nblock, false);
 	debugfs_remove_recursive(debugfs_wsa881x_dent);
 	debugfs_wsa881x_dent = NULL;
 	mutex_destroy(&wsa881x->res_lock);
diff --git a/asoc/kona-port-config.h b/asoc/kona-port-config.h
index 0f73791..723c94a 100644
--- a/asoc/kona-port-config.h
+++ b/asoc/kona-port-config.h
@@ -50,6 +50,15 @@
 	{3,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1},  /* TX4 */
 };
 
+/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */
+static struct port_params tx_frame_params_v2[SWR_MSTR_PORT_LEN] = {
+	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},/* PCM OUT */
+	{1,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1},  /* TX1 */
+	{1,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2},  /* TX2 */
+	{3,  2,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},  /* TX3 */
+	{3,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2},  /* TX4 */
+};
+
 static struct swr_mstr_port_map sm_port_map[] = {
 	{TX_MACRO, SWR_UC0, tx_frame_params_default},
 	{RX_MACRO, SWR_UC0, rx_frame_params_default},
@@ -57,4 +66,11 @@
 	{WSA_MACRO, SWR_UC0, wsa_frame_params_default},
 };
 
+static struct swr_mstr_port_map sm_port_map_v2[] = {
+	{TX_MACRO, SWR_UC0, tx_frame_params_v2},
+	{RX_MACRO, SWR_UC0, rx_frame_params_default},
+	{RX_MACRO, SWR_UC1, rx_frame_params_dsd},
+	{WSA_MACRO, SWR_UC0, wsa_frame_params_default},
+};
+
 #endif /* _KONA_PORT_CONFIG */
diff --git a/asoc/kona.c b/asoc/kona.c
index d91627b..c98de7a 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -76,6 +76,12 @@
 #define WCN_CDC_SLIM_TX_CH_MAX_LITO 3
 
 enum {
+	RX_PATH = 0,
+	TX_PATH,
+	MAX_PATH,
+};
+
+enum {
 	TDM_0 = 0,
 	TDM_1,
 	TDM_2,
@@ -87,6 +93,9 @@
 	TDM_PORT_MAX,
 };
 
+#define TDM_MAX_SLOTS 8
+#define TDM_SLOT_WIDTH_BITS 32
+
 enum {
 	TDM_PRI = 0,
 	TDM_SEC,
@@ -158,6 +167,7 @@
 struct msm_asoc_mach_data {
 	struct snd_info_entry *codec_root;
 	int usbc_en2_gpio; /* used by gpio driver API */
+	int lito_v2_enabled;
 	struct device_node *dmic01_gpio_p; /* used by pinctrl API */
 	struct device_node *dmic23_gpio_p; /* used by pinctrl API */
 	struct device_node *dmic45_gpio_p; /* used by pinctrl API */
@@ -176,6 +186,10 @@
 	u32 channel;
 };
 
+struct tdm_dev_config {
+	unsigned int tdm_slot_offset[TDM_MAX_SLOTS];
+};
+
 enum {
 	EXT_DISP_RX_IDX_DP = 0,
 	EXT_DISP_RX_IDX_DP1,
@@ -462,6 +476,153 @@
 	[SEN_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
 };
 
+static struct tdm_dev_config pri_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+	{ /* PRI TDM */
+		{ {0,   4, 0xFFFF} }, /* RX_0 */
+		{ {8,  12, 0xFFFF} }, /* RX_1 */
+		{ {16, 20, 0xFFFF} }, /* RX_2 */
+		{ {24, 28, 0xFFFF} }, /* RX_3 */
+		{ {0xFFFF} }, /* RX_4 */
+		{ {0xFFFF} }, /* RX_5 */
+		{ {0xFFFF} }, /* RX_6 */
+		{ {0xFFFF} }, /* RX_7 */
+	},
+	{
+		{ {0,   4,      8, 12, 0xFFFF} }, /* TX_0 */
+		{ {8,  12, 0xFFFF} }, /* TX_1 */
+		{ {16, 20, 0xFFFF} }, /* TX_2 */
+		{ {24, 28, 0xFFFF} }, /* TX_3 */
+		{ {0xFFFF} }, /* TX_4 */
+		{ {0xFFFF} }, /* TX_5 */
+		{ {0xFFFF} }, /* TX_6 */
+		{ {0xFFFF} }, /* TX_7 */
+	},
+};
+
+static struct tdm_dev_config sec_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+	{ /* SEC TDM */
+		{ {0,   4, 0xFFFF} }, /* RX_0 */
+		{ {8,  12, 0xFFFF} }, /* RX_1 */
+		{ {16, 20, 0xFFFF} }, /* RX_2 */
+		{ {24, 28, 0xFFFF} }, /* RX_3 */
+		{ {0xFFFF} }, /* RX_4 */
+		{ {0xFFFF} }, /* RX_5 */
+		{ {0xFFFF} }, /* RX_6 */
+		{ {0xFFFF} }, /* RX_7 */
+	},
+	{
+		{ {0,   4, 0xFFFF} }, /* TX_0 */
+		{ {8,  12, 0xFFFF} }, /* TX_1 */
+		{ {16, 20, 0xFFFF} }, /* TX_2 */
+		{ {24, 28, 0xFFFF} }, /* TX_3 */
+		{ {0xFFFF} }, /* TX_4 */
+		{ {0xFFFF} }, /* TX_5 */
+		{ {0xFFFF} }, /* TX_6 */
+		{ {0xFFFF} }, /* TX_7 */
+	},
+};
+
+static struct tdm_dev_config tert_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+	{ /* TERT TDM */
+		{ {0,   4, 0xFFFF} }, /* RX_0 */
+		{ {8,  12, 0xFFFF} }, /* RX_1 */
+		{ {16, 20, 0xFFFF} }, /* RX_2 */
+		{ {24, 28, 0xFFFF} }, /* RX_3 */
+		{ {0xFFFF} }, /* RX_4 */
+		{ {0xFFFF} }, /* RX_5 */
+		{ {0xFFFF} }, /* RX_6 */
+		{ {0xFFFF} }, /* RX_7 */
+	},
+	{
+		{ {0,   4, 0xFFFF} }, /* TX_0 */
+		{ {8,  12, 0xFFFF} }, /* TX_1 */
+		{ {16, 20, 0xFFFF} }, /* TX_2 */
+		{ {24, 28, 0xFFFF} }, /* TX_3 */
+		{ {0xFFFF} }, /* TX_4 */
+		{ {0xFFFF} }, /* TX_5 */
+		{ {0xFFFF} }, /* TX_6 */
+		{ {0xFFFF} }, /* TX_7 */
+	},
+};
+
+static struct tdm_dev_config quat_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+	{ /* QUAT TDM */
+		{ {0,   4, 0xFFFF} }, /* RX_0 */
+		{ {8,  12, 0xFFFF} }, /* RX_1 */
+		{ {16, 20, 0xFFFF} }, /* RX_2 */
+		{ {24, 28, 0xFFFF} }, /* RX_3 */
+		{ {0xFFFF} }, /* RX_4 */
+		{ {0xFFFF} }, /* RX_5 */
+		{ {0xFFFF} }, /* RX_6 */
+		{ {0xFFFF} }, /* RX_7 */
+	},
+	{
+		{ {0,   4, 0xFFFF} }, /* TX_0 */
+		{ {8,  12, 0xFFFF} }, /* TX_1 */
+		{ {16, 20, 0xFFFF} }, /* TX_2 */
+		{ {24, 28, 0xFFFF} }, /* TX_3 */
+		{ {0xFFFF} }, /* TX_4 */
+		{ {0xFFFF} }, /* TX_5 */
+		{ {0xFFFF} }, /* TX_6 */
+		{ {0xFFFF} }, /* TX_7 */
+	},
+};
+
+static struct tdm_dev_config quin_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+	{ /* QUIN TDM */
+		{ {0,   4, 0xFFFF} }, /* RX_0 */
+		{ {8,  12, 0xFFFF} }, /* RX_1 */
+		{ {16, 20, 0xFFFF} }, /* RX_2 */
+		{ {24, 28, 0xFFFF} }, /* RX_3 */
+		{ {0xFFFF} }, /* RX_4 */
+		{ {0xFFFF} }, /* RX_5 */
+		{ {0xFFFF} }, /* RX_6 */
+		{ {0xFFFF} }, /* RX_7 */
+	},
+	{
+		{ {0,   4, 0xFFFF} }, /* TX_0 */
+		{ {8,  12, 0xFFFF} }, /* TX_1 */
+		{ {16, 20, 0xFFFF} }, /* TX_2 */
+		{ {24, 28, 0xFFFF} }, /* TX_3 */
+		{ {0xFFFF} }, /* TX_4 */
+		{ {0xFFFF} }, /* TX_5 */
+		{ {0xFFFF} }, /* TX_6 */
+		{ {0xFFFF} }, /* TX_7 */
+	},
+};
+
+static struct tdm_dev_config sen_tdm_dev_config[MAX_PATH][TDM_PORT_MAX] = {
+	{ /* SEN TDM */
+		{ {0,   4, 0xFFFF} }, /* RX_0 */
+		{ {8,  12, 0xFFFF} }, /* RX_1 */
+		{ {16, 20, 0xFFFF} }, /* RX_2 */
+		{ {24, 28, 0xFFFF} }, /* RX_3 */
+		{ {0xFFFF} }, /* RX_4 */
+		{ {0xFFFF} }, /* RX_5 */
+		{ {0xFFFF} }, /* RX_6 */
+		{ {0xFFFF} }, /* RX_7 */
+	},
+	{
+		{ {0,   4, 0xFFFF} }, /* TX_0 */
+		{ {8,  12, 0xFFFF} }, /* TX_1 */
+		{ {16, 20, 0xFFFF} }, /* TX_2 */
+		{ {24, 28, 0xFFFF} }, /* TX_3 */
+		{ {0xFFFF} }, /* TX_4 */
+		{ {0xFFFF} }, /* TX_5 */
+		{ {0xFFFF} }, /* TX_6 */
+		{ {0xFFFF} }, /* TX_7 */
+	},
+};
+
+static void *tdm_cfg[TDM_INTERFACE_MAX] = {
+	pri_tdm_dev_config,
+	sec_tdm_dev_config,
+	tert_tdm_dev_config,
+	quat_tdm_dev_config,
+	quin_tdm_dev_config,
+	sen_tdm_dev_config,
+};
+
 /* Default configuration of Codec DMA Interface RX */
 static struct dev_config cdc_dma_rx_cfg[] = {
 	[WSA_CDC_DMA_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -1789,6 +1950,45 @@
 	return ret;
 }
 
+static int tdm_slot_map_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int slot_index = 0;
+	int interface = ucontrol->value.integer.value[0];
+	int channel = ucontrol->value.integer.value[1];
+	unsigned int offset_val = 0;
+	unsigned int *slot_offset = NULL;
+	struct tdm_dev_config *config = NULL;
+
+	if (interface < 0  || interface >= (TDM_INTERFACE_MAX * MAX_PATH)) {
+		pr_err("%s: incorrect interface = %d\n", __func__, interface);
+		return -EINVAL;
+	}
+	if (channel < 0  || channel >= TDM_PORT_MAX) {
+		pr_err("%s: incorrect channel = %d\n", __func__, channel);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: interface = %d, channel = %d\n", __func__,
+		interface, channel);
+
+	config = ((struct tdm_dev_config *) tdm_cfg[interface / MAX_PATH]) +
+			((interface % MAX_PATH) * TDM_PORT_MAX) + channel;
+	slot_offset = config->tdm_slot_offset;
+
+	for (slot_index = 0; slot_index < TDM_MAX_SLOTS; slot_index++) {
+		offset_val = ucontrol->value.integer.value[MAX_PATH +
+				slot_index];
+		/* Offset value can only be 0, 4, 8, ..28 */
+		if (offset_val % 4 == 0 && offset_val <= 28)
+			slot_offset[slot_index] = offset_val;
+		pr_debug("%s: slot offset[%d] = %d\n", __func__,
+			slot_index, slot_offset[slot_index]);
+	}
+
+	return 0;
+}
+
 static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
 {
 	int idx = 0;
@@ -3744,6 +3944,8 @@
 			afe_loopback_tx_ch_get, afe_loopback_tx_ch_put),
 	SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
 			msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+	SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0,
+			TDM_MAX_SLOTS + MAX_PATH, NULL, tdm_slot_map_put),
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -3813,8 +4015,9 @@
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 	int idx = 0, rc = 0;
 
-	pr_debug("%s: format = %d, rate = %d\n",
-		  __func__, params_format(params), params_rate(params));
+	pr_debug("%s: dai_id= %d, format = %d, rate = %d\n",
+		  __func__, dai_link->id, params_format(params),
+		  params_rate(params));
 
 	switch (dai_link->id) {
 	case MSM_BACKEND_DAI_USB_RX:
@@ -4280,65 +4483,51 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int ret = 0;
-	int slot_width = 32;
-	int channels, slots;
+	int slot_width = TDM_SLOT_WIDTH_BITS;
+	int channels, slots = TDM_MAX_SLOTS;
 	unsigned int slot_mask, rate, clk_freq;
-	unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+	unsigned int *slot_offset;
+	struct tdm_dev_config *config;
+	unsigned int path_dir = 0, interface = 0, channel_interface = 0;
 
 	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
 
-	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
-	switch (cpu_dai->id) {
-	case AFE_PORT_ID_PRIMARY_TDM_RX:
-		slots = tdm_rx_cfg[TDM_PRI][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_SECONDARY_TDM_RX:
-		slots = tdm_rx_cfg[TDM_SEC][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_TERTIARY_TDM_RX:
-		slots = tdm_rx_cfg[TDM_TERT][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_QUATERNARY_TDM_RX:
-		slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_QUINARY_TDM_RX:
-		slots = tdm_rx_cfg[TDM_QUIN][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_SENARY_TDM_RX:
-		slots = tdm_rx_cfg[TDM_SEN][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_PRIMARY_TDM_TX:
-		slots = tdm_tx_cfg[TDM_PRI][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_SECONDARY_TDM_TX:
-		slots = tdm_tx_cfg[TDM_SEC][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_TERTIARY_TDM_TX:
-		slots = tdm_tx_cfg[TDM_TERT][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_QUATERNARY_TDM_TX:
-		slots = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_QUINARY_TDM_TX:
-		slots = tdm_tx_cfg[TDM_QUIN][TDM_0].channels;
-		break;
-	case AFE_PORT_ID_SENARY_TDM_TX:
-		slots = tdm_tx_cfg[TDM_SEN][TDM_0].channels;
-		break;
-
-	default:
+	if (cpu_dai->id < AFE_PORT_ID_TDM_PORT_RANGE_START) {
 		pr_err("%s: dai id 0x%x not supported\n",
 			__func__, cpu_dai->id);
 		return -EINVAL;
 	}
 
+	/* RX or TX */
+	path_dir = cpu_dai->id % MAX_PATH;
+
+	/* PRI, SEC, TERT, QUAT, QUIN, ... */
+	interface = (cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START)
+			/ (MAX_PATH * TDM_PORT_MAX);
+
+	/* 0, 1, 2, .. 7 */
+	channel_interface =
+		((cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) / MAX_PATH)
+		% TDM_PORT_MAX;
+
+	pr_debug("%s: path dir: %u, interface %u, channel interface %u\n",
+		__func__, path_dir, interface, channel_interface);
+
+	config = ((struct tdm_dev_config *) tdm_cfg[interface]) +
+			(path_dir * TDM_PORT_MAX) + channel_interface;
+	slot_offset = config->tdm_slot_offset;
+
+	if (path_dir)
+		channels = tdm_tx_cfg[interface][channel_interface].channels;
+	else
+		channels = tdm_rx_cfg[interface][channel_interface].channels;
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/*2 slot config - bits 0 and 1 set for the first two slots */
 		slot_mask = 0x0000FFFF >> (16 - slots);
-		channels = slots;
 
-		pr_debug("%s: tdm rx slot_width %d slots %d\n",
-			__func__, slot_width, slots);
+		pr_debug("%s: tdm rx slot_width %d slots %d slot_mask %x\n",
+			__func__, slot_width, slots, slot_mask);
 
 		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
 			slots, slot_width);
@@ -4348,6 +4537,8 @@
 			goto end;
 		}
 
+		pr_debug("%s: tdm rx channels: %d\n", __func__, channels);
+
 		ret = snd_soc_dai_set_channel_map(cpu_dai,
 			0, NULL, channels, slot_offset);
 		if (ret < 0) {
@@ -4358,10 +4549,9 @@
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		/*2 slot config - bits 0 and 1 set for the first two slots */
 		slot_mask = 0x0000FFFF >> (16 - slots);
-		channels = slots;
 
-		pr_debug("%s: tdm tx slot_width %d slots %d\n",
-			__func__, slot_width, slots);
+		pr_debug("%s: tdm tx slot_width %d slots %d slot_mask %x\n",
+			__func__, slot_width, slots, slot_mask);
 
 		ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
 			slots, slot_width);
@@ -4371,6 +4561,8 @@
 			goto end;
 		}
 
+		pr_debug("%s: tdm tx channels: %d\n", __func__, channels);
+
 		ret = snd_soc_dai_set_channel_map(cpu_dai,
 			channels, slot_offset, 0, NULL);
 		if (ret < 0) {
@@ -5097,8 +5289,17 @@
 						WSA_MACRO_GAIN_OFFSET_M1P5_DB);
 			}
 		}
-		bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
-				    sm_port_map);
+		if (pdata->lito_v2_enabled) {
+			/*
+			 * Enable tx data line3 for saipan version v2 amd
+			 * write corresponding lpi register.
+			 */
+			bolero_set_port_map(component, ARRAY_SIZE(sm_port_map_v2),
+					sm_port_map_v2);
+		} else {
+			bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
+					sm_port_map);
+		}
 	}
 	card = rtd->card->snd_card;
 	if (!pdata->codec_root) {
@@ -7707,6 +7908,10 @@
 	if (!pdata)
 		return -ENOMEM;
 
+	of_property_read_u32(pdev->dev.of_node,
+				"qcom,lito-is-v2-enabled",
+				&pdata->lito_v2_enabled);
+
 	card = populate_snd_card_dailinks(&pdev->dev);
 	if (!card) {
 		dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
@@ -7828,6 +8033,10 @@
 	pdata->dmic45_gpio_p = of_parse_phandle(pdev->dev.of_node,
 					      "qcom,cdc-dmic45-gpios",
 					       0);
+	if (pdata->dmic01_gpio_p)
+		msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic01_gpio_p, false);
+	if (pdata->dmic23_gpio_p)
+		msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic23_gpio_p, false);
 	if (pdata->dmic45_gpio_p)
 		msm_cdc_pinctrl_set_wakeup_capable(pdata->dmic45_gpio_p, false);
 
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 75b217f..4347bec 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -10,6 +10,7 @@
 #include <linux/time.h>
 #include <linux/math64.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -106,6 +107,7 @@
 	struct msm_compr_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
 	bool is_in_use[MSM_FRONTEND_DAI_MAX];
 	struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE];
+	struct mutex lock;
 };
 
 struct msm_compr_audio {
@@ -978,6 +980,7 @@
 	struct asm_ape_cfg ape_cfg;
 	struct asm_dsd_cfg dsd_cfg;
 	struct aptx_dec_bt_addr_cfg aptx_cfg;
+	struct asm_amrwbplus_cfg amrwbplus_cfg;
 	union snd_codec_options *codec_options;
 
 	int ret = 0;
@@ -1266,6 +1269,26 @@
 					 __func__, ret);
 		}
 		break;
+	case FORMAT_AMRNB:
+		pr_debug("SND_AUDIOCODEC_AMR\n");
+		/* no media format block needed */
+		break;
+	case FORMAT_AMRWB:
+		pr_debug("SND_AUDIOCODEC_AMRWB\n");
+		/* no media format block needed */
+		break;
+	case FORMAT_AMR_WB_PLUS:
+		pr_debug("SND_AUDIOCODEC_AMRWBPLUS\n");
+		memset(&amrwbplus_cfg, 0x0, sizeof(struct asm_amrwbplus_cfg));
+		amrwbplus_cfg.amr_frame_fmt =
+			codec_options->amrwbplus.bit_stream_fmt;
+		ret =  q6asm_media_format_block_amrwbplus(
+				prtd->audio_client,
+				&amrwbplus_cfg);
+		if (ret < 0)
+			pr_err("%s: CMD AMRWBPLUS Format block failed ret %d\n",
+				__func__, ret);
+		break;
 	default:
 		pr_debug("%s, unsupported format, skip", __func__);
 		break;
@@ -1640,6 +1663,7 @@
 	struct snd_soc_component *component = NULL;
 	struct msm_compr_audio *prtd = NULL;
 	struct msm_compr_pdata *pdata = NULL;
+	enum apr_subsys_state subsys_state;
 
 	pr_debug("%s\n", __func__);
 	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
@@ -1653,6 +1677,13 @@
 			__func__, rtd->dai_link->cpu_dai_name, -EBUSY);
 		return -EBUSY;
 	}
+
+	subsys_state = apr_get_subsys_state();
+	if (subsys_state == APR_SUBSYS_DOWN) {
+		pr_debug("%s: adsp is down\n", __func__);
+		return -ENETRESET;
+	}
+
 	prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
 	if (prtd == NULL) {
 		pr_err("Failed to allocate memory for msm_compr_audio\n");
@@ -1747,6 +1778,7 @@
 	struct snd_soc_component *component = NULL;
 	struct msm_compr_audio *prtd;
 	struct msm_compr_pdata *pdata = NULL;
+	enum apr_subsys_state subsys_state;
 
 	pr_debug("%s\n", __func__);
 	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
@@ -1759,6 +1791,12 @@
 		pr_err("%s: pdata is NULL\n", __func__);
 		return -EINVAL;
 	}
+
+	subsys_state = apr_get_subsys_state();
+	if (subsys_state == APR_SUBSYS_DOWN) {
+		pr_debug("%s: adsp is down\n", __func__);
+		return -ENETRESET;
+	}
 	prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
 	if (!prtd) {
 		pr_err("Failed to allocate memory for msm_compr_audio\n");
@@ -1905,6 +1943,7 @@
 	}
 	spin_unlock_irqrestore(&prtd->lock, flags);
 
+	mutex_lock(&pdata->lock);
 	pdata->cstream[soc_prtd->dai_link->id] = NULL;
 	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
 		msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
@@ -1926,6 +1965,7 @@
 	pdata->is_in_use[soc_prtd->dai_link->id] = false;
 	kfree(prtd);
 	runtime->private_data = NULL;
+	mutex_unlock(&pdata->lock);
 
 	return 0;
 }
@@ -1982,6 +2022,7 @@
 	}
 	spin_unlock_irqrestore(&prtd->lock, flags);
 
+	mutex_lock(&pdata->lock);
 	pdata->cstream[soc_prtd->dai_link->id] = NULL;
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
 					SNDRV_PCM_STREAM_CAPTURE);
@@ -1992,6 +2033,7 @@
 
 	kfree(prtd);
 	runtime->private_data = NULL;
+	mutex_unlock(&pdata->lock);
 
 	return 0;
 }
@@ -2193,6 +2235,24 @@
 		break;
 	}
 
+	case SND_AUDIOCODEC_AMR: {
+		pr_debug("%s:SND_AUDIOCODEC_AMR\n", __func__);
+		prtd->codec = FORMAT_AMRNB;
+		break;
+	}
+
+	case SND_AUDIOCODEC_AMRWB: {
+		pr_debug("%s:SND_AUDIOCODEC_AMRWB\n", __func__);
+		prtd->codec = FORMAT_AMRWB;
+		break;
+	}
+
+	case SND_AUDIOCODEC_AMRWBPLUS: {
+		pr_debug("%s:SND_AUDIOCODEC_AMRWBPLUS\n", __func__);
+		prtd->codec = FORMAT_AMR_WB_PLUS;
+		break;
+	}
+
 	default:
 		pr_err("codec not supported, id =%d\n", params->codec.id);
 		return -EINVAL;
@@ -3267,6 +3327,9 @@
 	case FORMAT_VORBIS:
 	case FORMAT_ALAC:
 	case FORMAT_APE:
+	case FORMAT_AMRNB:
+	case FORMAT_AMRWB:
+	case FORMAT_AMR_WB_PLUS:
 		memcpy(&(prtd->gapless_state.codec_options),
 			codec_options,
 			sizeof(union snd_codec_options));
@@ -3349,6 +3412,7 @@
 	struct snd_compr_stream *cstream = NULL;
 	struct msm_compr_audio *prtd = NULL;
 	long *values = &(ucontrol->value.integer.value[0]);
+	int ret = 0;
 	int effects_module;
 
 	pr_debug("%s\n", __func__);
@@ -3357,21 +3421,25 @@
 			__func__, fe_id);
 		return -EINVAL;
 	}
+
+	mutex_lock(&pdata->lock);
 	cstream = pdata->cstream[fe_id];
 	audio_effects = pdata->audio_effects[fe_id];
 	if (!cstream || !audio_effects) {
 		pr_err("%s: stream or effects inactive\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	prtd = cstream->runtime->private_data;
 	if (!prtd) {
 		pr_err("%s: cannot set audio effects\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	if (prtd->compr_passthr != LEGACY_PCM) {
 		pr_debug("%s: No effects for compr_type[%d]\n",
 			__func__, prtd->compr_passthr);
-		return 0;
+		goto done;
 	}
 	pr_debug("%s: Effects supported for compr_type[%d]\n",
 		 __func__, prtd->compr_passthr);
@@ -3432,9 +3500,11 @@
 		break;
 	default:
 		pr_err("%s Invalid effects config module\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
 	}
-	return 0;
+done:
+	mutex_unlock(&pdata->lock);
+	return ret;
 }
 
 static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
@@ -3446,6 +3516,7 @@
 			snd_soc_component_get_drvdata(comp);
 	struct msm_compr_audio_effects *audio_effects = NULL;
 	struct snd_compr_stream *cstream = NULL;
+	int ret = 0;
 	struct msm_compr_audio *prtd = NULL;
 
 	pr_debug("%s\n", __func__);
@@ -3454,19 +3525,23 @@
 			__func__, fe_id);
 		return -EINVAL;
 	}
+
+	mutex_lock(&pdata->lock);
 	cstream = pdata->cstream[fe_id];
 	audio_effects = pdata->audio_effects[fe_id];
 	if (!cstream || !audio_effects) {
 		pr_debug("%s: stream or effects inactive\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	prtd = cstream->runtime->private_data;
 	if (!prtd) {
 		pr_err("%s: cannot set audio effects\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
 	}
-
-	return 0;
+done:
+	mutex_unlock(&pdata->lock);
+	return ret;
 }
 
 static int msm_compr_query_audio_effect_put(struct snd_kcontrol *kcontrol,
@@ -3479,6 +3554,7 @@
 	struct msm_compr_audio_effects *audio_effects = NULL;
 	struct snd_compr_stream *cstream = NULL;
 	struct msm_compr_audio *prtd = NULL;
+	int ret = 0;
 	long *values = &(ucontrol->value.integer.value[0]);
 
 	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3486,28 +3562,37 @@
 			__func__, fe_id);
 		return -EINVAL;
 	}
+
+	mutex_lock(&pdata->lock);
+
 	cstream = pdata->cstream[fe_id];
 	audio_effects = pdata->audio_effects[fe_id];
 	if (!cstream || !audio_effects) {
 		pr_err("%s: stream or effects inactive\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	prtd = cstream->runtime->private_data;
 	if (!prtd) {
 		pr_err("%s: cannot set audio effects\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	if (prtd->compr_passthr != LEGACY_PCM) {
 		pr_err("%s: No effects for compr_type[%d]\n",
 			__func__, prtd->compr_passthr);
-		return -EPERM;
+		ret = -EPERM;
+		goto done;
 	}
 	audio_effects->query.mod_id = (u32)*values++;
 	audio_effects->query.parm_id = (u32)*values++;
 	audio_effects->query.size = (u32)*values++;
 	audio_effects->query.offset = (u32)*values++;
 	audio_effects->query.device = (u32)*values++;
-	return 0;
+
+done:
+	mutex_unlock(&pdata->lock);
+	return ret;
 }
 
 static int msm_compr_query_audio_effect_get(struct snd_kcontrol *kcontrol,
@@ -3520,6 +3605,7 @@
 	struct msm_compr_audio_effects *audio_effects = NULL;
 	struct snd_compr_stream *cstream = NULL;
 	struct msm_compr_audio *prtd = NULL;
+	int ret = 0;
 	long *values = &(ucontrol->value.integer.value[0]);
 
 	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3527,23 +3613,29 @@
 			__func__, fe_id);
 		return -EINVAL;
 	}
+
+	mutex_lock(&pdata->lock);
 	cstream = pdata->cstream[fe_id];
 	audio_effects = pdata->audio_effects[fe_id];
 	if (!cstream || !audio_effects) {
 		pr_debug("%s: stream or effects inactive\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	prtd = cstream->runtime->private_data;
 	if (!prtd) {
 		pr_err("%s: cannot set audio effects\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto done;
 	}
 	values[0] = (long)audio_effects->query.mod_id;
 	values[1] = (long)audio_effects->query.parm_id;
 	values[2] = (long)audio_effects->query.size;
 	values[3] = (long)audio_effects->query.offset;
 	values[4] = (long)audio_effects->query.device;
-	return 0;
+done:
+	mutex_unlock(&pdata->lock);
+	return ret;
 }
 
 static int msm_compr_send_dec_params(struct snd_compr_stream *cstream,
@@ -3629,6 +3721,7 @@
 		goto end;
 	}
 
+	mutex_lock(&pdata->lock);
 	switch (prtd->codec) {
 	case FORMAT_MP3:
 	case FORMAT_MPEG4_AAC:
@@ -3641,6 +3734,9 @@
 	case FORMAT_TRUEHD:
 	case FORMAT_IEC61937:
 	case FORMAT_APTX:
+	case FORMAT_AMRNB:
+	case FORMAT_AMRWB:
+	case FORMAT_AMR_WB_PLUS:
 		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
 			 prtd->codec);
 		break;
@@ -3677,6 +3773,7 @@
 	}
 end:
 	pr_debug("%s: ret %d\n", __func__, rc);
+	mutex_unlock(&pdata->lock);
 	return rc;
 }
 
@@ -3896,6 +3993,7 @@
 		goto done;
 	}
 
+	mutex_lock(&pdata->lock);
 	if (prtd->audio_client == NULL) {
 		pr_err("%s: audio_client is null\n", __func__);
 		ret = -EINVAL;
@@ -3924,6 +4022,7 @@
 		pr_err("%s: failed to send stream event cmd, err = %d\n",
 			__func__, ret);
 done:
+	mutex_unlock(&pdata->lock);
 	return ret;
 }
 
@@ -3960,6 +4059,7 @@
 		goto done;
 	}
 
+	mutex_lock(&pdata->lock);
 	if (prtd->audio_client == NULL) {
 		pr_err("%s: audio_client is null\n", __func__);
 		ret = -EINVAL;
@@ -3971,6 +4071,7 @@
 	if (ret < 0)
 		pr_err("%s: failed to register ion fd\n", __func__);
 done:
+	mutex_unlock(&pdata->lock);
 	return ret;
 }
 
@@ -3993,6 +4094,7 @@
 		goto done;
 	}
 
+	mutex_lock(&pdata->lock);
 	cstream = pdata->cstream[fe_id];
 	if (cstream == NULL) {
 		pr_err("%s cstream is null\n", __func__);
@@ -4030,6 +4132,7 @@
 		pr_err("%s: failed to send rtic event ack, err = %d\n",
 			__func__, ret);
 done:
+	mutex_unlock(&pdata->lock);
 	return ret;
 }
 
@@ -5409,6 +5512,7 @@
 			kzalloc(sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 		return -ENOMEM;
+	mutex_init(&pdata->lock);
 	dev_set_drvdata(&pdev->dev, pdata);
 
 	return snd_soc_register_component(&pdev->dev,
@@ -5425,6 +5529,7 @@
 		for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++)
 			kfree(pdata->chmixer_pspd[i]);
 	}
+	mutex_destroy(&pdata->lock);
 	kfree(pdata);
 
 	snd_soc_unregister_component(&pdev->dev);
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index c6f61e4..1b15444 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -35,6 +35,9 @@
 #define CHANNEL_STATUS_SIZE 24
 #define CHANNEL_STATUS_MASK_INIT 0x0
 #define CHANNEL_STATUS_MASK 0x4
+#define PREEMPH_MASK 0x38
+#define PREEMPH_SHIFT 3
+#define GET_PREEMPH(b) ((b & PREEMPH_MASK) >> PREEMPH_SHIFT)
 #define AFE_API_VERSION_CLOCK_SET 1
 #define MSM_DAI_SYSFS_ENTRY_MAX_LEN 64
 
@@ -261,6 +264,17 @@
 	struct msm_dai_q6_mi2s_dai_config rx_dai;
 };
 
+struct msm_dai_q6_meta_mi2s_dai_data {
+	DECLARE_BITMAP(status_mask, STATUS_MAX);
+	u16 num_member_ports;
+	u16 member_port_id[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+	u16 channel_mode[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+	u32 rate;
+	u32 channels;
+	u32 bitwidth;
+	union afe_port_config port_config;
+};
+
 struct msm_dai_q6_cdc_dma_dai_data {
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
 	DECLARE_BITMAP(hwfree_status, STATUS_MAX);
@@ -268,6 +282,7 @@
 	u32 channels;
 	u32 bitwidth;
 	u32 is_island_dai;
+	u32 xt_logging_disable;
 	union afe_port_config port_config;
 };
 
@@ -1728,22 +1743,41 @@
 {
 	struct msm_dai_q6_spdif_event_msg *evt;
 	struct msm_dai_q6_spdif_dai_data *dai_data;
+	int preemph_old = 0;
+	int preemph_new = 0;
 
 	evt = (struct msm_dai_q6_spdif_event_msg *)payload;
 	dai_data = (struct msm_dai_q6_spdif_dai_data *)private_data;
 
-	pr_debug("%s: old state %d, fmt %d, rate %d\n",
+	preemph_old = GET_PREEMPH(dai_data->fmt_event.channel_status[0]);
+	preemph_new = GET_PREEMPH(evt->fmt_event.channel_status[0]);
+
+	pr_debug("%s: old state %d, fmt %d, rate %d, preemph %d\n",
 			__func__, dai_data->fmt_event.status,
 			dai_data->fmt_event.data_format,
-			dai_data->fmt_event.sample_rate);
-	pr_debug("%s: new state %d, fmt %d, rate %d\n",
+			dai_data->fmt_event.sample_rate,
+			preemph_old);
+	pr_debug("%s: new state %d, fmt %d, rate %d, preemph %d\n",
 			__func__, evt->fmt_event.status,
 			evt->fmt_event.data_format,
-			evt->fmt_event.sample_rate);
+			evt->fmt_event.sample_rate,
+			preemph_new);
 
 	dai_data->fmt_event.status = evt->fmt_event.status;
 	dai_data->fmt_event.data_format = evt->fmt_event.data_format;
 	dai_data->fmt_event.sample_rate = evt->fmt_event.sample_rate;
+	dai_data->fmt_event.channel_status[0] =
+		evt->fmt_event.channel_status[0];
+	dai_data->fmt_event.channel_status[1] =
+		evt->fmt_event.channel_status[1];
+	dai_data->fmt_event.channel_status[2] =
+		evt->fmt_event.channel_status[2];
+	dai_data->fmt_event.channel_status[3] =
+		evt->fmt_event.channel_status[3];
+	dai_data->fmt_event.channel_status[4] =
+		evt->fmt_event.channel_status[4];
+	dai_data->fmt_event.channel_status[5] =
+		evt->fmt_event.channel_status[5];
 }
 
 static int msm_dai_q6_spdif_hw_params(struct snd_pcm_substream *substream,
@@ -1887,17 +1921,40 @@
 	return ret;
 }
 
+static ssize_t msm_dai_q6_spdif_sysfs_rda_audio_preemph(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct msm_dai_q6_spdif_dai_data *dai_data = dev_get_drvdata(dev);
+	int preemph = 0;
+
+	if (!dai_data) {
+		pr_err("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	preemph = GET_PREEMPH(dai_data->fmt_event.channel_status[0]);
+
+	ret = snprintf(buf, MSM_DAI_SYSFS_ENTRY_MAX_LEN, "%d\n", preemph);
+	pr_debug("%s: '%d'\n", __func__, preemph);
+
+	return ret;
+}
+
 static DEVICE_ATTR(audio_state, 0444, msm_dai_q6_spdif_sysfs_rda_audio_state,
 	NULL);
 static DEVICE_ATTR(audio_format, 0444, msm_dai_q6_spdif_sysfs_rda_audio_format,
 	NULL);
 static DEVICE_ATTR(audio_rate, 0444, msm_dai_q6_spdif_sysfs_rda_audio_rate,
 	NULL);
+static DEVICE_ATTR(audio_preemph, 0444,
+	msm_dai_q6_spdif_sysfs_rda_audio_preemph, NULL);
 
 static struct attribute *msm_dai_q6_spdif_fs_attrs[] = {
 	&dev_attr_audio_state.attr,
 	&dev_attr_audio_format.attr,
 	&dev_attr_audio_rate.attr,
+	&dev_attr_audio_preemph.attr,
 	NULL,
 };
 static struct attribute_group msm_dai_q6_spdif_fs_attrs_group = {
@@ -2788,24 +2845,54 @@
 	return 0;
 }
 
-static int msm_dai_q6_xt_logging_disable_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
+static int msm_dai_q6_cdc_dma_xt_logging_disable_put(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
 {
-	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	struct msm_dai_q6_cdc_dma_dai_data *dai_data = kcontrol->private_data;
 
-	dai_data->xt_logging_disable = ucontrol->value.integer.value[0];
-	pr_debug("%s: setting xt logging disable to %d\n",
-		__func__, dai_data->xt_logging_disable);
+	if (dai_data) {
+		dai_data->xt_logging_disable = ucontrol->value.integer.value[0];
+		pr_debug("%s: setting xt logging disable to %d\n",
+			__func__, dai_data->xt_logging_disable);
+	}
 
 	return 0;
 }
 
-static int msm_dai_q6_xt_logging_disable_get(struct snd_kcontrol *kcontrol,
+static int msm_dai_q6_cdc_dma_xt_logging_disable_get(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_cdc_dma_dai_data *dai_data = kcontrol->private_data;
+
+	if (dai_data)
+		ucontrol->value.integer.value[0] = dai_data->xt_logging_disable;
+	return 0;
+}
+
+static int msm_dai_q6_sb_xt_logging_disable_put(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	if (dai_data) {
+		dai_data->xt_logging_disable = ucontrol->value.integer.value[0];
+		pr_debug("%s: setting xt logging disable to %d\n",
+			__func__, dai_data->xt_logging_disable);
+	}
+
+	return 0;
+}
+
+static int msm_dai_q6_sb_xt_logging_disable_get(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
 {
 	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
 
-	ucontrol->value.integer.value[0] = dai_data->xt_logging_disable;
+	if (dai_data)
+		ucontrol->value.integer.value[0] = dai_data->xt_logging_disable;
 	return 0;
 }
 
@@ -3670,8 +3757,8 @@
 		     msm_dai_q6_sb_format_get,
 		     msm_dai_q6_sb_format_put),
 	SOC_ENUM_EXT("SLIM_0_RX XTLoggingDisable", xt_logging_disable_enum[0],
-		     msm_dai_q6_xt_logging_disable_get,
-		     msm_dai_q6_xt_logging_disable_put),
+		     msm_dai_q6_sb_xt_logging_disable_get,
+		     msm_dai_q6_sb_xt_logging_disable_put),
 };
 
 static const struct snd_kcontrol_new rt_proxy_config_controls[] = {
@@ -6096,6 +6183,42 @@
 	return -EINVAL;
 }
 
+static u16 msm_dai_q6_mi2s_get_num_channels(u16 config)
+{
+	switch (config) {
+	case AFE_PORT_I2S_SD0:
+	case AFE_PORT_I2S_SD1:
+	case AFE_PORT_I2S_SD2:
+	case AFE_PORT_I2S_SD3:
+	case AFE_PORT_I2S_SD4:
+	case AFE_PORT_I2S_SD5:
+	case AFE_PORT_I2S_SD6:
+	case AFE_PORT_I2S_SD7:
+		return 2;
+	case AFE_PORT_I2S_QUAD01:
+	case AFE_PORT_I2S_QUAD23:
+	case AFE_PORT_I2S_QUAD45:
+	case AFE_PORT_I2S_QUAD67:
+		return 4;
+	case AFE_PORT_I2S_6CHS:
+		return 6;
+	case AFE_PORT_I2S_8CHS:
+	case AFE_PORT_I2S_8CHS_2:
+		return 8;
+	case AFE_PORT_I2S_10CHS:
+		return 10;
+	case AFE_PORT_I2S_12CHS:
+		return 12;
+	case AFE_PORT_I2S_14CHS:
+		return 14;
+	case AFE_PORT_I2S_16CHS:
+		return 16;
+	default:
+		pr_err("%s: invalid config\n", __func__);
+		return 0;
+	}
+}
+
 static int msm_dai_q6_mi2s_platform_data_validation(
 	struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
 {
@@ -6261,6 +6384,657 @@
 	return 0;
 }
 
+static int msm_dai_q6_dai_meta_mi2s_probe(struct snd_soc_dai *dai)
+{
+	struct msm_meta_mi2s_pdata *meta_mi2s_pdata =
+			(struct msm_meta_mi2s_pdata *) dai->dev->platform_data;
+	int rc = 0;
+
+	dai->id = meta_mi2s_pdata->intf_id;
+	rc = msm_dai_q6_dai_add_route(dai);
+	return rc;
+}
+
+static int msm_dai_q6_dai_meta_mi2s_remove(struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static int msm_dai_q6_meta_mi2s_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static int msm_meta_mi2s_get_port_id(u32 mi2s_id, int stream, u16 *port_id)
+{
+	int ret = 0;
+
+	switch (stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		switch (mi2s_id) {
+		case MSM_PRIM_META_MI2S:
+			*port_id = AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+			break;
+		case MSM_SEC_META_MI2S:
+			*port_id = AFE_PORT_ID_SECONDARY_META_MI2S_RX;
+			break;
+		default:
+			pr_err("%s: playback err id 0x%x\n",
+				__func__, mi2s_id);
+			ret = -1;
+			break;
+		}
+		break;
+
+	case SNDRV_PCM_STREAM_CAPTURE:
+		switch (mi2s_id) {
+		default:
+			pr_err("%s: capture err id 0x%x\n", __func__, mi2s_id);
+			ret = -1;
+			break;
+		}
+		break;
+
+	default:
+		pr_err("%s: default err %d\n", __func__, stream);
+		ret = -1;
+		break;
+	}
+	pr_debug("%s: port_id = 0x%x\n", __func__, *port_id);
+	return ret;
+}
+
+static int msm_dai_q6_meta_mi2s_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+		dev_get_drvdata(dai->dev);
+	u16 port_id = 0;
+	int rc = 0;
+
+	if (msm_meta_mi2s_get_port_id(dai->id, substream->stream,
+		&port_id) != 0) {
+		dev_err(dai->dev, "%s: Invalid Port ID 0x%x\n",
+			__func__, port_id);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "%s: dai id %d, afe port id = 0x%x\n"
+		"dai_data->channels = %u sample_rate = %u\n", __func__,
+		dai->id, port_id, dai_data->channels, dai_data->rate);
+
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		/* PORT START should be set if prepare called
+		 * in active state.
+		 */
+		rc = afe_port_start(port_id, &dai_data->port_config,
+				    dai_data->rate);
+		if (rc < 0)
+			dev_err(dai->dev, "fail to open AFE port 0x%x\n",
+				dai->id);
+		else
+			set_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+	}
+
+	return rc;
+}
+
+static int msm_dai_q6_meta_mi2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+		dev_get_drvdata(dai->dev);
+	struct afe_param_id_meta_i2s_cfg *port_cfg =
+		&dai_data->port_config.meta_i2s;
+	int idx = 0;
+	u16 port_channels = 0;
+	u16 channels_left = 0;
+
+	dai_data->channels = params_channels(params);
+	channels_left = dai_data->channels;
+
+	/* map requested channels to channels that member ports provide */
+	for (idx = 0; idx < dai_data->num_member_ports; idx++) {
+		port_channels = msm_dai_q6_mi2s_get_num_channels(
+			dai_data->channel_mode[idx]);
+
+		if (channels_left >= port_channels) {
+			port_cfg->member_port_id[idx] =
+				dai_data->member_port_id[idx];
+			port_cfg->member_port_channel_mode[idx] =
+				dai_data->channel_mode[idx];
+			channels_left -= port_channels;
+		} else {
+			switch (channels_left) {
+			case 15:
+			case 16:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_16CHS;
+					break;
+				default:
+					goto error_invalid_data;
+				};
+				break;
+			case 13:
+			case 14:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_14CHS:
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_14CHS;
+					break;
+				default:
+					goto error_invalid_data;
+				};
+				break;
+			case 11:
+			case 12:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_12CHS:
+				case AFE_PORT_I2S_14CHS:
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_12CHS;
+					break;
+				default:
+					goto error_invalid_data;
+				};
+				break;
+			case 9:
+			case 10:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_10CHS:
+				case AFE_PORT_I2S_12CHS:
+				case AFE_PORT_I2S_14CHS:
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_10CHS;
+					break;
+				default:
+					goto error_invalid_data;
+				};
+				break;
+			case 8:
+			case 7:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_8CHS:
+				case AFE_PORT_I2S_10CHS:
+				case AFE_PORT_I2S_12CHS:
+				case AFE_PORT_I2S_14CHS:
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_8CHS;
+					break;
+				case AFE_PORT_I2S_8CHS_2:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_8CHS_2;
+					break;
+				default:
+					goto error_invalid_data;
+				};
+				break;
+			case 6:
+			case 5:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_6CHS:
+				case AFE_PORT_I2S_8CHS:
+				case AFE_PORT_I2S_10CHS:
+				case AFE_PORT_I2S_12CHS:
+				case AFE_PORT_I2S_14CHS:
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_6CHS;
+					break;
+				default:
+					goto error_invalid_data;
+				};
+				break;
+			case 4:
+			case 3:
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_SD0:
+				case AFE_PORT_I2S_SD1:
+				case AFE_PORT_I2S_SD2:
+				case AFE_PORT_I2S_SD3:
+				case AFE_PORT_I2S_SD4:
+				case AFE_PORT_I2S_SD5:
+				case AFE_PORT_I2S_SD6:
+				case AFE_PORT_I2S_SD7:
+					goto error_invalid_data;
+				case AFE_PORT_I2S_QUAD01:
+				case AFE_PORT_I2S_QUAD23:
+				case AFE_PORT_I2S_QUAD45:
+				case AFE_PORT_I2S_QUAD67:
+					port_cfg->member_port_channel_mode[idx]
+						= dai_data->channel_mode[idx];
+					break;
+				case AFE_PORT_I2S_8CHS_2:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_QUAD45;
+					break;
+				default:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_QUAD01;
+				};
+				break;
+			case 2:
+			case 1:
+				if (dai_data->channel_mode[idx] <
+					AFE_PORT_I2S_SD0)
+					goto error_invalid_data;
+				switch (dai_data->channel_mode[idx]) {
+				case AFE_PORT_I2S_SD0:
+				case AFE_PORT_I2S_SD1:
+				case AFE_PORT_I2S_SD2:
+				case AFE_PORT_I2S_SD3:
+				case AFE_PORT_I2S_SD4:
+				case AFE_PORT_I2S_SD5:
+				case AFE_PORT_I2S_SD6:
+				case AFE_PORT_I2S_SD7:
+					port_cfg->member_port_channel_mode[idx]
+						= dai_data->channel_mode[idx];
+					break;
+				case AFE_PORT_I2S_QUAD01:
+				case AFE_PORT_I2S_6CHS:
+				case AFE_PORT_I2S_8CHS:
+				case AFE_PORT_I2S_10CHS:
+				case AFE_PORT_I2S_12CHS:
+				case AFE_PORT_I2S_14CHS:
+				case AFE_PORT_I2S_16CHS:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_SD0;
+					break;
+				case AFE_PORT_I2S_QUAD23:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_SD2;
+					break;
+				case AFE_PORT_I2S_QUAD45:
+				case AFE_PORT_I2S_8CHS_2:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_SD4;
+					break;
+				case AFE_PORT_I2S_QUAD67:
+					port_cfg->member_port_channel_mode[idx]
+						= AFE_PORT_I2S_SD6;
+					break;
+				}
+				break;
+			case 0:
+				port_cfg->member_port_channel_mode[idx] = 0;
+			}
+			if (port_cfg->member_port_channel_mode[idx] == 0) {
+				port_cfg->member_port_id[idx] =
+					AFE_PORT_ID_INVALID;
+			} else {
+				port_cfg->member_port_id[idx] =
+					dai_data->member_port_id[idx];
+				channels_left -=
+					msm_dai_q6_mi2s_get_num_channels(
+					port_cfg->member_port_channel_mode[idx]);
+			}
+		}
+	}
+
+	if (channels_left > 0) {
+		pr_err("%s: too many channels %d\n",
+			__func__, dai_data->channels);
+		return -EINVAL;
+	}
+
+	dai_data->rate = params_rate(params);
+	port_cfg->sample_rate = dai_data->rate;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_SPECIAL:
+		port_cfg->bit_width = 16;
+		dai_data->bitwidth = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		port_cfg->bit_width = 24;
+		dai_data->bitwidth = 24;
+		break;
+	default:
+		pr_err("%s: format %d\n",
+			__func__, params_format(params));
+		return -EINVAL;
+	}
+
+	port_cfg->minor_version = AFE_API_VERSION_META_I2S_CONFIG;
+	port_cfg->data_format = AFE_LINEAR_PCM_DATA;
+
+	dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
+		"bit_width = %hu ws_src = 0x%x sample_rate = %u\n"
+		"member_ports 0x%x 0x%x 0x%x 0x%x\n"
+		"sd_lines 0x%x 0x%x 0x%x 0x%x\n",
+		__func__, dai->id, dai_data->channels,
+		port_cfg->bit_width, port_cfg->ws_src, port_cfg->sample_rate,
+		port_cfg->member_port_id[0],
+		port_cfg->member_port_id[1],
+		port_cfg->member_port_id[2],
+		port_cfg->member_port_id[3],
+		port_cfg->member_port_channel_mode[0],
+		port_cfg->member_port_channel_mode[1],
+		port_cfg->member_port_channel_mode[2],
+		port_cfg->member_port_channel_mode[3]);
+	return 0;
+
+error_invalid_data:
+	pr_err("%s: error when assigning member port %d channels (channels_left %d)\n",
+		__func__, idx, channels_left);
+	return -EINVAL;
+}
+
+static int msm_dai_q6_meta_mi2s_set_fmt(struct snd_soc_dai *dai,
+	unsigned int fmt)
+{
+	struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+		dev_get_drvdata(dai->dev);
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		dev_err(dai->dev, "%s: err chg meta i2s mode while dai running",
+			__func__);
+		return -EPERM;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dai_data->port_config.meta_i2s.ws_src = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dai_data->port_config.meta_i2s.ws_src = 0;
+		break;
+	default:
+		pr_err("%s: fmt %d\n",
+			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void msm_dai_q6_meta_mi2s_shutdown(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+		dev_get_drvdata(dai->dev);
+	u16 port_id = 0;
+	int rc = 0;
+
+	if (msm_meta_mi2s_get_port_id(dai->id, substream->stream,
+				 &port_id) != 0) {
+		dev_err(dai->dev, "%s: Invalid Port ID 0x%x\n",
+			__func__, port_id);
+	}
+
+	dev_dbg(dai->dev, "%s: closing afe port id = 0x%x\n",
+			__func__, port_id);
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		rc = afe_close(port_id);
+		if (rc < 0)
+			dev_err(dai->dev, "fail to close AFE port\n");
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	}
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_meta_mi2s_ops = {
+	.startup	= msm_dai_q6_meta_mi2s_startup,
+	.prepare	= msm_dai_q6_meta_mi2s_prepare,
+	.hw_params	= msm_dai_q6_meta_mi2s_hw_params,
+	.set_fmt	= msm_dai_q6_meta_mi2s_set_fmt,
+	.shutdown	= msm_dai_q6_meta_mi2s_shutdown,
+};
+
+/* Channel min and max are initialized base on platform data */
+static struct snd_soc_dai_driver msm_dai_q6_meta_mi2s_dai[] = {
+	{
+		.playback = {
+			.stream_name = "Primary META MI2S Playback",
+			.aif_name = "PRI_META_MI2S_RX",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+				SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+				SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+				SNDRV_PCM_RATE_384000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S24_3LE,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.ops = &msm_dai_q6_meta_mi2s_ops,
+		.name = "Primary META MI2S",
+		.id = AFE_PORT_ID_PRIMARY_META_MI2S_RX,
+		.probe = msm_dai_q6_dai_meta_mi2s_probe,
+		.remove = msm_dai_q6_dai_meta_mi2s_remove,
+	},
+	{
+		.playback = {
+			.stream_name = "Secondary META MI2S Playback",
+			.aif_name = "SEC_META_MI2S_RX",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+				 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+				 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min =     8000,
+			.rate_max =     192000,
+		},
+		.ops = &msm_dai_q6_meta_mi2s_ops,
+		.name = "Secondary META MI2S",
+		.id = AFE_PORT_ID_SECONDARY_META_MI2S_RX,
+		.probe = msm_dai_q6_dai_meta_mi2s_probe,
+		.remove = msm_dai_q6_dai_meta_mi2s_remove,
+	},
+};
+
+static int msm_dai_q6_meta_mi2s_platform_data_validation(
+	struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
+{
+	struct msm_dai_q6_meta_mi2s_dai_data *dai_data =
+		dev_get_drvdata(&pdev->dev);
+	struct msm_meta_mi2s_pdata *meta_mi2s_pdata =
+		(struct msm_meta_mi2s_pdata *) pdev->dev.platform_data;
+	int rc = 0;
+	int idx = 0;
+	u16 channel_mode = 0;
+	unsigned int ch_cnt = 0;
+	unsigned int ch_cnt_sum = 0;
+	struct afe_param_id_meta_i2s_cfg *port_cfg =
+		&dai_data->port_config.meta_i2s;
+
+	if (meta_mi2s_pdata == NULL) {
+		pr_err("%s: meta_mi2s_pdata NULL", __func__);
+		return -EINVAL;
+	}
+
+	dai_data->num_member_ports = meta_mi2s_pdata->num_member_ports;
+	for (idx = 0; idx < meta_mi2s_pdata->num_member_ports; idx++) {
+		rc = msm_dai_q6_mi2s_get_lineconfig(
+			meta_mi2s_pdata->sd_lines[idx],
+			&channel_mode,
+			&ch_cnt);
+		if (rc < 0) {
+			dev_err(&pdev->dev, "invalid META MI2S RX sd line config\n");
+			goto rtn;
+		}
+		if (ch_cnt) {
+			msm_mi2s_get_port_id(meta_mi2s_pdata->member_port[idx],
+				SNDRV_PCM_STREAM_PLAYBACK,
+				&dai_data->member_port_id[idx]);
+			dai_data->channel_mode[idx] = channel_mode;
+			port_cfg->member_port_id[idx] =
+				dai_data->member_port_id[idx];
+			port_cfg->member_port_channel_mode[idx] = channel_mode;
+		}
+		ch_cnt_sum += ch_cnt;
+	}
+
+	if (ch_cnt_sum) {
+		dai_driver->playback.channels_min = 1;
+		dai_driver->playback.channels_max = ch_cnt_sum << 1;
+	} else {
+		dai_driver->playback.channels_min = 0;
+		dai_driver->playback.channels_max = 0;
+	}
+
+	dev_dbg(&pdev->dev, "%s: sdline 0x%x 0x%x 0x%x 0x%x\n", __func__,
+		dai_data->channel_mode[0], dai_data->channel_mode[1],
+		dai_data->channel_mode[2], dai_data->channel_mode[3]);
+	dev_dbg(&pdev->dev, "%s: playback ch_max %d\n",
+		__func__, dai_driver->playback.channels_max);
+rtn:
+	return rc;
+}
+
+static const struct snd_soc_component_driver msm_q6_meta_mi2s_dai_component = {
+	.name		= "msm-dai-q6-meta-mi2s",
+};
+
+static int msm_dai_q6_meta_mi2s_dev_probe(struct platform_device *pdev)
+{
+	struct msm_dai_q6_meta_mi2s_dai_data *dai_data;
+	const char *q6_meta_mi2s_dev_id = "qcom,msm-dai-q6-meta-mi2s-dev-id";
+	u32 dev_id = 0;
+	u32 meta_mi2s_intf = 0;
+	struct msm_meta_mi2s_pdata *meta_mi2s_pdata;
+	int rc;
+
+	rc = of_property_read_u32(pdev->dev.of_node, q6_meta_mi2s_dev_id,
+				  &dev_id);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"%s: missing %s in dt node\n", __func__,
+			q6_meta_mi2s_dev_id);
+		goto rtn;
+	}
+
+	dev_dbg(&pdev->dev, "dev name %s dev id 0x%x\n", dev_name(&pdev->dev),
+		dev_id);
+
+	switch (dev_id) {
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+		meta_mi2s_intf = 0;
+		break;
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+		meta_mi2s_intf = 1;
+		break;
+	default:
+		dev_err(&pdev->dev,
+			"%s: Invalid META MI2S ID 0x%x from Device Tree\n",
+			__func__, dev_id);
+		rc = -ENXIO;
+		goto rtn;
+	}
+
+	pdev->id = dev_id;
+
+	meta_mi2s_pdata = kzalloc(sizeof(struct msm_meta_mi2s_pdata),
+		GFP_KERNEL);
+	if (!meta_mi2s_pdata) {
+		rc = -ENOMEM;
+		goto rtn;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,msm-mi2s-num-members",
+		&meta_mi2s_pdata->num_member_ports);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: invalid num from DT file %s\n",
+			__func__, "qcom,msm-mi2s-num-members");
+		goto free_pdata;
+	}
+
+	if (meta_mi2s_pdata->num_member_ports >
+		MAX_NUM_I2S_META_PORT_MEMBER_PORTS) {
+		dev_err(&pdev->dev, "%s: num-members %d too large from DT file\n",
+			__func__, meta_mi2s_pdata->num_member_ports);
+		goto free_pdata;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,msm-mi2s-member-id",
+		meta_mi2s_pdata->member_port,
+		meta_mi2s_pdata->num_member_ports);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: member-id from DT file %s\n",
+			__func__, "qcom,msm-mi2s-member-id");
+		goto free_pdata;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,msm-mi2s-rx-lines",
+		meta_mi2s_pdata->sd_lines,
+		meta_mi2s_pdata->num_member_ports);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: Rx line from DT file %s\n",
+			__func__, "qcom,msm-mi2s-rx-lines");
+		goto free_pdata;
+	}
+
+	dev_dbg(&pdev->dev, "dev name %s num-members=%d\n",
+		dev_name(&pdev->dev), meta_mi2s_pdata->num_member_ports);
+	dev_dbg(&pdev->dev, "member array (%d, %d, %d, %d)\n",
+		meta_mi2s_pdata->member_port[0],
+		meta_mi2s_pdata->member_port[1],
+		meta_mi2s_pdata->member_port[2],
+		meta_mi2s_pdata->member_port[3]);
+	dev_dbg(&pdev->dev, "sd-lines array (0x%x, 0x%x, 0x%x, 0x%x)\n",
+		meta_mi2s_pdata->sd_lines[0],
+		meta_mi2s_pdata->sd_lines[1],
+		meta_mi2s_pdata->sd_lines[2],
+		meta_mi2s_pdata->sd_lines[3]);
+
+	meta_mi2s_pdata->intf_id = meta_mi2s_intf;
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_meta_mi2s_dai_data),
+			   GFP_KERNEL);
+	if (!dai_data) {
+		rc = -ENOMEM;
+		goto free_pdata;
+	} else
+		dev_set_drvdata(&pdev->dev, dai_data);
+
+	pdev->dev.platform_data = meta_mi2s_pdata;
+
+	rc = msm_dai_q6_meta_mi2s_platform_data_validation(pdev,
+		&msm_dai_q6_meta_mi2s_dai[meta_mi2s_intf]);
+	if (rc < 0)
+		goto free_dai_data;
+
+	rc = snd_soc_register_component(&pdev->dev,
+		&msm_q6_meta_mi2s_dai_component,
+		&msm_dai_q6_meta_mi2s_dai[meta_mi2s_intf], 1);
+	if (rc < 0)
+		goto err_register;
+	return 0;
+
+err_register:
+	dev_err(&pdev->dev, "fail to %s\n", __func__);
+free_dai_data:
+	kfree(dai_data);
+free_pdata:
+	kfree(meta_mi2s_pdata);
+rtn:
+	return rc;
+}
+
+static int msm_dai_q6_meta_mi2s_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_component(&pdev->dev);
+	return 0;
+}
+
 static const struct snd_soc_component_driver msm_dai_q6_component = {
 	.name		= "msm-dai-q6-dev",
 };
@@ -6627,6 +7401,24 @@
 	},
 };
 
+static const struct of_device_id msm_dai_q6_meta_mi2s_dev_dt_match[] = {
+	{ .compatible = "qcom,msm-dai-q6-meta-mi2s", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_q6_meta_mi2s_dev_dt_match);
+
+static struct platform_driver msm_dai_q6_meta_mi2s_driver = {
+	.probe  = msm_dai_q6_meta_mi2s_dev_probe,
+	.remove  = msm_dai_q6_meta_mi2s_dev_remove,
+	.driver = {
+		.name = "msm-dai-q6-meta-mi2s",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_dai_q6_meta_mi2s_dev_dt_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
 static int msm_dai_q6_spdif_dev_probe(struct platform_device *pdev)
 {
 	int rc, id;
@@ -8540,6 +9332,42 @@
 	return rc;
 }
 
+static unsigned int tdm_param_set_slot_mask(u16 *slot_offset, int slot_width,
+					    int slots_per_frame)
+{
+	unsigned int i = 0;
+	unsigned int slot_index = 0;
+	unsigned long slot_mask = 0;
+	unsigned int slot_width_bytes = slot_width / 8;
+	unsigned int channel_count = AFE_PORT_MAX_AUDIO_CHAN_CNT;
+
+	if (q6core_get_avcs_api_version_per_service(
+		APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V3)
+		channel_count = AFE_PORT_MAX_AUDIO_CHAN_CNT_V2;
+
+	if (slot_width_bytes == 0) {
+		pr_err("%s: slot width is zero\n", __func__);
+		return slot_mask;
+	}
+
+	for (i = 0; i < channel_count; i++) {
+		if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) {
+			slot_index = slot_offset[i] / slot_width_bytes;
+			if (slot_index < slots_per_frame)
+				set_bit(slot_index, &slot_mask);
+			else {
+				pr_err("%s: invalid slot map setting\n",
+				       __func__);
+				return 0;
+			}
+		} else {
+			break;
+		}
+	}
+
+	return slot_mask;
+}
+
 static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
@@ -8644,7 +9472,16 @@
 	 */
 	tdm->nslots_per_frame = tdm_group->nslots_per_frame;
 	tdm->slot_width = tdm_group->slot_width;
-	tdm->slot_mask = tdm_group->slot_mask;
+	if (q6core_get_avcs_api_version_per_service(
+		APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V3)
+		tdm->slot_mask = tdm_param_set_slot_mask(
+					slot_mapping_v2->offset,
+					tdm_group->slot_width,
+					tdm_group->nslots_per_frame);
+	else
+		tdm->slot_mask = tdm_param_set_slot_mask(slot_mapping->offset,
+					tdm_group->slot_width,
+					tdm_group->nslots_per_frame);
 
 	pr_debug("%s: TDM:\n"
 		"num_channels=%d sample_rate=%d bit_width=%d\n"
@@ -11234,8 +12071,8 @@
 		     msm_dai_q6_cdc_dma_format_put),
 	SOC_ENUM_EXT("WSA_CDC_DMA_0 RX XTLoggingDisable",
 		     xt_logging_disable_enum[0],
-		     msm_dai_q6_xt_logging_disable_get,
-		     msm_dai_q6_xt_logging_disable_put),
+		     msm_dai_q6_cdc_dma_xt_logging_disable_get,
+		     msm_dai_q6_cdc_dma_xt_logging_disable_put),
 };
 
 /* SOC probe for codec DMA interface */
@@ -12175,6 +13012,13 @@
 		goto dai_q6_mi2s_drv_fail;
 	}
 
+	rc = platform_driver_register(&msm_dai_q6_meta_mi2s_driver);
+	if (rc) {
+		pr_err("%s: fail to register dai META MI2S dev drv\n",
+			__func__);
+		goto dai_q6_meta_mi2s_drv_fail;
+	}
+
 	rc = platform_driver_register(&msm_dai_mi2s_q6);
 	if (rc) {
 		pr_err("%s: fail to register dai MI2S\n", __func__);
@@ -12224,6 +13068,8 @@
 dai_spdif_q6_fail:
 	platform_driver_unregister(&msm_dai_mi2s_q6);
 dai_mi2s_q6_fail:
+	platform_driver_unregister(&msm_dai_q6_meta_mi2s_driver);
+dai_q6_meta_mi2s_drv_fail:
 	platform_driver_unregister(&msm_dai_q6_mi2s_driver);
 dai_q6_mi2s_drv_fail:
 	platform_driver_unregister(&msm_dai_q6_dev);
@@ -12243,6 +13089,7 @@
 	platform_driver_unregister(&msm_dai_q6_tdm_driver);
 	platform_driver_unregister(&msm_dai_q6_spdif_driver);
 	platform_driver_unregister(&msm_dai_mi2s_q6);
+	platform_driver_unregister(&msm_dai_q6_meta_mi2s_driver);
 	platform_driver_unregister(&msm_dai_q6_mi2s_driver);
 	platform_driver_unregister(&msm_dai_q6_dev);
 	platform_driver_unregister(&msm_dai_q6);
diff --git a/asoc/msm-dai-q6-v2.h b/asoc/msm-dai-q6-v2.h
index b65e4e1..3ad049d 100644
--- a/asoc/msm-dai-q6-v2.h
+++ b/asoc/msm-dai-q6-v2.h
@@ -23,8 +23,8 @@
 #define MSM_TERT_MI2S 2
 #define MSM_QUAT_MI2S  3
 #define MSM_QUIN_MI2S  4
-#define MSM_SEC_MI2S_SD1  5
-#define MSM_SENARY_MI2S  6
+#define MSM_SENARY_MI2S  5
+#define MSM_SEC_MI2S_SD1  6
 #define MSM_INT0_MI2S  7
 #define MSM_INT1_MI2S  8
 #define MSM_INT2_MI2S  9
@@ -38,6 +38,11 @@
 #define MSM_DISPLAY_PORT	0
 #define MSM_DISPLAY_PORT1	1
 
+#define MSM_PRIM_META_MI2S 0
+#define MSM_SEC_META_MI2S  1
+#define MSM_META_MI2S_MIN  MSM_PRIM_META_MI2S
+#define MSM_META_MI2S_MAX  MSM_SEC_META_MI2S
+
 struct msm_dai_auxpcm_config {
 	u16 mode;
 	u16 sync;
@@ -60,6 +65,13 @@
 	u16 intf_id;
 };
 
+struct msm_meta_mi2s_pdata {
+	u32 num_member_ports;
+	u32 member_port[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+	u32 sd_lines[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+	u16 intf_id;
+};
+
 struct msm_i2s_data {
 	u32 capability; /* RX or TX */
 	u16 sd_lines;
diff --git a/asoc/msm-pcm-loopback-v2.c b/asoc/msm-pcm-loopback-v2.c
index 07cf20b..70c94e4 100644
--- a/asoc/msm-pcm-loopback-v2.c
+++ b/asoc/msm-pcm-loopback-v2.c
@@ -252,7 +252,6 @@
 	struct msm_pcm_loopback *pcm = NULL;
 	int ret = 0;
 	uint16_t bits_per_sample = 16;
-	struct msm_pcm_routing_evt event;
 	struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
 	uint32_t param_id;
 	struct msm_pcm_pdata *pdata;
@@ -279,10 +278,6 @@
 	dev_dbg(component->dev, "%s: pcm out open: %d,%d\n", __func__,
 			pcm->instance, substream->stream);
 	if (pcm->instance == 2) {
-		struct snd_soc_pcm_runtime *soc_pcm_rx =
-				pcm->playback_substream->private_data;
-		struct snd_soc_pcm_runtime *soc_pcm_tx =
-				pcm->capture_substream->private_data;
 		if (pcm->audio_client != NULL)
 			stop_pcm(pcm);
 
@@ -314,15 +309,6 @@
 			mutex_unlock(&pcm->lock);
 			return -ENOMEM;
 		}
-		event.event_func = msm_pcm_route_event_handler;
-		event.priv_data = (void *) pcm;
-		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->id,
-			pcm->audio_client->perf_mode,
-			pcm->session_id, pcm->capture_substream->stream);
-		msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->id,
-			pcm->audio_client->perf_mode,
-			pcm->session_id, pcm->playback_substream->stream,
-			event);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			pcm->playback_substream = substream;
 			ret = pcm_loopback_set_volume(pcm, pcm->volume);
@@ -442,7 +428,9 @@
 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
 	struct snd_soc_component *component =
 			snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct msm_pcm_routing_evt event;
 
+	memset(&event, 0, sizeof(event));
 	if (!component) {
 		pr_err("%s: component is NULL\n", __func__);
 		return -EINVAL;
@@ -452,6 +440,12 @@
 
 	dev_dbg(component->dev, "%s: ASM loopback stream:%d\n",
 		__func__, substream->stream);
+
+	if (pcm->playback_start && pcm->capture_start) {
+		mutex_unlock(&pcm->lock);
+		return ret;
+	}
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (!pcm->playback_start)
 			pcm->playback_start = 1;
@@ -459,6 +453,23 @@
 		if (!pcm->capture_start)
 			pcm->capture_start = 1;
 	}
+
+	if (pcm->playback_start && pcm->capture_start) {
+		struct snd_soc_pcm_runtime *soc_pcm_rx =
+				pcm->playback_substream->private_data;
+		struct snd_soc_pcm_runtime *soc_pcm_tx =
+			pcm->capture_substream->private_data;
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) pcm;
+		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->capture_substream->stream);
+		msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->playback_substream->stream,
+			event);
+	}
+
 	mutex_unlock(&pcm->lock);
 
 	return ret;
diff --git a/asoc/msm-pcm-q6-noirq.c b/asoc/msm-pcm-q6-noirq.c
index 6d1d30d..cd69d77 100644
--- a/asoc/msm-pcm-q6-noirq.c
+++ b/asoc/msm-pcm-q6-noirq.c
@@ -181,7 +181,13 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd;
 	int ret = 0;
+	enum apr_subsys_state subsys_state;
 
+	subsys_state = apr_get_subsys_state();
+	if (subsys_state == APR_SUBSYS_DOWN) {
+		pr_debug("%s: adsp is down\n", __func__);
+		return -ENETRESET;
+	}
 	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
 
 	if (prtd == NULL)
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 88ce6bb..7197ad6 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <linux/wait.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -676,6 +677,7 @@
 			snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
 	struct msm_audio *prtd;
 	struct msm_plat_data *pdata;
+	enum apr_subsys_state subsys_state;
 	int ret = 0;
 
 	if (!component) {
@@ -689,6 +691,13 @@
 		pr_err("%s: platform data not populated\n", __func__);
 		return -EINVAL;
 	}
+
+	subsys_state = apr_get_subsys_state();
+	if (subsys_state == APR_SUBSYS_DOWN) {
+		pr_debug("%s: adsp is down\n", __func__);
+		return -ENETRESET;
+	}
+
 	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
 	if (prtd == NULL)
 		return -ENOMEM;
@@ -889,19 +898,25 @@
 
 	pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
 
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+	if (!pdata) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&pdata->lock);
 	if (prtd->audio_client) {
 		dir = IN;
-		if (!component) {
-			pr_err("%s: component is NULL\n", __func__);
-			return -EINVAL;
-		}
 
 		/*
 		 * Unvote to downgrade the Rx thread priority from
 		 * RT Thread for Low-Latency use case.
 		 */
-		pdata = (struct msm_plat_data *)
-			dev_get_drvdata(component->dev);
 		if (pdata) {
 			if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
 				apr_end_rx_rt(prtd->audio_client->apr);
@@ -935,7 +950,7 @@
 	msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
 	kfree(prtd);
 	runtime->private_data = NULL;
-
+	mutex_unlock(&pdata->lock);
 	return 0;
 }
 
@@ -1027,9 +1042,25 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd = runtime->private_data;
+	struct snd_soc_component *component =
+			snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	struct msm_plat_data *pdata;
 	int dir = OUT;
 
 	pr_debug("%s\n", __func__);
+
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+	if (!pdata) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&pdata->lock);
 	if (prtd->audio_client) {
 		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 		q6asm_audio_client_buf_free_contiguous(dir,
@@ -1041,7 +1072,7 @@
 		SNDRV_PCM_STREAM_CAPTURE);
 	kfree(prtd);
 	runtime->private_data = NULL;
-
+	mutex_unlock(&pdata->lock);
 	return 0;
 }
 
@@ -1308,6 +1339,7 @@
 		goto done;
 	}
 
+	mutex_lock(&pdata->lock);
 	event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
 	if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
 	    (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
@@ -1330,6 +1362,7 @@
 		pr_err("%s: failed to send stream event cmd, err = %d\n",
 			__func__, ret);
 done:
+	mutex_unlock(&pdata->lock);
 	return ret;
 }
 
@@ -1505,25 +1538,46 @@
 {
 	int rc = 0;
 	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = NULL;
 	struct snd_pcm_substream *substream =
 		vol->pcm->streams[vol->stream].substream;
+	struct snd_soc_pcm_runtime *soc_prtd = NULL;
+	struct snd_soc_component *component = NULL;
 	struct msm_audio *prtd;
 	int volume = ucontrol->value.integer.value[0];
 
 	pr_debug("%s: volume : 0x%x\n", __func__, volume);
 	if (!substream) {
-		pr_err("%s substream not found\n", __func__);
+		pr_err("%s: substream not found\n", __func__);
 		return -ENODEV;
 	}
-	if (!substream->runtime) {
-		pr_err("%s substream runtime not found\n", __func__);
+
+	soc_prtd = substream->private_data;
+	if (!substream->runtime || !soc_prtd) {
+		pr_err("%s: substream runtime or private_data not found\n",
+				__func__);
 		return 0;
 	}
+
+	component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+	if (!pdata) {
+		pr_err("%s: pdata not found\n", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&pdata->lock);
 	prtd = substream->runtime->private_data;
 	if (prtd) {
 		rc = msm_pcm_set_volume(prtd, volume);
 		prtd->volume = volume;
 	}
+	mutex_unlock(&pdata->lock);
 	return rc;
 }
 
@@ -1703,9 +1757,27 @@
 	substream = snd_pcm_chmap_substream(info, idx);
 	if (!substream)
 		return -ENODEV;
-	if (!substream->runtime)
+
+	rtd = substream->private_data;
+	if (rtd) {
+		component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+		if (component) {
+			pdata = (struct msm_plat_data *)
+						dev_get_drvdata(component->dev);
+			if (!pdata) {
+				pr_err("%s: pdata not found\n", __func__);
+				return -ENODEV;
+			}
+		} else {
+			pr_err("%s: component is NULL\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (!substream->runtime || !rtd)
 		return 0;
 
+	mutex_lock(&pdata->lock);
 	prtd = substream->runtime->private_data;
 	if (prtd) {
 		prtd->set_channel_map = true;
@@ -1714,13 +1786,9 @@
 				(char)(ucontrol->value.integer.value[i]);
 
 		/* update chmixer_pspd chmap cached with routing driver as well */
-		rtd = substream->private_data;
 		if (rtd) {
-			component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 			if (component) {
 				fe_id = rtd->dai_link->id;
-				pdata = (struct msm_plat_data *)
-						dev_get_drvdata(component->dev);
 				chmixer_pspd = pdata ?
 					pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
 
@@ -1734,6 +1802,7 @@
 			}
 		}
 	}
+	mutex_unlock(&pdata->lock);
 	return 0;
 }
 
@@ -1745,16 +1814,37 @@
 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	struct snd_pcm_substream *substream;
 	struct msm_audio *prtd;
+	struct snd_soc_pcm_runtime *rtd = NULL;
+	struct msm_plat_data *pdata = NULL;
+	struct snd_soc_component *component = NULL;
 
 	pr_debug("%s", __func__);
 	substream = snd_pcm_chmap_substream(info, idx);
 	if (!substream)
 		return -ENODEV;
+
+	rtd = substream->private_data;
+	if (rtd) {
+		component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+		if (component) {
+			pdata = (struct msm_plat_data *)
+						dev_get_drvdata(component->dev);
+			if (!pdata) {
+				pr_err("%s: pdata not found\n", __func__);
+				return -ENODEV;
+			}
+		} else {
+			pr_err("%s: component is NULL\n", __func__);
+			return -EINVAL;
+		}
+	}
+
 	memset(ucontrol->value.integer.value, 0,
 		sizeof(ucontrol->value.integer.value));
-	if (!substream->runtime)
+	if (!substream->runtime || !rtd)
 		return 0; /* no channels set */
 
+	mutex_lock(&pdata->lock);
 	prtd = substream->runtime->private_data;
 
 	if (prtd && prtd->set_channel_map == true) {
@@ -1766,6 +1856,7 @@
 			ucontrol->value.integer.value[i] = 0;
 	}
 
+	mutex_unlock(&pdata->lock);
 	return 0;
 }
 
@@ -2035,6 +2126,7 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&pdata->lock);
 	prtd = substream->runtime ? substream->runtime->private_data : NULL;
 	if (chmixer_pspd->enable && prtd) {
 		if (session_type == SESSION_TYPE_RX &&
@@ -2087,6 +2179,7 @@
 	if (reset_override_in_ch_map)
 		chmixer_pspd->override_in_ch_map = false;
 
+	mutex_unlock(&pdata->lock);
 	return ret;
 }
 
@@ -2748,7 +2841,7 @@
 	} else {
 		pdata->perf_mode = LEGACY_PCM_MODE;
 	}
-
+	mutex_init(&pdata->lock);
 	dev_set_drvdata(&pdev->dev, pdata);
 
 
@@ -2771,6 +2864,7 @@
 			kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
 		}
 	}
+	mutex_destroy(&pdata->lock);
 	kfree(pdata);
 	snd_soc_unregister_component(&pdev->dev);
 	return 0;
diff --git a/asoc/msm-pcm-q6-v2.h b/asoc/msm-pcm-q6-v2.h
index 62fcebd..6498f07 100644
--- a/asoc/msm-pcm-q6-v2.h
+++ b/asoc/msm-pcm-q6-v2.h
@@ -117,6 +117,7 @@
 	struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
 	struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
 	struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
+	struct mutex lock;
 };
 
 struct msm_pcm_ch_map {
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index ffd09e8..921bca2 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -80,6 +80,7 @@
 static bool is_custom_stereo_on;
 static bool is_ds2_on;
 static bool swap_ch;
+static bool hifi_filter_enabled;
 static int aanc_level;
 static int num_app_cfg_types;
 static int msm_ec_ref_port_id;
@@ -689,6 +690,10 @@
 	{ SLIMBUS_9_RX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_SLIMBUS_9_RX},
 	{ SLIMBUS_9_TX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_SLIMBUS_9_TX},
 	{ AFE_LOOPBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_AFE_LOOPBACK_TX},
+	{ AFE_PORT_ID_PRIMARY_META_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0,
+	  LPASS_BE_PRI_META_MI2S_RX},
+	{ AFE_PORT_ID_SECONDARY_META_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0,
+	  LPASS_BE_SEC_META_MI2S_RX},
 };
 
 /* Track ASM playback & capture sessions of DAI
@@ -1520,6 +1525,9 @@
 				topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
 			pr_debug("%s: Before adm open topology %d\n", __func__,
 				topology);
+			if (hifi_filter_enabled)
+				bit_width = msm_routing_get_bit_width(
+						SNDRV_PCM_FORMAT_S32_LE);
 
 			copp_idx =
 				adm_open(port_id, path_type, sample_rate,
@@ -1865,6 +1873,9 @@
 			topology = msm_routing_get_adm_topology(fedai_id,
 								session_type,
 								i);
+			if (hifi_filter_enabled)
+				bits_per_sample = msm_routing_get_bit_width(
+							SNDRV_PCM_FORMAT_S32_LE);
 			copp_idx = adm_open(port_id, path_type,
 					    sample_rate, channels, topology,
 					    perf_mode, bits_per_sample,
@@ -2132,6 +2143,9 @@
 								reg);
 			acdb_dev_id =
 			fe_dai_app_type_cfg[val][session_type][reg].acdb_dev_id;
+			if (hifi_filter_enabled)
+				bits_per_sample = msm_routing_get_bit_width(
+							SNDRV_PCM_FORMAT_S32_LE);
 			copp_idx = adm_open(port_id, path_type,
 					    sample_rate, channels, topology,
 					    fdai->perf_mode, bits_per_sample,
@@ -3435,7 +3449,8 @@
 "RX_CDC_DMA_RX_4", "TX_CDC_DMA_TX_4", "RX_CDC_DMA_RX_5", "TX_CDC_DMA_TX_5",
 "RX_CDC_DMA_RX_6", "RX_CDC_DMA_RX_7",
 "PRI_SPDIF_TX", "SEC_SPDIF_RX", "SEC_SPDIF_TX",
-"SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX"
+"SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX", "PRI_META_MI2S_RX",
+"SEC_META_MI2S_RX"
 };
 
 static SOC_ENUM_SINGLE_DECL(mm1_channel_mux,
@@ -5410,6 +5425,10 @@
 		*index = 36;
 		port_id = AFE_PORT_ID_SECONDARY_TDM_TX;
 		break;
+	case 37:
+		*index = 37;
+		port_id = AFE_PORT_ID_HDMI_OVER_DP_RX;
+		break;
 	default:
 		*index = 0; /* NONE */
 		pr_err("%s: Invalid value %d\n", __func__, value);
@@ -5450,9 +5469,10 @@
 	"32000", "44100", "48000", "96000", "192000", "384000"};
 
 static const struct soc_enum msm_route_ec_ref_params_enum[] = {
-	SOC_ENUM_SINGLE_EXT(17, ec_ref_ch_text),
-	SOC_ENUM_SINGLE_EXT(3, ec_ref_bit_format_text),
-	SOC_ENUM_SINGLE_EXT(9, ec_ref_rate_text),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_ch_text), ec_ref_ch_text),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_bit_format_text),
+				ec_ref_bit_format_text),
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rate_text), ec_ref_rate_text),
 };
 
 static const char *const ec_ref_rx[] = { "None", "SLIM_RX", "I2S_RX",
@@ -5462,11 +5482,11 @@
 	"QUAT_TDM_RX_0", "QUAT_TDM_RX_1", "QUAT_TDM_RX_2", "SLIM_6_RX",
 	"TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "USB_AUDIO_RX",
 	"INT0_MI2S_RX", "INT4_MI2S_RX", "INT3_MI2S_TX", "DISPLAY_PORT",
-	"DISPLAY_PORT1",
 	"WSA_CDC_DMA_RX_0", "WSA_CDC_DMA_RX_1",
 	"WSA_CDC_DMA_TX_0", "WSA_CDC_DMA_TX_1", "WSA_CDC_DMA_TX_2",
 	"SLIM_7_RX", "RX_CDC_DMA_RX_0", "RX_CDC_DMA_RX_1", "RX_CDC_DMA_RX_2",
 	"RX_CDC_DMA_RX_3", "TX_CDC_DMA_TX_0", "TERT_TDM_RX_2", "SEC_TDM_TX_0",
+	"DISPLAY_PORT1",
 };
 
 static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
@@ -5662,6 +5682,9 @@
 	case EXT_EC_REF_SLIM_1_TX:
 		ext_ec_ref_port_id = SLIMBUS_1_TX;
 		break;
+	case EXT_EC_REF_PRI_TDM_TX:
+		ext_ec_ref_port_id = AFE_PORT_ID_PRIMARY_TDM_TX;
+		break;
 	case EXT_EC_REF_SEC_TDM_TX:
 		ext_ec_ref_port_id = AFE_PORT_ID_SECONDARY_TDM_TX;
 		break;
@@ -5689,7 +5712,8 @@
 static const char * const ext_ec_ref_rx[] = {"NONE", "PRI_MI2S_TX",
 					"SEC_MI2S_TX", "TERT_MI2S_TX",
 					"QUAT_MI2S_TX", "QUIN_MI2S_TX",
-					"SLIM_1_TX", "SEC_TDM_TX"};
+					"SLIM_1_TX", "PRI_TDM_TX",
+					"SEC_TDM_TX"};
 
 static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ext_ec_ref_rx), ext_ec_ref_rx),
@@ -7138,6 +7162,189 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new pri_meta_mi2s_rx_mixer_controls[] = {
+	SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+
+};
+
+static const struct snd_kcontrol_new sec_meta_mi2s_rx_mixer_controls[] = {
+	SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
 	SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_HDMI_RX,
@@ -21496,16 +21703,16 @@
 				kcontrol->private_value)->shift;
 	int i = 0, j;
 
-	num_app_cfg_types = ucontrol->value.integer.value[i++];
-	memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
-	       sizeof(struct msm_pcm_routing_app_type_data));
-
-	if (num_app_cfg_types > MAX_APP_TYPES) {
+	if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) {
 		pr_err("%s: number of app types exceed the max supported\n",
 			__func__);
 		return -EINVAL;
 	}
 
+	num_app_cfg_types = ucontrol->value.integer.value[i++];
+	memset(lsm_app_type_cfg, 0, MAX_APP_TYPES*
+	       sizeof(struct msm_pcm_routing_app_type_data));
+
 	for (j = 0; j < num_app_cfg_types; j++) {
 		lsm_app_type_cfg[j].app_type =
 				ucontrol->value.integer.value[i++];
@@ -21553,6 +21760,28 @@
 	msm_routing_put_use_ds1_or_ds2_control),
 };
 
+static int msm_routing_get_hifi_filter_control(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = hifi_filter_enabled;
+	return 0;
+}
+
+static int msm_routing_put_hifi_filter_control(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	hifi_filter_enabled = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static const struct snd_kcontrol_new hifi_filter_controls[] = {
+	SOC_SINGLE_EXT("HiFi Filter", SND_SOC_NOPM, 0,
+		1, 0, msm_routing_get_hifi_filter_control,
+		msm_routing_put_hifi_filter_control),
+};
+
 int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol) {
 	int rc = 0;
@@ -23164,6 +23393,10 @@
 				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEN_TDM_TX_7", "Senary TDM7 Capture",
 				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRI_META_MI2S_RX", "Primary META MI2S Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_META_MI2S_RX", "Secondary META MI2S Playback",
+			     0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("WSA_CDC_DMA_RX_0", "WSA CDC DMA0 Playback",
 				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("WSA_CDC_DMA_TX_0", "WSA CDC DMA0 Capture",
@@ -23474,6 +23707,12 @@
 	SND_SOC_DAPM_MIXER("SEN_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				sen_tdm_rx_3_mixer_controls,
 				ARRAY_SIZE(sen_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_META_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_meta_mi2s_rx_mixer_controls,
+				ARRAY_SIZE(pri_meta_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_META_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_meta_mi2s_rx_mixer_controls,
+				ARRAY_SIZE(sec_meta_mi2s_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("WSA_CDC_DMA_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				wsa_cdc_dma_rx_0_mixer_controls,
 				ARRAY_SIZE(wsa_cdc_dma_rx_0_mixer_controls)),
@@ -24697,6 +24936,44 @@
 	{"SEN_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"SEN_MI2S_RX", NULL, "SEN_MI2S_RX Audio Mixer"},
 
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_META_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"},
+	{"PRI_META_MI2S_RX", NULL, "PRI_META_MI2S_RX Audio Mixer"},
+
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_META_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"},
+	{"SEC_META_MI2S_RX", NULL, "SEC_META_MI2S_RX Audio Mixer"},
+
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -26436,6 +26713,7 @@
 	{"VOC_EXT_EC MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"VOC_EXT_EC MUX", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
 	{"VOC_EXT_EC MUX", "SLIM_1_TX",    "SLIMBUS_1_TX"},
+	{"VOC_EXT_EC MUX", "PRI_TDM_TX",   "PRI_TDM_TX_0"},
 	{"VOC_EXT_EC MUX", "SEC_TDM_TX",   "SEC_TDM_TX_0"},
 	{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
 	{"VOICEMMODE1_UL", NULL, "VOC_EXT_EC MUX"},
@@ -28209,6 +28487,9 @@
 				|| (fdai->passthr_mode == COMPRESSED_PASSTHROUGH_IEC61937))
 				topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
 
+			if (hifi_filter_enabled)
+				bits_per_sample = msm_routing_get_bit_width(
+							SNDRV_PCM_FORMAT_S32_LE);
 			copp_idx = adm_open(port_id, path_type,
 					    sample_rate, channels, topology,
 					    fdai->perf_mode, bits_per_sample,
@@ -28809,6 +29090,10 @@
 			ARRAY_SIZE(use_ds1_or_ds2_controls));
 
 	snd_soc_add_component_controls(component,
+			hifi_filter_controls,
+			ARRAY_SIZE(hifi_filter_controls));
+
+	snd_soc_add_component_controls(component,
 				device_pp_params_mixer_controls,
 				ARRAY_SIZE(device_pp_params_mixer_controls));
 
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index c9544cb..8003d91 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -81,6 +81,9 @@
 #define LPASS_BE_SENARY_MI2S_TX "SENARY_MI2S_TX"
 #define LPASS_BE_SENARY_MI2S_RX "SENARY_MI2S_RX"
 
+#define LPASS_BE_PRI_META_MI2S_RX "PRI_META_MI2S_RX"
+#define LPASS_BE_SEC_META_MI2S_RX "SEC_META_MI2S_RX"
+
 #define LPASS_BE_PRI_TDM_RX_0 "PRI_TDM_RX_0"
 #define LPASS_BE_PRI_TDM_TX_0 "PRI_TDM_TX_0"
 #define LPASS_BE_PRI_TDM_RX_1 "PRI_TDM_RX_1"
@@ -494,6 +497,8 @@
 	MSM_BACKEND_DAI_SLIMBUS_9_RX,
 	MSM_BACKEND_DAI_SLIMBUS_9_TX,
 	MSM_BACKEND_DAI_AFE_LOOPBACK_TX,
+	MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
 	MSM_BACKEND_DAI_MAX,
 };
 
@@ -511,6 +516,7 @@
 	EXT_EC_REF_QUAT_MI2S_TX,
 	EXT_EC_REF_QUIN_MI2S_TX,
 	EXT_EC_REF_SLIM_1_TX,
+	EXT_EC_REF_PRI_TDM_TX,
 	EXT_EC_REF_SEC_TDM_TX,
 };
 
diff --git a/asoc/msm-qti-pp-config.c b/asoc/msm-qti-pp-config.c
index d2da56e..89386c4 100644
--- a/asoc/msm-qti-pp-config.c
+++ b/asoc/msm-qti-pp-config.c
@@ -1484,14 +1484,16 @@
 };
 
 static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
-	SOC_SINGLE_MULTI_EXT("Playback Device Channel Map", SND_SOC_NOPM, 0, 47,
-	0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, msm_qti_pp_get_channel_map_mixer,
+	SOC_SINGLE_MULTI_EXT("Playback Device Channel Map", SND_SOC_NOPM,
+	0, PCM_MAX_CHMAP_ID, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8,
+	msm_qti_pp_get_channel_map_mixer,
 	msm_qti_pp_put_channel_map_mixer),
 };
 
 static const struct snd_kcontrol_new multi_ch_channel_map_capture_controls[] = {
-	SOC_SINGLE_MULTI_EXT("Capture Device Channel Map", SND_SOC_NOPM, 0, 47,
-	0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, msm_qti_pp_get_channel_map_capture,
+	SOC_SINGLE_MULTI_EXT("Capture Device Channel Map", SND_SOC_NOPM,
+	0, PCM_MAX_CHMAP_ID, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8,
+	msm_qti_pp_get_channel_map_capture,
 	msm_qti_pp_put_channel_map_capture),
 };
 
diff --git a/asoc/msm-transcode-loopback-q6-v2.c b/asoc/msm-transcode-loopback-q6-v2.c
index 5d572f1..df48f5a 100644
--- a/asoc/msm-transcode-loopback-q6-v2.c
+++ b/asoc/msm-transcode-loopback-q6-v2.c
@@ -426,12 +426,19 @@
 	struct trans_loopback_pdata *pdata;
 	uint32_t bit_width = 16;
 	int ret = 0;
+	enum apr_subsys_state subsys_state;
 
 	if (trans == NULL) {
 		pr_err("%s: Invalid param\n", __func__);
 		return -EINVAL;
 	}
 
+	subsys_state = apr_get_subsys_state();
+	if (subsys_state == APR_SUBSYS_DOWN) {
+		pr_debug("%s: adsp is down\n", __func__);
+		return -ENETRESET;
+	}
+
 	mutex_lock(&trans->lock);
 
 	rtd = snd_pcm_substream_chip(cstream);
diff --git a/asoc/qcs405.c b/asoc/qcs405.c
index cadcd40..18dfb82 100644
--- a/asoc/qcs405.c
+++ b/asoc/qcs405.c
@@ -106,6 +106,12 @@
 };
 
 enum {
+	PRIM_META_MI2S = 0,
+	SEC_META_MI2S,
+	META_MI2S_MAX,
+};
+
+enum {
 	PRIM_AUX_PCM = 0,
 	SEC_AUX_PCM,
 	TERT_AUX_PCM,
@@ -157,6 +163,12 @@
 	Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT
 };
 
+struct meta_mi2s_conf {
+	u32 num_member_ports;
+	u32 member_port[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+	bool clk_enable[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+};
+
 struct dev_config {
 	u32 sample_rate;
 	u32 bit_format;
@@ -402,6 +414,11 @@
 	[SEN_MI2S]  = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
 };
 
+static struct dev_config meta_mi2s_rx_cfg[] = {
+	[PRIM_META_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+	[SEC_META_MI2S]  = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
 /* Default configuration of SPDIF channels */
 static struct dev_config spdif_rx_cfg[] = {
 	[PRIM_SPDIF_RX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -487,6 +504,14 @@
 		"Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
 		"Fourteen", "Fifteen", "Sixteen"
 };
+static const char *const meta_mi2s_ch_text[] = {
+		"One", "Two", "Three", "Four", "Five", "Six", "Seven",
+		"Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
+		"Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen",
+		"Nineteen", "Twenty", "TwentyOne", "TwentyTwo", "TwentyThree",
+		"TwentyFour", "TwentyFive", "TwentySix", "TwentySeven",
+		"TwentyEight", "TwentyNine", "Thirty", "ThirtyOne", "ThirtyTwo"
+};
 static const char *const qos_text[] = {"Disable", "Enable"};
 
 static const char *const cdc_dma_rx_ch_text[] = {"One", "Two"};
@@ -576,6 +601,12 @@
 static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_chs, meta_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_chs, meta_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_rx_0_chs, cdc_dma_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_rx_1_chs, cdc_dma_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text);
@@ -689,6 +720,8 @@
 
 static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
 
+static struct meta_mi2s_conf meta_mi2s_intf_conf[META_MI2S_MAX];
+
 static int msm_island_vad_get_portid_from_beid(int32_t be_id, int *port_id)
 {
 	*port_id = 0xFFFF;
@@ -3070,6 +3103,143 @@
 	return 0;
 }
 
+static int msm_meta_mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+	int idx = 0;
+
+	if (strnstr(kcontrol->id.name, "PRIM_META_MI2S_RX",
+	    sizeof("PRIM_META_MI2S_RX"))) {
+		idx = PRIM_META_MI2S;
+	} else if (strnstr(kcontrol->id.name, "SEC_META_MI2S_RX",
+		   sizeof("SEC_META_MI2S_RX"))) {
+		idx = SEC_META_MI2S;
+	} else {
+		pr_err("%s: unsupported port: %s",
+			__func__, kcontrol->id.name);
+		idx = -EINVAL;
+	}
+
+	return idx;
+}
+
+static int msm_meta_mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] =
+		mi2s_get_sample_rate_val(meta_mi2s_rx_cfg[idx].sample_rate);
+
+	pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].sample_rate,
+		 ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	meta_mi2s_rx_cfg[idx].sample_rate =
+		mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+	pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].sample_rate,
+		 ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] = meta_mi2s_rx_cfg[idx].channels - 1;
+
+	pr_debug("%s: meta_mi2s_[%d]_rx_ch  = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].channels);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	meta_mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+
+	pr_debug("%s: meta_mi2s_[%d]_rx_ch  = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].channels);
+
+	return 1;
+}
+
+static int msm_meta_mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] =
+		mi2s_auxpcm_get_format_value(meta_mi2s_rx_cfg[idx].bit_format);
+
+	pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+		idx, meta_mi2s_rx_cfg[idx].bit_format,
+		ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct snd_soc_card *card = NULL;
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	card = kcontrol->private_data;
+	pdata = snd_soc_card_get_drvdata(card);
+
+	if (idx < 0)
+		return idx;
+
+	/* check for PRIM_META_MI2S and CSRAx to allow 24bit BE config only */
+	if ((idx == PRIM_META_MI2S) && pdata->codec_is_csra) {
+		meta_mi2s_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		pr_debug("%s: Keeping default format idx[%d]_rx_format = %d, item = %d\n",
+			__func__, idx, meta_mi2s_rx_cfg[idx].bit_format,
+			ucontrol->value.enumerated.item[0]);
+	} else {
+		meta_mi2s_rx_cfg[idx].bit_format =
+			mi2s_auxpcm_get_format(
+			ucontrol->value.enumerated.item[0]);
+
+		pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+			idx, meta_mi2s_rx_cfg[idx].bit_format,
+			ucontrol->value.enumerated.item[0]);
+	}
+
+	return 0;
+}
+
 static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -3979,6 +4149,26 @@
 			msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
 	SOC_ENUM_EXT("SEN_MI2S_TX Format", mi2s_tx_format,
 			msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+	SOC_ENUM_EXT("PRIM_META_MI2S_RX SampleRate",
+			prim_meta_mi2s_rx_sample_rate,
+			msm_meta_mi2s_rx_sample_rate_get,
+			msm_meta_mi2s_rx_sample_rate_put),
+	SOC_ENUM_EXT("SEC_META_MI2S_RX SampleRate",
+			sec_meta_mi2s_rx_sample_rate,
+			msm_meta_mi2s_rx_sample_rate_get,
+			msm_meta_mi2s_rx_sample_rate_put),
+	SOC_ENUM_EXT("PRIM_META_MI2S_RX Channels", prim_meta_mi2s_rx_chs,
+			msm_meta_mi2s_rx_ch_get,
+			msm_meta_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("SEC_META_MI2S_RX Channels", sec_meta_mi2s_rx_chs,
+			msm_meta_mi2s_rx_ch_get,
+			msm_meta_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("PRIM_META_MI2S_RX Format", mi2s_rx_format,
+			msm_meta_mi2s_rx_format_get,
+			msm_meta_mi2s_rx_format_put),
+	SOC_ENUM_EXT("SEC_META_MI2S_RX Format", mi2s_rx_format,
+			msm_meta_mi2s_rx_format_get,
+			msm_meta_mi2s_rx_format_put),
 	SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
 			msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
 	SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
@@ -4761,6 +4951,25 @@
 		channels->min = channels->max =
 			mi2s_tx_cfg[SEN_MI2S].channels;
 		break;
+
+	case MSM_BACKEND_DAI_PRI_META_MI2S_RX:
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			meta_mi2s_rx_cfg[PRIM_META_MI2S].bit_format);
+		rate->min = rate->max =
+			meta_mi2s_rx_cfg[PRIM_META_MI2S].sample_rate;
+		channels->min = channels->max =
+			meta_mi2s_rx_cfg[PRIM_META_MI2S].channels;
+		break;
+
+	case MSM_BACKEND_DAI_SEC_META_MI2S_RX:
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			meta_mi2s_rx_cfg[SEC_META_MI2S].bit_format);
+		rate->min = rate->max =
+			meta_mi2s_rx_cfg[SEC_META_MI2S].sample_rate;
+		channels->min = channels->max =
+			meta_mi2s_rx_cfg[SEC_META_MI2S].channels;
+		break;
+
 	case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0:
 	case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_1:
 		idx = msm_cdc_dma_get_idx_from_beid(dai_link->id);
@@ -5063,6 +5272,7 @@
 	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
 	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3");
 	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+	snd_soc_dapm_ignore_suspend(dapm, "lineout booster");
 
 	snd_soc_dapm_sync(dapm);
 
@@ -5996,6 +6206,172 @@
 	mutex_unlock(&mi2s_intf_conf[index].lock);
 }
 
+static int msm_meta_mi2s_set_sclk(struct snd_pcm_substream *substream,
+	int member_id, bool enable)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int be_id = 0;
+	int port_id = 0;
+	int index = cpu_dai->id;
+	u32 bit_per_sample = 0;
+
+	switch (member_id) {
+	case PRIM_MI2S:
+		be_id = MSM_BACKEND_DAI_PRI_MI2S_RX;
+		break;
+	case SEC_MI2S:
+		be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX;
+		break;
+	case TERT_MI2S:
+		be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX;
+		break;
+	case QUAT_MI2S:
+		be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX;
+		break;
+	default:
+		dev_err(rtd->card->dev, "%s: Invalid member_id\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	port_id = msm_get_port_id(be_id);
+	if (port_id < 0) {
+		dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+		ret = port_id;
+		goto err;
+	}
+
+	if (enable) {
+		bit_per_sample =
+			get_mi2s_bits_per_sample(
+				meta_mi2s_rx_cfg[index].bit_format);
+		mi2s_clk[member_id].clk_freq_in_hz =
+			meta_mi2s_rx_cfg[index].sample_rate * 2 *
+			bit_per_sample;
+
+		dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+			mi2s_clk[member_id].clk_freq_in_hz);
+	}
+
+	mi2s_clk[member_id].enable = enable;
+	ret = afe_set_lpass_clock_v2(port_id, &mi2s_clk[member_id]);
+	if (ret < 0) {
+		dev_err(rtd->card->dev,
+			"%s: afe lpass clock failed for port 0x%x , err:%d\n",
+			__func__, port_id, ret);
+		goto err;
+	}
+
+err:
+	return ret;
+}
+
+static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	int i = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int index = cpu_dai->id;
+	int member_port = 0;
+	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	dev_dbg(rtd->card->dev,
+		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
+		__func__, substream->name, substream->stream,
+		cpu_dai->name, cpu_dai->id);
+
+	if (index < PRIM_META_MI2S || index >= META_MI2S_MAX) {
+		ret = -EINVAL;
+		dev_err(rtd->card->dev,
+			"%s: CPU DAI id (%d) out of range\n",
+			__func__, cpu_dai->id);
+		goto err;
+	}
+
+	for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+		member_port = meta_mi2s_intf_conf[index].member_port[i];
+
+		if (!mi2s_intf_conf[member_port].msm_is_mi2s_master) {
+			mi2s_clk[member_port].clk_id =
+				mi2s_ebit_clk[member_port];
+			fmt = SND_SOC_DAIFMT_CBM_CFM;
+		}
+
+		ret = msm_meta_mi2s_set_sclk(substream, member_port, true);
+		if (ret < 0) {
+			dev_err(rtd->card->dev,
+				"%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+				__func__, ret);
+			goto clk_off;
+		}
+		meta_mi2s_intf_conf[index].clk_enable[i] = true;
+
+		if (i == 0) {
+			ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+			if (ret < 0) {
+				pr_err("%s: set fmt cpu dai failed for META_MI2S (%d), err:%d\n",
+					__func__, index, ret);
+				goto clk_off;
+			}
+		}
+		if (pdata->mi2s_gpio_p[member_port])
+			msm_cdc_pinctrl_select_active_state(
+					pdata->mi2s_gpio_p[member_port]);
+	}
+	return 0;
+
+clk_off:
+	for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+		member_port = meta_mi2s_intf_conf[index].member_port[i];
+		if (pdata->mi2s_gpio_p[member_port])
+			msm_cdc_pinctrl_select_sleep_state(
+					pdata->mi2s_gpio_p[member_port]);
+
+		if (meta_mi2s_intf_conf[index].clk_enable[i]) {
+			msm_meta_mi2s_set_sclk(substream, member_port, false);
+			meta_mi2s_intf_conf[index].clk_enable[i] = false;
+		}
+	}
+err:
+	return ret;
+}
+
+static void msm_meta_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	int i = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int index = rtd->cpu_dai->id;
+	int member_port = 0;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	if (index < PRIM_MI2S || index >= MI2S_MAX) {
+		pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+		return;
+	}
+
+	for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+		member_port = meta_mi2s_intf_conf[index].member_port[i];
+
+		if (pdata->mi2s_gpio_p[member_port])
+			msm_cdc_pinctrl_select_sleep_state(
+					pdata->mi2s_gpio_p[member_port]);
+
+		ret = msm_meta_mi2s_set_sclk(substream, member_port, false);
+		if (ret < 0)
+			pr_err("%s:clock disable failed for META MI2S (%d); ret=%d\n",
+				__func__, index, ret);
+	}
+}
+
 static int msm_spdif_set_clk(struct snd_pcm_substream *substream, bool enable)
 {
 	int ret = 0;
@@ -6131,6 +6507,11 @@
 	.shutdown = msm_mi2s_snd_shutdown,
 };
 
+static struct snd_soc_ops msm_meta_mi2s_be_ops = {
+	.startup = msm_meta_mi2s_snd_startup,
+	.shutdown = msm_meta_mi2s_snd_shutdown,
+};
+
 static struct snd_soc_ops msm_auxpcm_be_ops = {
 	.startup = msm_snd_auxpcm_startup,
 };
@@ -7567,6 +7948,39 @@
 
 };
 
+static struct snd_soc_dai_link msm_meta_mi2s_be_dai_links[] = {
+	{
+		.name = LPASS_BE_PRI_META_MI2S_RX,
+		.stream_name = "Primary META MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-meta-mi2s.4864",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_meta_mi2s_be_ops,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_SEC_META_MI2S_RX,
+		.stream_name = "Secondary META MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-meta-mi2s.4866",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_meta_mi2s_be_ops,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+	},
+};
+
 static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
 	/* Primary AUX PCM Backend DAI Links */
 	{
@@ -7885,6 +8299,7 @@
 			 ARRAY_SIZE(msm_tasha_be_dai_links) +
 			 ARRAY_SIZE(msm_wcn_be_dai_links) +
 			 ARRAY_SIZE(msm_mi2s_be_dai_links) +
+			 ARRAY_SIZE(msm_meta_mi2s_be_dai_links) +
 			 ARRAY_SIZE(msm_auxpcm_be_dai_links) +
 			 ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) +
 			 ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) +
@@ -8140,7 +8555,7 @@
 	uint32_t tasha_codec = 0, auxpcm_audio_intf = 0;
 	uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0;
 	uint32_t spdif_audio_intf = 0, wcn_audio_intf = 0;
-	uint32_t afe_loopback_intf = 0;
+	uint32_t afe_loopback_intf = 0, meta_mi2s_intf = 0;
 	const struct of_device_id *match;
 	char __iomem *spdif_cfg, *spdif_pin_ctl;
 	int rc = 0;
@@ -8248,6 +8663,22 @@
 				ARRAY_SIZE(msm_mi2s_be_dai_links);
 			}
 		}
+
+		rc = of_property_read_u32(dev->of_node, "qcom,meta-mi2s-intf",
+					  &meta_mi2s_intf);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match META-MI2S interface\n",
+				__func__);
+		} else {
+			if (meta_mi2s_intf) {
+				memcpy(msm_qcs405_dai_links + total_links,
+				msm_meta_mi2s_be_dai_links,
+				sizeof(msm_meta_mi2s_be_dai_links));
+				total_links +=
+				ARRAY_SIZE(msm_meta_mi2s_be_dai_links);
+			}
+		}
+
 		rc = of_property_read_u32(dev->of_node,
 					  "qcom,auxpcm-audio-intf",
 					  &auxpcm_audio_intf);
@@ -8807,6 +9238,81 @@
 	}
 }
 
+static void msm_meta_mi2s_init(struct platform_device *pdev)
+{
+	int rc = 0;
+	int i = 0;
+	int index = 0;
+	bool parse_of = false;
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct snd_soc_dai_link *dai_link = card->dai_link;
+
+	dev_dbg(&pdev->dev, "%s: read from DT\n", __func__);
+
+	for (index = 0; index < META_MI2S_MAX; index++) {
+		meta_mi2s_intf_conf[index].num_member_ports = 0;
+		meta_mi2s_intf_conf[index].member_port[0] = 0;
+		meta_mi2s_intf_conf[index].member_port[1] = 0;
+		meta_mi2s_intf_conf[index].member_port[2] = 0;
+		meta_mi2s_intf_conf[index].member_port[3] = 0;
+		meta_mi2s_intf_conf[index].clk_enable[0] = false;
+		meta_mi2s_intf_conf[index].clk_enable[1] = false;
+		meta_mi2s_intf_conf[index].clk_enable[2] = false;
+		meta_mi2s_intf_conf[index].clk_enable[3] = false;
+	}
+
+	/* get member port info to set matching clocks for involved ports */
+	for (i = 0; i < card->num_links; i++) {
+		if (dai_link[i].id == MSM_BACKEND_DAI_PRI_META_MI2S_RX) {
+			parse_of = true;
+			index = PRIM_META_MI2S;
+		} else if (dai_link[i].id == MSM_BACKEND_DAI_SEC_META_MI2S_RX) {
+			parse_of = true;
+			index = SEC_META_MI2S;
+		} else {
+			parse_of = false;
+		}
+		if (parse_of && dai_link[i].cpu_of_node) {
+			rc = of_property_read_u32(dai_link[i].cpu_of_node,
+				"qcom,msm-mi2s-num-members",
+				&meta_mi2s_intf_conf[index].num_member_ports);
+			if (rc) {
+				dev_err(&pdev->dev, "%s: invalid num from DT file %s\n",
+					__func__, "qcom,msm-mi2s-num-members");
+			}
+
+			if (meta_mi2s_intf_conf[index].num_member_ports >
+				MAX_NUM_I2S_META_PORT_MEMBER_PORTS) {
+				dev_err(&pdev->dev, "%s: num-members %d too large from DT file\n",
+					__func__,
+					meta_mi2s_intf_conf[index].num_member_ports);
+			}
+
+			if (meta_mi2s_intf_conf[index].num_member_ports > 0) {
+				rc = of_property_read_u32_array(
+					dai_link[i].cpu_of_node,
+					"qcom,msm-mi2s-member-id",
+					meta_mi2s_intf_conf[index].member_port,
+					meta_mi2s_intf_conf[index].num_member_ports);
+				if (rc) {
+					dev_err(&pdev->dev, "%s: member-id from DT file %s\n",
+						__func__,
+						"qcom,msm-mi2s-member-id");
+				}
+			}
+
+			dev_dbg(&pdev->dev, "dev name %s num-members=%d\n",
+				dev_name(&pdev->dev),
+				meta_mi2s_intf_conf[index].num_member_ports);
+			dev_dbg(&pdev->dev, "member array (%d, %d, %d, %d)\n",
+				meta_mi2s_intf_conf[index].member_port[0],
+				meta_mi2s_intf_conf[index].member_port[1],
+				meta_mi2s_intf_conf[index].member_port[2],
+				meta_mi2s_intf_conf[index].member_port[3]);
+		}
+	}
+}
+
 static int msm_scan_i2c_addr(struct platform_device *pdev,
 		uint32_t busnum, uint32_t addr)
 {
@@ -8984,6 +9490,8 @@
 	if (val) {
 		pdata->codec_is_csra = true;
 		mi2s_rx_cfg[PRIM_MI2S].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		meta_mi2s_rx_cfg[PRIM_META_MI2S].bit_format =
+			SNDRV_PCM_FORMAT_S24_LE;
 		ret = msm_init_csra_dev(pdev, card);
 		if (ret)
 			goto err;
@@ -9065,6 +9573,8 @@
 
 	msm_i2s_auxpcm_init(pdev);
 
+	msm_meta_mi2s_init(pdev);
+
 	is_initial_boot = true;
 	return 0;
 err:
diff --git a/dsp/avtimer.c b/dsp/avtimer.c
index 8d9402c..ad5e13a 100644
--- a/dsp/avtimer.c
+++ b/dsp/avtimer.c
@@ -89,6 +89,13 @@
 		}
 
 		payload1 = data->payload;
+
+		if (data->payload_size < 2 * sizeof(uint32_t)) {
+			pr_err("%s: payload has invalid size %d\n",
+				__func__, data->payload_size);
+			return -EINVAL;
+		}
+
 		switch (payload1[0]) {
 		case AVCS_CMD_REMOTE_AVTIMER_RELEASE_REQUEST:
 			pr_debug("%s: Cmd = TIMER RELEASE status[0x%x]\n",
@@ -114,6 +121,11 @@
 	}
 
 	case AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST:
+		if (data->payload_size < sizeof(uint32_t)) {
+			pr_err("%s: payload has invalid size %d\n",
+				__func__, data->payload_size);
+			return -EINVAL;
+		}
 		payload1 = data->payload;
 		pr_debug("%s: RSP_REMOTE_AVTIMER_VOTE_REQUEST handle %x\n",
 			__func__, payload1[0]);
@@ -323,6 +335,11 @@
 	uint64_t avtimer_tick_temp, avtimer_tick, sys_time = 0;
 	struct timespec ts;
 
+	if (!atomic_read(&avtimer.adsp_ready)) {
+		pr_debug("%s:In SSR, return\n", __func__);
+		return -ENETRESET;
+	}
+
 	if ((avtimer.p_avtimer_lsw == NULL) ||
 	    (avtimer.p_avtimer_msw == NULL)) {
 		return -EINVAL;
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 6dbbbc0..b161df9 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -3044,14 +3044,19 @@
 	}
 
 	if ((topology == VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY) ||
-	    (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
-	    (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)||
 	    (topology == VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY)) {
 		if ((rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K) &&
 		    (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K) &&
 		    (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K) &&
 		    (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_48K))
-		rate = 16000;
+			rate = 16000;
+	}
+	if ((topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+	    (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)) {
+		if ((rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_8K) &&
+		    (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K) &&
+		    (rate != ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K))
+			rate = 16000;
 	}
 
 	if (topology == FFECNS_TOPOLOGY) {
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 20ff039..8120536 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -915,6 +915,10 @@
 	case AFE_PORT_ID_SENARY_MI2S_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg);
 		break;
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+		ret_size = SIZEOF_CFG_CMD(afe_param_id_meta_i2s_cfg);
+		break;
 	case HDMI_RX:
 	case DISPLAY_PORT_RX:
 		ret_size =
@@ -4556,6 +4560,10 @@
 	case AFE_PORT_ID_INT6_MI2S_TX:
 		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
 		break;
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+		cfg_type = AFE_PARAM_ID_META_I2S_CONFIG;
+		break;
 	case HDMI_RX:
 	case DISPLAY_PORT_RX:
 		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
@@ -5091,6 +5099,10 @@
 		return IDX_AFE_PORT_ID_INT6_MI2S_RX;
 	case AFE_PORT_ID_INT6_MI2S_TX:
 		return IDX_AFE_PORT_ID_INT6_MI2S_TX;
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+		return IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+		return IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX;
 	case AFE_PORT_ID_VA_CODEC_DMA_TX_0:
 		return IDX_AFE_PORT_ID_VA_CODEC_DMA_TX_0;
 	case AFE_PORT_ID_VA_CODEC_DMA_TX_1:
@@ -5254,6 +5266,10 @@
 	case AFE_PORT_ID_SENARY_MI2S_TX:
 		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
 		break;
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+		cfg_type = AFE_PARAM_ID_META_I2S_CONFIG;
+		break;
 	case HDMI_RX:
 	case DISPLAY_PORT_RX:
 		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
@@ -7231,6 +7247,8 @@
 	case AFE_PORT_ID_QUINARY_MI2S_TX:
 	case AFE_PORT_ID_SENARY_MI2S_RX:
 	case AFE_PORT_ID_SENARY_MI2S_TX:
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
 	case AFE_PORT_ID_PRIMARY_TDM_RX:
 	case AFE_PORT_ID_PRIMARY_TDM_TX:
 	case AFE_PORT_ID_PRIMARY_TDM_RX_1:
@@ -8503,7 +8521,7 @@
 	uint32_t mode;
 
 	if (cal_data == NULL ||
-	    data_size != sizeof(*cal_data) ||
+	    data_size > sizeof(*cal_data) ||
 	    this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
 		goto done;
 
@@ -8647,7 +8665,7 @@
 	int ret = 0;
 
 	if (cal_data == NULL ||
-	    data_size != sizeof(*cal_data) ||
+	    data_size > sizeof(*cal_data) ||
 	    this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
 		return 0;
 
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 37ea0d0..11b307a 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -3542,6 +3542,15 @@
 	case FORMAT_WMA_V10PRO:
 		open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
 		break;
+	case FORMAT_AMRNB:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
+		break;
+	case FORMAT_AMRWB:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
+		break;
+	case FORMAT_AMR_WB_PLUS:
+		open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
+		break;
 	case FORMAT_MP3:
 		open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
 		break;
diff --git a/dsp/q6audio-v2.c b/dsp/q6audio-v2.c
index 8de6060..68b3736 100644
--- a/dsp/q6audio-v2.c
+++ b/dsp/q6audio-v2.c
@@ -337,6 +337,10 @@
 		return IDX_AFE_PORT_ID_INT6_MI2S_RX;
 	case AFE_PORT_ID_INT6_MI2S_TX:
 		return IDX_AFE_PORT_ID_INT6_MI2S_TX;
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+		return IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+		return IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX;
 	case AFE_PORT_ID_WSA_CODEC_DMA_RX_0:
 		return IDX_AFE_PORT_ID_WSA_CODEC_DMA_RX_0;
 	case AFE_PORT_ID_WSA_CODEC_DMA_TX_0:
@@ -487,6 +491,10 @@
 			return AUDIO_PORT_ID_I2S_RX;
 	case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
 			return AFE_PORT_ID_SECONDARY_MI2S_RX_SD1;
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+			return AFE_PORT_ID_PRIMARY_META_MI2S_RX;
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
+			return AFE_PORT_ID_SECONDARY_META_MI2S_RX;
 	case AFE_PORT_ID_PRIMARY_TDM_RX:
 		return AFE_PORT_ID_PRIMARY_TDM_RX;
 	case AFE_PORT_ID_PRIMARY_TDM_TX:
@@ -820,6 +828,8 @@
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 	case AUDIO_PORT_ID_I2S_RX:
 	case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
 	case AFE_PORT_ID_PRIMARY_TDM_RX:
 	case AFE_PORT_ID_PRIMARY_TDM_TX:
 	case AFE_PORT_ID_PRIMARY_TDM_RX_1:
@@ -1048,6 +1058,8 @@
 	case AFE_PORT_ID_QUINARY_MI2S_RX:
 	case AFE_PORT_ID_QUINARY_MI2S_TX:
 	case AFE_PORT_ID_SECONDARY_MI2S_RX_SD1:
+	case AFE_PORT_ID_PRIMARY_META_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_META_MI2S_RX:
 	case AFE_PORT_ID_PRIMARY_TDM_RX:
 	case AFE_PORT_ID_PRIMARY_TDM_TX:
 	case AFE_PORT_ID_PRIMARY_TDM_RX_1:
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index d55dfc3..9c5bf3d 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -285,12 +285,15 @@
 
 static int q6lsm_mmap_apr_dereg(void)
 {
-	if (atomic_read(&lsm_common.apr_users) <= 0) {
-		WARN("%s: APR common port already closed\n", __func__);
-	} else {
-		if (atomic_dec_return(&lsm_common.apr_users) == 0) {
-			apr_deregister(lsm_common.apr);
-			pr_debug("%s: APR De-Register common port\n", __func__);
+	if (lsm_common.apr) {
+		if (atomic_read(&lsm_common.apr_users) <= 0) {
+			WARN("%s: APR common port already closed\n", __func__);
+		} else {
+			if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+				apr_deregister(lsm_common.apr);
+				pr_debug("%s: APR De-Register common port\n",
+					__func__);
+			}
 		}
 	}
 	return 0;
@@ -372,9 +375,9 @@
 		pr_err("%s: Invalid Session %d\n", __func__, client->session);
 		return;
 	}
-	mutex_lock(&session_lock);
 	apr_deregister(client->apr);
 	client->mmap_apr = NULL;
+	mutex_lock(&session_lock);
 	q6lsm_session_free(client);
 	q6lsm_mmap_apr_dereg();
 	mutex_destroy(&client->cmd_lock);
@@ -446,6 +449,8 @@
 	if (wait)
 		mutex_unlock(&lsm_common.apr_lock);
 
+	if (mmap_p && *mmap_p == 0)
+		ret = -ENOMEM;
 	pr_debug("%s: leave ret %d\n", __func__, ret);
 	return ret;
 }
diff --git a/include/asoc/wcd-mbhc-v2.h b/include/asoc/wcd-mbhc-v2.h
index 9341e3d..1f9d64e 100644
--- a/include/asoc/wcd-mbhc-v2.h
+++ b/include/asoc/wcd-mbhc-v2.h
@@ -140,7 +140,6 @@
 #define FW_READ_ATTEMPTS 15
 #define FW_READ_TIMEOUT 4000000
 #define FAKE_REM_RETRY_ATTEMPTS 3
-#define MAX_IMPED 60000
 
 #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS  50
 #define ANC_DETECT_RETRY_CNT 7
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index a9a552e..0fcc76a 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -1505,6 +1505,9 @@
 /* ID of the senary auxiliary PCM Tx port. */
 #define AFE_PORT_ID_SENARY_PCM_TX                0x103F
 
+#define AFE_PORT_ID_PRIMARY_META_MI2S_RX         0x1300
+#define AFE_PORT_ID_SECONDARY_META_MI2S_RX       0x1302
+
 #define AFE_PORT_ID_PRIMARY_SPDIF_RX             0x5000
 #define AFE_PORT_ID_PRIMARY_SPDIF_TX             0x5001
 #define AFE_PORT_ID_SECONDARY_SPDIF_RX           0x5002
@@ -2650,6 +2653,98 @@
 	/* This field must be set to zero. */
 } __packed;
 
+/* This param id is used to configure META I2S interface */
+#define AFE_PARAM_ID_META_I2S_CONFIG 0x000102C5
+#define AFE_API_VERSION_META_I2S_CONFIG 0x1
+#define MAX_NUM_I2S_META_PORT_MEMBER_PORTS 4
+
+/*  Payload of the #AFE_PARAM_ID_META_I2S_CONFIG
+ * command's (I2S configuration
+ * parameter).
+ */
+struct afe_param_id_meta_i2s_cfg {
+	u32     minor_version;
+/* Minor version used for tracking the version of the I2S
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_META_I2S_CONFIG
+ */
+
+	u16     bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+
+	u16     ws_src;
+/* Word select source: internal or external.
+ * Supported values:
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL
+ * - #AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL
+ */
+
+	u32     sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+
+	u16     member_port_id[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+/* Array of member port IDs in this meta device.
+ * Supported values:
+ * - #AFE_PORT_ID_PRIMARY_MI2S_RX
+ * - #AFE_PORT_ID_SECONDARY_MI2S_RX
+ * - #AFE_PORT_ID_TERTIARY_MI2S_RX
+ * - #AFE_PORT_ID_QUATERNY_MI2S_RX
+ * - #AFE_PORT_ID_INVALID
+ *
+ * Fill these values from index 0. Set unused index to AFE_PORT_ID_INVALID.
+ *
+ * Note:
+ * the first member port will act as WS master in case
+ * meta port ws_src is configured as AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL.
+ * In all other cases member ports will act as slave.
+ * This must be considered when HLOS enables the interface clocks
+ */
+
+	u16     member_port_channel_mode[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+/* I2S lines and multichannel operation per member port.
+ * The sequence matches the sequence in member_port_id,
+ * value will be ignored if member port is set to AFE_PORT_ID_INVALID
+ *
+ * Supported values:
+ * - #AFE_PORT_I2S_SD0
+ * - #AFE_PORT_I2S_SD1
+ * - #AFE_PORT_I2S_SD2
+ * - #AFE_PORT_I2S_SD3
+ * - #AFE_PORT_I2S_QUAD01
+ * - #AFE_PORT_I2S_QUAD23
+ * - #AFE_PORT_I2S_6CHS
+ * - #AFE_PORT_I2S_8CHS
+ * - #AFE_PORT_I2S_10CHS
+ * - #AFE_PORT_I2S_12CHS
+ * - #AFE_PORT_I2S_14CHS
+ * - #AFE_PORT_I2S_16CHS
+ * - #AFE_PORT_I2S_SD4
+ * - #AFE_PORT_I2S_SD5
+ * - #AFE_PORT_I2S_SD6
+ * - #AFE_PORT_I2S_SD7
+ * - #AFE_PORT_I2S_QUAD45
+ * - #AFE_PORT_I2S_QUAD67
+ * - #AFE_PORT_I2S_8CHS_2
+ */
+
+	u16     data_format;
+/* data format
+ * Supported values:
+ * - #LINEAR_PCM_DATA
+ */
+	u16     reserved;
+	/* This field must be set to zero. */
+} __packed;
+
 /*
  * This param id is used to configure PCM interface
  */
@@ -4846,6 +4941,7 @@
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
+	struct afe_param_id_meta_i2s_cfg          meta_i2s;
 	struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
 	struct afe_param_id_slimbus_cfg           slim_sch;
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
@@ -5663,9 +5759,7 @@
 /* Left side direct channel. */
 #define PCM_CHANNEL_LSD  33
 
-/* Right side direct channel. Update PCM_MAX_CHMAP_ID when
- * this list is extended.
- */
+/* Right side direct channel. */
 #define PCM_CHANNEL_RSD  34
 
 /* Mark unused channel. */
@@ -5690,7 +5784,7 @@
 #define PCM_MAX_CHANNEL_MAP   63
 
 /* Max valid channel map index */
-#define PCM_MAX_CHMAP_ID PCM_CHANNEL_RSD
+#define PCM_MAX_CHMAP_ID PCM_MAX_CHANNEL_MAP
 
 #define PCM_FORMAT_MAX_NUM_CHANNEL  8
 #define PCM_FORMAT_MAX_CHANNELS_9   9
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index 9504ad6..d1b4f3c 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -281,6 +281,9 @@
 	IDX_AFE_PORT_ID_SENARY_TDM_TX_6,
 	IDX_AFE_PORT_ID_SENARY_TDM_RX_7,
 	IDX_AFE_PORT_ID_SENARY_TDM_TX_7,
+	/* IDX 208-> 209 */
+	IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX,
+	IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX,
 	AFE_MAX_PORTS
 };
 
diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h
index 25c5339..4ec5094 100644
--- a/include/soc/swr-wcd.h
+++ b/include/soc/swr-wcd.h
@@ -22,6 +22,8 @@
 	SWR_REGISTER_WAKE_IRQ,
 	SWR_SET_PORT_MAP,
 	SWR_REQ_CLK_SWITCH,
+	SWR_REGISTER_WAKEUP,
+	SWR_DEREGISTER_WAKEUP,
 };
 
 struct swr_mstr_port {
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index 157e2c5..3aff320 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -23,6 +23,7 @@
 #include "pinctrl-utils.h"
 
 #define LPI_AUTO_SUSPEND_DELAY           100 /* delay in msec */
+#define LPI_AUTO_SUSPEND_DELAY_ERROR     1   /* delay in msec */
 
 #define LPI_ADDRESS_SIZE                 0x20000
 #define LPI_SLEW_ADDRESS_SIZE            0x1000
@@ -824,13 +825,19 @@
 
 	mutex_lock(&state->core_hw_vote_lock);
 	ret = clk_prepare_enable(state->lpass_core_hw_vote);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_set_autosuspend_delay(dev,
+						 LPI_AUTO_SUSPEND_DELAY_ERROR);
 		dev_err(dev, "%s:lpass core hw island enable failed\n",
 			__func__);
-	else
+		goto exit;
+	} else {
 		state->core_hw_vote_status = true;
+	}
 
 	pm_runtime_set_autosuspend_delay(dev, LPI_AUTO_SUSPEND_DELAY);
+
+exit:
 	mutex_unlock(&state->core_hw_vote_lock);
 	return 0;
 }
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index c4deb20..44d245d 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -18,8 +18,6 @@
 #include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
 #include <soc/soundwire.h>
 #include <soc/swr-common.h>
 #include <linux/regmap.h>
@@ -42,6 +40,8 @@
 #define SWR_HSTOP_MAX_VAL 0xF
 #define SWR_HSTART_MIN_VAL 0x0
 
+#define ERR_AUTO_SUSPEND_TIMER_VAL 0x1
+
 #define SWRM_INTERRUPT_STATUS_MASK 0x1FDFD
 /* pm runtime auto suspend timer in msecs */
 static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
@@ -77,30 +77,19 @@
 #define SWRM_MAX_PORT_REG    120
 #define SWRM_MAX_INIT_REG    11
 
-#define SWR_MSTR_MAX_REG_ADDR	0x1740
-#define SWR_MSTR_START_REG_ADDR	0x00
-#define SWR_MSTR_MAX_BUF_LEN     32
-#define BYTES_PER_LINE          12
-#define SWR_MSTR_RD_BUF_LEN      8
-#define SWR_MSTR_WR_BUF_LEN      32
-
 #define MAX_FIFO_RD_FAIL_RETRY 3
 
-static struct swr_mstr_ctrl *dbgswrm;
-static struct dentry *debugfs_swrm_dent;
-static struct dentry *debugfs_peek;
-static struct dentry *debugfs_poke;
-static struct dentry *debugfs_reg_dump;
-static unsigned int read_data;
-
 static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm);
 static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);
+static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
+static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);
 
 static bool swrm_is_msm_variant(int val)
 {
 	return (val == SWRM_VERSION_1_3);
 }
 
+#ifdef CONFIG_DEBUG_FS
 static int swrm_debug_open(struct inode *inode, struct file *file)
 {
 	file->private_data = inode->i_private;
@@ -130,20 +119,32 @@
 	return 0;
 }
 
-static ssize_t swrm_reg_show(char __user *ubuf, size_t count,
-					  loff_t *ppos)
+static ssize_t swrm_reg_show(struct swr_mstr_ctrl *swrm, char __user *ubuf,
+			     size_t count, loff_t *ppos)
 {
 	int i, reg_val, len;
 	ssize_t total = 0;
 	char tmp_buf[SWR_MSTR_MAX_BUF_LEN];
+	int rem = 0;
 
 	if (!ubuf || !ppos)
 		return 0;
 
-	for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_MSTR_START_REG_ADDR);
-		i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
-		reg_val = dbgswrm->read(dbgswrm->handle, i);
+	i = ((int) *ppos + SWR_MSTR_START_REG_ADDR);
+	rem = i%4;
+
+	if (rem)
+		i = (i - rem);
+
+	for (; i <= SWR_MSTR_MAX_REG_ADDR; i += 4) {
+		usleep_range(100, 150);
+		reg_val = swr_master_read(swrm, i);
 		len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i, reg_val);
+		if (len < 0) {
+			pr_err("%s: fail to fill the buffer\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
 		if ((total + len) >= count - 1)
 			break;
 		if (copy_to_user((ubuf + total), tmp_buf, len)) {
@@ -159,85 +160,142 @@
 	return total;
 }
 
-static ssize_t swrm_debug_read(struct file *file, char __user *ubuf,
+static ssize_t swrm_debug_reg_dump(struct file *file, char __user *ubuf,
 				size_t count, loff_t *ppos)
 {
-	char lbuf[SWR_MSTR_RD_BUF_LEN];
-	char *access_str;
-	ssize_t ret_cnt;
+	struct swr_mstr_ctrl *swrm;
 
 	if (!count || !file || !ppos || !ubuf)
 		return -EINVAL;
 
-	access_str = file->private_data;
+	swrm = file->private_data;
+	if (!swrm)
+		return -EINVAL;
+
 	if (*ppos < 0)
 		return -EINVAL;
 
-	if (!strcmp(access_str, "swrm_peek")) {
-		snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
-		ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
-					       strnlen(lbuf, 7));
-	} else if (!strcmp(access_str, "swrm_reg_dump")) {
-		ret_cnt = swrm_reg_show(ubuf, count, ppos);
-	} else {
-		pr_err("%s: %s not permitted to read\n", __func__, access_str);
-		ret_cnt = -EPERM;
-	}
-	return ret_cnt;
+	return swrm_reg_show(swrm, ubuf, count, ppos);
 }
 
-static ssize_t swrm_debug_write(struct file *filp,
-	const char __user *ubuf, size_t cnt, loff_t *ppos)
+static ssize_t swrm_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[SWR_MSTR_RD_BUF_LEN];
+	struct swr_mstr_ctrl *swrm = NULL;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	swrm = file->private_data;
+	if (!swrm)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	snprintf(lbuf, sizeof(lbuf), "0x%x\n", swrm->read_data);
+
+	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+					       strnlen(lbuf, 7));
+}
+
+static ssize_t swrm_debug_peek_write(struct file *file, const char __user *ubuf,
+				     size_t count, loff_t *ppos)
+{
+	char lbuf[SWR_MSTR_RD_BUF_LEN];
+	int rc;
+	u32 param[5];
+	struct swr_mstr_ctrl *swrm = NULL;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	swrm = file->private_data;
+	if (!swrm)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (count > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, count);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[count] = '\0';
+	rc = get_parameters(lbuf, param, 1);
+	if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) && (rc == 0))
+		swrm->read_data = swr_master_read(swrm, param[0]);
+	else
+		rc = -EINVAL;
+
+	if (rc == 0)
+		rc = count;
+	else
+		dev_err(swrm->dev, "%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static ssize_t swrm_debug_write(struct file *file,
+	const char __user *ubuf, size_t count, loff_t *ppos)
 {
 	char lbuf[SWR_MSTR_WR_BUF_LEN];
 	int rc;
 	u32 param[5];
-	char *access_str;
+	struct swr_mstr_ctrl *swrm;
 
-	if (!filp || !ppos || !ubuf)
+	if (!file || !ppos || !ubuf)
 		return -EINVAL;
 
-	access_str = filp->private_data;
-	if (cnt > sizeof(lbuf) - 1)
+	swrm = file->private_data;
+	if (!swrm)
 		return -EINVAL;
 
-	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (count > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, count);
 	if (rc)
 		return -EFAULT;
 
-	lbuf[cnt] = '\0';
-	if (!strcmp(access_str, "swrm_poke")) {
-		/* write */
-		rc = get_parameters(lbuf, param, 2);
-		if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) &&
-			(param[1] <= 0xFFFFFFFF) &&
-			(rc == 0))
-			rc = dbgswrm->write(dbgswrm->handle, param[0],
-					    param[1]);
-		else
-			rc = -EINVAL;
-	} else if (!strcmp(access_str, "swrm_peek")) {
-		/* read */
-		rc = get_parameters(lbuf, param, 1);
-		if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) && (rc == 0))
-			read_data = dbgswrm->read(dbgswrm->handle, param[0]);
-		else
-			rc = -EINVAL;
-	}
+	lbuf[count] = '\0';
+	rc = get_parameters(lbuf, param, 2);
+	if ((param[0] <= SWR_MSTR_MAX_REG_ADDR) &&
+		(param[1] <= 0xFFFFFFFF) &&
+		(rc == 0))
+		swr_master_write(swrm, param[0], param[1]);
+	else
+		rc = -EINVAL;
+
 	if (rc == 0)
-		rc = cnt;
+		rc = count;
 	else
 		pr_err("%s: rc = %d\n", __func__, rc);
 
 	return rc;
 }
 
-static const struct file_operations swrm_debug_ops = {
+static const struct file_operations swrm_debug_read_ops = {
 	.open = swrm_debug_open,
-	.write = swrm_debug_write,
+	.write = swrm_debug_peek_write,
 	.read = swrm_debug_read,
 };
 
+static const struct file_operations swrm_debug_write_ops = {
+	.open = swrm_debug_open,
+	.write = swrm_debug_write,
+};
+
+static const struct file_operations swrm_debug_dump_ops = {
+	.open = swrm_debug_open,
+	.read = swrm_debug_reg_dump,
+};
+#endif
+
 static void swrm_reg_dump(struct swr_mstr_ctrl *swrm,
 			  u32 *reg, u32 *val, int len, const char* func)
 {
@@ -296,6 +354,15 @@
 			ret = -ENODEV;
 			goto exit;
 		}
+		if (swrm->core_vote) {
+			ret = swrm->core_vote(swrm->handle, true);
+			if (ret) {
+				dev_err_ratelimited(swrm->dev,
+					"%s: clock enable req failed",
+					__func__);
+				goto exit;
+			}
+		}
 		swrm->clk_ref_count++;
 		if (swrm->clk_ref_count == 1) {
 			ret = swrm->clk(swrm->handle, true);
@@ -397,7 +464,11 @@
 		mutex_lock(&swrm->iolock);
 		for (i = 0; i < length; i++) {
 		/* wait for FIFO WR command to complete to avoid overflow */
-			usleep_range(100, 105);
+		/*
+		 * Reduce sleep from 100us to 10us to meet KPIs
+		 * This still meets the hardware spec
+		 */
+			usleep_range(10, 12);
 			swr_master_write(swrm, reg_addr[i], val[i]);
 		}
 		mutex_unlock(&swrm->iolock);
@@ -559,7 +630,7 @@
 	 * skip delay if write is handled in platform driver.
 	 */
 	if(!swrm->write)
-		usleep_range(250, 255);
+		usleep_range(150, 155);
 	if (cmd_id == 0xF) {
 		/*
 		 * sleep for 10ms for MSM soundwire variant to allow broadcast
@@ -1407,6 +1478,7 @@
 					continue;
 				if (swr_dev->slave_irq) {
 					do {
+						swr_dev->slave_irq_pending = 0;
 						handle_nested_irq(
 							irq_find_mapping(
 							swr_dev->slave_irq, 0));
@@ -1535,6 +1607,12 @@
 	struct swr_device *swr_dev;
 	struct swr_master *mstr = &swrm->master;
 
+	if (!swrm->dev_up || swrm->state == SWR_MSTR_SSR) {
+		complete(&swrm->broadcast);
+		dev_dbg(swrm->dev, "%s swrm is not up\n", __func__);
+		return IRQ_NONE;
+	}
+
 	if (unlikely(swrm_lock_sleep(swrm) == false)) {
 		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
 		return IRQ_NONE;
@@ -1549,7 +1627,12 @@
 		ret = IRQ_NONE;
 		goto err_audio_hw_vote;
 	}
-	swrm_clk_request(swrm, true);
+	ret = swrm_clk_request(swrm, true);
+	if (ret) {
+		dev_err(dev, "%s: swrm clk failed\n", __func__);
+		ret = IRQ_NONE;
+		goto err_audio_core_vote;
+	}
 	mutex_unlock(&swrm->reslock);
 
 	intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
@@ -1725,6 +1808,7 @@
 
 	mutex_lock(&swrm->reslock);
 	swrm_clk_request(swrm, false);
+err_audio_core_vote:
 	swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
 
 err_audio_hw_vote:
@@ -2113,6 +2197,7 @@
 					swrm->swrm_base_reg, SWRM_MAX_REGISTER);
 	}
 
+	swrm->core_vote = pdata->core_vote;
 	swrm->clk = pdata->clk;
 	if (!swrm->clk) {
 		dev_err(&pdev->dev, "%s: swrm->clk is NULL\n",
@@ -2320,23 +2405,23 @@
 	if (pdev->dev.of_node)
 		of_register_swr_devices(&swrm->master);
 
-	dbgswrm = swrm;
-	debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
-	if (!IS_ERR(debugfs_swrm_dent)) {
-		debugfs_peek = debugfs_create_file("swrm_peek",
-				S_IFREG | 0444, debugfs_swrm_dent,
-				(void *) "swrm_peek", &swrm_debug_ops);
+#ifdef CONFIG_DEBUG_FS
+	swrm->debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
+	if (!IS_ERR(swrm->debugfs_swrm_dent)) {
+		swrm->debugfs_peek = debugfs_create_file("swrm_peek",
+				S_IFREG | 0444, swrm->debugfs_swrm_dent,
+				(void *) swrm, &swrm_debug_read_ops);
 
-		debugfs_poke = debugfs_create_file("swrm_poke",
-				S_IFREG | 0444, debugfs_swrm_dent,
-				(void *) "swrm_poke", &swrm_debug_ops);
+		swrm->debugfs_poke = debugfs_create_file("swrm_poke",
+				S_IFREG | 0444, swrm->debugfs_swrm_dent,
+				(void *) swrm, &swrm_debug_write_ops);
 
-		debugfs_reg_dump = debugfs_create_file("swrm_reg_dump",
-				   S_IFREG | 0444, debugfs_swrm_dent,
-				   (void *) "swrm_reg_dump",
-				   &swrm_debug_ops);
+		swrm->debugfs_reg_dump = debugfs_create_file("swrm_reg_dump",
+				   S_IFREG | 0444, swrm->debugfs_swrm_dent,
+				   (void *) swrm,
+				   &swrm_debug_dump_ops);
 	}
-
+#endif
 	ret = device_init_wakeup(swrm->dev, true);
 	if (ret) {
 		dev_err(swrm->dev, "Device wakeup init failed: %d\n", ret);
@@ -2425,6 +2510,7 @@
 	struct platform_device *pdev = to_platform_device(dev);
 	struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
 	int ret = 0;
+	bool swrm_clk_req_err = false;
 	bool hw_core_err = false;
 	bool aud_core_err = false;
 	struct swr_master *mstr = &swrm->master;
@@ -2458,7 +2544,7 @@
 			 * Set autosuspend timer to 1 for
 			 * master to enter into suspend.
 			 */
-			auto_suspend_timer = 1;
+			swrm_clk_req_err = true;
 			goto exit;
 		}
 		if (!swrm->clk_stop_mode0_supp || swrm->state == SWR_MSTR_SSR) {
@@ -2501,8 +2587,12 @@
 		swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
 	if (!hw_core_err)
 		swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
-	pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
-	auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
+	if (swrm_clk_req_err)
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+				ERR_AUTO_SUSPEND_TIMER_VAL);
+	else
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+				auto_suspend_timer);
 	mutex_unlock(&swrm->reslock);
 
 	return ret;
@@ -2574,7 +2664,12 @@
 			mutex_lock(&swrm->reslock);
 			usleep_range(100, 105);
 		}
-		swrm_clk_request(swrm, false);
+		ret = swrm_clk_request(swrm, false);
+		if (ret) {
+			dev_err(dev, "%s: swrmn clk failed\n", __func__);
+			ret = 0;
+			goto exit;
+		}
 
 		if (swrm->clk_stop_mode0_supp) {
 			if (swrm->wake_irq > 0) {
@@ -2880,6 +2975,14 @@
 			mutex_unlock(&swrm->mlock);
 		}
 		break;
+	case SWR_REGISTER_WAKEUP:
+		msm_aud_evt_blocking_notifier_call_chain(
+					SWR_WAKE_IRQ_REGISTER, (void *)swrm);
+		break;
+	case SWR_DEREGISTER_WAKEUP:
+		msm_aud_evt_blocking_notifier_call_chain(
+					SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
+		break;
 	case SWR_SET_PORT_MAP:
 		if (!data) {
 			dev_err(swrm->dev, "%s: data is NULL for id=%d\n",
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index e05ede2..321e84f 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -11,6 +11,18 @@
 #include <soc/qcom/pm.h>
 #include <soc/swr-common.h>
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_MSTR_MAX_REG_ADDR	0x1740
+#define SWR_MSTR_START_REG_ADDR	0x00
+#define SWR_MSTR_MAX_BUF_LEN     32
+#define BYTES_PER_LINE          12
+#define SWR_MSTR_RD_BUF_LEN      8
+#define SWR_MSTR_WR_BUF_LEN      32
+#endif
+
 #define SWR_ROW_48		0
 #define SWR_ROW_50		1
 #define SWR_ROW_64		2
@@ -91,6 +103,7 @@
 	int (*write)(void *handle, int reg, int val);
 	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
 	int (*clk)(void *handle, bool enable);
+	int (*core_vote)(void *handle, bool enable);
 	int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
 			void *data), void *swr_handle, int type);
 };
@@ -120,6 +133,7 @@
 	int (*write)(void *handle, int reg, int val);
 	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
 	int (*clk)(void *handle, bool enable);
+	int (*core_vote)(void *handle, bool enable);
 	int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
 			void *data), void *swr_handle, int type);
 	int irq;
@@ -160,6 +174,13 @@
 	u32 swr_irq_wakeup_capable;
 	int hw_core_clk_en;
 	int aud_core_clk_en;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_swrm_dent;
+	struct dentry *debugfs_peek;
+	struct dentry *debugfs_poke;
+	struct dentry *debugfs_reg_dump;
+	unsigned int read_data;
+#endif
 };
 
 #endif /* _SWR_WCD_CTRL_H */