Merge "dsp: codecs: fix range check for audio buffer copying"
diff --git a/asoc/codecs/audio-ext-clk-up.c b/asoc/codecs/audio-ext-clk-up.c
index e86b30e..6ed5ddd 100644
--- a/asoc/codecs/audio-ext-clk-up.c
+++ b/asoc/codecs/audio-ext-clk-up.c
@@ -194,6 +194,7 @@
 	"qpnp_clkdiv_1",
 	"pms405_div_clk1",
 	"pm6150_div_clk1",
+	"pm6125_div_clk1",
 };
 
 static int audio_ext_clk_dummy_prepare(struct clk_hw *hw)
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index f1283f3..a21b57b 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -103,7 +103,8 @@
 		goto err;
 	}
 
-	pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+	if (priv->macro_params[VA_MACRO].dev)
+		pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
 	current_mclk_mux_macro =
 		priv->current_mclk_mux_macro[macro_id];
 	if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) {
@@ -125,8 +126,10 @@
 	priv->macro_params[current_mclk_mux_macro].mclk_fn(
 			priv->macro_params[current_mclk_mux_macro].dev, false);
 err:
-	pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev);
-	pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev);
+	if (priv->macro_params[VA_MACRO].dev) {
+		pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev);
+		pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev);
+	}
 	mutex_unlock(&priv->clk_lock);
 	return ret;
 }
@@ -143,7 +146,8 @@
 			"%s: SSR in progress, exit\n", __func__);
 		goto err;
 	}
-	ret = pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+	if (priv->macro_params[VA_MACRO].dev)
+		ret = pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
 	current_mclk_mux_macro =
 		priv->current_mclk_mux_macro[macro_id];
 	if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) {
@@ -165,8 +169,10 @@
 	priv->macro_params[current_mclk_mux_macro].mclk_fn(
 			priv->macro_params[current_mclk_mux_macro].dev, false);
 err:
-	pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev);
-	pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev);
+	if (priv->macro_params[VA_MACRO].dev) {
+		pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev);
+		pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev);
+	}
 	mutex_unlock(&priv->clk_lock);
 	return ret;
 }
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index 4d9ccb4..0352152 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -453,6 +453,10 @@
 	SOC_DAPM_SINGLE("RX AUX VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
 };
 
+static const char * const hph_idle_detect_text[] = {"OFF", "ON"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text);
+
 RX_MACRO_DAPM_ENUM(rx_int0_2, BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1, 0,
 		rx_int_mix_mux_text);
 RX_MACRO_DAPM_ENUM(rx_int1_2, BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG1, 0,
@@ -1684,6 +1688,40 @@
 	}
 }
 
+static int rx_macro_hph_idle_detect_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro_priv *rx_priv = NULL;
+	struct device *rx_dev = NULL;
+
+	if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__))
+		return -EINVAL;
+
+	ucontrol->value.integer.value[0] =
+		rx_priv->idle_det_cfg.hph_idle_detect_en;
+
+	return 0;
+}
+
+static int rx_macro_hph_idle_detect_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct rx_macro_priv *rx_priv = NULL;
+	struct device *rx_dev = NULL;
+
+	if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__))
+		return -EINVAL;
+
+	rx_priv->idle_det_cfg.hph_idle_detect_en =
+		ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
 static int rx_macro_get_compander(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -2611,6 +2649,9 @@
 	SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0,
 		rx_macro_get_compander, rx_macro_set_compander),
 
+	SOC_ENUM_EXT("HPH Idle Detect", hph_idle_detect_enum,
+		rx_macro_hph_idle_detect_get, rx_macro_hph_idle_detect_put),
+
 	SOC_ENUM_EXT("RX_EAR Mode", rx_macro_ear_mode_enum,
 		rx_macro_get_ear_mode, rx_macro_put_ear_mode),
 
@@ -3221,8 +3262,12 @@
 		__func__, (enable ? "enable" : "disable"));
 	if (enable) {
 		if (rx_priv->swr_clk_users == 0) {
+			msm_cdc_pinctrl_select_active_state(
+						rx_priv->rx_swr_gpio_p);
 			ret = rx_macro_mclk_enable(rx_priv, 1, true);
 			if (ret < 0) {
+				msm_cdc_pinctrl_select_sleep_state(
+						rx_priv->rx_swr_gpio_p);
 				dev_err(rx_priv->dev,
 					"%s: rx request clock enable failed\n",
 					__func__);
@@ -3240,8 +3285,6 @@
 					BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
 					0x02, 0x00);
 			rx_priv->reset_swr = false;
-			msm_cdc_pinctrl_select_active_state(
-						rx_priv->rx_swr_gpio_p);
 		}
 		rx_priv->swr_clk_users++;
 	} else {
@@ -3257,9 +3300,9 @@
 			regmap_update_bits(regmap,
 				BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
 				0x01, 0x00);
+			rx_macro_mclk_enable(rx_priv, 0, true);
 			msm_cdc_pinctrl_select_sleep_state(
 						rx_priv->rx_swr_gpio_p);
-			rx_macro_mclk_enable(rx_priv, 0, true);
 		}
 	}
 	dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n",
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index b24721f..58f3689 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -1437,8 +1437,12 @@
 		__func__, (enable ? "enable" : "disable"));
 	if (enable) {
 		if (tx_priv->swr_clk_users == 0) {
+			msm_cdc_pinctrl_select_active_state(
+						tx_priv->tx_swr_gpio_p);
 			ret = tx_macro_mclk_enable(tx_priv, 1);
 			if (ret < 0) {
+				msm_cdc_pinctrl_select_sleep_state(
+						tx_priv->tx_swr_gpio_p);
 				dev_err(tx_priv->dev,
 					"%s: request clock enable failed\n",
 					__func__);
@@ -1456,11 +1460,6 @@
 					BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
 					0x02, 0x00);
 			tx_priv->reset_swr = false;
-			regmap_update_bits(regmap,
-				BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
-				0x1C, 0x0C);
-			msm_cdc_pinctrl_select_active_state(
-						tx_priv->tx_swr_gpio_p);
 		}
 		tx_priv->swr_clk_users++;
 	} else {
@@ -1475,9 +1474,9 @@
 			regmap_update_bits(regmap,
 				BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
 				0x01, 0x00);
+			tx_macro_mclk_enable(tx_priv, 0);
 			msm_cdc_pinctrl_select_sleep_state(
 						tx_priv->tx_swr_gpio_p);
-			tx_macro_mclk_enable(tx_priv, 0);
 		}
 	}
 	dev_dbg(tx_priv->dev, "%s: swrm clock users %d\n",
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 00d3d2c..b0a4b1e 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -2570,8 +2570,12 @@
 		__func__, (enable ? "enable" : "disable"));
 	if (enable) {
 		if (wsa_priv->swr_clk_users == 0) {
+			msm_cdc_pinctrl_select_active_state(
+						wsa_priv->wsa_swr_gpio_p);
 			ret = wsa_macro_mclk_enable(wsa_priv, 1, true);
 			if (ret < 0) {
+				msm_cdc_pinctrl_select_sleep_state(
+						wsa_priv->wsa_swr_gpio_p);
 				dev_err(wsa_priv->dev,
 					"%s: wsa request clock enable failed\n",
 					__func__);
@@ -2589,11 +2593,6 @@
 					BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
 					0x02, 0x00);
 			wsa_priv->reset_swr = false;
-			regmap_update_bits(regmap,
-				BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
-				0x1C, 0x0C);
-			msm_cdc_pinctrl_select_active_state(
-						wsa_priv->wsa_swr_gpio_p);
 		}
 		wsa_priv->swr_clk_users++;
 	} else {
@@ -2608,9 +2607,9 @@
 			regmap_update_bits(regmap,
 				BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
 				0x01, 0x00);
+			wsa_macro_mclk_enable(wsa_priv, 0, true);
 			msm_cdc_pinctrl_select_sleep_state(
 						wsa_priv->wsa_swr_gpio_p);
-			wsa_macro_mclk_enable(wsa_priv, 0, true);
 		}
 	}
 	dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n",
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 6839203..1159b11 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -1,5 +1,5 @@
 // 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>
 #include <linux/init.h>
@@ -850,7 +850,7 @@
 {
 	bool ret = false;
 
-	if (!mbhc->mbhc_cfg->moisture_en ||
+	if (!mbhc->mbhc_cfg->moisture_en &&
 	    !mbhc->mbhc_cfg->moisture_duty_cycle_en)
 		return ret;
 
@@ -1342,9 +1342,15 @@
 	else
 		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
 
+	/* Configure for moisture detection when duty cycle is not enabled.
+	 * Otherwise disable moisture detection.
+	 */
 	if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config
 		&& !mbhc->mbhc_cfg->moisture_duty_cycle_en)
 		mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
+	else if (mbhc->mbhc_cfg->moisture_duty_cycle_en &&
+		 mbhc->mbhc_cb->mbhc_moisture_detect_en)
+		mbhc->mbhc_cb->mbhc_moisture_detect_en(mbhc, false);
 
 	/*
 	 * For USB analog we need to override the switch configuration.
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index ae286bd..beb4b17 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -131,7 +131,9 @@
 				0xFF, 0x3A);
 	snd_soc_component_update_bits(component, WCD937X_RX_OCP_CTL,
 				0x0F, 0x02);
-
+	snd_soc_component_update_bits(component,
+				WCD937X_HPH_SURGE_HPHLR_SURGE_EN,
+				0xFF, 0xD9);
 	return 0;
 }
 
@@ -1507,6 +1509,10 @@
 		wcd937x_get_logical_addr(wcd937x->rx_swr_dev);
 		regcache_mark_dirty(wcd937x->regmap);
 		regcache_sync(wcd937x->regmap);
+		/* Enable surge protection */
+		snd_soc_component_update_bits(component,
+				WCD937X_HPH_SURGE_HPHLR_SURGE_EN,
+				0xFF, 0xD9);
 		/* Initialize MBHC module */
 		mbhc = &wcd937x->mbhc->wcd_mbhc;
 		ret = wcd937x_mbhc_post_ssr_init(wcd937x->mbhc, component);
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index 8ebef1f..8a5622f 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -49,6 +49,10 @@
 };
 
 enum {
+	WCD_ADC1 = 0,
+	WCD_ADC2,
+	WCD_ADC3,
+	WCD_ADC4,
 	ALLOW_BUCK_DISABLE,
 	HPH_COMP_DELAY,
 	HPH_PA_DELAY,
@@ -1227,12 +1231,14 @@
 		default:
 			break;
 		}
+		set_bit(w->shift, &wcd938x->status_mask);
 		wcd938x_tx_connect_port(component, ADC1 + (w->shift), true);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		wcd938x_tx_connect_port(component, ADC1 + (w->shift), false);
 		snd_soc_component_update_bits(component,
 				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00);
+		clear_bit(w->shift, &wcd938x->status_mask);
 		break;
 	};
 
@@ -1469,8 +1475,6 @@
 				void *data)
 {
 	u16 event = (val & 0xffff);
-	u16 amic;
-	u16 mask = 0x40, reg = 0x0;
 	int ret = 0;
 	struct wcd938x_priv *wcd938x = dev_get_drvdata((struct device *)data);
 	struct snd_soc_component *component = wcd938x->component;
@@ -1478,16 +1482,26 @@
 
 	switch (event) {
 	case BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR:
-		amic = (val >> 0x10);
-		if (amic == 0x1 || amic == 0x2)
-			reg = WCD938X_ANA_TX_CH2;
-		else if (amic == 0x3)
-			reg = WCD938X_ANA_TX_CH4;
-		else
-			return 0;
-		if (amic == 0x2)
-			mask = 0x20;
-		snd_soc_component_update_bits(component, reg, mask, 0x00);
+		if (test_bit(WCD_ADC1, &wcd938x->status_mask)) {
+			snd_soc_component_update_bits(component,
+					WCD938X_ANA_TX_CH2, 0x40, 0x00);
+			clear_bit(WCD_ADC1, &wcd938x->status_mask);
+		}
+		if (test_bit(WCD_ADC2, &wcd938x->status_mask)) {
+			snd_soc_component_update_bits(component,
+					WCD938X_ANA_TX_CH2, 0x20, 0x00);
+			clear_bit(WCD_ADC2, &wcd938x->status_mask);
+		}
+		if (test_bit(WCD_ADC3, &wcd938x->status_mask)) {
+			snd_soc_component_update_bits(component,
+					WCD938X_ANA_TX_CH4, 0x40, 0x00);
+			clear_bit(WCD_ADC3, &wcd938x->status_mask);
+		}
+		if (test_bit(WCD_ADC4, &wcd938x->status_mask)) {
+			snd_soc_component_update_bits(component,
+					WCD938X_ANA_TX_CH4, 0x20, 0x00);
+			clear_bit(WCD_ADC4, &wcd938x->status_mask);
+		}
 		break;
 	case BOLERO_WCD_EVT_PA_OFF_PRE_SSR:
 		snd_soc_component_update_bits(component, WCD938X_ANA_HPH,
diff --git a/asoc/kona.c b/asoc/kona.c
index d8c81fc..6935358 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -4058,7 +4058,6 @@
 		.ignore_pmdown_time = 1,
 		.id = MSM_FRONTEND_DAI_MULTIMEDIA3,
 	},
-	/* Hostless PCM purpose */
 	{/* hw:x,5 */
 		.name = "MSM AFE-PCM RX",
 		.stream_name = "AFE-PROXY RX",
@@ -4099,6 +4098,7 @@
 		 /* this dainlink has playback support */
 		.id = MSM_FRONTEND_DAI_MULTIMEDIA4,
 	},
+	/* Hostless PCM purpose */
 	{/* hw:x,8 */
 		.name = "AUXPCM Hostless",
 		.stream_name = "AUXPCM Hostless",
@@ -4486,10 +4486,25 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{/* hw:x,32 */
+		.name = "Tertiary MI2S TX_Hostless",
+		.stream_name = "Tertiary MI2S_TX Hostless Capture",
+		.cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
 };
 
 static struct snd_soc_dai_link msm_bolero_fe_dai_links[] = {
-	{/* hw:x,37 */
+	{/* hw:x,33 */
 		.name = LPASS_BE_WSA_CDC_DMA_TX_0,
 		.stream_name = "WSA CDC DMA0 Capture",
 		.cpu_dai_name = "msm-dai-cdc-dma-dev.45057",
@@ -4505,7 +4520,7 @@
 };
 
 static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
-	{
+	{/* hw:x,34 */
 		.name = MSM_DAILINK_NAME(ASM Loopback),
 		.stream_name = "MultiMedia6",
 		.cpu_dai_name = "MultiMedia6",
@@ -4522,7 +4537,7 @@
 		.ignore_pmdown_time = 1,
 		.id = MSM_FRONTEND_DAI_MULTIMEDIA6,
 	},
-	{
+	{/* hw:x,35 */
 		.name = "USB Audio Hostless",
 		.stream_name = "USB Audio Hostless",
 		.cpu_dai_name = "USBAUDIO_HOSTLESS",
@@ -4538,7 +4553,7 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
-	{
+	{/* hw:x,36 */
 		.name = "SLIMBUS_7 Hostless",
 		.stream_name = "SLIMBUS_7 Hostless",
 		.cpu_dai_name = "SLIMBUS7_HOSTLESS",
@@ -4554,7 +4569,7 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
-	{
+	{/* hw:x,37 */
 		.name = "Compress Capture",
 		.stream_name = "Compress9",
 		.cpu_dai_name = "MultiMedia17",
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 2bde61a..be10bc1 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -101,6 +101,7 @@
 	struct msm_compr_dec_params *dec_params[MSM_FRONTEND_DAI_MAX];
 	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 msm_compr_audio {
@@ -3711,6 +3712,7 @@
 	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
 			snd_soc_component_get_drvdata(comp);
 	int rc = 0, i;
+	struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
 
 	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
 
@@ -3726,6 +3728,17 @@
 		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
 			pdata->ch_map[fe_id]->channel_map[i] =
 				(char)(ucontrol->value.integer.value[i]);
+
+		/* update chmixer_pspd chmap cached with routing driver as well */
+		chmixer_pspd = pdata->chmixer_pspd[fe_id];
+		if (chmixer_pspd && chmixer_pspd->enable) {
+			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+				chmixer_pspd->in_ch_map[i] =
+					pdata->ch_map[fe_id]->channel_map[i];
+			chmixer_pspd->override_in_ch_map = true;
+			msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+					SESSION_TYPE_RX, chmixer_pspd);
+		}
 	} else {
 		pr_debug("%s: no memory for ch_map, default will be set\n",
 			__func__);
@@ -3971,10 +3984,11 @@
 	const char *qdsp_version;
 
 	pr_debug("%s\n", __func__);
-	pdata = (struct msm_compr_pdata *)
-			kzalloc(sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return -ENOMEM;
+	pdata = (struct msm_compr_pdata *) dev_get_drvdata(component->dev);
+	if (!pdata) {
+		pr_err("%s platform data not set\n", __func__);
+		return -EINVAL;
+	}
 
 	snd_soc_component_set_drvdata(component, pdata);
 
@@ -4068,8 +4082,8 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
 	uinfo->value.integer.min = 0;
-	/* See PCM_CHANNEL_RSD=34 in apr_audio-v2.h */
-	uinfo->value.integer.max = 34;
+	/* See PCM_CHANNEL_UNUSED=47 in apr_audio-v2.h */
+	uinfo->value.integer.max = 47;
 	return 0;
 }
 
@@ -4640,6 +4654,580 @@
 	return ret;
 }
 
+static struct msm_pcm_channel_mixer *msm_compr_get_chmixer(
+			struct msm_compr_pdata *pdata, u64 fe_id)
+{
+	if (!pdata) {
+		pr_err("%s: missing pdata\n", __func__);
+		return NULL;
+	}
+
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+		return NULL;
+	}
+
+	return pdata->chmixer_pspd[fe_id];
+}
+
+static int msm_compr_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int ret = 0, i = 0, stream_id = 0, be_id = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_compr_audio *prtd = NULL;
+	struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
+	u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
+	bool reset_override_out_ch_map = false;
+	bool reset_override_in_ch_map = false;
+
+	if ((session_type != SESSION_TYPE_TX) &&
+		(session_type != SESSION_TYPE_RX)) {
+		pr_err("%s: invalid session type %d\n", __func__, session_type);
+		return -EINVAL;
+	}
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->enable = ucontrol->value.integer.value[0];
+	chmixer_pspd->rule = ucontrol->value.integer.value[1];
+	chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
+	chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
+	chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
+
+	if (chmixer_pspd->enable) {
+		if (session_type == SESSION_TYPE_RX &&
+			!chmixer_pspd->override_in_ch_map) {
+			if (pdata->ch_map[fe_id]->set_ch_map) {
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->in_ch_map[i] =
+						pdata->ch_map[fe_id]->channel_map[i];
+			} else {
+				q6asm_map_channels(asm_ch_map,
+					chmixer_pspd->input_channel, false);
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
+			}
+			chmixer_pspd->override_in_ch_map = true;
+			reset_override_in_ch_map = true;
+		} else if (session_type == SESSION_TYPE_TX &&
+				!chmixer_pspd->override_out_ch_map) {
+			if (pdata->ch_map[fe_id]->set_ch_map) {
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->out_ch_map[i] =
+						pdata->ch_map[fe_id]->channel_map[i];
+			} else {
+				q6asm_map_channels(asm_ch_map,
+					chmixer_pspd->output_channel, false);
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
+			}
+			chmixer_pspd->override_out_ch_map = true;
+			reset_override_out_ch_map = true;
+		}
+	} else {
+		chmixer_pspd->override_out_ch_map = false;
+		chmixer_pspd->override_in_ch_map = false;
+	}
+
+	/* cache value and take effect during adm_open stage */
+	msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+			session_type,
+			chmixer_pspd);
+
+	cstream = pdata->cstream[fe_id];
+	if (chmixer_pspd->enable && cstream && cstream->runtime) {
+		prtd = cstream->runtime->private_data;
+		if (!prtd) {
+			pr_err("%s invalid prtd\n", __func__);
+			ret = -EINVAL;
+			goto done;
+		}
+
+		if (prtd->audio_client) {
+			stream_id = prtd->audio_client->session;
+			be_id = chmixer_pspd->port_idx;
+			ret = msm_pcm_routing_set_channel_mixer_runtime(be_id,
+					stream_id, session_type, chmixer_pspd);
+		}
+	}
+
+	if (reset_override_out_ch_map)
+		chmixer_pspd->override_out_ch_map = false;
+	if (reset_override_in_ch_map)
+		chmixer_pspd->override_in_ch_map = false;
+
+done:
+	return ret;
+}
+
+static int msm_compr_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = chmixer_pspd->enable;
+	ucontrol->value.integer.value[1] = chmixer_pspd->rule;
+	ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
+	ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
+	ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
+	return 0;
+}
+
+static int msm_compr_channel_mixer_output_map_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int i = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->override_out_ch_map = true;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->out_ch_map[i] =
+			ucontrol->value.integer.value[i];
+
+	return 0;
+}
+
+static int msm_compr_channel_mixer_output_map_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int i = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->out_ch_map[i];
+	return 0;
+}
+
+static int msm_compr_channel_mixer_input_map_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int i = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->override_in_ch_map = true;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
+
+	return 0;
+}
+
+static int msm_compr_channel_mixer_input_map_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int i = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->in_ch_map[i];
+	return 0;
+}
+
+static int msm_compr_channel_mixer_weight_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int channel = (kcontrol->private_value >> 16) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: invalid channel number %d\n", __func__, channel);
+		return -EINVAL;
+	}
+	channel--;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->channel_weight[channel][i] =
+			ucontrol->value.integer.value[i];
+	return 0;
+}
+
+static int msm_compr_channel_mixer_weight_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int channel = (kcontrol->private_value >> 16) & 0xFF;
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	int i = 0;
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: invalid channel number %d\n", __func__, channel);
+		return -EINVAL;
+	}
+	channel--;
+
+	chmixer_pspd = msm_compr_get_chmixer(pdata, fe_id);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->channel_weight[channel][i];
+	return 0;
+}
+
+static int msm_compr_add_platform_controls(struct snd_kcontrol_new *kctl,
+			struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
+			const char *name_suffix, int session_type, int channels)
+{
+	int ret = -EINVAL;
+	char *mixer_name = NULL;
+	const char *deviceNo = "NN";
+	const char *channelNo = "NN";
+	int ctl_len = 0;
+	struct snd_soc_component *component = NULL;
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
+		strlen(channelNo) + 1 + strlen(name_suffix) + 1;
+
+	mixer_name = kzalloc(ctl_len, GFP_KERNEL);
+	if (mixer_name == NULL)
+		return -ENOMEM;
+
+	if (channels >= 0) {
+		snprintf(mixer_name, ctl_len, "%s %d %s %d",
+			name_prefix, rtd->pcm->device, name_suffix, channels);
+		kctl->private_value = (rtd->dai_link->id) | (channels << 16);
+	} else {
+		snprintf(mixer_name, ctl_len, "%s %d %s",
+			name_prefix, rtd->pcm->device, name_suffix);
+		kctl->private_value = (rtd->dai_link->id);
+	}
+	if (session_type != INVALID_SESSION)
+		kctl->private_value |= (session_type << 8);
+
+	kctl->name = mixer_name;
+	ret = snd_soc_add_component_controls(component, kctl, 1);
+	kfree(mixer_name);
+	return ret;
+}
+
+static int msm_compr_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid channel map value ranges from 1 to 64 */
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 64;
+	return 0;
+}
+
+static int msm_compr_add_channel_mixer_output_map_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Output Map";
+	const char *mixer_ctl_name  = NULL;
+	int ret = 0, session_type = INVALID_SESSION, channel = -1;
+	struct snd_kcontrol_new channel_mixer_output_map_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_channel_mixer_output_map_info,
+		.put = msm_compr_channel_mixer_output_map_ctl_put,
+		.get = msm_compr_channel_mixer_output_map_ctl_get,
+		.private_value = 0,
+	};
+
+	mixer_ctl_name = rtd->compr->direction == SND_COMPRESS_PLAYBACK ?
+			playback_mixer_ctl_name : capture_mixer_ctl_name ;
+	ret = msm_compr_add_platform_controls(&channel_mixer_output_map_control,
+			rtd, mixer_ctl_name, suffix, session_type, channel);
+	if (ret < 0) {
+		pr_err("%s: failed add platform ctl, err = %d\n",
+			 __func__, ret);
+	}
+
+	return ret;
+}
+
+static int msm_compr_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid channel map value ranges from 1 to 64 */
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 64;
+	return 0;
+}
+
+static int msm_compr_add_channel_mixer_input_map_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix = "ChMixer Input Map";
+	const char *mixer_ctl_name  = NULL;
+	int ret = 0, session_type = INVALID_SESSION, channel = -1;
+	struct snd_kcontrol_new channel_mixer_input_map_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_channel_mixer_input_map_info,
+		.put = msm_compr_channel_mixer_input_map_ctl_put,
+		.get = msm_compr_channel_mixer_input_map_ctl_get,
+		.private_value = 0,
+	};
+
+	mixer_ctl_name = rtd->compr->direction == SND_COMPRESS_PLAYBACK ?
+			playback_mixer_ctl_name : capture_mixer_ctl_name ;
+	ret = msm_compr_add_platform_controls(&channel_mixer_input_map_control,
+			rtd, mixer_ctl_name, suffix, session_type, channel);
+	if (ret < 0) {
+		pr_err("%s: failed add platform ctl, err = %d\n",
+			 __func__, ret);
+	}
+
+	return ret;
+}
+
+static int msm_compr_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	/* five int values: enable, rule, in_channels, out_channels and port_id */
+	uinfo->count = 5;
+	/* Valid range is all positive values to support above controls */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = INT_MAX;
+	return 0;
+}
+
+static int msm_compr_add_channel_mixer_cfg_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Cfg";
+	const char *mixer_ctl_name = NULL;
+	int ret = 0, session_type = INVALID_SESSION, channel = -1;
+	struct snd_kcontrol_new channel_mixer_cfg_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_channel_mixer_cfg_info,
+		.put = msm_compr_channel_mixer_cfg_ctl_put,
+		.get = msm_compr_channel_mixer_cfg_ctl_get,
+		.private_value = 0,
+	};
+
+	if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) {
+		session_type = SESSION_TYPE_RX;
+		mixer_ctl_name = playback_mixer_ctl_name;
+	} else {
+		session_type = SESSION_TYPE_TX;
+		mixer_ctl_name = capture_mixer_ctl_name;
+	}
+
+	ret = msm_compr_add_platform_controls(&channel_mixer_cfg_control,
+			rtd, mixer_ctl_name, suffix, session_type, channel);
+	if (ret < 0) {
+		pr_err("%s: failed add platform ctl, err = %d\n",
+			 __func__, ret);
+	}
+
+	return ret;
+}
+
+static int msm_compr_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid range: 0 to 0x4000(Unity) gain weightage */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x4000;
+	return 0;
+}
+
+static int msm_compr_add_channel_mixer_weight_controls(
+		struct snd_soc_pcm_runtime *rtd,
+		int channel)
+{
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Weight Ch";
+	const char *mixer_ctl_name = NULL;
+	int ret = 0, session_type = INVALID_SESSION;
+	struct snd_kcontrol_new channel_mixer_weight_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_channel_mixer_weight_info,
+		.put = msm_compr_channel_mixer_weight_ctl_put,
+		.get = msm_compr_channel_mixer_weight_ctl_get,
+		.private_value = 0,
+	};
+
+	mixer_ctl_name = rtd->compr->direction == SND_COMPRESS_PLAYBACK ?
+			playback_mixer_ctl_name : capture_mixer_ctl_name ;
+	ret = msm_compr_add_platform_controls(&channel_mixer_weight_control,
+			rtd, mixer_ctl_name, suffix, session_type, channel);
+	if (ret < 0) {
+		pr_err("%s: failed add platform ctl, err = %d\n",
+			 __func__, ret);
+	}
+
+	return ret;
+}
+
+static int msm_compr_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	int i, ret = 0;
+	struct msm_compr_pdata *pdata = NULL;
+	struct snd_soc_component *component = NULL;
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		return -EINVAL;
+	}
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = (struct msm_compr_pdata *)
+		snd_soc_component_get_drvdata(component);
+	if (!pdata) {
+		pr_err("%s: platform data not populated\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!pdata->chmixer_pspd[rtd->dai_link->id]) {
+		pdata->chmixer_pspd[rtd->dai_link->id] =
+			kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
+		if (!pdata->chmixer_pspd[rtd->dai_link->id])
+			return -ENOMEM;
+	}
+
+	ret = msm_compr_add_channel_mixer_cfg_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+	ret = msm_compr_add_channel_mixer_input_map_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+	ret = msm_compr_add_channel_mixer_output_map_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+
+	for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
+		ret =  msm_compr_add_channel_mixer_weight_controls(rtd, i);
+		if (ret) {
+			pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
+				__func__, ret);
+			goto fail;
+		}
+	}
+	return 0;
+
+fail:
+	kfree(pdata->chmixer_pspd[rtd->dai_link->id]);
+	pdata->chmixer_pspd[rtd->dai_link->id] = NULL;
+	return ret;
+}
+
 static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
 {
 	int rc;
@@ -4690,6 +5278,10 @@
 	if (rc)
 		pr_err("%s: Could not add Compr Channel Map Control\n",
 			__func__);
+	rc = msm_compr_add_channel_mixer_controls(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr Channel Mixer Controls\n",
+			__func__);
 	return 0;
 }
 
@@ -4717,14 +5309,31 @@
 
 static int msm_compr_dev_probe(struct platform_device *pdev)
 {
+	struct msm_compr_pdata *pdata = NULL;
 
 	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	pdata = (struct msm_compr_pdata *)
+			kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	dev_set_drvdata(&pdev->dev, pdata);
+
 	return snd_soc_register_component(&pdev->dev,
 					&msm_soc_component, NULL, 0);
 }
 
 static int msm_compr_remove(struct platform_device *pdev)
 {
+	int i = 0;
+	struct msm_compr_pdata *pdata = NULL;
+
+	pdata = dev_get_drvdata(&pdev->dev);
+	if (pdata) {
+		for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++)
+			kfree(pdata->chmixer_pspd[i]);
+	}
+	kfree(pdata);
+
 	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 10acd50..c2be85b 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -3226,11 +3226,64 @@
 	return 0;
 }
 
+static int msm_dai_q6_afe_feedback_dec_cfg_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	u32 format_size = 0;
+
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	format_size = sizeof(dai_data->dec_config.format);
+	memcpy(ucontrol->value.bytes.data,
+		&dai_data->dec_config.format,
+		format_size);
+
+	pr_debug("%s: abr_dec_cfg for %d format\n",
+			__func__, dai_data->dec_config.format);
+	memcpy(ucontrol->value.bytes.data + format_size,
+		&dai_data->dec_config.abr_dec_cfg,
+		sizeof(struct afe_imc_dec_enc_info));
+
+	return 0;
+}
+
+static int msm_dai_q6_afe_feedback_dec_cfg_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	u32 format_size = 0;
+
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&dai_data->dec_config, 0x0,
+		sizeof(struct afe_dec_config));
+	format_size = sizeof(dai_data->dec_config.format);
+	memcpy(&dai_data->dec_config.format,
+		ucontrol->value.bytes.data,
+		format_size);
+
+	pr_debug("%s: abr_dec_cfg for %d format\n",
+			__func__, dai_data->dec_config.format);
+	memcpy(&dai_data->dec_config.abr_dec_cfg,
+		ucontrol->value.bytes.data + format_size,
+		sizeof(struct afe_imc_dec_enc_info));
+	dai_data->dec_config.abr_dec_cfg.is_abr_enabled = true;
+	return 0;
+}
+
 static int msm_dai_q6_afe_dec_cfg_get(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
 	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
 	u32 format_size = 0;
+	int ret = 0;
 
 	if (!dai_data) {
 		pr_err("%s: Invalid dai data\n", __func__);
@@ -3247,20 +3300,23 @@
 			&dai_data->dec_config.data,
 			sizeof(struct asm_aac_dec_cfg_v2_t));
 		break;
+	case DEC_FMT_APTX_ADAPTIVE:
+		memcpy(ucontrol->value.bytes.data + format_size,
+			&dai_data->dec_config.data,
+			sizeof(struct asm_aptx_ad_dec_cfg_t));
+		break;
 	case DEC_FMT_SBC:
 	case DEC_FMT_MP3:
 		/* No decoder specific data available */
 		break;
 	default:
-		pr_debug("%s: Default decoder config for %d format: Expect abr_dec_cfg\n",
+		pr_err("%s: Invalid format %d\n",
 				__func__, dai_data->dec_config.format);
-		memcpy(ucontrol->value.bytes.data + format_size,
-			&dai_data->dec_config.abr_dec_cfg,
-			sizeof(struct afe_abr_dec_cfg_t));
-
+		ret = -EINVAL;
 		break;
 	}
-	return 0;
+
+	return ret;
 }
 
 static int msm_dai_q6_afe_dec_cfg_put(struct snd_kcontrol *kcontrol,
@@ -3268,6 +3324,7 @@
 {
 	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
 	u32 format_size = 0;
+	int ret = 0;
 
 	if (!dai_data) {
 		pr_err("%s: Invalid dai data\n", __func__);
@@ -3293,15 +3350,19 @@
 			ucontrol->value.bytes.data + format_size,
 			sizeof(struct asm_sbc_dec_cfg_t));
 		break;
-	default:
-		pr_debug("%s: Default decoder config for %d format: Expect abr_dec_cfg\n",
-				__func__, dai_data->dec_config.format);
-		memcpy(&dai_data->dec_config.abr_dec_cfg,
+	case DEC_FMT_APTX_ADAPTIVE:
+		memcpy(&dai_data->dec_config.data,
 			ucontrol->value.bytes.data + format_size,
-			sizeof(struct afe_abr_dec_cfg_t));
+			sizeof(struct asm_aptx_ad_dec_cfg_t));
+		break;
+	default:
+		pr_err("%s: Invalid format %d\n",
+				__func__, dai_data->dec_config.format);
+		ret = -EINVAL;
 		break;
 	}
-	return 0;
+
+	return ret;
 }
 
 static const struct snd_kcontrol_new afe_dec_config_controls[] = {
@@ -3311,8 +3372,8 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
 		.name = "SLIM_7_TX Decoder Config",
 		.info = msm_dai_q6_afe_dec_cfg_info,
-		.get = msm_dai_q6_afe_dec_cfg_get,
-		.put = msm_dai_q6_afe_dec_cfg_put,
+		.get = msm_dai_q6_afe_feedback_dec_cfg_get,
+		.put = msm_dai_q6_afe_feedback_dec_cfg_put,
 	},
 	{
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c
index 6bf44c4..379b5e5 100644
--- a/asoc/msm-lsm-client.c
+++ b/asoc/msm-lsm-client.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
  */
 #include <linux/init.h>
 #include <linux/err.h>
@@ -1050,7 +1050,7 @@
 		if (ses_data_v2.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
 			dev_err(rtd->dev,
 				"%s:Invalid App id %d for Listen client\n",
-			       __func__, session_data.app_id);
+			       __func__, ses_data_v2.app_id);
 			rc = -EINVAL;
 			break;
 		}
diff --git a/asoc/msm-pcm-loopback-v2.c b/asoc/msm-pcm-loopback-v2.c
index b516634..a686984 100644
--- a/asoc/msm-pcm-loopback-v2.c
+++ b/asoc/msm-pcm-loopback-v2.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -64,6 +64,8 @@
 
 struct msm_pcm_pdata {
 	int perf_mode;
+	struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
+	struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
 };
 
 static void stop_pcm(struct msm_pcm_loopback *pcm);
@@ -734,6 +736,671 @@
 	return 0;
 }
 
+static struct msm_pcm_channel_mixer *msm_pcm_get_chmixer(
+			struct msm_pcm_pdata *pdata,
+			u64 fe_id, int session_type)
+{
+	if (!pdata) {
+		pr_err("%s: missing pdata\n", __func__);
+		return NULL;
+	}
+
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+		return NULL;
+	}
+
+	if ((session_type != SESSION_TYPE_TX) &&
+		(session_type != SESSION_TYPE_RX)) {
+		pr_err("%s: invalid session type %d\n", __func__, session_type);
+		return NULL;
+	}
+
+	return pdata->chmixer_pspd[fe_id][session_type];
+}
+
+static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int ret = 0;
+	int stream_id = 0;
+	int be_id = 0, i = 0;
+	struct msm_pcm_loopback *prtd = NULL;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct snd_pcm *pcm = NULL;
+	struct snd_pcm_substream *substream = NULL;
+	struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
+	u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
+	bool reset_override_out_ch_map = false;
+	bool reset_override_in_ch_map = false;
+
+	pcm = pdata->pcm_device[fe_id];
+	if (!pcm) {
+		pr_err("%s invalid pcm handle for fe_id %llu\n",
+				__func__, fe_id);
+		return -EINVAL;
+	}
+
+	if (session_type == SESSION_TYPE_RX)
+		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	else
+		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	if (!substream) {
+		pr_err("%s substream not found\n", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->enable = ucontrol->value.integer.value[0];
+	chmixer_pspd->rule = ucontrol->value.integer.value[1];
+	chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
+	chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
+	chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
+
+	if (chmixer_pspd->enable) {
+		if (session_type == SESSION_TYPE_RX &&
+			!chmixer_pspd->override_in_ch_map) {
+			q6asm_map_channels(asm_ch_map,
+				chmixer_pspd->input_channel, false);
+			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+				chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
+			chmixer_pspd->override_in_ch_map = true;
+			reset_override_in_ch_map = true;
+		} else if (session_type == SESSION_TYPE_TX &&
+			!chmixer_pspd->override_out_ch_map) {
+			q6asm_map_channels(asm_ch_map,
+				chmixer_pspd->output_channel, false);
+			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+				chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
+			chmixer_pspd->override_out_ch_map = true;
+			reset_override_out_ch_map = true;
+		}
+	} else {
+		chmixer_pspd->override_out_ch_map = false;
+		chmixer_pspd->override_in_ch_map = false;
+	}
+
+	/* cache value and take effect during adm_open stage */
+	msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+			session_type,
+			chmixer_pspd);
+
+	if (chmixer_pspd->enable && substream->runtime) {
+		prtd = substream->runtime->private_data;
+		if (!prtd) {
+			pr_err("%s find invalid prtd fail\n", __func__);
+			ret = -EINVAL;
+			goto done;
+		}
+
+		if (prtd->audio_client) {
+			stream_id = prtd->audio_client->session;
+			be_id = chmixer_pspd->port_idx;
+			msm_pcm_routing_set_channel_mixer_runtime(be_id,
+					stream_id,
+					session_type,
+					chmixer_pspd);
+		}
+	}
+
+	if (reset_override_out_ch_map)
+		chmixer_pspd->override_out_ch_map = false;
+	if (reset_override_in_ch_map)
+		chmixer_pspd->override_in_ch_map = false;
+
+done:
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = chmixer_pspd->enable;
+	ucontrol->value.integer.value[1] = chmixer_pspd->rule;
+	ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
+	ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
+	ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->override_out_ch_map = true;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->out_ch_map[i] =
+			ucontrol->value.integer.value[i];
+
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->out_ch_map[i];
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->override_in_ch_map = true;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
+
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->in_ch_map[i];
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int channel = (kcontrol->private_value >> 16) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: invalid channel number %d\n", __func__, channel);
+		return -EINVAL;
+	}
+	channel--;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->channel_weight[channel][i] =
+			ucontrol->value.integer.value[i];
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int channel = (kcontrol->private_value >> 16) & 0xFF;
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct msm_pcm_pdata *pdata = dev_get_drvdata(component->dev);
+	int i = 0;
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: invalid channel number %d\n", __func__, channel);
+		return -EINVAL;
+	}
+	channel--;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->channel_weight[channel][i];
+	return 0;
+}
+
+static int msm_pcm_add_platform_controls(struct snd_kcontrol_new *kctl,
+			struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
+			const char *name_suffix, int session_type, int channels)
+{
+	int ret = -EINVAL;
+	char *mixer_name = NULL;
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *deviceNo = "NN";
+	const char *channelNo = "NN";
+	int ctl_len = 0;
+	struct snd_soc_component *component = NULL;
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
+		strlen(channelNo) + 1 + strlen(name_suffix) + 1;
+
+	mixer_name = kzalloc(ctl_len, GFP_KERNEL);
+	if (mixer_name == NULL)
+		return -ENOMEM;
+
+	if (channels >= 0) {
+		snprintf(mixer_name, ctl_len, "%s %d %s %d",
+			name_prefix, pcm->device, name_suffix, channels);
+		kctl->private_value = (rtd->dai_link->id) | (session_type << 8) |
+							(channels << 16);
+	} else {
+		snprintf(mixer_name, ctl_len, "%s %d %s",
+			name_prefix, pcm->device, name_suffix);
+		kctl->private_value = (rtd->dai_link->id) | (session_type << 8);
+	}
+
+	kctl->name = mixer_name;
+	ret = snd_soc_add_component_controls(component, kctl, 1);
+	kfree(mixer_name);
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid channel map value ranges from 1 to 64 */
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 64;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_output_map_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Output Map";
+	int session_type = 0, ret = 0, channel = -1;
+	struct snd_kcontrol_new channel_mixer_output_map_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_output_map_info,
+		.put = msm_pcm_channel_mixer_output_map_ctl_put,
+		.get = msm_pcm_channel_mixer_output_map_ctl_get,
+		.private_value = 0,
+	};
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid channel map value ranges from 1 to 64 */
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 64;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_input_map_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix = "ChMixer Input Map";
+	int session_type = 0, ret = 0, channel = -1;
+	struct snd_kcontrol_new channel_mixer_input_map_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_input_map_info,
+		.put = msm_pcm_channel_mixer_input_map_ctl_put,
+		.get = msm_pcm_channel_mixer_input_map_ctl_get,
+		.private_value = 0,
+	};
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	/* five int values: enable, rule, in_channels, out_channels and port_id */
+	uinfo->count = 5;
+	/* Valid range is all positive values to support above controls */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = INT_MAX;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_cfg_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Cfg";
+	int session_type = 0, ret = 0, channel = -1;
+	struct msm_pcm_pdata *pdata = NULL;
+	struct snd_soc_component *component = NULL;
+	struct snd_kcontrol_new channel_mixer_cfg_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_cfg_info,
+		.put = msm_pcm_channel_mixer_cfg_ctl_put,
+		.get = msm_pcm_channel_mixer_cfg_ctl_get,
+		.private_value = 0,
+	};
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+	pdata = (struct msm_pcm_pdata *)
+		dev_get_drvdata(component->dev);
+	if (pdata == NULL) {
+		pr_err("%s: platform data not populated\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid range: 0 to 0x4000(Unity) gain weightage */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x4000;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_weight_controls(
+		struct snd_soc_pcm_runtime *rtd,
+		int channel)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Weight Ch";
+	int session_type = 0, ret = 0;
+	struct snd_kcontrol_new channel_mixer_weight_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_weight_info,
+		.put = msm_pcm_channel_mixer_weight_ctl_put,
+		.get = msm_pcm_channel_mixer_weight_ctl_get,
+		.private_value = 0,
+	};
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+
+	return ret;
+}
+
+static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	int i, ret = 0;
+	struct snd_pcm *pcm = NULL;
+	struct msm_pcm_pdata *pdata = NULL;
+	struct snd_soc_component *component = NULL;
+
+	if (!rtd || !rtd->pcm) {
+		pr_err("%s invalid rtd or pcm\n", __func__);
+		return -EINVAL;
+	}
+	pcm = rtd->pcm;
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = (struct msm_pcm_pdata *)
+				dev_get_drvdata(component->dev);
+	if (!pdata) {
+		pr_err("%s: platform data not populated\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream &&
+		!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
+		pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] =
+			kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
+		if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
+		!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
+		pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] =
+			kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
+		if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+	ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+	ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+
+	for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
+		ret =  msm_pcm_add_channel_mixer_weight_controls(rtd, i);
+		if (ret) {
+			pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
+					__func__, ret);
+			goto fail;
+		}
+	}
+	return 0;
+
+fail:
+	kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]);
+	kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
+	pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
+	pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
+
+	return ret;
+}
+
 static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret = 0;
@@ -747,6 +1414,11 @@
 	if (ret)
 		pr_err("%s: pcm add app type controls failed:%d\n",
 			__func__, ret);
+
+	ret = msm_pcm_add_channel_mixer_controls(rtd);
+	if (ret)
+		pr_err("%s: pcm add channel mixer controls failed:%d\n",
+			__func__, ret);
 	return ret;
 }
 
@@ -797,6 +1469,17 @@
 
 static int msm_pcm_remove(struct platform_device *pdev)
 {
+	struct msm_pcm_pdata *pdata;
+	int i = 0;
+
+	pdata = dev_get_drvdata(&pdev->dev);
+	if (pdata) {
+		for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
+			kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
+			kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
+		}
+	}
+	kfree(pdata);
 	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 5886736..bea58c9 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -1601,6 +1601,11 @@
 	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 msm_pcm_channel_mixer *chmixer_pspd = NULL;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u64 fe_id = 0;
 
 	pr_debug("%s", __func__);
 	substream = snd_pcm_chmap_substream(info, idx);
@@ -1615,6 +1620,24 @@
 			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
 				prtd->channel_map[i] =
 				(char)(ucontrol->value.integer.value[i]);
+
+		/* update chmixer_pspd chmap cached with routing driver as well */
+		rtd = substream->private_data;
+		if (rtd) {
+			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;
+
+			if (chmixer_pspd && chmixer_pspd->enable) {
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
+				chmixer_pspd->override_in_ch_map = true;
+				msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+						SESSION_TYPE_RX, chmixer_pspd);
+			}
+		}
 	}
 	return 0;
 }
@@ -1838,6 +1861,674 @@
 	return 0;
 }
 
+static struct msm_pcm_channel_mixer *msm_pcm_get_chmixer(
+			struct msm_plat_data *pdata,
+			u64 fe_id, int session_type)
+{
+	if (!pdata) {
+		pr_err("%s: missing pdata\n", __func__);
+		return NULL;
+	}
+
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+		return NULL;
+	}
+
+	if ((session_type != SESSION_TYPE_TX) &&
+		(session_type != SESSION_TYPE_RX)) {
+		pr_err("%s: invalid session type %d\n", __func__, session_type);
+		return NULL;
+	}
+
+	return pdata->chmixer_pspd[fe_id][session_type];
+}
+
+static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int ret = 0;
+	int stream_id = 0;
+	int be_id = 0, i = 0;
+	struct msm_audio *prtd = NULL;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct snd_pcm *pcm = NULL;
+	struct snd_pcm_substream *substream = NULL;
+	struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
+	u8 asm_ch_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
+	bool reset_override_out_ch_map = false;
+	bool reset_override_in_ch_map = false;
+
+	pcm = pdata->pcm_device[fe_id];
+	if (!pcm) {
+		pr_err("%s invalid pcm handle for fe_id %llu\n",
+				__func__, fe_id);
+		return -EINVAL;
+	}
+
+	if (session_type == SESSION_TYPE_RX)
+		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	else
+		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	if (!substream) {
+		pr_err("%s substream not found\n", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->enable = ucontrol->value.integer.value[0];
+	chmixer_pspd->rule = ucontrol->value.integer.value[1];
+	chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
+	chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
+	chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
+
+	if (chmixer_pspd->enable) {
+		if (session_type == SESSION_TYPE_RX &&
+			!chmixer_pspd->override_in_ch_map) {
+			if (pdata->ch_map[fe_id] &&
+				pdata->ch_map[fe_id]->set_ch_map) {
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->in_ch_map[i] =
+						pdata->ch_map[fe_id]->channel_map[i];
+			} else {
+				q6asm_map_channels(asm_ch_map,
+					chmixer_pspd->input_channel, false);
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->in_ch_map[i] = asm_ch_map[i];
+			}
+			chmixer_pspd->override_in_ch_map = true;
+			reset_override_in_ch_map = true;
+		} else if (session_type == SESSION_TYPE_TX &&
+				!chmixer_pspd->override_out_ch_map) {
+			if (pdata->ch_map[fe_id] &&
+				pdata->ch_map[fe_id]->set_ch_map) {
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->out_ch_map[i] =
+						pdata->ch_map[fe_id]->channel_map[i];
+			} else {
+				q6asm_map_channels(asm_ch_map,
+					chmixer_pspd->output_channel, false);
+				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+					chmixer_pspd->out_ch_map[i] = asm_ch_map[i];
+			}
+			chmixer_pspd->override_out_ch_map = true;
+			reset_override_out_ch_map = true;
+		}
+	} else {
+		chmixer_pspd->override_out_ch_map = false;
+		chmixer_pspd->override_in_ch_map = false;
+	}
+
+	/* cache value and take effect during adm_open stage */
+	msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+			session_type,
+			chmixer_pspd);
+
+	if (chmixer_pspd->enable && substream->runtime) {
+		prtd = substream->runtime->private_data;
+		if (!prtd) {
+			pr_err("%s find invalid prtd fail\n", __func__);
+			ret = -EINVAL;
+			goto done;
+		}
+
+		if (prtd->audio_client) {
+			stream_id = prtd->audio_client->session;
+			be_id = chmixer_pspd->port_idx;
+			msm_pcm_routing_set_channel_mixer_runtime(be_id,
+					stream_id,
+					session_type,
+					chmixer_pspd);
+		}
+	}
+
+	if (reset_override_out_ch_map)
+		chmixer_pspd->override_out_ch_map = false;
+	if (reset_override_in_ch_map)
+		chmixer_pspd->override_in_ch_map = false;
+
+done:
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = chmixer_pspd->enable;
+	ucontrol->value.integer.value[1] = chmixer_pspd->rule;
+	ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
+	ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
+	ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->override_out_ch_map = true;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->out_ch_map[i] =
+			ucontrol->value.integer.value[i];
+
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->out_ch_map[i];
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	chmixer_pspd->override_in_ch_map = true;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
+
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->in_ch_map[i];
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_put(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int channel = (kcontrol->private_value >> 16) & 0xFF;
+	int i = 0;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: invalid channel number %d\n", __func__, channel);
+		return -EINVAL;
+	}
+	channel--;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		chmixer_pspd->channel_weight[channel][i] =
+			ucontrol->value.integer.value[i];
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_get(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	u64 fe_id = kcontrol->private_value & 0xFF;
+	int session_type = (kcontrol->private_value >> 8) & 0xFF;
+	int channel = (kcontrol->private_value >> 16) & 0xFF;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct msm_plat_data *pdata = dev_get_drvdata(component->dev);
+	int i = 0;
+	struct msm_pcm_channel_mixer *chmixer_pspd;
+
+	if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: invalid channel number %d\n", __func__, channel);
+		return -EINVAL;
+	}
+	channel--;
+
+	chmixer_pspd = msm_pcm_get_chmixer(pdata, fe_id, session_type);
+	if (!chmixer_pspd) {
+		pr_err("%s: invalid chmixer_pspd in pdata", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			chmixer_pspd->channel_weight[channel][i];
+	return 0;
+}
+
+static int msm_pcm_add_platform_controls(struct snd_kcontrol_new *kctl,
+			struct snd_soc_pcm_runtime *rtd, const char *name_prefix,
+			const char *name_suffix, int session_type, int channels)
+{
+	int ret = -EINVAL;
+	char *mixer_name = NULL;
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *deviceNo = "NN";
+	const char *channelNo = "NN";
+	int ctl_len = 0;
+	struct snd_soc_component *component = NULL;
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl_len = strlen(name_prefix) + 1 + strlen(deviceNo) + 1 +
+		strlen(channelNo) + 1 + strlen(name_suffix) + 1;
+
+	mixer_name = kzalloc(ctl_len, GFP_KERNEL);
+	if (mixer_name == NULL)
+		return -ENOMEM;
+
+	if (channels >= 0) {
+		snprintf(mixer_name, ctl_len, "%s %d %s %d",
+			name_prefix, pcm->device, name_suffix, channels);
+		kctl->private_value = (rtd->dai_link->id) | (session_type << 8) |
+							(channels << 16);
+	} else {
+		snprintf(mixer_name, ctl_len, "%s %d %s",
+			name_prefix, pcm->device, name_suffix);
+		kctl->private_value = (rtd->dai_link->id) | (session_type << 8);
+	}
+
+	kctl->name = mixer_name;
+	ret = snd_soc_add_component_controls(component, kctl, 1);
+	kfree(mixer_name);
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid channel map value ranges from 1 to 64 */
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 64;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_output_map_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Output Map";
+	int session_type = 0, ret = 0, channel = -1;
+	struct snd_kcontrol_new channel_mixer_output_map_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_output_map_info,
+		.put = msm_pcm_channel_mixer_output_map_ctl_put,
+		.get = msm_pcm_channel_mixer_output_map_ctl_get,
+		.private_value = 0,
+	};
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_output_map_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid channel map value ranges from 1 to 64 */
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 64;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_input_map_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix = "ChMixer Input Map";
+	int session_type = 0, ret = 0, channel = -1;
+	struct snd_kcontrol_new channel_mixer_input_map_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_input_map_info,
+		.put = msm_pcm_channel_mixer_input_map_ctl_put,
+		.get = msm_pcm_channel_mixer_input_map_ctl_get,
+		.private_value = 0,
+	};
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_input_map_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	/* five int values: enable, rule, in_channels, out_channels and port_id */
+	uinfo->count = 5;
+	/* Valid range is all positive values to support above controls */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = INT_MAX;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_cfg_controls(
+		struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Cfg";
+	int session_type = 0, ret = 0, channel = -1;
+	struct msm_plat_data *pdata = NULL;
+	struct snd_soc_component *component = NULL;
+	struct snd_kcontrol_new channel_mixer_cfg_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_cfg_info,
+		.put = msm_pcm_channel_mixer_cfg_ctl_put,
+		.get = msm_pcm_channel_mixer_cfg_ctl_get,
+		.private_value = 0,
+	};
+
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = (struct msm_plat_data *)
+		dev_get_drvdata(component->dev);
+
+	pdata->pcm_device[rtd->dai_link->id] = rtd->pcm;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_cfg_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+
+	return ret;
+}
+
+static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V8;
+	/* Valid range: 0 to 0x4000(Unity) gain weightage */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x4000;
+	return 0;
+}
+
+static int msm_pcm_add_channel_mixer_weight_controls(
+		struct snd_soc_pcm_runtime *rtd,
+		int channel)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	const char *playback_mixer_ctl_name	= "AudStr";
+	const char *capture_mixer_ctl_name	= "AudStr Capture";
+	const char *suffix		= "ChMixer Weight Ch";
+	int session_type = 0, ret = 0;
+	struct snd_kcontrol_new channel_mixer_weight_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_mixer_weight_info,
+		.put = msm_pcm_channel_mixer_weight_ctl_put,
+		.get = msm_pcm_channel_mixer_weight_ctl_get,
+		.private_value = 0,
+	};
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+		session_type = SESSION_TYPE_RX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
+				rtd, playback_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+		session_type = SESSION_TYPE_TX;
+		ret = msm_pcm_add_platform_controls(&channel_mixer_weight_control,
+				rtd, capture_mixer_ctl_name, suffix, session_type, channel);
+		if (ret < 0)
+			goto fail;
+	}
+	return 0;
+
+fail:
+	pr_err("%s: failed add platform ctl, err = %d\n",
+		 __func__, ret);
+
+	return ret;
+}
+
+static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	int i, ret = 0;
+	struct snd_pcm *pcm = NULL;
+	struct msm_plat_data *pdata = NULL;
+	struct snd_soc_component *component = NULL;
+
+	if (!rtd || !rtd->pcm) {
+		pr_err("%s invalid rtd or pcm\n", __func__);
+		return -EINVAL;
+	}
+	pcm = rtd->pcm;
+
+	component = snd_soc_rtdcom_lookup(rtd, 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: platform data not populated\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream &&
+		!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
+		pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] =
+			kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
+		if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream &&
+		!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
+		pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] =
+			kzalloc(sizeof(struct msm_pcm_channel_mixer), GFP_KERNEL);
+		if (!pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+	ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+	ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
+	if (ret) {
+		pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
+				__func__, ret);
+		goto fail;
+	}
+
+	for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
+		ret =  msm_pcm_add_channel_mixer_weight_controls(rtd, i);
+		if (ret) {
+			pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
+				__func__, ret);
+			goto fail;
+		}
+	}
+	return 0;
+
+fail:
+	kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX]);
+	kfree(pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX]);
+	pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_RX] = NULL;
+	pdata->chmixer_pspd[rtd->dai_link->id][SESSION_TYPE_TX] = NULL;
+
+	return ret;
+}
+
 static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret = 0;
@@ -1850,6 +2541,10 @@
 	if (ret)
 		pr_err("%s: pcm add app type controls failed:%d\n",
 			__func__, ret);
+	ret = msm_pcm_add_channel_mixer_controls(rtd);
+	if (ret)
+		pr_err("%s: pcm add channel mixer controls failed:%d\n",
+			__func__, ret);
 	return ret;
 }
 
@@ -1973,8 +2668,15 @@
 static int msm_pcm_remove(struct platform_device *pdev)
 {
 	struct msm_plat_data *pdata;
+	int i = 0;
 
 	pdata = dev_get_drvdata(&pdev->dev);
+	if (pdata) {
+		for (i = 0; i < MSM_FRONTEND_DAI_MM_SIZE; i++) {
+			kfree(pdata->chmixer_pspd[i][SESSION_TYPE_RX]);
+			kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
+		}
+	}
 	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 8699a48..62fcebd 100644
--- a/asoc/msm-pcm-q6-v2.h
+++ b/asoc/msm-pcm-q6-v2.h
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017, 2019 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _MSM_PCM_H
@@ -115,6 +115,8 @@
 	int perf_mode;
 	struct snd_pcm *pcm;
 	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 msm_pcm_ch_map {
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index c49a757..dc403a5 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -84,6 +84,11 @@
 #define WEIGHT_0_DB 0x4000
 /* all the FEs which can support channel mixer */
 static struct msm_pcm_channel_mixer channel_mixer[MSM_FRONTEND_DAI_MM_SIZE];
+
+/* all the FES which can support channel mixer for bidirection */
+static struct msm_pcm_channel_mixer
+	channel_mixer_v2[MSM_FRONTEND_DAI_MM_SIZE][2];
+
 /* input BE for each FE */
 static int channel_input[MSM_FRONTEND_DAI_MM_SIZE][ADM_MAX_CHANNELS];
 
@@ -928,6 +933,51 @@
 }
 EXPORT_SYMBOL(msm_pcm_routing_send_chmix_cfg);
 
+/**
+ * msm_pcm_routing_set_channel_mixer_cfg - cache channel mixer
+ * setting before use case start.
+ *
+ * @fe_id: frontend idx
+ * @type: stream direction type
+ * @params: parameters of channel mixer setting
+ *
+ * Return 0 for success
+ */
+int msm_pcm_routing_set_channel_mixer_cfg(
+	int fe_id, int type,
+	struct msm_pcm_channel_mixer *params)
+{
+	int i, j = 0;
+
+	channel_mixer_v2[fe_id][type].enable = params->enable;
+	channel_mixer_v2[fe_id][type].rule = params->rule;
+	channel_mixer_v2[fe_id][type].input_channel =
+		params->input_channel;
+	channel_mixer_v2[fe_id][type].output_channel =
+		params->output_channel;
+	channel_mixer_v2[fe_id][type].port_idx = params->port_idx;
+
+	for (i = 0; i < ADM_MAX_CHANNELS; i++)
+		channel_mixer_v2[fe_id][type].in_ch_map[i] =
+			params->in_ch_map[i];
+	for (i = 0; i < ADM_MAX_CHANNELS; i++)
+		channel_mixer_v2[fe_id][type].out_ch_map[i] =
+			params->out_ch_map[i];
+
+	for (i = 0; i < ADM_MAX_CHANNELS; i++)
+		for (j = 0; j < ADM_MAX_CHANNELS; j++)
+			channel_mixer_v2[fe_id][type].channel_weight[i][j] =
+				params->channel_weight[i][j];
+
+	channel_mixer_v2[fe_id][type].override_in_ch_map =
+			params->override_in_ch_map;
+	channel_mixer_v2[fe_id][type].override_out_ch_map =
+			params->override_out_ch_map;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_cfg);
+
 int msm_pcm_routing_reg_stream_app_type_cfg(
 	int fedai_id, int session_type, int be_id,
 	struct msm_pcm_stream_app_type_cfg *cfg_data)
@@ -1490,6 +1540,60 @@
 	return session_id;
 }
 
+static int msm_pcm_routing_channel_mixer_v2(int fe_id, bool perf_mode,
+				int dspst_id, int stream_type)
+{
+	int copp_idx = 0;
+	int sess_type = 0;
+	int j = 0, be_id = 0;
+	int ret = 0;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return 0;
+	}
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+		sess_type = SESSION_TYPE_RX;
+	else
+		sess_type = SESSION_TYPE_TX;
+
+	if (!(channel_mixer_v2[fe_id][sess_type].enable)) {
+		pr_debug("%s: channel mixer not enabled for FE %d direction %d\n",
+			__func__, fe_id, sess_type);
+		return 0;
+	}
+
+	be_id = channel_mixer_v2[fe_id][sess_type].port_idx - 1;
+	channel_mixer_v2[fe_id][sess_type].input_channels[0] =
+		channel_mixer_v2[fe_id][sess_type].input_channel;
+
+	pr_debug("%s sess type %d,fe_id %d,override in:%d out:%d,be active %d\n",
+			__func__, sess_type, fe_id,
+			channel_mixer_v2[fe_id][sess_type].override_in_ch_map,
+			channel_mixer_v2[fe_id][sess_type].override_out_ch_map,
+			msm_bedais[be_id].active);
+
+	if ((msm_bedais[be_id].active) &&
+		test_bit(fe_id, &msm_bedais[be_id].fe_sessions[0])) {
+		unsigned long copp =
+			session_copp_map[fe_id][sess_type][be_id];
+		for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+			if (test_bit(j, &copp)) {
+				copp_idx = j;
+				break;
+			}
+		}
+
+		ret = adm_programable_channel_mixer(
+			msm_bedais[be_id].port_id,
+			copp_idx, dspst_id, sess_type,
+			&channel_mixer_v2[fe_id][sess_type], 0);
+	}
+
+	return ret;
+}
+
 static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode,
 				int dspst_id, int stream_type)
 {
@@ -1498,6 +1602,14 @@
 	int i = 0, j = 0, be_id;
 	int ret = 0;
 
+	ret = msm_pcm_routing_channel_mixer_v2(fe_id, perf_mode,
+				dspst_id, stream_type);
+	if (ret) {
+		pr_err("%s channel mixer v2 cmd  set failure%d\n", __func__,
+				fe_id);
+		return ret;
+	}
+
 	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
 		pr_err("%s: invalid FE %d\n", __func__, fe_id);
 		return 0;
@@ -1537,7 +1649,7 @@
 				fe_id, be_id, msm_bedais[be_id].channel,
 				copp_idx);
 			ret = adm_programable_channel_mixer(
-					msm_bedais[be_id].port_id,
+					get_port_id(msm_bedais[be_id].port_id),
 					copp_idx, dspst_id, sess_type,
 					channel_mixer + fe_id, i);
 		}
@@ -1546,6 +1658,72 @@
 	return ret;
 }
 
+/**
+ * msm_pcm_routing_set_channel_mixer_runtime - apply channel mixer
+ * setting during runtime.
+ *
+ * @be_id: backend index
+ * @session_id: session index
+ * @session_type: session type
+ * @params: parameters for channel mixer
+ *
+ * Retuen: 0 for success, else error
+ */
+int msm_pcm_routing_set_channel_mixer_runtime(int be_id, int session_id,
+			int session_type,
+			struct msm_pcm_channel_mixer *params)
+{
+	int rc = 0;
+	int port_id, copp_idx = 0;
+
+	be_id--;
+	if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: invalid backend id %d\n", __func__,
+				be_id);
+		return -EINVAL;
+	}
+
+	port_id = msm_bedais[be_id].port_id;
+	copp_idx = adm_get_default_copp_idx(port_id);
+	pr_debug("%s: port_id - %d, copp_idx %d session id - %d\n",
+		 __func__, port_id, copp_idx, session_id);
+
+	if ((params->input_channel < 0) ||
+		(params->input_channel > ADM_MAX_CHANNELS)) {
+		pr_err("%s: invalid input channel %d\n", __func__,
+				params->input_channel);
+		return -EINVAL;
+	}
+
+	if ((params->output_channel < 0) ||
+		(params->output_channel > ADM_MAX_CHANNELS)) {
+		pr_err("%s: invalid output channel %d\n", __func__,
+				params->output_channel);
+		return -EINVAL;
+	}
+
+	params->input_channels[0] = params->input_channel;
+
+	pr_debug("%s sess type %d,override in:%d out:%d,be active %d\n",
+			__func__, session_type,
+			params->override_in_ch_map,
+			params->override_out_ch_map,
+			msm_bedais[be_id].active);
+
+	rc = adm_programable_channel_mixer(port_id,
+					copp_idx,
+					session_id,
+					session_type,
+					params,
+					0);
+	if (rc) {
+		pr_err("%s: send params failed rc=%d\n", __func__, rc);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_runtime);
+
 int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
 					int dspst_id, int stream_type)
 {
@@ -3104,20 +3282,21 @@
 "QUIN_TDM_RX_2", "QUIN_TDM_TX_2", "QUIN_TDM_RX_3", "QUIN_TDM_TX_3",
 "QUIN_TDM_RX_4", "QUIN_TDM_TX_4", "QUIN_TDM_RX_5", "QUIN_TDM_TX_5",
 "QUIN_TDM_RX_6", "QUIN_TDM_TX_6", "QUIN_TDM_RX_7", "QUIN_TDM_TX_7",
-"INT_BT_A2DP_RX", "USB_RX", "USB_TX", "DISPLAY_PORT_RX", "DISPLAY_PORT_RX1",
-"TERT_AUXPCM_RX", "TERT_AUXPCM_TX", "QUAT_AUXPCM_RX", "QUAT_AUXPCM_TX",
-"QUIN_AUXPCM_RX", "QUIN_AUXPCM_TX",
-"INT0_MI2S_RX", "INT0_MI2S_TX", "INT1_MI2S_RX", "INT1_MI2S_TX",
-"INT2_MI2S_RX", "INT2_MI2S_TX", "INT3_MI2S_RX", "INT3_MI2S_TX",
-"INT4_MI2S_RX", "INT4_MI2S_TX", "INT5_MI2S_RX", "INT5_MI2S_TX",
-"INT6_MI2S_RX", "INT6_MI2S_TX", "WSA_CDC_DMA_RX_0",
-"WSA_CDC_DMA_TX_0", "WSA_CDC_DMA_RX_1", "WSA_CDC_DMA_TX_1",
+"INT_BT_A2DP_RX", "USB_RX", "USB_TX", "DISPLAY_PORT_RX",
+"DISPLAY_PORT_RX1", "TERT_AUXPCM_RX", "TERT_AUXPCM_TX", "QUAT_AUXPCM_RX",
+"QUAT_AUXPCM_TX", "QUIN_AUXPCM_RX", "QUIN_AUXPCM_TX", "INT0_MI2S_RX",
+"INT0_MI2S_TX", "INT1_MI2S_RX", "INT1_MI2S_TX", "INT2_MI2S_RX",
+"INT2_MI2S_TX", "INT3_MI2S_RX", "INT3_MI2S_TX", "INT4_MI2S_RX",
+"INT4_MI2S_TX", "INT5_MI2S_RX", "INT5_MI2S_TX", "INT6_MI2S_RX",
+"INT6_MI2S_TX", "SEN_AUXPCM_RX", "SEN_AUXPCM_TX", "SENARY_MI2S_RX",
+"WSA_CDC_DMA_RX_0", "WSA_CDC_DMA_TX_0", "WSA_CDC_DMA_RX_1","WSA_CDC_DMA_TX_1",
 "WSA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_2",
 "RX_CDC_DMA_RX_0", "TX_CDC_DMA_TX_0", "RX_CDC_DMA_RX_1", "TX_CDC_DMA_TX_1",
 "RX_CDC_DMA_RX_2", "TX_CDC_DMA_TX_2", "RX_CDC_DMA_RX_3", "TX_CDC_DMA_TX_3",
 "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"
 };
 
 static SOC_ENUM_SINGLE_DECL(mm1_channel_mux,
@@ -9373,6 +9552,10 @@
 		MSM_BACKEND_DAI_SLIMBUS_0_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+		MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM,
 		MSM_BACKEND_DAI_AUXPCM_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -9791,6 +9974,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_INT_FM_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
@@ -9990,6 +10177,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
@@ -10185,6 +10376,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_INT_FM_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
@@ -10412,6 +10607,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
@@ -10607,6 +10806,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
@@ -10814,6 +11017,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
@@ -11027,6 +11234,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
@@ -11170,6 +11381,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
@@ -11346,6 +11561,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
@@ -11455,6 +11674,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
@@ -11568,6 +11791,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
@@ -11596,6 +11823,10 @@
 	MSM_BACKEND_DAI_INCALL_RECORD_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
@@ -11991,6 +12222,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("SLIM_6_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_SLIMBUS_6_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer,
@@ -12042,6 +12277,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
@@ -12070,6 +12309,10 @@
 	MSM_BACKEND_DAI_INCALL_RECORD_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
@@ -12151,6 +12394,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
@@ -12179,6 +12426,10 @@
 	MSM_BACKEND_DAI_INCALL_RECORD_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
@@ -20255,12 +20506,19 @@
 	{"MultiMedia8 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
 	{"MultiMedia8 Mixer", "SLIM_9_TX", "SLIMBUS_9_TX"},
 	{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia4 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia17 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia18 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia19 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia28 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia28 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia29 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia29 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia8 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia17 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -20270,6 +20528,9 @@
 	{"MultiMedia29 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia18 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"MultiMedia19 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"MultiMedia28 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"MultiMedia29 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"MultiMedia17 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"MultiMedia18 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"MultiMedia19 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -20282,16 +20543,26 @@
 	{"MultiMedia29 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
 	{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia3 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia5 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia10 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia10 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia16 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia16 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
 	{"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"MultiMedia5 Mixer", "SLIM_9_TX", "SLIMBUS_9_TX"},
 	{"MultiMedia10 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
 	{"MultiMedia10 Mixer", "SLIM_9_TX", "SLIMBUS_9_TX"},
 	{"MultiMedia18 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"},
+	{"MultiMedia19 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"},
+	{"MultiMedia28 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"},
+	{"MultiMedia29 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"},
 	{"MultiMedia18 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"},
+	{"MultiMedia19 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"},
+	{"MultiMedia28 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"},
+	{"MultiMedia29 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"},
 
 	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -20957,6 +21228,7 @@
 	{"MultiMedia1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
 	{"MultiMedia2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia1 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
 	{"MultiMedia5 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -20987,6 +21259,7 @@
 	{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia2 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia6 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -21264,6 +21537,7 @@
 	{"MultiMedia8 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"},
 	{"MultiMedia8 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"},
 
+	{"MultiMedia9 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia9 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
 	{"MultiMedia9 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
 	{"MultiMedia9 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
@@ -21388,6 +21662,7 @@
 	{"MultiMedia21 Mixer", "AFE_LOOPBACK_TX", "AFE_LOOPBACK_TX"},
 
 	{"MultiMedia27 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"MultiMedia27 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"MultiMedia27 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
 	{"MultiMedia27 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
 	{"MultiMedia27 Mixer", "SLIM_9_TX", "SLIMBUS_9_TX"},
@@ -22786,11 +23061,14 @@
 
 	{"WSA_CDC_DMA_RX_0 Port Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"},
 	{"WSA_CDC_DMA_RX_0 Port Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
-	{"RX_CDC_DMA_RX_0 Port Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
 	{"WSA_CDC_DMA_RX_0 Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
-	{"RX_CDC_DMA_RX_0 Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"WSA_CDC_DMA_RX_0 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"WSA_CDC_DMA_RX_0", NULL, "WSA_CDC_DMA_RX_0 Port Mixer"},
+
+	{"RX_CDC_DMA_RX_0 Port Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
+	{"RX_CDC_DMA_RX_0 Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"RX_CDC_DMA_RX_0 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"RX_CDC_DMA_RX_0", NULL, "RX_CDC_DMA_RX_0 Port Mixer"},
 
 	{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index 9b663ff..fc93059 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -4,6 +4,7 @@
 #ifndef _MSM_PCM_ROUTING_H
 #define _MSM_PCM_ROUTING_H
 #include <dsp/apr_audio-v2.h>
+#include <dsp/q6adm-v2.h>
 
 /*
  * These names are used by HAL to specify the BE. If any changes are
@@ -594,4 +595,13 @@
 	int op_channel_cnt, int *ch_wght_coeff,
 	int session_type, int stream_type);
 int msm_pcm_routing_get_pp_ch_cnt(int fe_id, int session_type);
+
+int msm_pcm_routing_set_channel_mixer_cfg(
+	int fe_id, int session_type,
+	struct msm_pcm_channel_mixer *params);
+
+int msm_pcm_routing_set_channel_mixer_runtime(
+	int be_id, int session_id,
+	int session_type,
+	struct msm_pcm_channel_mixer *params);
 #endif /*_MSM_PCM_H*/
diff --git a/asoc/msm-qti-pp-config.c b/asoc/msm-qti-pp-config.c
index 222a3a9..48a784e 100644
--- a/asoc/msm-qti-pp-config.c
+++ b/asoc/msm-qti-pp-config.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/err.h>
@@ -824,6 +824,32 @@
 	return 0;
 }
 
+static int msm_qti_pp_get_channel_map_capture(struct snd_kcontrol *kcontrol,
+					    struct snd_ctl_elem_value *ucontrol)
+{
+	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8] = {0};
+	int i;
+
+	adm_get_multi_ch_map(channel_map, ADM_PATH_LIVE_REC);
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		ucontrol->value.integer.value[i] =
+			(unsigned int) channel_map[i];
+	return 0;
+}
+
+static int msm_qti_pp_put_channel_map_capture(struct snd_kcontrol *kcontrol,
+					    struct snd_ctl_elem_value *ucontrol)
+{
+	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL_V8];
+	int i;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+		channel_map[i] = (char)(ucontrol->value.integer.value[i]);
+	adm_set_multi_ch_map(channel_map, ADM_PATH_LIVE_REC);
+
+	return 0;
+}
+
 /* Audio Sphere functions */
 
 static void msm_qti_pp_asphere_init_state(void)
@@ -1172,6 +1198,13 @@
 	}
 
 	event_data = (struct msm_adsp_event_data *)payload;
+	if (event_data->payload_len < sizeof(struct msm_adsp_event_data)) {
+		pr_err("%s: event_data size of %x is less than expected.\n",
+			__func__, event_data->payload_len);
+		ret = -EINVAL;
+		goto done;
+	}
+
 	kctl->info(kctl, &kctl_info);
 
 	if (event_data->payload_len >
@@ -1406,11 +1439,17 @@
 };
 
 static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
-	SOC_SINGLE_MULTI_EXT("Playback Device Channel Map", SND_SOC_NOPM, 0, 34,
+	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,
 	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,
+	msm_qti_pp_put_channel_map_capture),
+};
+
 
 static const struct snd_kcontrol_new get_rms_controls[] = {
 	SOC_SINGLE_EXT("Get RMS", SND_SOC_NOPM, 0, 0xFFFFFFFF,
@@ -1607,6 +1646,11 @@
 	snd_soc_add_component_controls(component, get_rms_controls,
 			ARRAY_SIZE(get_rms_controls));
 
+	snd_soc_add_component_controls(component,
+				multi_ch_channel_map_capture_controls,
+			ARRAY_SIZE(multi_ch_channel_map_capture_controls));
+
+
 	snd_soc_add_component_controls(component, eq_enable_mixer_controls,
 			ARRAY_SIZE(eq_enable_mixer_controls));
 
diff --git a/asoc/msm-transcode-loopback-q6-v2.c b/asoc/msm-transcode-loopback-q6-v2.c
index 1b431ae..9980874 100644
--- a/asoc/msm-transcode-loopback-q6-v2.c
+++ b/asoc/msm-transcode-loopback-q6-v2.c
@@ -178,10 +178,11 @@
 
 	if (cstream->direction == SND_COMPRESS_CAPTURE) {
 		compr_cap.direction = SND_COMPRESS_CAPTURE;
-		compr_cap.num_codecs = 3;
+		compr_cap.num_codecs = 4;
 		compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
 		compr_cap.codecs[1] = SND_AUDIOCODEC_AC3;
 		compr_cap.codecs[2] = SND_AUDIOCODEC_EAC3;
+		compr_cap.codecs[3] = SND_AUDIOCODEC_TRUEHD;
 		memcpy(&trans->source_compr_cap, &compr_cap,
 				sizeof(struct snd_compr_caps));
 	}
@@ -482,6 +483,11 @@
 			trans->source.codec_format =
 				FORMAT_EAC3;
 			break;
+		case SND_AUDIOCODEC_TRUEHD:
+			pr_debug("Source SND_AUDIOCODEC_TRUEHD\n");
+			trans->source.codec_format =
+				FORMAT_TRUEHD;
+			break;
 		default:
 			pr_debug("%s: unknown source codec\n", __func__);
 			ret = -EINVAL;
diff --git a/asoc/qcs405.c b/asoc/qcs405.c
index 6e4596f..0bbe37b 100644
--- a/asoc/qcs405.c
+++ b/asoc/qcs405.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/clk.h>
 #include <linux/delay.h>
@@ -179,6 +179,7 @@
 	struct device_node *dmic_23_gpio_p; /* used by pinctrl API */
 	struct device_node *dmic_45_gpio_p; /* used by pinctrl API */
 	struct device_node *dmic_67_gpio_p; /* used by pinctrl API */
+	struct device_node *lineout_booster_gpio_p; /* used by pinctrl API */
 	struct device_node *mi2s_gpio_p[MI2S_MAX]; /* used by pinctrl API */
 	int dmic_01_gpio_cnt;
 	int dmic_23_gpio_cnt;
@@ -3838,6 +3839,30 @@
 	return 0;
 }
 
+static int msm_lineout_booster_ctrl_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_component *component =
+			snd_soc_dapm_to_component(w->dapm);
+	struct snd_soc_card *card = component->card;
+	struct msm_asoc_mach_data *pdata =
+				snd_soc_card_get_drvdata(card);
+
+	pr_debug("%s: event = %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msm_cdc_pinctrl_select_active_state(
+					pdata->lineout_booster_gpio_p);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		msm_cdc_pinctrl_select_sleep_state(
+					pdata->lineout_booster_gpio_p);
+		break;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
 
 	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
@@ -3847,6 +3872,7 @@
 	SND_SOC_DAPM_SUPPLY("MCLK TX",  SND_SOC_NOPM, 0, 0,
 	msm_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_SPK("lineout booster", msm_lineout_booster_ctrl_event),
 	SND_SOC_DAPM_MIC("Analog Mic3", NULL),
 	SND_SOC_DAPM_MIC("Analog Mic4", NULL),
 
@@ -5047,7 +5073,6 @@
 	return ret;
 }
 
-
 static int msm_snd_cdc_dma_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params)
 {
@@ -6483,8 +6508,8 @@
 		.codec_name = "snd-soc-dummy",
 	},
 	{
-		.name = MSM_DAILINK_NAME(Compr Capture),
-		.stream_name = "Compr Capture",
+		.name = MSM_DAILINK_NAME(Compr Capture2),
+		.stream_name = "Compr Capture2",
 		.cpu_dai_name = "MultiMedia18",
 		.platform_name = "msm-compress-dsp",
 		.dynamic = 1,
@@ -6527,6 +6552,48 @@
 		.ignore_pmdown_time = 1,
 		.id = MSM_FRONTEND_DAI_MULTIMEDIA27,
 	},
+	{
+		.name = MSM_DAILINK_NAME(Compr Capture3),
+		.stream_name = "Compr Capture3",
+		.cpu_dai_name = "MultiMedia19",
+		.platform_name = "msm-compress-dsp",
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_pmdown_time = 1,
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA19,
+	},
+	{
+		.name = MSM_DAILINK_NAME(Compr Capture4),
+		.stream_name = "Compr Capture4",
+		.cpu_dai_name = "MultiMedia28",
+		.platform_name = "msm-compress-dsp",
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_pmdown_time = 1,
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA28,
+	},
+	{
+		.name = MSM_DAILINK_NAME(Compr Capture5),
+		.stream_name = "Compr Capture5",
+		.cpu_dai_name = "MultiMedia29",
+		.platform_name = "msm-compress-dsp",
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_pmdown_time = 1,
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA29,
+	},
 };
 
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {
@@ -8603,6 +8670,8 @@
 					"qcom,cdc-dmic45-gpios", 0);
 	pdata->dmic_67_gpio_p = of_parse_phandle(pdev->dev.of_node,
 					"qcom,cdc-dmic67-gpios", 0);
+	pdata->lineout_booster_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,lineout-booster-gpio", 0);
 
 	pdata->mi2s_gpio_p[PRIM_MI2S] = of_parse_phandle(pdev->dev.of_node,
 					"qcom,pri-mi2s-gpios", 0);
diff --git a/asoc/sm6150.c b/asoc/sm6150.c
index 55fe178..84e05c8 100644
--- a/asoc/sm6150.c
+++ b/asoc/sm6150.c
@@ -29,6 +29,7 @@
 #include "msm-pcm-routing-v2.h"
 #include <asoc/msm-cdc-pinctrl.h>
 #include "codecs/wcd934x/wcd934x.h"
+#include "codecs/wcd9335.h"
 #include "codecs/wcd934x/wcd934x-mbhc.h"
 #include "codecs/wcd937x/wcd937x-mbhc.h"
 #include "codecs/wsa881x.h"
@@ -204,6 +205,8 @@
 	struct snd_info_entry *codec_root;
 	int usbc_en2_gpio; /* used by gpio driver API */
 	struct device_node *mi2s_gpio_p[MI2S_MAX]; /* used by pinctrl API */
+	int hph_en1_gpio;
+	int hph_en0_gpio;
 	struct device_node *dmic01_gpio_p; /* used by pinctrl API */
 	struct device_node *dmic23_gpio_p; /* used by pinctrl API */
 	struct device_node *us_euro_gpio_p; /* used by pinctrl API */
@@ -653,13 +656,14 @@
 	.key_code[6] = 0,
 	.key_code[7] = 0,
 	.linein_th = 5000,
-	.moisture_en = true,
+	.moisture_en = false,
 	.mbhc_micbias = MIC_BIAS_2,
 	.anc_micbias = MIC_BIAS_2,
 	.enable_anc_mic_detect = false,
+	.moisture_duty_cycle_en = true,
 };
 
-static struct snd_soc_dapm_route wcd_audio_paths_tavil[] = {
+static struct snd_soc_dapm_route wcd_audio_paths[] = {
 	{"MIC BIAS1", NULL, "MCLK TX"},
 	{"MIC BIAS2", NULL, "MCLK TX"},
 	{"MIC BIAS3", NULL, "MCLK TX"},
@@ -3578,7 +3582,7 @@
 			cdc_dma_tx_sample_rate_put),
 };
 
-static const struct snd_kcontrol_new msm_tavil_snd_controls[] = {
+static const struct snd_kcontrol_new msm_ext_snd_controls[] = {
 	SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
 			slim_rx_ch_get, slim_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_2_RX Channels", slim_2_rx_chs,
@@ -3867,6 +3871,8 @@
 
 	if (!strcmp(component->name, "tavil_codec")) {
 		ret = tavil_cdc_mclk_enable(component, enable);
+	} else if (!strcmp(dev_name(component->dev), "tasha_codec")) {
+		ret = tasha_cdc_mclk_enable(component, enable, dapm);
 	} else {
 		dev_err(component->dev, "%s: unknown codec to enable ext clk\n",
 			__func__);
@@ -3882,6 +3888,8 @@
 
 	if (!strcmp(component->name, "tavil_codec")) {
 		ret = tavil_cdc_mclk_tx_enable(component, enable);
+	} else if (!strcmp(dev_name(component->dev), "tasha_codec")) {
+		ret = tasha_cdc_mclk_tx_enable(component, enable, dapm);
 	} else {
 		dev_err(component->dev, "%s: unknown codec to enable TX ext clk\n",
 			__func__);
@@ -3961,7 +3969,7 @@
 	return 0;
 }
 
-static const struct snd_soc_dapm_widget msm_dapm_widgets_tavil[] = {
+static const struct snd_soc_dapm_widget msm_ext_dapm_widgets[] = {
 
 	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
 			    msm_mclk_event,
@@ -3972,12 +3980,19 @@
 
 	SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
 	SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
+	SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
+	SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
 	SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event),
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Secondary Mic", NULL),
 	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic4", NULL),
 	SND_SOC_DAPM_MIC("Analog Mic5", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic8", NULL),
 
 	SND_SOC_DAPM_MIC("Digital Mic0", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
@@ -3985,6 +4000,7 @@
 	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
 };
 
 static int msm_dmic_event(struct snd_soc_dapm_widget *w,
@@ -4744,6 +4760,28 @@
 	afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
 }
 
+static int msm_config_hph_en0_gpio(struct snd_soc_component *component, bool high)
+{
+	struct snd_soc_card *card = component->card;
+	struct msm_asoc_mach_data *pdata;
+	int val;
+
+	if (!card)
+		return 0;
+
+	pdata = snd_soc_card_get_drvdata(card);
+	if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
+		return 0;
+
+	val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
+	if ((!!val) == high)
+		return 0;
+
+	gpio_direction_output(pdata->hph_en0_gpio, (int)high);
+
+	return 1;
+}
+
 static int msm_audrx_tavil_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret = 0;
@@ -4781,8 +4819,8 @@
 	}
 	dapm = snd_soc_component_get_dapm(component);
 
-	ret = snd_soc_add_component_controls(component, msm_tavil_snd_controls,
-					 ARRAY_SIZE(msm_tavil_snd_controls));
+	ret = snd_soc_add_component_controls(component, msm_ext_snd_controls,
+					 ARRAY_SIZE(msm_ext_snd_controls));
 	if (ret < 0) {
 		pr_err("%s: add_codec_controls failed, err %d\n",
 			__func__, ret);
@@ -4797,11 +4835,11 @@
 		return ret;
 	}
 
-	snd_soc_dapm_new_controls(dapm, msm_dapm_widgets_tavil,
-				ARRAY_SIZE(msm_dapm_widgets_tavil));
+	snd_soc_dapm_new_controls(dapm, msm_ext_dapm_widgets,
+				ARRAY_SIZE(msm_ext_dapm_widgets));
 
-	snd_soc_dapm_add_routes(dapm, wcd_audio_paths_tavil,
-				ARRAY_SIZE(wcd_audio_paths_tavil));
+	snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
+				ARRAY_SIZE(wcd_audio_paths));
 
 	snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
 	snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
@@ -4875,16 +4913,197 @@
 	}
 
 	card = rtd->card->snd_card;
-	entry = snd_info_create_subdir(card->module, "codecs",
-					 card->proc_root);
-	if (!entry) {
-		pr_debug("%s: Cannot create codecs module entry\n",
-			 __func__);
-		ret = 0;
+	if (!pdata->codec_root) {
+		entry = snd_info_create_subdir(card->module, "codecs",
+						 card->proc_root);
+		if (!entry) {
+			pr_debug("%s: Cannot create codecs module entry\n",
+				 __func__);
+			ret = 0;
+			goto err;
+		}
+		pdata->codec_root = entry;
+	}
+	tavil_codec_info_create_codec_entry(pdata->codec_root, component);
+
+	codec_reg_done = true;
+	return 0;
+err:
+	return ret;
+}
+
+static int msm_audrx_tasha_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+	void *config_data;
+	struct snd_soc_component *component = NULL;
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_component *aux_comp;
+	struct snd_card *card;
+	struct snd_info_entry *entry;
+	struct msm_asoc_mach_data *pdata =
+				snd_soc_card_get_drvdata(rtd->card);
+
+	/* Codec SLIMBUS configuration
+	 * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+	 * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+	 * TX14, TX15, TX16
+	 */
+	unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+					    151, 152, 153, 154, 155, 156};
+	unsigned int tx_ch[TASHA_TX_MAX]  = {128, 129, 130, 131, 132, 133,
+					     134, 135, 136, 137, 138, 139,
+					     140, 141, 142, 143};
+
+	pr_info("%s: dev_name:%s\n", __func__, dev_name(cpu_dai->dev));
+
+	rtd->pmdown_time = 0;
+
+	component = snd_soc_rtdcom_lookup(rtd, "tasha_codec");
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	dapm = snd_soc_component_get_dapm(component);
+
+	ret = snd_soc_add_component_controls(component, msm_ext_snd_controls,
+					 ARRAY_SIZE(msm_ext_snd_controls));
+	if (ret < 0) {
+		pr_err("%s: add_component_controls failed, err %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_add_component_controls(component, msm_common_snd_controls,
+					 ARRAY_SIZE(msm_common_snd_controls));
+	if (ret < 0) {
+		pr_err("%s: add_component_controls failed, err %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	snd_soc_dapm_new_controls(dapm, msm_ext_dapm_widgets,
+				ARRAY_SIZE(msm_ext_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
+				ARRAY_SIZE(wcd_audio_paths));
+
+	snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+	snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
+	snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
+	snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+	snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+	snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic");
+	snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
+	snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
+	snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
+	snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
+	snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
+	snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
+	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
+	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
+	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
+
+	snd_soc_dapm_ignore_suspend(dapm, "EAR");
+	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
+	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
+	snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
+	snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+	snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+	snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+	snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+	snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
+	snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+	snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+	snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+	snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
+	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+
+	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+	snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+
+	snd_soc_dapm_sync(dapm);
+
+	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+	msm_codec_fn.get_afe_config_fn = tasha_get_afe_config;
+
+	ret = msm_afe_set_config(component);
+	if (ret) {
+		pr_err("%s: Failed to set AFE config %d\n", __func__, ret);
 		goto err;
 	}
-	pdata->codec_root = entry;
-	tavil_codec_info_create_codec_entry(pdata->codec_root, component);
+	pdata->is_afe_config_done = true;
+
+	config_data = msm_codec_fn.get_afe_config_fn(component,
+						     AFE_AANC_VERSION);
+	if (config_data) {
+		ret = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+		if (ret) {
+			pr_err("%s: Failed to set aanc version %d\n",
+				__func__, ret);
+			goto err;
+		}
+	}
+
+	/*
+	 * Send speaker configuration only for WSA8810.
+	 * Default configuration is for WSA8815.
+	 */
+	pr_debug("%s: Number of aux devices: %d\n",
+		__func__, rtd->card->num_aux_devs);
+	if (rtd->card->num_aux_devs &&
+	    !list_empty(&rtd->card->aux_comp_list)) {
+		aux_comp = list_first_entry(&rtd->card->aux_comp_list,
+				struct snd_soc_component, card_aux_list);
+		if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
+		    !strcmp(aux_comp->name, WSA8810_NAME_2)) {
+			tasha_set_spkr_mode(component, SPKR_MODE_1);
+			tasha_set_spkr_gain_offset(component,
+					RX_GAIN_OFFSET_M1P5_DB);
+		}
+	}
+
+	card = rtd->card->snd_card;
+	if (!pdata->codec_root) {
+		entry = snd_info_create_subdir(card->module, "codecs",
+						 card->proc_root);
+		if (!entry) {
+			pr_debug("%s: Cannot create codecs module entry\n",
+				 __func__);
+			ret = 0;
+			goto err;
+		}
+		pdata->codec_root = entry;
+	}
+	tasha_codec_info_create_codec_entry(pdata->codec_root, component);
+	tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, component);
 
 	codec_reg_done = true;
 	return 0;
@@ -5297,6 +5516,48 @@
 	return ret;
 }
 
+int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+			  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai_link *dai_link = rtd->dai_link;
+	int ret = 0;
+	u32 tx_ch[SLIM_MAX_TX_PORTS];
+	u32 tx_ch_cnt = 0;
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
+		pr_err("%s: Invalid stream type %d\n",
+			__func__, substream->stream);
+		ret = -EINVAL;
+		goto end;
+	}
+
+	pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
+		 codec_dai->name, codec_dai->id);
+	ret = snd_soc_dai_get_channel_map(codec_dai,
+				 &tx_ch_cnt, tx_ch, NULL, NULL);
+	if (ret < 0) {
+		pr_err("%s: failed to get codec chan map\n, err:%d\n",
+			__func__, ret);
+		goto end;
+	}
+
+	pr_debug("%s: tx_ch_cnt(%d) id %d\n",
+		 __func__, tx_ch_cnt, dai_link->id);
+
+	ret = snd_soc_dai_set_channel_map(cpu_dai,
+					  tx_ch_cnt, tx_ch, 0, 0);
+	if (ret < 0) {
+		pr_err("%s: failed to set cpu chan map, err:%d\n",
+			__func__, ret);
+		goto end;
+	}
+end:
+	return ret;
+}
+
 static int msm_get_port_id(int be_id)
 {
 	int afe_port_id;
@@ -5780,6 +6041,9 @@
 	.hw_params = msm_wcn_hw_params,
 };
 
+static struct snd_soc_ops msm_ext_cpe_ops = {
+	.hw_params = msm_snd_cpe_hw_params,
+};
 
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm_common_dai_links[] = {
@@ -6382,7 +6646,6 @@
 	},
 };
 
-
 static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = {
 	{/* hw:x,37 */
 		.name = LPASS_BE_SLIMBUS_4_TX,
@@ -6513,6 +6776,96 @@
 	},
 };
 
+static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = {
+	/* tasha_vifeedback for speaker protection */
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_vifeedback",
+		.id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	/* Ultrasound RX DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Playback",
+		.stream_name = "SLIMBUS_2 Hostless Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16388",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_rx2",
+		.ignore_suspend = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_pmdown_time = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &msm_slimbus_2_be_ops,
+	},
+	/* Ultrasound TX DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Capture",
+		.stream_name = "SLIMBUS_2 Hostless Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16389",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_tx2",
+		.ignore_suspend = 1,
+		.dpcm_capture = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &msm_slimbus_2_be_ops,
+	},
+	/* CPE LSM direct dai-link */
+	{
+		.name = "CPE Listen service",
+		.stream_name = "CPE Listen Audio Service",
+		.cpu_dai_name = "msm-dai-slim",
+		.platform_name = "msm-cpe-lsm",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.dpcm_capture = 1,
+		.codec_dai_name = "tasha_mad1",
+		.codec_name = "tasha_codec",
+		.ops = &msm_ext_cpe_ops,
+	},
+	{
+		.name = "SLIMBUS_6 Hostless Playback",
+		.stream_name = "SLIMBUS_6 Hostless",
+		.cpu_dai_name = "SLIMBUS6_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		 /* this dailink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	/* CPE LSM EC PP direct dai-link */
+	{
+		.name = "CPE Listen service ECPP",
+		.stream_name = "CPE Listen Audio Service ECPP",
+		.cpu_dai_name = "CPE_LSM_NOHOST",
+		.platform_name = "msm-cpe-lsm.3",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "tasha_cpe",
+		.codec_name = "tasha_codec",
+	},
+};
+
 static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
 	{
 		.name = MSM_DAILINK_NAME(ASM Loopback),
@@ -6998,6 +7351,165 @@
 	},
 };
 
+static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_mix_rx1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_tasha_init,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_tx1",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+		.ops = &msm_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_mix_rx1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_tx3",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_mix_rx1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_tx1",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_mix_rx1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_5_RX,
+		.stream_name = "Slimbus5 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16394",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_rx3",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	/* MAD BE */
+	{
+		.name = LPASS_BE_SLIMBUS_5_TX,
+		.stream_name = "Slimbus5 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16395",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_mad1",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_6_RX,
+		.stream_name = "Slimbus6 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16396",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tasha_codec",
+		.codec_dai_name = "tasha_rx4",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
 static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
 	{
 		.name = LPASS_BE_SLIMBUS_7_RX,
@@ -7519,10 +8031,12 @@
 			 ARRAY_SIZE(msm_common_dai_links) +
 			 ARRAY_SIZE(msm_tavil_fe_dai_links) +
 			 ARRAY_SIZE(msm_bolero_fe_dai_links) +
+			 ARRAY_SIZE(msm_tasha_fe_dai_links) +
 			 ARRAY_SIZE(msm_common_misc_fe_dai_links) +
 			 ARRAY_SIZE(msm_int_compress_capture_dai) +
 			 ARRAY_SIZE(msm_common_be_dai_links) +
 			 ARRAY_SIZE(msm_tavil_be_dai_links) +
+			 ARRAY_SIZE(msm_tasha_be_dai_links) +
 			 ARRAY_SIZE(msm_wcn_be_dai_links) +
 			 ARRAY_SIZE(ext_disp_be_dai_link) +
 			 ARRAY_SIZE(msm_mi2s_be_dai_links) +
@@ -7574,6 +8088,50 @@
 	return ret;
 }
 
+static int msm_snd_card_tasha_late_probe(struct snd_soc_card *card)
+{
+	const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_component *component;
+	int ret = 0;
+	void *mbhc_calibration;
+
+	rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+	if (!rtd) {
+		dev_err(card->dev,
+			"%s: snd_soc_get_pcm_runtime for %s failed!\n",
+			__func__, be_dl_name);
+		ret = -EINVAL;
+		goto err_pcm_runtime;
+	}
+
+	component = snd_soc_rtdcom_lookup(rtd, "tasha_codec");
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err_pcm_runtime;
+	}
+
+	mbhc_calibration = def_wcd_mbhc_cal();
+	if (!mbhc_calibration) {
+		ret = -ENOMEM;
+		goto err_mbhc_cal;
+	}
+	wcd_mbhc_cfg.calibration = mbhc_calibration;
+	ret = tasha_mbhc_hs_detect(component, &wcd_mbhc_cfg);
+	if (ret) {
+		dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n",
+			__func__, ret);
+		goto err_hs_detect;
+	}
+	return 0;
+
+err_hs_detect:
+	kfree(mbhc_calibration);
+err_mbhc_cal:
+err_pcm_runtime:
+	return ret;
+}
 
 static int msm_populate_dai_link_component_of_node(
 					struct snd_soc_card *card)
@@ -7667,8 +8225,8 @@
 	struct snd_soc_component *component =
 			snd_soc_rtdcom_lookup(rtd, "msm-stub-codec");
 
-	ret = snd_soc_add_component_controls(component, msm_tavil_snd_controls,
-					 ARRAY_SIZE(msm_tavil_snd_controls));
+	ret = snd_soc_add_component_controls(component, msm_ext_snd_controls,
+					 ARRAY_SIZE(msm_ext_snd_controls));
 	if (ret < 0) {
 		dev_err(component->dev,
 			"%s: add_codec_controls failed, err = %d\n",
@@ -7798,6 +8356,7 @@
 	u32 mi2s_audio_intf = 0, ext_disp_audio_intf = 0;
 	u32 wcn_btfm_intf = 0;
 	const struct of_device_id *match;
+	u32 tasha_codec = 0;
 
 	match = of_match_node(sm6150_asoc_machine_of_match, dev->of_node);
 	if (!match) {
@@ -7822,22 +8381,33 @@
 
 		rc = of_property_read_u32(dev->of_node, "qcom,tavil_codec",
 						&tavil_codec);
-		if (rc) {
+		if (rc)
 			dev_dbg(dev, "%s: No DT match for tavil codec\n",
 				__func__);
-		} else {
-			if (tavil_codec) {
-				card->late_probe =
-					msm_snd_card_tavil_late_probe;
-				memcpy(msm_sm6150_dai_links + total_links,
-					msm_tavil_fe_dai_links,
-					sizeof(msm_tavil_fe_dai_links));
-				total_links +=
-					ARRAY_SIZE(msm_tavil_fe_dai_links);
-			}
-		}
 
-		if (!tavil_codec) {
+		rc = of_property_read_u32(dev->of_node, "qcom,tasha_codec",
+						&tasha_codec);
+		if (rc)
+			dev_dbg(dev, "%s: No DT match for tasha codec\n",
+				__func__);
+
+		if (tavil_codec) {
+			card->late_probe =
+				msm_snd_card_tavil_late_probe;
+			memcpy(msm_sm6150_dai_links + total_links,
+				msm_tavil_fe_dai_links,
+				sizeof(msm_tavil_fe_dai_links));
+			total_links +=
+				ARRAY_SIZE(msm_tavil_fe_dai_links);
+		} else if (tasha_codec) {
+			card->late_probe =
+				msm_snd_card_tasha_late_probe;
+			memcpy(msm_sm6150_dai_links + total_links,
+				msm_tasha_fe_dai_links,
+				sizeof(msm_tasha_fe_dai_links));
+			total_links +=
+				ARRAY_SIZE(msm_tasha_fe_dai_links);
+		} else {
 			memcpy(msm_sm6150_dai_links + total_links,
 				msm_bolero_fe_dai_links,
 				sizeof(msm_bolero_fe_dai_links));
@@ -7862,6 +8432,11 @@
 					msm_tavil_be_dai_links,
 					sizeof(msm_tavil_be_dai_links));
 			total_links += ARRAY_SIZE(msm_tavil_be_dai_links);
+		} else if (tasha_codec) {
+			memcpy(msm_sm6150_dai_links + total_links,
+					msm_tasha_be_dai_links,
+					sizeof(msm_tasha_be_dai_links));
+			total_links += ARRAY_SIZE(msm_tasha_be_dai_links);
 		} else {
 			memcpy(msm_sm6150_dai_links + total_links,
 			       msm_wsa_cdc_dma_be_dai_links,
@@ -8196,7 +8771,8 @@
 		__func__, found);
 
 codec_aux_dev:
-	if (strcmp(card->name, "sm6150-tavil-snd-card")) {
+	if (!strnstr(card->name, "tavil", strlen(card->name)) &&
+	    !strnstr(card->name, "tasha", strlen(card->name))) {
 		/* Get maximum aux codec device count for this platform */
 		ret = of_property_read_u32(pdev->dev.of_node,
 					   "qcom,codec-max-aux-devs",
@@ -8431,7 +9007,8 @@
 		goto err;
 	}
 
-	if (!strcmp(card->name, "sm6150-tavil-snd-card")) {
+	if (strnstr(card->name, "tavil", strlen(card->name)) ||
+	    strnstr(card->name, "tasha", strlen(card->name))) {
 		pdata = snd_soc_card_get_drvdata(card);
 		if (!pdata->is_afe_config_done) {
 			const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
@@ -8481,13 +9058,41 @@
 	dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__);
 	snd_soc_card_change_online_state(card, 0);
 
-	if (!strcmp(card->name, "sm6150-tavil-snd-card")) {
+	if (strnstr(card->name, "tavil", strlen(card->name)) ||
+	    strnstr(card->name, "tasha", strlen(card->name))) {
 		pdata = snd_soc_card_get_drvdata(card);
 		msm_afe_clear_config();
 		pdata->is_afe_config_done = false;
 	}
 }
 
+static int msm_ext_prepare_hifi(struct msm_asoc_mach_data *pdata)
+{
+	int ret = 0;
+
+	if (gpio_is_valid(pdata->hph_en1_gpio)) {
+		pr_debug("%s: hph_en1_gpio request %d\n", __func__,
+			pdata->hph_en1_gpio);
+		ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
+		if (ret) {
+			pr_err("%s: hph_en1_gpio request failed, ret:%d\n",
+				__func__, ret);
+			goto err;
+		}
+	}
+	if (gpio_is_valid(pdata->hph_en0_gpio)) {
+		pr_debug("%s: hph_en0_gpio request %d\n", __func__,
+			pdata->hph_en0_gpio);
+		ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
+		if (ret)
+			pr_err("%s: hph_en0_gpio request failed, ret:%d\n",
+				__func__, ret);
+	}
+
+err:
+	return ret;
+}
+
 static const struct snd_event_ops sm6150_ssr_ops = {
 	.enable = sm6150_ssr_enable,
 	.disable = sm6150_ssr_disable,
@@ -8589,20 +9194,31 @@
 	}
 	dev_info(&pdev->dev, "Sound card %s registered\n", card->name);
 
-	pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
+	pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
 						"qcom,hph-en1-gpio", 0);
-	if (!pdata->hph_en1_gpio_p) {
-		dev_dbg(&pdev->dev, "property %s not detected in node %s\n",
-			"qcom,hph-en1-gpio",
-			pdev->dev.of_node->full_name);
+	if (!gpio_is_valid(pdata->hph_en1_gpio))
+		pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,hph-en1-gpio", 0);
+	if (!gpio_is_valid(pdata->hph_en1_gpio) && (!pdata->hph_en1_gpio_p)) {
+		dev_dbg(&pdev->dev, "property %s not detected in node %s",
+			"qcom,hph-en1-gpio", pdev->dev.of_node->full_name);
 	}
 
-	pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
+	pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
 						"qcom,hph-en0-gpio", 0);
-	if (!pdata->hph_en0_gpio_p) {
-		dev_dbg(&pdev->dev, "property %s not detected in node %s\n",
-			"qcom,hph-en0-gpio",
-			pdev->dev.of_node->full_name);
+	if (!gpio_is_valid(pdata->hph_en0_gpio))
+		pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,hph-en0-gpio", 0);
+	if (!gpio_is_valid(pdata->hph_en0_gpio) && (!pdata->hph_en0_gpio_p)) {
+		dev_dbg(&pdev->dev, "property %s not detected in node %s",
+			"qcom,hph-en0-gpio", pdev->dev.of_node->full_name);
+	}
+
+	ret = msm_ext_prepare_hifi(pdata);
+	if (ret) {
+		dev_dbg(&pdev->dev, "msm_ext_prepare_hifi failed (%d)\n",
+			ret);
+		ret = 0;
 	}
 
 	ret = of_property_read_string(pdev->dev.of_node,
@@ -8669,7 +9285,8 @@
 	}
 
 	msm_i2s_auxpcm_init(pdev);
-	if (strcmp(card->name, "sm6150-tavil-snd-card")) {
+	if (!strnstr(card->name, "tavil", strlen(card->name)) &&
+	    !strnstr(card->name, "tasha", strlen(card->name))) {
 		pdata->dmic01_gpio_p = of_parse_phandle(pdev->dev.of_node,
 						      "qcom,cdc-dmic01-gpios",
 						       0);
diff --git a/asoc/sm8250-port-config.h b/asoc/sm8250-port-config.h
index a29f106..0a33c5f 100644
--- a/asoc/sm8250-port-config.h
+++ b/asoc/sm8250-port-config.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 _SM8250_PORT_CONFIG
@@ -17,10 +17,10 @@
 static struct port_params wsa_frame_params_default[SWR_MSTR_PORT_LEN] = {
 	{7,  1,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
 	{31, 2,  0,    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
-	{63, 12, 31,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+	{63, 12, 31,   0xFF, 0xFF, 0xFF,  0x1, 0xFF, 0xFF},
 	{7,  6,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
 	{31, 18, 0,    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
-	{63, 13, 31,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+	{63, 13, 31,   0xFF, 0xFF, 0xFF,  0x1, 0xFF, 0xFF},
 	{15, 7,  0,    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
 	{15, 10, 0,    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
 };
diff --git a/dsp/codecs/audio_aac.c b/dsp/codecs/audio_aac.c
index cf3d448..32106e5 100644
--- a/dsp/codecs/audio_aac.c
+++ b/dsp/codecs/audio_aac.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/msm_audio_aac.h>
@@ -383,7 +393,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_alac.c b/dsp/codecs/audio_alac.c
index ea05d71..f7e0932 100644
--- a/dsp/codecs/audio_alac.c
+++ b/dsp/codecs/audio_alac.c
@@ -1,6 +1,15 @@
 // 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -290,7 +299,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_amrnb.c b/dsp/codecs/audio_amrnb.c
index efec4d2..ea6d02f 100644
--- a/dsp/codecs/audio_amrnb.c
+++ b/dsp/codecs/audio_amrnb.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -137,7 +147,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
@@ -178,7 +188,7 @@
 	if (IS_ERR(audio->dentry))
 		pr_debug("debugfs_create_file failed\n");
 #endif
-	pr_info("%s:amrnb decoder open success, session_id = %d\n", __func__,
+	pr_info_ratelimited("%s:amrnb decoder open success, session_id = %d\n", __func__,
 				audio->ac->session);
 	return rc;
 fail:
diff --git a/dsp/codecs/audio_amrwbplus.c b/dsp/codecs/audio_amrwbplus.c
index d06b054..6cadab7 100644
--- a/dsp/codecs/audio_amrwbplus.c
+++ b/dsp/codecs/audio_amrwbplus.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 #include <linux/msm_audio_amrwbplus.h>
 #include <linux/compat.h>
@@ -313,7 +323,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_ape.c b/dsp/codecs/audio_ape.c
index 219df40..1e12981 100644
--- a/dsp/codecs/audio_ape.c
+++ b/dsp/codecs/audio_ape.c
@@ -1,5 +1,15 @@
 // 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -271,7 +281,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_evrc.c b/dsp/codecs/audio_evrc.c
index c3bf9b8..48d2652 100644
--- a/dsp/codecs/audio_evrc.c
+++ b/dsp/codecs/audio_evrc.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include "audio_utils_aio.h"
@@ -94,7 +104,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_g711alaw.c b/dsp/codecs/audio_g711alaw.c
index 3dac27d..b4a1d7e 100644
--- a/dsp/codecs/audio_g711alaw.c
+++ b/dsp/codecs/audio_g711alaw.c
@@ -1,5 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -245,7 +255,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_g711mlaw.c b/dsp/codecs/audio_g711mlaw.c
index c0102d0..1cf8a97 100644
--- a/dsp/codecs/audio_g711mlaw.c
+++ b/dsp/codecs/audio_g711mlaw.c
@@ -1,5 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -244,7 +254,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_mp3.c b/dsp/codecs/audio_mp3.c
index 47446d3..7228cba 100644
--- a/dsp/codecs/audio_mp3.c
+++ b/dsp/codecs/audio_mp3.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include "audio_utils_aio.h"
@@ -96,7 +106,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_multi_aac.c b/dsp/codecs/audio_multi_aac.c
index fc3f492..2c88ebf 100644
--- a/dsp/codecs/audio_multi_aac.c
+++ b/dsp/codecs/audio_multi_aac.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/msm_audio_aac.h>
@@ -437,7 +447,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_qcelp.c b/dsp/codecs/audio_qcelp.c
index fcf39f5..7e88cfd 100644
--- a/dsp/codecs/audio_qcelp.c
+++ b/dsp/codecs/audio_qcelp.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include "audio_utils_aio.h"
@@ -101,7 +111,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_utils_aio.c b/dsp/codecs/audio_utils_aio.c
index eabf170..f221635 100644
--- a/dsp/codecs/audio_utils_aio.c
+++ b/dsp/codecs/audio_utils_aio.c
@@ -1,7 +1,17 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/module.h>
@@ -1335,7 +1345,7 @@
 		audio->drv_ops.in_flush = audio_aio_async_in_flush;
 		q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
 	} else {
-		pr_err("%s[%pK]:SIO interface not supported\n",
+		pr_err_ratelimited("%s[%pK]:SIO interface not supported\n",
 			__func__, audio);
 		rc = -EACCES;
 		goto fail;
@@ -1548,7 +1558,7 @@
 		break;
 	}
 	default:
-		pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+		pr_err_ratelimited("%s: Unknown ioctl cmd = %d", __func__, cmd);
 		rc =  -EINVAL;
 	}
 	return rc;
diff --git a/dsp/codecs/audio_wma.c b/dsp/codecs/audio_wma.c
index cdd23ff..66c818d 100644
--- a/dsp/codecs/audio_wma.c
+++ b/dsp/codecs/audio_wma.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -253,7 +263,7 @@
 	}
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/codecs/audio_wmapro.c b/dsp/codecs/audio_wmapro.c
index c0a2757..4fc3312 100644
--- a/dsp/codecs/audio_wmapro.c
+++ b/dsp/codecs/audio_wmapro.c
@@ -3,7 +3,17 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  */
 
 #include <linux/types.h>
@@ -327,7 +337,7 @@
 
 	rc = audio_aio_open(audio, file);
 	if (rc < 0) {
-		pr_err("%s: audio_aio_open rc=%d\n",
+		pr_err_ratelimited("%s: audio_aio_open rc=%d\n",
 			__func__, rc);
 		goto fail;
 	}
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 688012f..edba25f 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -1317,12 +1317,22 @@
 	switch (opcode) {
 	case ADM_CMDRSP_GET_PP_PARAMS_V5:
 		struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v5);
+		if (payload_size < struct_size) {
+			pr_err("%s: payload size %d < expected size %d\n",
+				__func__, payload_size, struct_size);
+			break;
+		}
 		v5_rsp = (struct adm_cmd_rsp_get_pp_params_v5 *) payload;
 		data_size = v5_rsp->param_hdr.param_size;
 		param_data = v5_rsp->param_data;
 		break;
 	case ADM_CMDRSP_GET_PP_PARAMS_V6:
 		struct_size = sizeof(struct adm_cmd_rsp_get_pp_params_v6);
+		if (payload_size < struct_size) {
+			pr_err("%s: payload size %d < expected size %d\n",
+				__func__, payload_size, struct_size);
+			break;
+		}
 		v6_rsp = (struct adm_cmd_rsp_get_pp_params_v6 *) payload;
 		data_size = v6_rsp->param_hdr.param_size;
 		param_data = v6_rsp->param_data;
@@ -1518,6 +1528,11 @@
 			return 0;
 		}
 		if (data->opcode == APR_BASIC_RSP_RESULT) {
+			if (data->payload_size < (2 * sizeof(uint32_t))) {
+				pr_err("%s: Invalid payload size %d\n", __func__,
+					data->payload_size);
+				return 0;
+			}
 			pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n",
 				__func__, payload[0]);
 			if (payload[1] != 0) {
@@ -1644,9 +1659,14 @@
 		case ADM_CMDRSP_DEVICE_OPEN_V5:
 		case ADM_CMDRSP_DEVICE_OPEN_V6:
 		case ADM_CMDRSP_DEVICE_OPEN_V8: {
-			struct adm_cmd_rsp_device_open_v5 *open =
-			(struct adm_cmd_rsp_device_open_v5 *)data->payload;
-
+			struct adm_cmd_rsp_device_open_v5 *open = NULL;
+			if (data->payload_size <
+				sizeof(struct adm_cmd_rsp_device_open_v5)) {
+				pr_err("%s: Invalid payload size %d\n", __func__,
+					data->payload_size);
+				return 0;
+			}
+			open = (struct adm_cmd_rsp_device_open_v5 *)data->payload;
 			if (open->copp_id == INVALID_COPP_ID) {
 				pr_err("%s: invalid coppid rxed %d\n",
 					__func__, open->copp_id);
@@ -2657,7 +2677,7 @@
 		ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
 		ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
 		ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
-		ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+		ep_payload->dev_channel_mapping[9] = PCM_CHANNEL_TS;
 	} else if (channel_mode == 12) {
 		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
 		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
@@ -2681,7 +2701,7 @@
 		ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
 		ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
 		ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
-		ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+		ep_payload->dev_channel_mapping[9] = PCM_CHANNEL_TS;
 		ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_CVH;
 		ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_MS;
 		ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
@@ -2784,8 +2804,14 @@
 
 	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_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;
+	}
 
 	if (topology == VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY)
 		channel_mode = 1;
@@ -2895,12 +2921,12 @@
 			open_v8.endpoint_id_2 = 0xFFFF;
 			open_v8.endpoint_id_3 = 0xFFFF;
 
-			if ((this_adm.ec_ref_rx != -1) &&
-			    (path != ADM_PATH_PLAYBACK)) {
+			if (((this_adm.ec_ref_rx & AFE_PORT_INVALID) !=
+				AFE_PORT_INVALID) &&
+				(path != ADM_PATH_PLAYBACK)) {
 				if (this_adm.num_ec_ref_rx_chans != 0) {
 					open_v8.endpoint_id_2 =
 						this_adm.ec_ref_rx;
-					this_adm.ec_ref_rx = -1;
 				} else {
 					pr_err("%s: EC channels not set %d\n",
 						__func__,
@@ -2944,7 +2970,6 @@
 				if (this_adm.ec_ref_rx_bit_width != 0) {
 					ep2_payload.bit_width =
 						this_adm.ec_ref_rx_bit_width;
-					this_adm.ec_ref_rx_bit_width = 0;
 				} else {
 					ep2_payload.bit_width = bit_width;
 				}
@@ -2952,7 +2977,6 @@
 				if (this_adm.ec_ref_rx_sampling_rate != 0) {
 					ep2_payload.sample_rate =
 					this_adm.ec_ref_rx_sampling_rate;
-					this_adm.ec_ref_rx_sampling_rate = 0;
 				} else {
 					ep2_payload.sample_rate = rate;
 				}
@@ -3022,7 +3046,6 @@
 			if (this_adm.ec_ref_rx && (path != 1) &&
 			    (afe_get_port_type(tmp_port) == MSM_AFE_PORT_TYPE_TX)) {
 				open.endpoint_id_2 = this_adm.ec_ref_rx;
-				this_adm.ec_ref_rx = -1;
 			}
 
 			open.topology_id = topology;
@@ -3054,12 +3077,10 @@
 				open_v6.hdr.pkt_size = sizeof(open_v6);
 				open_v6.dev_num_channel_eid2 =
 					this_adm.num_ec_ref_rx_chans;
-				this_adm.num_ec_ref_rx_chans = 0;
 
 				if (this_adm.ec_ref_rx_bit_width != 0) {
 					open_v6.bit_width_eid2 =
 						this_adm.ec_ref_rx_bit_width;
-					this_adm.ec_ref_rx_bit_width = 0;
 				} else {
 					open_v6.bit_width_eid2 = bit_width;
 				}
@@ -3067,7 +3088,6 @@
 				if (this_adm.ec_ref_rx_sampling_rate != 0) {
 					open_v6.sample_rate_eid2 =
 					       this_adm.ec_ref_rx_sampling_rate;
-					this_adm.ec_ref_rx_sampling_rate = 0;
 				} else {
 					open_v6.sample_rate_eid2 = rate;
 				}
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 1b5c94d..7f170ea 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
  */
 #include <linux/slab.h>
 #include <linux/debugfs.h>
@@ -76,6 +75,11 @@
 	Q6AFE_MSM_SPKR_FTM_MODE
 };
 
+enum {
+	APTX_AD_48 = 0,
+	APTX_AD_44_1 = 1
+};
+
 struct wlock {
 	struct wakeup_source ws;
 };
@@ -460,6 +464,15 @@
 	schedule_work(&this_afe.afe_spdif_work);
 }
 
+static bool afe_token_is_valid(uint32_t token)
+{
+	if (token >= AFE_MAX_PORTS) {
+		pr_err("%s: token %d is invalid.\n", __func__, token);
+		return false;
+	}
+	return true;
+}
+
 static int32_t afe_callback(struct apr_client_data *data, void *priv)
 {
 	if (!data) {
@@ -536,7 +549,10 @@
 						 data->payload_size))
 				return -EINVAL;
 		}
-		wake_up(&this_afe.wait[data->token]);
+		if (afe_token_is_valid(data->token))
+			wake_up(&this_afe.wait[data->token]);
+		else
+			return -EINVAL;
 	} else if (data->opcode == AFE_EVENT_MBHC_DETECTION_SW_WA) {
 		msm_aud_evt_notifier_call_chain(SWR_WAKE_IRQ_EVENT, NULL);
 	} else if (data->payload_size) {
@@ -572,7 +588,10 @@
 			case AFE_SVC_CMD_SET_PARAM_V2:
 			case AFE_PORT_CMD_MOD_EVENT_CFG:
 				atomic_set(&this_afe.state, 0);
-				wake_up(&this_afe.wait[data->token]);
+				if (afe_token_is_valid(data->token))
+					wake_up(&this_afe.wait[data->token]);
+				else
+					return -EINVAL;
 				break;
 			case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER:
 				break;
@@ -584,7 +603,10 @@
 				break;
 			case AFE_CMD_ADD_TOPOLOGIES:
 				atomic_set(&this_afe.state, 0);
-				wake_up(&this_afe.wait[data->token]);
+				if (afe_token_is_valid(data->token))
+					wake_up(&this_afe.wait[data->token]);
+				else
+					return -EINVAL;
 				pr_debug("%s: AFE_CMD_ADD_TOPOLOGIES cmd 0x%x\n",
 						__func__, payload[1]);
 				break;
@@ -608,7 +630,10 @@
 						return 0;
 				}
 				atomic_set(&this_afe.state, payload[1]);
-				wake_up(&this_afe.wait[data->token]);
+				if (afe_token_is_valid(data->token))
+					wake_up(&this_afe.wait[data->token]);
+				else
+					return -EINVAL;
 				break;
 			case AFE_SVC_CMD_EVENT_CFG:
 				atomic_set(&this_afe.state, payload[1]);
@@ -632,7 +657,10 @@
 			else
 				this_afe.mmap_handle = payload[0];
 			atomic_set(&this_afe.state, 0);
-			wake_up(&this_afe.wait[data->token]);
+			if (afe_token_is_valid(data->token))
+				wake_up(&this_afe.wait[data->token]);
+			else
+				return -EINVAL;
 		} else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
 			port_id = (uint16_t)(0x0000FFFF & payload[0]);
 		} else if (data->opcode == AFE_PORT_MOD_EVENT) {
@@ -3541,6 +3569,29 @@
 			goto exit;
 		}
 		break;
+	case ASM_MEDIA_FMT_APTX_ADAPTIVE:
+		if (!cfg->abr_dec_cfg.is_abr_enabled) {
+			pr_debug("%s: sending aptx adaptive congestion buffer size to dsp\n",
+				__func__);
+			param_hdr.param_id =
+				AFE_DECODER_PARAM_ID_CONGESTION_BUFFER_SIZE;
+			param_hdr.param_size =
+			   sizeof(struct avs_dec_congestion_buffer_param_t);
+			dec_buffer_id_param.version = 0;
+			dec_buffer_id_param.max_nr_buffers  = 226;
+			dec_buffer_id_param.pre_buffer_size = 226;
+			ret = q6afe_pack_and_set_param_in_band(port_id,
+						q6audio_get_port_index(port_id),
+						param_hdr,
+						(u8 *) &dec_buffer_id_param);
+			if (ret) {
+				pr_err("%s: aptx adaptive congestion buffer size for port 0x%x failed %d\n",
+					__func__, port_id, ret);
+				goto exit;
+			}
+			break;
+		}
+		/* fall through for abr enabled case */
 	default:
 		pr_debug("%s:sending AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION to DSP payload\n",
 			  __func__);
@@ -3561,7 +3612,7 @@
 		break;
 	}
 
-	pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP", __func__);
+	pr_debug("%s: Send AFE_API_VERSION_PORT_MEDIA_TYPE to DSP\n", __func__);
 	param_hdr.module_id = AFE_MODULE_PORT;
 	param_hdr.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
 	param_hdr.param_size = sizeof(struct afe_port_media_type_t);
@@ -3575,6 +3626,15 @@
 		media_type.sample_rate =
 			cfg->data.sbc_config.sample_rate;
 		break;
+	case ASM_MEDIA_FMT_APTX_ADAPTIVE:
+		if (!cfg->abr_dec_cfg.is_abr_enabled) {
+			media_type.sample_rate =
+			(cfg->data.aptx_ad_config.sample_rate == APTX_AD_44_1) ?
+				AFE_PORT_SAMPLE_RATE_44_1K :
+				AFE_PORT_SAMPLE_RATE_48K;
+			break;
+		}
+		/* fall through for abr enabled case */
 	default:
 		media_type.sample_rate =
 			afe_config.slim_sch.sample_rate;
@@ -3600,11 +3660,19 @@
 		goto exit;
 	}
 
-	if (format != ASM_MEDIA_FMT_SBC && format != ASM_MEDIA_FMT_AAC_V2) {
+	if (format != ASM_MEDIA_FMT_SBC && format != ASM_MEDIA_FMT_AAC_V2 &&
+		format != ASM_MEDIA_FMT_APTX_ADAPTIVE) {
 		pr_debug("%s:Unsuppported dec format. Ignore AFE config %u\n",
 				__func__, format);
 		goto exit;
 	}
+
+	if (format == ASM_MEDIA_FMT_APTX_ADAPTIVE &&
+		cfg->abr_dec_cfg.is_abr_enabled) {
+		pr_debug("%s: Ignore AFE config for abr case\n", __func__);
+		goto exit;
+	}
+
 	pr_debug("%s: sending AFE_DECODER_PARAM_ID_DEC_MEDIA_FMT to DSP payload\n",
 		  __func__);
 	param_hdr.module_id = AFE_MODULE_ID_DECODER;
@@ -3623,9 +3691,10 @@
 
 	switch (cfg->format) {
 	case ASM_MEDIA_FMT_AAC_V2:
+	case ASM_MEDIA_FMT_APTX_ADAPTIVE:
 		param_hdr.param_size = sizeof(struct afe_dec_media_fmt_t);
 
-		pr_debug("%s:send AFE_DECODER_PARAM_ID DEC_MEDIA_FMT to DSP payload\n",
+		pr_debug("%s:send AVS_DECODER_PARAM_ID DEC_MEDIA_FMT to DSP payload\n",
 			 __func__);
 		param_hdr.param_id = AVS_DECODER_PARAM_ID_DEC_MEDIA_FMT;
 		dec_media_fmt.dec_media_config = cfg->data;
@@ -3634,7 +3703,7 @@
 						param_hdr,
 						(u8 *) &dec_media_fmt);
 		if (ret) {
-			pr_err("%s: AFE_DECODER_PARAM_ID DEC_MEDIA_FMT for port 0x%x failed %d\n",
+			pr_err("%s: AVS_DECODER_PARAM_ID DEC_MEDIA_FMT for port 0x%x failed %d\n",
 				__func__, port_id, ret);
 			goto exit;
 		}
@@ -7282,7 +7351,16 @@
 
 	return ret;
 }
-
+/**
+ * afe_enable_lpass_core_shared_clock -
+ *      Configures the core clk on LPASS.
+ *      Need on targets where lpass provides
+ *      clocks
+ * @port_id: afe port id
+ * @enable: enable or disable clk
+ *
+ * Returns success or failure of call.
+ */
 int afe_enable_lpass_core_shared_clock(u16 port_id, u32 enable)
 {
 	struct afe_param_id_lpass_core_shared_clk_cfg clk_cfg;
@@ -7321,7 +7399,16 @@
 	mutex_unlock(&this_afe.afe_cmd_lock);
 	return ret;
 }
+EXPORT_SYMBOL(afe_enable_lpass_core_shared_clock);
 
+/**
+ * q6afe_check_osr_clk_freq -
+ *   Gets supported OSR CLK frequencies
+ *
+ * @freq: frequency to check
+ *
+ * Returns success if freq is supported.
+ */
 int q6afe_check_osr_clk_freq(u32 freq)
 {
 	int ret = 0;
@@ -7346,6 +7433,7 @@
 	}
 	return ret;
 }
+EXPORT_SYMBOL(q6afe_check_osr_clk_freq);
 
 int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi)
 {
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index acdd759..934fc58 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -1713,14 +1713,14 @@
 		return 0;
 	}
 
-	if (data->payload_size > sizeof(int)) {
+	if (data->payload_size >= 2 * sizeof(uint32_t)) {
 		pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
 			__func__, payload[0], payload[1], data->opcode,
 			data->token, data->payload_size, data->src_port,
 			data->dest_port, asm_token._token.session_id, dir);
 		pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
 			__func__, payload[0], payload[1]);
-	} else if (data->payload_size == sizeof(int)) {
+	} else if (data->payload_size == sizeof(uint32_t)) {
 		pr_debug("%s:ptr0[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
 			__func__, payload[0], data->opcode,
 			data->token, data->payload_size, data->src_port,
@@ -1734,7 +1734,7 @@
 		case ASM_CMD_SHARED_MEM_MAP_REGIONS:
 		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
 		case ASM_CMD_ADD_TOPOLOGIES:
-			if (payload[1] != 0) {
+			if (data->payload_size >= 2 * sizeof(uint32_t) && payload[1] != 0) {
 				pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
 				       __func__, payload[0], payload[1],
 				       asm_token._token.session_id);
@@ -1752,8 +1752,12 @@
 
 			if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
 				wake_up(&ac->mem_wait);
-			dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n",
+			if (data->payload_size >= 2 * sizeof(uint32_t))
+				dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n",
 					__func__, payload[0], payload[1]);
+			else
+				dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
+					__func__, data->payload_size);
 			break;
 		default:
 			pr_debug("%s: command[0x%x] not expecting rsp\n",
@@ -1782,8 +1786,13 @@
 		break;
 	}
 	case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
-		pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
-					__func__, payload[0], payload[1]);
+		if (data->payload_size >= 2 * sizeof(uint32_t))
+			pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
+						__func__, payload[0], payload[1]);
+		else
+			pr_debug("%s: Payload size of %d is less than expected.\n",
+				__func__, data->payload_size);
+
 		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
 		if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
 			wake_up(&ac->mem_wait);
@@ -1792,8 +1801,12 @@
 		break;
 	}
 	default:
-		pr_debug("%s: command[0x%x]success [0x%x]\n",
-					__func__, payload[0], payload[1]);
+		if (data->payload_size >= 2 * sizeof(uint32_t))
+			pr_debug("%s: command[0x%x]success [0x%x]\n",
+				__func__, payload[0], payload[1]);
+		else
+			pr_debug("%s: Payload size of %d is less than expected.\n",
+				__func__, data->payload_size);
 	}
 	if (ac->cb)
 		ac->cb(data->opcode, data->token,
@@ -1944,8 +1957,12 @@
 				&(session[session_id].session_lock), flags);
 			return -EINVAL;
 		}
-		dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
-			__func__, payload[0], payload[1], data->opcode);
+		if(data->payload_size >= 2 * sizeof(uint32_t))
+			dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
+				__func__, payload[0], payload[1], data->opcode);
+		else
+			dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
+				__func__, data->payload_size);
 	}
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
 		switch (payload[0]) {
@@ -1991,32 +2008,37 @@
 		case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
-			pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
-				__func__, ac->session,
-				data->opcode, data->token,
-				payload[0], payload[1],
-				data->src_port, data->dest_port);
-			if (payload[1] != 0) {
-				pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
-					__func__, payload[0], payload[1]);
-				if (wakeup_flag) {
-					if ((is_adsp_reg_event(payload[0]) >=
-					     0) ||
-					    (payload[0] ==
-					     ASM_STREAM_CMD_SET_PP_PARAMS_V2) ||
-					    (payload[0] ==
-					     ASM_STREAM_CMD_SET_PP_PARAMS_V3))
-						atomic_set(&ac->cmd_state_pp,
+			if (data->payload_size >= 2 * sizeof(uint32_t)) {
+				pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
+					__func__, ac->session,
+					data->opcode, data->token,
+					payload[0], payload[1],
+					data->src_port, data->dest_port);
+				if (payload[1] != 0) {
+					pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+						__func__, payload[0], payload[1]);
+					if (wakeup_flag) {
+						if ((is_adsp_reg_event(payload[0]) >=
+						     0) ||
+						    (payload[0] ==
+						     ASM_STREAM_CMD_SET_PP_PARAMS_V2) ||
+						    (payload[0] ==
+						     ASM_STREAM_CMD_SET_PP_PARAMS_V3))
+							atomic_set(&ac->cmd_state_pp,
 								payload[1]);
-					else
-						atomic_set(&ac->cmd_state,
+						else
+							atomic_set(&ac->cmd_state,
 								payload[1]);
-					wake_up(&ac->cmd_wait);
+						wake_up(&ac->cmd_wait);
+					}
+					spin_unlock_irqrestore(
+						&(session[session_id].session_lock),
+						flags);
+					return 0;
 				}
-				spin_unlock_irqrestore(
-					&(session[session_id].session_lock),
-					flags);
-				return 0;
+			} else {
+				pr_err("%s: payload size of %x is less than expected.\n",
+					__func__, data->payload_size);
 			}
 			if ((is_adsp_reg_event(payload[0]) >= 0) ||
 			    (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2) ||
@@ -2038,19 +2060,24 @@
 					(uint32_t *)data->payload, ac->priv);
 			break;
 		case ASM_CMD_ADD_TOPOLOGIES:
-			pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
-				 __func__, payload[0], payload[1]);
-			if (payload[1] != 0) {
-				pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
-					 __func__, payload[0], payload[1]);
-				if (wakeup_flag) {
-					atomic_set(&ac->mem_state, payload[1]);
-					wake_up(&ac->mem_wait);
+			if (data->payload_size >= 2 * sizeof(uint32_t)) {
+				pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
+						__func__, payload[0], payload[1]);
+				if (payload[1] != 0) {
+					pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+						 __func__, payload[0], payload[1]);
+					if (wakeup_flag) {
+						atomic_set(&ac->mem_state, payload[1]);
+						wake_up(&ac->mem_wait);
+					}
+					spin_unlock_irqrestore(
+						&(session[session_id].session_lock),
+						flags);
+					return 0;
 				}
-				spin_unlock_irqrestore(
-					&(session[session_id].session_lock),
-					flags);
-				return 0;
+			} else {
+				pr_err("%s: payload size of %x is less than expected.\n",
+					__func__, data->payload_size);
 			}
 			if (atomic_read(&ac->mem_state) && wakeup_flag) {
 				atomic_set(&ac->mem_state, 0);
@@ -2061,8 +2088,12 @@
 					(uint32_t *)data->payload, ac->priv);
 			break;
 		case ASM_DATA_EVENT_WATERMARK: {
-			pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
-				 __func__, payload[0], payload[1]);
+			if (data->payload_size >= 2 * sizeof(uint32_t))
+				pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
+					__func__, payload[0], payload[1]);
+			else
+				pr_err("%s: payload size of %x is less than expected.\n",
+					__func__, data->payload_size);
 			break;
 		}
 		case ASM_STREAM_CMD_GET_PP_PARAMS_V2:
@@ -2074,11 +2105,16 @@
 			/* error or malformed APR packet. Otherwise */
 			/* response will be returned as */
 			/* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */
-			if (payload[1] != 0) {
-				pr_err("%s: ASM get param error = %d, resuming\n",
-					__func__, payload[1]);
-				rtac_make_asm_callback(ac->session, payload,
-							data->payload_size);
+			if (data->payload_size >= 2 * sizeof(uint32_t)) {
+				if (payload[1] != 0) {
+					pr_err("%s: ASM get param error = %d, resuming\n",
+						__func__, payload[1]);
+					rtac_make_asm_callback(ac->session, payload,
+								data->payload_size);
+				}
+			} else {
+				pr_err("%s: payload size of %x is less than expected.\n",
+					__func__, data->payload_size);
 			}
 			break;
 		case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
@@ -2086,11 +2122,16 @@
 				__func__, ac->session,
 				data->opcode, data->token,
 				data->src_port, data->dest_port);
-			if (payload[1] != 0)
-				pr_err("%s: ASM get param error = %d, resuming\n",
-					__func__, payload[1]);
-			atomic_set(&ac->cmd_state_pp, payload[1]);
-			wake_up(&ac->cmd_wait);
+			if (data->payload_size >= 2 * sizeof(uint32_t)) {
+				if (payload[1] != 0)
+					pr_err("%s: ASM get param error = %d, resuming\n",
+						__func__, payload[1]);
+				atomic_set(&ac->cmd_state_pp, payload[1]);
+				wake_up(&ac->cmd_wait);
+			} else {
+				pr_err("%s: payload size of %x is less than expected.\n",
+					__func__, data->payload_size);
+			}
 			break;
 		default:
 			pr_debug("%s: command[0x%x] not expecting rsp\n",
@@ -2106,10 +2147,13 @@
 	switch (data->opcode) {
 	case ASM_DATA_EVENT_WRITE_DONE_V2:{
 		struct audio_port_data *port = &ac->port[IN];
-
-		dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
-				__func__, payload[0], payload[1],
-				data->token);
+		if (data->payload_size >= 2 * sizeof(uint32_t))
+			dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
+					__func__, payload[0], payload[1],
+					data->token);
+		else
+			dev_err(ac->dev, "%s: payload size of %x is less than expected.\n",
+				__func__, data->payload_size);
 		if (ac->io_mode & SYNC_IO_MODE) {
 			if (port->buf == NULL) {
 				pr_err("%s: Unexpected Write Done\n",
@@ -2121,10 +2165,11 @@
 			}
 			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
 			buf_index = asm_token._token.buf_index;
-			if (lower_32_bits(port->buf[buf_index].phys) !=
-			payload[0] ||
-			msm_audio_populate_upper_32_bits(
-				port->buf[buf_index].phys) !=	payload[1]) {
+			if ( data->payload_size >= 2 * sizeof(uint32_t) &&
+				(lower_32_bits(port->buf[buf_index].phys) !=
+				payload[0] || 
+				msm_audio_populate_upper_32_bits(
+					port->buf[buf_index].phys) != payload[1])) {
 				pr_debug("%s: Expected addr %pK\n",
 				__func__, &port->buf[buf_index].phys);
 				pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n",
@@ -2159,14 +2204,25 @@
 		} else if (generic_get_data) {
 			generic_get_data->valid = 1;
 			if (generic_get_data->is_inband) {
-				pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
-				  __func__, payload[1], payload[2], payload[3]);
-				generic_get_data->size_in_ints = payload[3]>>2;
-				for (i = 0; i < payload[3]>>2; i++) {
-					generic_get_data->ints[i] =
-								   payload[4+i];
-					pr_debug("%s: ASM callback val %i = %i\n",
-						 __func__, i, payload[4+i]);
+				if (data->payload_size >= 4 * sizeof(uint32_t))
+					pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
+							__func__, payload[1], payload[2], payload[3]);
+				else
+					pr_err("%s: payload size of %x is less than expected.\n",
+						__func__,
+						data->payload_size);
+
+				if (data->payload_size >= (4 + (payload[3]>>2)) * sizeof(uint32_t)) {
+					generic_get_data->size_in_ints = payload[3]>>2;
+					for (i = 0; i < payload[3]>>2; i++) {
+						generic_get_data->ints[i] =
+									   payload[4+i];
+						pr_debug("%s: ASM callback val %i = %i\n",
+							 __func__, i, payload[4+i]);
+					}
+				} else {
+					pr_err("%s: payload size of %x is less than expected.\n",
+						__func__, data->payload_size);
 				}
 				pr_debug("%s: callback size in ints = %i\n",
 					 __func__,
@@ -2253,11 +2309,16 @@
 				data->src_port, data->dest_port);
 		break;
 	case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
-		dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
-				 __func__,
-				 payload[0], payload[1], payload[2]);
-		ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
-				payload[1]);
+		if (data->payload_size >= 3 * sizeof(uint32_t)) {
+			dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
+					 __func__,
+					 payload[0], payload[1], payload[2]);
+			ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
+					payload[1]);
+		} else {
+			dev_err(ac->dev, "%s: payload size of %x is less than expected.n",
+				__func__, data->payload_size);
+		}
 		if (atomic_cmpxchg(&ac->time_flag, 1, 0))
 			wake_up(&ac->time_wait);
 		break;
@@ -2267,19 +2328,30 @@
 				__func__, ac->session,
 				data->opcode, data->token,
 				data->src_port, data->dest_port);
-		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
-				 __func__,
-				payload[0], payload[1], payload[2],
-				payload[3]);
+		if (data->payload_size >= 4 * sizeof(uint32_t))
+			pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
+					 __func__,
+					payload[0], payload[1], payload[2],
+					payload[3]);
+		else
+			pr_debug("%s: payload size of %x is less than expected.\n",
+				__func__, data->payload_size);
 		break;
 	case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
 		q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
 		break;
 	case ASM_STREAM_PP_EVENT:
 	case ASM_STREAM_CMD_ENCDEC_EVENTS:
-	case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
-		pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
-				 __func__, payload[0], payload[1]);
+	case ASM_IEC_61937_MEDIA_FMT_EVENT:
+		if (data->payload_size >= 2 * sizeof(uint32_t))
+			pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
+					 __func__, payload[0], payload[1]);
+		else if (data->payload_size >= sizeof(uint32_t))
+			pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x]",
+				__func__, payload[0]);
+		else
+			pr_debug("%s: payload size of %x is less than expected.\n",
+				__func__, data->payload_size);
 		i = is_adsp_raise_event(data->opcode);
 		if (i < 0) {
 			spin_unlock_irqrestore(
@@ -2311,6 +2383,34 @@
 		pp_event_package->payload_len = payload_size;
 		memcpy((void *)pp_event_package->payload,
 			data->payload, payload_size);
+		if ((data->opcode == ASM_IEC_61937_MEDIA_FMT_EVENT) &&
+		    (payload_size == 4)) {
+			switch (payload[0]) {
+			case ASM_MEDIA_FMT_AC3:
+				((uint32_t *)pp_event_package->payload)[0] =
+					SND_AUDIOCODEC_AC3;
+				break;
+			case ASM_MEDIA_FMT_EAC3:
+				((uint32_t *)pp_event_package->payload)[0] =
+					SND_AUDIOCODEC_EAC3;
+				break;
+			case ASM_MEDIA_FMT_DTS:
+				((uint32_t *)pp_event_package->payload)[0] =
+					SND_AUDIOCODEC_DTS;
+				break;
+			case ASM_MEDIA_FMT_TRUEHD:
+				((uint32_t *)pp_event_package->payload)[0] =
+					SND_AUDIOCODEC_TRUEHD;
+				break;
+			case ASM_MEDIA_FMT_AAC_V2:
+				((uint32_t *)pp_event_package->payload)[0] =
+					SND_AUDIOCODEC_AAC;
+				break;
+			default:
+				pr_debug("%s: Event with unknown media_fmt 0x%x\n",
+					__func__, payload[0]);
+			}
+		}
 		ac->cb(data->opcode, data->token,
 			(void *)pp_event_package, ac->priv);
 		kfree(pp_event_package);
@@ -2318,16 +2418,24 @@
 			&(session[session_id].session_lock), flags);
 		return 0;
 	case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
-		pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
-			 __func__, ac->session, payload[0], payload[2],
-			 payload[1]);
+		if (data->payload_size >= 3 * sizeof(uint32_t))
+			pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
+				 __func__, ac->session, payload[0], payload[2],
+				 payload[1]);
+		else
+			pr_err("%s: payload size of %x is less than expected.\n",
+				__func__, data->payload_size);
 		wake_up(&ac->cmd_wait);
 		break;
 	case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
-		pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
-				__func__, ac->session, payload[0], payload[2],
-				payload[1]);
-		if (payload[0] == 0) {
+		if (data->payload_size >= 3 * sizeof(uint32_t))
+			pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
+					__func__, ac->session, payload[0], payload[2],
+					payload[1]);
+		else
+			pr_err("%s: payload size of %x is less than expected.\n",
+				__func__, data->payload_size);
+		if (payload[0] == 0 && data->payload_size >= 2 * sizeof(uint32_t)) {
 			atomic_set(&ac->cmd_state, 0);
 			/* ignore msw, as a delay that large shouldn't happen */
 			ac->path_delay = payload[1];
diff --git a/dsp/q6usm.c b/dsp/q6usm.c
index ce25c71..70c3a6b 100644
--- a/dsp/q6usm.c
+++ b/dsp/q6usm.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
  */
 #include <linux/mutex.h>
 #include <linux/wait.h>
@@ -490,6 +490,11 @@
 	uint32_t token;
 	uint32_t *payload = 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;
+	}
 	pr_debug("%s: ptr0[0x%x]; ptr1[0x%x]; opcode[0x%x]\n",
 		 __func__, payload[0], payload[1], data->opcode);
 	pr_debug("%s: token[0x%x]; payload_size[%d]; src[%d]; dest[%d];\n",
@@ -551,6 +556,11 @@
 	}
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size < (2 * sizeof(uint32_t))) {
+			pr_err("%s: payload has invalid size[%d]\n", __func__,
+			       data->payload_size);
+			return -EINVAL;
+		}
 		/* status field check */
 		if (payload[1]) {
 			pr_err("%s: wrong response[%d] on cmd [%d]\n",
@@ -614,6 +624,12 @@
 
 		opcode = Q6USM_EVENT_READ_DONE;
 		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+		if (data->payload_size <
+		    (sizeof(uint32_t)*(READDONE_IDX_STATUS + 1))) {
+			pr_err("%s: Invalid payload size for READDONE[%d]\n",
+			       __func__, data->payload_size);
+			return -EINVAL;
+		}
 		if (payload[READDONE_IDX_STATUS]) {
 			pr_err("%s: wrong READDONE[%d]; token[%d]\n",
 			       __func__,
@@ -660,6 +676,12 @@
 		struct us_port_data *port = &usc->port[IN];
 
 		opcode = Q6USM_EVENT_WRITE_DONE;
+		if (data->payload_size <
+		    (sizeof(uint32_t)*(WRITEDONE_IDX_STATUS + 1))) {
+			pr_err("%s: Invalid payload size for WRITEDONE[%d]\n",
+			       __func__, data->payload_size);
+			return -EINVAL;
+		}
 		if (payload[WRITEDONE_IDX_STATUS]) {
 			pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n",
 			       __func__,
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index 9daebe5..bceab12 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -254,6 +254,9 @@
 /* Sample rate is 16000 Hz.*/
 #define ADM_CMD_COPP_OPEN_SAMPLE_RATE_16K 16000
 
+/* Sample rate is 32000 Hz.*/
+#define ADM_CMD_COPP_OPEN_SAMPLE_RATE_32K 32000
+
 /* Sample rate is 48000 Hz.*/
 #define ADM_CMD_COPP_OPEN_SAMPLE_RATE_48K 48000
 
@@ -643,8 +646,9 @@
 
 #define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
 #define ASM_STREAM_PP_EVENT 0x00013214
-#define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x13333
-#define ASM_IEC_61937_MEDIA_FMT_EVENT 0x13334
+#define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x1321C
+#define ASM_IEC_61937_MEDIA_FMT_EVENT 0x1321D
+
 
 #define DSP_STREAM_CMD "ADSP Stream Cmd"
 #define DSP_STREAM_CALLBACK "ADSP Stream Callback Event"
@@ -2477,6 +2481,7 @@
 #define AFE_MODULE_AUDIO_DEV_INTERFACE    0x0001020C
 #define AFE_PORT_SAMPLE_RATE_8K           8000
 #define AFE_PORT_SAMPLE_RATE_16K          16000
+#define AFE_PORT_SAMPLE_RATE_44_1K        44100
 #define AFE_PORT_SAMPLE_RATE_48K          48000
 #define AFE_PORT_SAMPLE_RATE_96K          96000
 #define AFE_PORT_SAMPLE_RATE_176P4K       176400
@@ -3795,6 +3800,7 @@
 
 struct afe_abr_dec_cfg_t {
 	struct afe_imc_dec_enc_info imc_info;
+	bool is_abr_enabled;
 } __packed;
 
 struct afe_abr_enc_cfg_t {
@@ -4437,6 +4443,19 @@
 	 */
 } __packed;
 
+/*
+ * Payload of the APTX AD decoder configuration parameters in the
+ * #ASM_MEDIA_FMT_APTX_ADAPTIVE media format.
+ */
+struct asm_aptx_ad_dec_cfg_t {
+	uint32_t          sample_rate;
+	/*
+	 * Number of samples per second.
+	 *
+	 * @values 0x0(48000Hz), 0x1(44100Hz)
+	 */
+} __packed;
+
 union afe_enc_config_data {
 	struct asm_sbc_enc_cfg_t sbc_config;
 	struct asm_aac_enc_cfg_t aac_config;
@@ -4458,6 +4477,7 @@
 	struct asm_sbc_dec_cfg_t sbc_config;
 	struct asm_aac_dec_cfg_v2_t aac_config;
 	struct asm_mp3_dec_cfg_t mp3_config;
+	struct asm_aptx_ad_dec_cfg_t aptx_ad_config;
 };
 
 struct afe_dec_config {
@@ -5082,6 +5102,7 @@
 #define VPM_TX_DM_RFECNS_COPP_TOPOLOGY			0x00010F86
 #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX		0x10015002
 #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE	0x10028000
+#define VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY		0x10000005
 
 /* Memory map regions command payload used by the
  * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS
@@ -5396,7 +5417,7 @@
 #define PCM_CHANNEL_RB   9
 
 /* Top surround channel. */
-#define PCM_CHANNELS   10
+#define PCM_CHANNEL_TS   10
 
 /* Center vertical height channel.*/
 #define PCM_CHANNEL_CVH  11
@@ -5476,6 +5497,9 @@
 /* Right side direct channel. */
 #define PCM_CHANNEL_RSD  34
 
+/* Mark unused channel. */
+#define PCM_CHANNEL_UNUSED  47
+
 #define PCM_FORMAT_MAX_NUM_CHANNEL  8
 #define PCM_FORMAT_MAX_CHANNELS_9   9
 
@@ -5605,7 +5629,7 @@
  * - #PCM_CHANNEL_CS
  * - #PCM_CHANNEL_LB
  * - #PCM_CHANNEL_RB
- * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_TS
  * - #PCM_CHANNEL_CVH
  * - #PCM_CHANNEL_MS
  * - #PCM_CHANNEL_FLC
@@ -9539,7 +9563,7 @@
 	 * - #PCM_CHANNEL_CS
 	 * - #PCM_CHANNEL_LB
 	 * - #PCM_CHANNEL_RB
-	 * - #PCM_CHANNELS
+	 * - #PCM_CHANNEL_TS
 	 * - #PCM_CHANNEL_CVH
 	 * - #PCM_CHANNEL_MS
 	 * - #PCM_CHANNEL_FLC
@@ -9611,7 +9635,7 @@
  * - #PCM_CHANNEL_CS
  * - #PCM_CHANNEL_LB
  * - #PCM_CHANNEL_RB
- * - #PCM_CHANNELS
+ * - #PCM_CHANNEL_TS
  * - #PCM_CHANNEL_CVH
  * - #PCM_CHANNEL_MS
  * - #PCM_CHANNEL_FLC
diff --git a/ipc/apr_tal_rpmsg.c b/ipc/apr_tal_rpmsg.c
index 723de56..c8830d1 100644
--- a/ipc/apr_tal_rpmsg.c
+++ b/ipc/apr_tal_rpmsg.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -10,6 +10,7 @@
 #include <linux/delay.h>
 #include <linux/rpmsg.h>
 #include <ipc/apr_tal.h>
+#include <linux/of_device.h>
 
 enum apr_channel_state {
 	APR_CH_DISCONNECTED,
@@ -125,14 +126,13 @@
 	int rc = 0;
 	struct apr_svc_ch_dev *apr_ch = NULL;
 
-	if ((clnt != APR_CLIENT_AUDIO) || (dest != APR_DEST_QDSP6) ||
+	if ((clnt != APR_CLIENT_AUDIO) || (dest >= APR_DEST_MAX) ||
 	    (dl != APR_DL_SMD)) {
 		pr_err("%s: Invalid params, clnt:%d, dest:%d, dl:%d\n",
 		       __func__, clnt, dest, dl);
 		return NULL;
 	}
-
-	apr_ch = &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO];
+	apr_ch = &apr_svc_ch[dl][dest][clnt];
 	mutex_lock(&apr_ch->m_lock);
 	if (!apr_ch->handle) {
 		rc = wait_event_timeout(apr_ch->wait,
@@ -207,24 +207,46 @@
 static int apr_tal_rpmsg_probe(struct rpmsg_device *rpdev)
 {
 	struct apr_svc_ch_dev *apr_ch = NULL;
+	int ret = 0;
+	const char* dest;
+
+	ret = of_property_read_string(rpdev->dev.parent->of_node,
+				   "mbox-names", &dest);
+
+	if(ret < 0){
+		pr_err("%s no parent source pid found\n", __func__);
+		return -EINVAL;
+	}
 
 	if (!strcmp(rpdev->id.name, "apr_audio_svc")) {
 		dev_info(&rpdev->dev, "%s: Channel[%s] state[Up]\n",
 			 __func__, rpdev->id.name);
-
+	} else {
+		dev_err(&rpdev->dev, "%s, Invalid Channel [%s]\n",
+			__func__, rpdev->id.name);
+		return -EINVAL;
+	}
+	if(strstr(dest, "adsp")) {
 		apr_ch =
 		&apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO];
 		apr_ch->handle = rpdev;
 		apr_ch->channel_state = APR_CH_CONNECTED;
 		dev_set_drvdata(&rpdev->dev, apr_ch);
 		wake_up(&apr_ch->wait);
+	} else if(strstr(dest, "mpss")) {
+		apr_ch =
+		&apr_svc_ch[APR_DL_SMD][APR_DEST_MODEM][APR_CLIENT_AUDIO];
+		apr_ch->handle = rpdev;
+		apr_ch->channel_state = APR_CH_CONNECTED;
+		dev_set_drvdata(&rpdev->dev, apr_ch);
+		wake_up(&apr_ch->wait);
 	} else {
-		dev_err(&rpdev->dev, "%s, Invalid Channel [%s]\n",
-			__func__, rpdev->id.name);
+		dev_err(&rpdev->dev, "%s, unsupported dest %s\n",
+			__func__, dest);
 		return -EINVAL;
 	}
 
-	return 0;
+	return ret;
 }
 
 static void apr_tal_rpmsg_remove(struct rpmsg_device *rpdev)
diff --git a/ipc/apr_v3.c b/ipc/apr_v3.c
index 7bf4774..4160bee 100644
--- a/ipc/apr_v3.c
+++ b/ipc/apr_v3.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, 2019 The Linux Foundation. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -13,10 +13,16 @@
 
 #define DEST_ID APR_DEST_MODEM
 
+/**
+ * apr_get_subsys_state - get modem subsys status
+ *
+ * Returns apr_subsys_state
+ */
 enum apr_subsys_state apr_get_subsys_state(void)
 {
 	return apr_get_modem_state();
 }
+EXPORT_SYMBOL(apr_get_subsys_state);
 
 void apr_set_subsys_state(void)
 {
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index 4212816..bef9cba 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/gpio.h>
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/clk.h>
+#include <linux/bitops.h>
 #include <soc/snd_event.h>
 #include <linux/pm_runtime.h>
 #include <dsp/audio_notifier.h>
@@ -21,39 +22,45 @@
 #include "core.h"
 #include "pinctrl-utils.h"
 
-#define LPI_AUTO_SUSPEND_DELAY          100 /* delay in msec */
+#define LPI_AUTO_SUSPEND_DELAY           100 /* delay in msec */
 
-#define LPI_ADDRESS_SIZE			0x20000
+#define LPI_ADDRESS_SIZE                 0x20000
+#define LPI_SLEW_ADDRESS_SIZE            0x1000
 
-#define LPI_GPIO_REG_VAL_CTL			0x00
-#define LPI_GPIO_REG_DIR_CTL			0x04
+#define LPI_GPIO_REG_VAL_CTL             0x00
+#define LPI_GPIO_REG_DIR_CTL             0x04
 
-#define LPI_GPIO_REG_PULL_SHIFT			0x0
-#define LPI_GPIO_REG_PULL_MASK			0x3
+#define LPI_SLEW_REG_VAL_CTL             0x00
+#define LPI_SLEW_RATE_MAX                0x03
+#define LPI_SLEW_BITS_SIZE               0x02
+#define LPI_SLEW_OFFSET_INVALID          0xFFFFFFFF
 
-#define LPI_GPIO_REG_FUNCTION_SHIFT		0x2
-#define LPI_GPIO_REG_FUNCTION_MASK		0x3C
+#define LPI_GPIO_REG_PULL_SHIFT          0x0
+#define LPI_GPIO_REG_PULL_MASK           0x3
 
-#define LPI_GPIO_REG_OUT_STRENGTH_SHIFT		0x6
-#define LPI_GPIO_REG_OUT_STRENGTH_MASK		0x1C0
+#define LPI_GPIO_REG_FUNCTION_SHIFT      0x2
+#define LPI_GPIO_REG_FUNCTION_MASK       0x3C
 
-#define LPI_GPIO_REG_OE_SHIFT			0x9
-#define LPI_GPIO_REG_OE_MASK			0x200
+#define LPI_GPIO_REG_OUT_STRENGTH_SHIFT  0x6
+#define LPI_GPIO_REG_OUT_STRENGTH_MASK   0x1C0
 
-#define LPI_GPIO_REG_DIR_SHIFT			0x1
-#define LPI_GPIO_REG_DIR_MASK			0x2
+#define LPI_GPIO_REG_OE_SHIFT            0x9
+#define LPI_GPIO_REG_OE_MASK             0x200
 
-#define LPI_GPIO_BIAS_DISABLE			0x0
-#define LPI_GPIO_PULL_DOWN			0x1
-#define LPI_GPIO_KEEPER				0x2
-#define LPI_GPIO_PULL_UP			0x3
+#define LPI_GPIO_REG_DIR_SHIFT           0x1
+#define LPI_GPIO_REG_DIR_MASK            0x2
 
-#define LPI_GPIO_FUNC_GPIO			"gpio"
-#define LPI_GPIO_FUNC_FUNC1			"func1"
-#define LPI_GPIO_FUNC_FUNC2			"func2"
-#define LPI_GPIO_FUNC_FUNC3			"func3"
-#define LPI_GPIO_FUNC_FUNC4			"func4"
-#define LPI_GPIO_FUNC_FUNC5			"func5"
+#define LPI_GPIO_BIAS_DISABLE            0x0
+#define LPI_GPIO_PULL_DOWN               0x1
+#define LPI_GPIO_KEEPER                  0x2
+#define LPI_GPIO_PULL_UP                 0x3
+
+#define LPI_GPIO_FUNC_GPIO               "gpio"
+#define LPI_GPIO_FUNC_FUNC1              "func1"
+#define LPI_GPIO_FUNC_FUNC2              "func2"
+#define LPI_GPIO_FUNC_FUNC3              "func3"
+#define LPI_GPIO_FUNC_FUNC4              "func4"
+#define LPI_GPIO_FUNC_FUNC5              "func5"
 
 static bool lpi_dev_up;
 static struct device *lpi_dev;
@@ -70,30 +77,39 @@
 
 /**
  * struct lpi_gpio_pad - keep current GPIO settings
- * @offset: Nth GPIO in supported GPIOs.
+ * @offset: stores one of gpio_offset or slew_offset at a given time.
+ * @gpio_offset: Nth GPIO in supported GPIOs.
+ * @slew_offset: Nth GPIO's position in slew register in supported GPIOs.
  * @output_enabled: Set to true if GPIO output logic is enabled.
  * @value: value of a pin
- * @base: Address base of LPI GPIO PAD.
+ * @base: stores one of gpio_base or slew_base at a given time.
+ * @gpio_base: Address base of LPI GPIO PAD.
+ * @slew_base: Address base of LPI SLEW PAD.
  * @pullup: Constant current which flow through GPIO output buffer.
  * @strength: No, Low, Medium, High
  * @function: See lpi_gpio_functions[]
  */
 struct lpi_gpio_pad {
-	u32		offset;
-	bool		output_enabled;
-	bool		value;
-	char __iomem	*base;
-	unsigned int	pullup;
-	unsigned int	strength;
-	unsigned int	function;
+	u32             offset;
+	u32             gpio_offset;
+	u32             slew_offset;
+	bool            output_enabled;
+	bool            value;
+	char __iomem    *base;
+	char __iomem    *gpio_base;
+	char __iomem    *slew_base;
+	unsigned int    pullup;
+	unsigned int    strength;
+	unsigned int    function;
 };
 
 struct lpi_gpio_state {
-	struct device	*dev;
-	struct pinctrl_dev *ctrl;
-	struct gpio_chip chip;
-	char __iomem	*base;
-	struct clk *lpass_npa_rsc_island;
+	struct device       *dev;
+	struct pinctrl_dev  *ctrl;
+	struct gpio_chip     chip;
+	char __iomem        *base;
+	struct clk          *lpass_npa_rsc_island;
+	struct mutex         slew_access_lock;
 };
 
 static const char *const lpi_gpio_groups[] = {
@@ -106,6 +122,7 @@
 
 #define LPI_TLMM_MAX_PINS 100
 static u32 lpi_offset[LPI_TLMM_MAX_PINS];
+static u32 lpi_slew_offset[LPI_TLMM_MAX_PINS];
 
 static const char *const lpi_gpio_functions[] = {
 	[LPI_GPIO_FUNC_INDEX_GPIO]	= LPI_GPIO_FUNC_GPIO,
@@ -272,7 +289,9 @@
 {
 	struct lpi_gpio_pad *pad;
 	unsigned int param, arg;
-	int i, ret = 0, val;
+	int i, ret = 0;
+	volatile unsigned long val;
+	struct lpi_gpio_state *state = dev_get_drvdata(pctldev->dev);
 
 	pad = pctldev->desc->pins[pin].drv_data;
 
@@ -306,12 +325,44 @@
 		case PIN_CONFIG_DRIVE_STRENGTH:
 			pad->strength = arg;
 			break;
+		case PIN_CONFIG_SLEW_RATE:
+			if (pad->slew_base == NULL ||
+				pad->slew_offset == LPI_SLEW_OFFSET_INVALID) {
+				dev_dbg(pctldev->dev, "%s: invalid slew settings for pin: %d\n",
+					__func__, pin);
+				goto set_gpio;
+			}
+			if (arg > LPI_SLEW_RATE_MAX) {
+				dev_err(pctldev->dev, "%s: invalid slew rate %u for pin: %d\n",
+					__func__, arg, pin);
+				goto set_gpio;
+			}
+			pad->base = pad->slew_base;
+			pad->offset = 0;
+			mutex_lock(&state->slew_access_lock);
+			val = lpi_gpio_read(pad, LPI_SLEW_REG_VAL_CTL);
+			pad->offset = pad->slew_offset;
+			for (i = 0; i < LPI_SLEW_BITS_SIZE; i++) {
+				if (arg & 0x01)
+					set_bit(pad->offset, &val);
+				else
+					clear_bit(pad->offset, &val);
+				pad->offset++;
+				arg = arg >> 1;
+			}
+			pad->offset = 0;
+			lpi_gpio_write(pad, LPI_SLEW_REG_VAL_CTL, val);
+			mutex_unlock(&state->slew_access_lock);
+			break;
 		default:
 			ret = -EINVAL;
 			goto done;
 		}
 	}
 
+set_gpio:
+	pad->base = pad->gpio_base;
+	pad->offset = pad->gpio_offset;
 	val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
 	val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK |
 		 LPI_GPIO_REG_OE_MASK);
@@ -502,7 +553,8 @@
 	struct lpi_gpio_state *state;
 	int ret, npins, i;
 	char __iomem *lpi_base;
-	u32 reg;
+	char __iomem *slew_base;
+	u32 reg, slew_reg;
 	struct clk *lpass_npa_rsc_island = NULL;
 
 	ret = of_property_read_u32(dev->of_node, "reg", &reg);
@@ -524,6 +576,16 @@
 		return ret;
 	}
 
+	ret = of_property_read_u32_array(dev->of_node,
+					 "qcom,lpi-slew-offset-tbl",
+					 lpi_slew_offset, npins);
+	if (ret < 0) {
+		for (i = 0; i < npins; i++)
+			lpi_slew_offset[i] = LPI_SLEW_OFFSET_INVALID;
+		dev_dbg(dev, "%s: error in reading lpi slew offset table: %d\n",
+			__func__, ret);
+	}
+
 	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return -ENOMEM;
@@ -532,6 +594,23 @@
 
 	state->dev = &pdev->dev;
 
+	slew_reg = 0;
+	ret = of_property_read_u32(dev->of_node, "qcom,slew-reg", &slew_reg);
+	if (!ret) {
+		slew_base = devm_ioremap(dev, slew_reg, LPI_SLEW_ADDRESS_SIZE);
+		if (slew_base == NULL) {
+			dev_err(dev,
+				"%s devm_ioremap failed for slew rate reg\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err_io;
+		}
+	} else {
+		slew_base = NULL;
+		dev_dbg(dev, "error in reading lpi slew register: %d\n",
+			__func__, ret);
+	}
+
 	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
 	if (!pindesc)
 		return -ENOMEM;
@@ -566,8 +645,13 @@
 		pindesc->number = i;
 		pindesc->name = lpi_gpio_groups[i];
 
-		pad->base = lpi_base;
-		pad->offset = lpi_offset[i];
+		pad->gpio_base = lpi_base;
+		pad->slew_base = slew_base;
+		pad->base = pad->gpio_base;
+
+		pad->gpio_offset = lpi_offset[i];
+		pad->slew_offset = lpi_slew_offset[i];
+		pad->offset = pad->gpio_offset;
 	}
 
 	state->chip = lpi_gpio_template;
@@ -578,6 +662,8 @@
 	state->chip.of_gpio_n_cells = 2;
 	state->chip.can_sleep = false;
 
+	mutex_init(&state->slew_access_lock);
+
 	state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
 	if (IS_ERR(state->ctrl))
 		return PTR_ERR(state->ctrl);
@@ -636,18 +722,23 @@
 err_range:
 	gpiochip_remove(&state->chip);
 err_chip:
+	mutex_destroy(&state->slew_access_lock);
+err_io:
 	return ret;
 }
 
 static int lpi_pinctrl_remove(struct platform_device *pdev)
 {
 	struct lpi_gpio_state *state = platform_get_drvdata(pdev);
+
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
 	snd_event_client_deregister(&pdev->dev);
 	audio_notifier_deregister("lpi_tlmm");
 	gpiochip_remove(&state->chip);
+	mutex_destroy(&state->slew_access_lock);
+
 	return 0;
 }
 
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 2235934..f9dbc24 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -1415,6 +1415,195 @@
 	return ret;
 }
 
+static irqreturn_t swr_mstr_interrupt_v2(int irq, void *dev)
+{
+	struct swr_mstr_ctrl *swrm = dev;
+	u32 value, intr_sts, intr_sts_masked;
+	u32 temp = 0;
+	u32 status, chg_sts, i;
+	u8 devnum = 0;
+	int ret = IRQ_HANDLED;
+	struct swr_device *swr_dev;
+	struct swr_master *mstr = &swrm->master;
+
+	if (unlikely(swrm_lock_sleep(swrm) == false)) {
+		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
+		return IRQ_NONE;
+	}
+
+	mutex_lock(&swrm->reslock);
+	swrm_clk_request(swrm, true);
+	mutex_unlock(&swrm->reslock);
+
+	intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
+	intr_sts_masked = intr_sts & swrm->intr_mask;
+handle_irq:
+	for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
+		value = intr_sts_masked & (1 << i);
+		if (!value)
+			continue;
+
+		switch (value) {
+		case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ:
+			dev_dbg(swrm->dev, "%s: Trigger irq to slave device\n",
+				__func__);
+			status = swr_master_read(swrm, SWRM_MCP_SLV_STATUS);
+			ret = swrm_find_alert_slave(swrm, status, &devnum);
+			if (ret) {
+				dev_err_ratelimited(swrm->dev,
+				   "%s: no slave alert found.spurious interrupt\n",
+					__func__);
+				break;
+			}
+			swrm_cmd_fifo_rd_cmd(swrm, &temp, devnum, 0x0,
+						SWRS_SCP_INT_STATUS_CLEAR_1, 1);
+			swrm_cmd_fifo_wr_cmd(swrm, 0x4, devnum, 0x0,
+						SWRS_SCP_INT_STATUS_CLEAR_1);
+			swrm_cmd_fifo_wr_cmd(swrm, 0x0, devnum, 0x0,
+						SWRS_SCP_INT_STATUS_CLEAR_1);
+
+
+			list_for_each_entry(swr_dev, &mstr->devices, dev_list) {
+				if (swr_dev->dev_num != devnum)
+					continue;
+				if (swr_dev->slave_irq) {
+					do {
+						handle_nested_irq(
+							irq_find_mapping(
+							swr_dev->slave_irq, 0));
+					} while (swr_dev->slave_irq_pending);
+				}
+
+			}
+			break;
+		case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED:
+			dev_dbg(swrm->dev, "%s: SWR new slave attached\n",
+				__func__);
+			break;
+		case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
+			status = swr_master_read(swrm, SWRM_MCP_SLV_STATUS);
+			if (status == swrm->slave_status) {
+				dev_dbg(swrm->dev,
+					"%s: No change in slave status: %d\n",
+					__func__, status);
+				break;
+			}
+			chg_sts = swrm_check_slave_change_status(swrm, status,
+								&devnum);
+			switch (chg_sts) {
+			case SWR_NOT_PRESENT:
+				dev_dbg(swrm->dev,
+					"%s: device %d got detached\n",
+					__func__, devnum);
+				break;
+			case SWR_ATTACHED_OK:
+				dev_dbg(swrm->dev,
+					"%s: device %d got attached\n",
+					__func__, devnum);
+				/* enable host irq from slave device*/
+				swrm_cmd_fifo_wr_cmd(swrm, 0xFF, devnum, 0x0,
+					SWRS_SCP_INT_STATUS_CLEAR_1);
+				swrm_cmd_fifo_wr_cmd(swrm, 0x4, devnum, 0x0,
+					SWRS_SCP_INT_STATUS_MASK_1);
+
+				break;
+			case SWR_ALERT:
+				dev_dbg(swrm->dev,
+					"%s: device %d has pending interrupt\n",
+					__func__, devnum);
+				break;
+			}
+			break;
+		case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET:
+			dev_err_ratelimited(swrm->dev,
+					"%s: SWR bus clsh detected\n",
+					__func__);
+			break;
+		case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW:
+			dev_dbg(swrm->dev, "%s: SWR read FIFO overflow\n",
+				__func__);
+			break;
+		case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW:
+			dev_dbg(swrm->dev, "%s: SWR read FIFO underflow\n",
+				__func__);
+			break;
+		case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW:
+			dev_dbg(swrm->dev, "%s: SWR write FIFO overflow\n",
+				__func__);
+			break;
+		case SWRM_INTERRUPT_STATUS_CMD_ERROR:
+			value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS);
+			dev_err_ratelimited(swrm->dev,
+			"%s: SWR CMD error, fifo status 0x%x, flushing fifo\n",
+					__func__, value);
+			swr_master_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
+			break;
+		case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION:
+			dev_err_ratelimited(swrm->dev,
+					"%s: SWR Port collision detected\n",
+					__func__);
+			swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION;
+			swr_master_write(swrm,
+				SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, swrm->intr_mask);
+			break;
+		case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH:
+			dev_dbg(swrm->dev,
+				"%s: SWR read enable valid mismatch\n",
+				__func__);
+			swrm->intr_mask &=
+				~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH;
+			swr_master_write(swrm,
+				 SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, swrm->intr_mask);
+			break;
+		case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED:
+			complete(&swrm->broadcast);
+			dev_dbg(swrm->dev, "%s: SWR cmd id finished\n",
+				__func__);
+			break;
+		case SWRM_INTERRUPT_STATUS_AUTO_ENUM_FAILED_V2:
+			break;
+		case SWRM_INTERRUPT_STATUS_AUTO_ENUM_TABLE_IS_FULL_V2:
+			break;
+		case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2:
+			break;
+		case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2:
+			break;
+		case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP:
+			if (swrm->state == SWR_MSTR_UP)
+				dev_dbg(swrm->dev,
+					"%s:SWR Master is already up\n",
+					__func__);
+			else
+				dev_err_ratelimited(swrm->dev,
+					"%s: SWR wokeup during clock stop\n",
+					__func__);
+			break;
+		default:
+			dev_err_ratelimited(swrm->dev,
+					"%s: SWR unknown interrupt value: %d\n",
+					__func__, value);
+			ret = IRQ_NONE;
+			break;
+		}
+	}
+	swr_master_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts);
+	swr_master_write(swrm, SWRM_INTERRUPT_CLEAR, 0x0);
+
+	intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
+	intr_sts_masked = intr_sts & swrm->intr_mask;
+
+	if (intr_sts_masked) {
+		dev_dbg(swrm->dev, "%s: new interrupt received\n", __func__);
+		goto handle_irq;
+	}
+
+	mutex_lock(&swrm->reslock);
+	swrm_clk_request(swrm, false);
+	mutex_unlock(&swrm->reslock);
+	swrm_unlock_sleep(swrm);
+	return ret;
+}
+
 static irqreturn_t swrm_wakeup_interrupt(int irq, void *dev)
 {
 	struct swr_mstr_ctrl *swrm = dev;
@@ -1899,7 +2088,7 @@
 		}
 
 		ret = request_threaded_irq(swrm->irq, NULL,
-					   swr_mstr_interrupt,
+					   swr_mstr_interrupt_v2,
 					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 					   "swr_master_irq", swrm);
 		if (ret) {
diff --git a/soc/swrm_registers.h b/soc/swrm_registers.h
index c53d37b..6f2544b 100644
--- a/soc/swrm_registers.h
+++ b/soc/swrm_registers.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2018-2019 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SWRM_REGISTERS_H
@@ -49,6 +49,13 @@
 #define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED			0x8000
 #define SWRM_INTERRUPT_STATUS_ERROR_PORT_TEST			0x10000
 
+#define SWRM_INTERRUPT_STATUS_AUTO_ENUM_FAILED_V2               0x800
+#define SWRM_INTERRUPT_STATUS_AUTO_ENUM_TABLE_IS_FULL_V2        0x1000
+#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2             0x2000
+#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2              0x4000
+#define SWRM_INTERRUPT_STATUS_ERROR_PORT_TEST_V2                0x8000
+#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP               0x10000
+
 #define SWRM_INTERRUPT_MASK_ADDR		(SWRM_BASE_ADDRESS+0x00000204)
 #define SWRM_INTERRUPT_MASK_RMSK		0x1FFFF