Merge "asoc: dsp: add support for aptx adaptive speech"
diff --git a/asoc/Android.mk b/asoc/Android.mk
index db01167..ca2dffc 100644
--- a/asoc/Android.mk
+++ b/asoc/Android.mk
@@ -23,9 +23,14 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+TARGET := lito
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/asoc/Kbuild b/asoc/Kbuild
index 945d554..2b0696b 100644
--- a/asoc/Kbuild
+++ b/asoc/Kbuild
@@ -34,6 +34,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_SDMSHRIKE), y)
 		include $(AUDIO_ROOT)/config/sm8150auto.conf
 		export
@@ -94,6 +99,10 @@
 	MACHINE_OBJS += kona.o
 endif
 
+ifdef CONFIG_SND_SOC_LITO
+	MACHINE_OBJS += kona.o
+endif
+
 ifdef CONFIG_SND_SOC_CPE
 	CPE_LSM_OBJS += msm-cpe-lsm.o
 endif
@@ -192,6 +201,9 @@
 obj-$(CONFIG_SND_SOC_KONA) += machine_dlkm.o
 machine_dlkm-y := $(MACHINE_OBJS)
 
+obj-$(CONFIG_SND_SOC_LITO) += machine_dlkm.o
+machine_dlkm-y := $(MACHINE_OBJS)
+
 obj-$(CONFIG_SND_SOC_CPE) += cpe_lsm_dlkm.o
 cpe_lsm_dlkm-y := $(CPE_LSM_OBJS)
 
diff --git a/asoc/codecs/Android.mk b/asoc/codecs/Android.mk
index b73b983..539bd55 100644
--- a/asoc/codecs/Android.mk
+++ b/asoc/codecs/Android.mk
@@ -19,9 +19,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/asoc/codecs/Kbuild b/asoc/codecs/Kbuild
index a40c75f..1d7142a 100644
--- a/asoc/codecs/Kbuild
+++ b/asoc/codecs/Kbuild
@@ -34,6 +34,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_SDMSHRIKE), y)
 		include $(AUDIO_ROOT)/config/sm8150auto.conf
 		export
diff --git a/asoc/codecs/bolero/Android.mk b/asoc/codecs/bolero/Android.mk
index d96d616..cf51a44 100644
--- a/asoc/codecs/bolero/Android.mk
+++ b/asoc/codecs/bolero/Android.mk
@@ -11,9 +11,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/asoc/codecs/bolero/Kbuild b/asoc/codecs/bolero/Kbuild
index 25d7881..374b528 100644
--- a/asoc/codecs/bolero/Kbuild
+++ b/asoc/codecs/bolero/Kbuild
@@ -31,6 +31,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_QCS405), y)
 		include $(AUDIO_ROOT)/config/qcs405auto.conf
 		export
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index 0fc13ee..e43fa62 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -7,6 +7,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -20,6 +21,7 @@
 #include "bolero-cdc-registers.h"
 #include "bolero-clk-rsc.h"
 
+#define AUTO_SUSPEND_DELAY  50 /* delay in msec */
 #define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
 			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
@@ -1623,6 +1625,9 @@
 	case INTERP_AUX:
 		snd_soc_component_update_bits(component,
 				BOLERO_CDC_RX_RX2_RX_PATH_CFG0,
+				0x08, 0x08);
+		snd_soc_component_update_bits(component,
+				BOLERO_CDC_RX_RX2_RX_PATH_CFG0,
 				0x10, 0x10);
 		break;
 	}
@@ -2195,16 +2200,18 @@
 			(interp_idx * RX_MACRO_RX_PATH_OFFSET);
 	dsm_reg = BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL +
 			(interp_idx * RX_MACRO_RX_PATH_OFFSET);
+	if (interp_idx == INTERP_AUX)
+		dsm_reg = BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL;
 	rx_cfg2_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG2 +
 			(interp_idx * RX_MACRO_RX_PATH_OFFSET);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		if (rx_priv->main_clk_users[interp_idx] == 0) {
-			snd_soc_component_update_bits(component, dsm_reg,
-					0x01, 0x01);
 			/* Main path PGA mute enable */
 			snd_soc_component_update_bits(component, main_reg,
 					0x10, 0x10);
+			snd_soc_component_update_bits(component, dsm_reg,
+					0x01, 0x01);
 			/* Clk enable */
 			snd_soc_component_update_bits(component, main_reg,
 					0x20, 0x20);
@@ -3235,6 +3242,7 @@
 	dev_dbg(rx_priv->dev, "%s: swrm clock %s\n",
 		__func__, (enable ? "enable" : "disable"));
 	if (enable) {
+		pm_runtime_get_sync(rx_priv->dev);
 		if (rx_priv->swr_clk_users == 0) {
 			msm_cdc_pinctrl_select_active_state(
 						rx_priv->rx_swr_gpio_p);
@@ -3260,6 +3268,8 @@
 					0x02, 0x00);
 			rx_priv->reset_swr = false;
 		}
+		pm_runtime_mark_last_busy(rx_priv->dev);
+		pm_runtime_put_autosuspend(rx_priv->dev);
 		rx_priv->swr_clk_users++;
 	} else {
 		if (rx_priv->swr_clk_users <= 0) {
@@ -3647,6 +3657,10 @@
 		goto err_reg_macro;
 	}
 	schedule_work(&rx_priv->rx_macro_add_child_devices_work);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
 
 	return 0;
 
@@ -3670,6 +3684,8 @@
 		count < RX_MACRO_CHILD_DEVICES_MAX; count++)
 		platform_device_unregister(rx_priv->pdev_child_devices[count]);
 
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
 	bolero_unregister_macro(&pdev->dev, RX_MACRO);
 	mutex_destroy(&rx_priv->mclk_lock);
 	mutex_destroy(&rx_priv->swr_clk_lock);
@@ -3682,10 +3698,19 @@
 	{}
 };
 
+static const struct dev_pm_ops bolero_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(
+		bolero_runtime_suspend,
+		bolero_runtime_resume,
+		NULL
+	)
+};
+
 static struct platform_driver rx_macro_driver = {
 	.driver = {
 		.name = "rx_macro",
 		.owner = THIS_MODULE,
+		.pm = &bolero_dev_pm_ops,
 		.of_match_table = rx_macro_dt_match,
 	},
 	.probe = rx_macro_probe,
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index b7d7d37..49b7da5 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -8,6 +8,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
@@ -18,6 +19,7 @@
 #include "bolero-cdc-registers.h"
 #include "bolero-clk-rsc.h"
 
+#define AUTO_SUSPEND_DELAY  50 /* delay in msec */
 #define TX_MACRO_MAX_OFFSET 0x1000
 
 #define NUM_DECIMATORS 8
@@ -110,6 +112,11 @@
 	ANC_FB_TUNE1
 };
 
+enum {
+	TX_MCLK,
+	VA_MCLK,
+};
+
 struct tx_mute_work {
 	struct tx_macro_priv *tx_priv;
 	u32 decimator;
@@ -152,6 +159,7 @@
 	int child_count;
 	int tx_swr_clk_cnt;
 	int va_swr_clk_cnt;
+	int swr_clk_type;
 };
 
 static bool tx_macro_get_data(struct snd_soc_component *component,
@@ -1457,6 +1465,138 @@
 			  0, -84, 40, digital_gain),
 };
 
+static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv,
+				      struct regmap *regmap, int clk_type,
+				      bool enable)
+{
+	int ret = 0;
+
+	dev_dbg(tx_priv->dev,
+		"%s: clock type %s, enable: %s tx_mclk_users: %d\n",
+		__func__, (clk_type ? "VA_MCLK" : "TX_MCLK"),
+		(enable ? "enable" : "disable"), tx_priv->tx_mclk_users);
+
+	if (enable) {
+		if (tx_priv->swr_clk_users == 0) {
+			msm_cdc_pinctrl_select_active_state(
+						tx_priv->tx_swr_gpio_p);
+
+			ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+							   TX_CORE_CLK,
+							   TX_CORE_CLK,
+							   true);
+			if (clk_type == TX_MCLK) {
+				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_ratelimited(tx_priv->dev,
+						"%s: request clock enable failed\n",
+						__func__);
+					goto done;
+				}
+			}
+			if (clk_type == VA_MCLK) {
+				ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+								   TX_CORE_CLK,
+								   VA_CORE_CLK,
+								   true);
+				if (ret < 0) {
+					msm_cdc_pinctrl_select_sleep_state(
+							tx_priv->tx_swr_gpio_p);
+					dev_err_ratelimited(tx_priv->dev,
+						"%s: swr request clk failed\n",
+						__func__);
+					goto done;
+				}
+				if (tx_priv->tx_mclk_users == 0) {
+					regmap_update_bits(regmap,
+						BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK,
+						0x01, 0x01);
+					regmap_update_bits(regmap,
+					BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+						0x01, 0x01);
+					regmap_update_bits(regmap,
+				      BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+						0x01, 0x01);
+				}
+			}
+			dev_dbg(tx_priv->dev, "%s: reset_swr: %d\n",
+				__func__, tx_priv->reset_swr);
+			if (tx_priv->reset_swr)
+				regmap_update_bits(regmap,
+					BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+					0x02, 0x02);
+			regmap_update_bits(regmap,
+				BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x01);
+			if (tx_priv->reset_swr)
+				regmap_update_bits(regmap,
+					BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+					0x02, 0x00);
+			ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+							   TX_CORE_CLK,
+							   TX_CORE_CLK,
+							   false);
+			tx_priv->reset_swr = false;
+		}
+		tx_priv->swr_clk_users++;
+	} else {
+		if (tx_priv->swr_clk_users <= 0) {
+			dev_err_ratelimited(tx_priv->dev,
+				"tx swrm clock users already 0\n");
+			tx_priv->swr_clk_users = 0;
+			return 0;
+		}
+		tx_priv->swr_clk_users--;
+		if (tx_priv->swr_clk_users == 0) {
+			ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+							   TX_CORE_CLK,
+							   TX_CORE_CLK,
+							   true);
+			regmap_update_bits(regmap,
+				BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x00);
+			if (clk_type == TX_MCLK)
+				tx_macro_mclk_enable(tx_priv, 0);
+			if (clk_type == VA_MCLK) {
+				if (tx_priv->tx_mclk_users == 0) {
+					regmap_update_bits(regmap,
+				      BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+						0x01, 0x00);
+					regmap_update_bits(regmap,
+					BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+						0x01, 0x00);
+				}
+				ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+								   TX_CORE_CLK,
+								   VA_CORE_CLK,
+								   false);
+				if (ret < 0) {
+					dev_err_ratelimited(tx_priv->dev,
+						"%s: swr request clk failed\n",
+						__func__);
+					goto done;
+				}
+			}
+			ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+							   TX_CORE_CLK,
+							   TX_CORE_CLK,
+							   false);
+			msm_cdc_pinctrl_select_sleep_state(
+						tx_priv->tx_swr_gpio_p);
+		}
+	}
+	return 0;
+
+done:
+	bolero_clk_rsc_request_clock(tx_priv->dev,
+				TX_CORE_CLK,
+				TX_CORE_CLK,
+				false);
+	return ret;
+}
+
 static int tx_macro_swrm_clock(void *handle, bool enable)
 {
 	struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
@@ -1469,56 +1609,54 @@
 	}
 
 	mutex_lock(&tx_priv->swr_clk_lock);
-
 	dev_dbg(tx_priv->dev, "%s: swrm clock %s\n",
 		__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__);
-				goto exit;
-			}
-			if (tx_priv->reset_swr)
-				regmap_update_bits(regmap,
-					BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
-					0x02, 0x02);
-			regmap_update_bits(regmap,
-				BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
-				0x01, 0x01);
-			if (tx_priv->reset_swr)
-				regmap_update_bits(regmap,
-					BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
-					0x02, 0x00);
-			tx_priv->reset_swr = false;
+		pm_runtime_get_sync(tx_priv->dev);
+		/*For standalone VA usecase, enable VA macro clock */
+		if (tx_priv->va_swr_clk_cnt && !tx_priv->tx_swr_clk_cnt
+			&& (tx_priv->swr_clk_type == TX_MCLK)) {
+			ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
+							VA_MCLK, enable);
+			if (ret)
+				goto done;
+			tx_priv->swr_clk_type = VA_MCLK;
+		} else {
+			/* Disable VA MCLK if its already enabled */
+			if (tx_priv->swr_clk_type == VA_MCLK)
+				tx_macro_tx_va_mclk_enable(tx_priv,
+							regmap, VA_MCLK, false);
+			ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
+							TX_MCLK, enable);
+			if (ret)
+				goto done;
+			tx_priv->swr_clk_type = TX_MCLK;
 		}
-		tx_priv->swr_clk_users++;
+		pm_runtime_mark_last_busy(tx_priv->dev);
+		pm_runtime_put_autosuspend(tx_priv->dev);
 	} else {
-		if (tx_priv->swr_clk_users <= 0) {
-			dev_err(tx_priv->dev,
-				"tx swrm clock users already 0\n");
-			tx_priv->swr_clk_users = 0;
-			goto exit;
-		}
-		tx_priv->swr_clk_users--;
-		if (tx_priv->swr_clk_users == 0) {
-			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);
+		if (tx_priv->swr_clk_type == VA_MCLK) {
+			ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
+							VA_MCLK, enable);
+			if (ret)
+				goto done;
+			tx_priv->swr_clk_type = TX_MCLK;
+		} else {
+			ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap,
+							TX_MCLK, enable);
+			if (tx_priv->va_swr_clk_cnt) {
+				ret = tx_macro_tx_va_mclk_enable(tx_priv,
+						regmap, VA_MCLK, true);
+				if (ret)
+					goto done;
+				tx_priv->swr_clk_type = VA_MCLK;
+			}
 		}
 	}
 	dev_dbg(tx_priv->dev, "%s: swrm clock users %d\n",
 		__func__, tx_priv->swr_clk_users);
-exit:
+done:
 	mutex_unlock(&tx_priv->swr_clk_lock);
 	return ret;
 }
@@ -1884,6 +2022,11 @@
 	}
 
 	schedule_work(&tx_priv->tx_macro_add_child_devices_work);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	return 0;
 err_reg_macro:
 	mutex_destroy(&tx_priv->mclk_lock);
@@ -1906,6 +2049,8 @@
 		count < TX_MACRO_CHILD_DEVICES_MAX; count++)
 		platform_device_unregister(tx_priv->pdev_child_devices[count]);
 
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
 	mutex_destroy(&tx_priv->mclk_lock);
 	mutex_destroy(&tx_priv->swr_clk_lock);
 	bolero_unregister_macro(&pdev->dev, TX_MACRO);
@@ -1918,10 +2063,19 @@
 	{}
 };
 
+static const struct dev_pm_ops bolero_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(
+		bolero_runtime_suspend,
+		bolero_runtime_resume,
+		NULL
+	)
+};
+
 static struct platform_driver tx_macro_driver = {
 	.driver = {
 		.name = "tx_macro",
 		.owner = THIS_MODULE,
+		.pm = &bolero_dev_pm_ops,
 		.of_match_table = tx_macro_dt_match,
 	},
 	.probe = tx_macro_probe,
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index a4f3c7d..cdfe6c7 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -588,10 +588,6 @@
 		/* apply gain after decimator is enabled */
 		snd_soc_component_write(component, tx_gain_ctl_reg,
 			snd_soc_component_read32(component, tx_gain_ctl_reg));
-		bolero_clk_rsc_request_clock(va_priv->dev,
-					   va_priv->default_clk_id,
-					   TX_CORE_CLK,
-					   false);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		hpf_cut_off_freq =
@@ -632,6 +628,37 @@
 	return 0;
 }
 
+static int va_macro_enable_tx(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(w->dapm);
+	struct device *va_dev = NULL;
+	struct va_macro_priv *va_priv = NULL;
+	int ret = 0;
+
+	if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+		return -EINVAL;
+
+	dev_dbg(va_dev, "%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		ret = bolero_clk_rsc_request_clock(va_priv->dev,
+						   va_priv->default_clk_id,
+						   TX_CORE_CLK,
+						   false);
+		break;
+	default:
+		dev_err(va_priv->dev,
+			"%s: invalid DAPM event %d\n", __func__, event);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int va_macro_enable_micbias(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -1007,14 +1034,17 @@
 };
 
 static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
-	SND_SOC_DAPM_AIF_OUT("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
-		SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0),
+	SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
+		SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0,
+		va_macro_enable_tx, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_AIF_OUT("VA_AIF2 CAP", "VA_AIF2 Capture", 0,
-		SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0),
+	SND_SOC_DAPM_AIF_OUT_E("VA_AIF2 CAP", "VA_AIF2 Capture", 0,
+		SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0,
+		va_macro_enable_tx, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_AIF_OUT("VA_AIF3 CAP", "VA_AIF3 Capture", 0,
-		SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0),
+	SND_SOC_DAPM_AIF_OUT_E("VA_AIF3 CAP", "VA_AIF3 Capture", 0,
+		SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0,
+		va_macro_enable_tx, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM,
 		VA_MACRO_AIF1_CAP, 0,
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index dd3f4fe..c8a5e1d 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -7,6 +7,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
@@ -19,6 +20,7 @@
 #include "wsa-macro.h"
 #include "bolero-clk-rsc.h"
 
+#define AUTO_SUSPEND_DELAY  50 /* delay in msec */
 #define WSA_MACRO_MAX_OFFSET 0x1000
 
 #define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
@@ -2548,6 +2550,7 @@
 	dev_dbg(wsa_priv->dev, "%s: swrm clock %s\n",
 		__func__, (enable ? "enable" : "disable"));
 	if (enable) {
+		pm_runtime_get_sync(wsa_priv->dev);
 		if (wsa_priv->swr_clk_users == 0) {
 			msm_cdc_pinctrl_select_active_state(
 						wsa_priv->wsa_swr_gpio_p);
@@ -2573,6 +2576,8 @@
 					0x02, 0x00);
 			wsa_priv->reset_swr = false;
 		}
+		pm_runtime_mark_last_busy(wsa_priv->dev);
+		pm_runtime_put_autosuspend(wsa_priv->dev);
 		wsa_priv->swr_clk_users++;
 	} else {
 		if (wsa_priv->swr_clk_users <= 0) {
@@ -2871,6 +2876,11 @@
 		goto reg_macro_fail;
 	}
 	schedule_work(&wsa_priv->wsa_macro_add_child_devices_work);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	return ret;
 reg_macro_fail:
 	mutex_destroy(&wsa_priv->mclk_lock);
@@ -2892,6 +2902,8 @@
 		count < WSA_MACRO_CHILD_DEVICES_MAX; count++)
 		platform_device_unregister(wsa_priv->pdev_child_devices[count]);
 
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
 	bolero_unregister_macro(&pdev->dev, WSA_MACRO);
 	mutex_destroy(&wsa_priv->mclk_lock);
 	mutex_destroy(&wsa_priv->swr_clk_lock);
@@ -2903,10 +2915,19 @@
 	{}
 };
 
+static const struct dev_pm_ops bolero_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(
+		bolero_runtime_suspend,
+		bolero_runtime_resume,
+		NULL
+	)
+};
+
 static struct platform_driver wsa_macro_driver = {
 	.driver = {
 		.name = "wsa_macro",
 		.owner = THIS_MODULE,
+		.pm = &bolero_dev_pm_ops,
 		.of_match_table = wsa_macro_dt_match,
 	},
 	.probe = wsa_macro_probe,
diff --git a/asoc/codecs/wcd-spi.c b/asoc/codecs/wcd-spi.c
index 145c4df..0173e15 100644
--- a/asoc/codecs/wcd-spi.c
+++ b/asoc/codecs/wcd-spi.c
@@ -14,8 +14,10 @@
 #include <linux/regmap.h>
 #include <linux/component.h>
 #include <linux/ratelimit.h>
+#include <linux/platform_device.h>
 #include <sound/wcd-dsp-mgr.h>
 #include <sound/wcd-spi.h>
+#include <soc/wcd-spi-ac.h>
 #include "wcd-spi-registers.h"
 
 /* Byte manipulations */
@@ -157,6 +159,8 @@
 	/* DMA handles for transfer buffers */
 	dma_addr_t tx_dma;
 	dma_addr_t rx_dma;
+	/* Handle to child (qmi client) device */
+	struct device *ac_dev;
 };
 
 enum xfer_request {
@@ -567,6 +571,19 @@
 	int ret;
 	u32 rd_status = 0;
 
+	/* Get the SPI access first */
+	if (wcd_spi->ac_dev) {
+		ret = wcd_spi_access_ctl(wcd_spi->ac_dev,
+					 WCD_SPI_ACCESS_REQUEST,
+					 WCD_SPI_AC_DATA_TRANSFER);
+		if (ret) {
+			dev_err(&spi->dev,
+				"%s: Can't get spi access, err = %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+
 	ret = wcd_spi_cmd_nop(spi);
 	if (ret < 0) {
 		dev_err(&spi->dev, "%s: NOP1 failed, err = %d\n",
@@ -620,6 +637,17 @@
 	 */
 	clear_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask);
 
+	/* once the clock is released, SPI access can be released as well */
+	if (wcd_spi->ac_dev) {
+		ret = wcd_spi_access_ctl(wcd_spi->ac_dev,
+					 WCD_SPI_ACCESS_RELEASE,
+					 WCD_SPI_AC_DATA_TRANSFER);
+		if (ret)
+			dev_err(&spi->dev,
+				"%s: SPI access release failed, err = %d\n",
+				__func__, ret);
+	}
+
 	return ret;
 }
 
@@ -944,6 +972,18 @@
 		__func__, event);
 
 	switch (event) {
+	case WDSP_EVENT_PRE_SHUTDOWN:
+		if (wcd_spi->ac_dev) {
+			ret = wcd_spi_access_ctl(wcd_spi->ac_dev,
+					 WCD_SPI_ACCESS_REQUEST,
+					 WCD_SPI_AC_REMOTE_DOWN);
+			if (ret)
+				dev_err(&spi->dev,
+					"%s: request access failed %d\n",
+					__func__, ret);
+		}
+		break;
+
 	case WDSP_EVENT_POST_SHUTDOWN:
 		cancel_delayed_work_sync(&wcd_spi->clk_dwork);
 		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
@@ -953,6 +993,18 @@
 		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
 		break;
 
+	case WDSP_EVENT_POST_BOOTUP:
+		if (wcd_spi->ac_dev) {
+			ret = wcd_spi_access_ctl(wcd_spi->ac_dev,
+					 WCD_SPI_ACCESS_RELEASE,
+					 WCD_SPI_AC_REMOTE_DOWN);
+			if (ret)
+				dev_err(&spi->dev,
+					"%s: release access failed %d\n",
+					__func__, ret);
+		}
+		break;
+
 	case WDSP_EVENT_PRE_DLOAD_CODE:
 	case WDSP_EVENT_PRE_DLOAD_DATA:
 		ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE,
@@ -1299,10 +1351,50 @@
 	.readable_reg = wcd_spi_is_readable_reg,
 };
 
+static int wcd_spi_add_ac_dev(struct device *dev,
+			       struct device_node *node)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct platform_device *pdev;
+	int ret = 0;
+
+	pdev = platform_device_alloc("wcd-spi-ac", -1);
+	if (IS_ERR_OR_NULL(pdev)) {
+		ret = PTR_ERR(pdev);
+		dev_err(dev, "%s: pdev alloc failed, ret = %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	pdev->dev.parent = dev;
+	pdev->dev.of_node = node;
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		dev_err(dev, "%s: pdev add failed, ret = %d\n",
+			__func__, ret);
+		goto dealloc_pdev;
+	}
+
+	wcd_spi->ac_dev = &pdev->dev;
+	return 0;
+
+dealloc_pdev:
+	platform_device_put(pdev);
+	return ret;
+}
+
 static int wdsp_spi_init(struct device *dev, void *priv_data)
 {
 	struct spi_device *spi = to_spi_device(dev);
 	int ret;
+	struct device_node *node;
+
+	for_each_child_of_node(dev->of_node, node) {
+		if (!strcmp(node->name, "wcd_spi_ac"))
+			wcd_spi_add_ac_dev(dev, node);
+	}
 
 	ret = wcd_spi_init(spi);
 	if (ret < 0)
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index 5e9994f..fcc4e6f 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -1491,7 +1491,6 @@
 		dev_err(&swr_dev->dev,
 			"%s get devnum %d for dev addr %lx failed\n",
 			__func__, devnum, swr_dev->addr);
-		swr_remove_device(swr_dev);
 		return ret;
 	}
 	swr_dev->dev_num = devnum;
diff --git a/asoc/codecs/wcd938x/Android.mk b/asoc/codecs/wcd938x/Android.mk
index 81bb356..96fb6f5 100644
--- a/asoc/codecs/wcd938x/Android.mk
+++ b/asoc/codecs/wcd938x/Android.mk
@@ -7,9 +7,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,kona),true)
+ifeq ($(call is-board-platform-in-list,kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/asoc/codecs/wcd938x/Kbuild b/asoc/codecs/wcd938x/Kbuild
index 3090890..e301bd5 100644
--- a/asoc/codecs/wcd938x/Kbuild
+++ b/asoc/codecs/wcd938x/Kbuild
@@ -19,6 +19,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 
 endif
 
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index 96d9b98..ca20bc4 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -39,8 +39,7 @@
 
 enum {
 	WCD9380 = 0,
-	WCD9385,
-	WCD9385FX,
+	WCD9385 = 5,
 };
 
 enum {
@@ -1762,6 +1761,14 @@
 	return 0;
 }
 
+static const char * const tx_mode_mux_text_wcd9380[] = {
+	"ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
+};
+
+static const struct soc_enum tx_mode_mux_enum_wcd9380 =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_mux_text_wcd9380),
+			    tx_mode_mux_text_wcd9380);
+
 static const char * const tx_mode_mux_text[] = {
 	"ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
 	"ADC_ULP1", "ADC_ULP2",
@@ -1780,10 +1787,18 @@
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
 			    rx_hph_mode_mux_text);
 
-static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
-	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
-		wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put),
+static const struct snd_kcontrol_new wcd9380_snd_controls[] = {
+	SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum_wcd9380,
+			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+	SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum_wcd9380,
+			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+	SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum_wcd9380,
+			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+	SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum_wcd9380,
+			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+};
 
+static const struct snd_kcontrol_new wcd9385_snd_controls[] = {
 	SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum,
 			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
 	SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum,
@@ -1792,6 +1807,11 @@
 			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
 	SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum,
 			wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+};
+
+static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
+	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+		wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put),
 
 	SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0,
 		wcd938x_get_compander, wcd938x_set_compander),
@@ -2413,6 +2433,26 @@
 	wcd_cls_h_init(&wcd938x->clsh_info);
 	wcd938x_init_reg(component);
 
+	if (wcd938x->variant == WCD9380) {
+		ret = snd_soc_add_component_controls(component, wcd9380_snd_controls,
+					ARRAY_SIZE(wcd9380_snd_controls));
+		if (ret < 0) {
+			dev_err(component->dev,
+				"%s: Failed to add snd ctrls for variant: %d\n",
+				__func__, wcd938x->variant);
+			goto err_hwdep;
+		}
+	}
+	if (wcd938x->variant == WCD9385) {
+		ret = snd_soc_add_component_controls(component, wcd9385_snd_controls,
+					ARRAY_SIZE(wcd9385_snd_controls));
+		if (ret < 0) {
+			dev_err(component->dev,
+				"%s: Failed to add snd ctrls for variant: %d\n",
+				__func__, wcd938x->variant);
+			goto err_hwdep;
+		}
+	}
 	wcd938x->version = WCD938X_VERSION_1_0;
        /* Register event notifier */
 	wcd938x->nblock.notifier_call = wcd938x_event_notify;
diff --git a/asoc/kona.c b/asoc/kona.c
index 9508b95..574c652 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -378,6 +378,8 @@
 	[AFE_LOOPBACK_TX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
 };
 
+static int msm_vi_feed_tx_ch = 2;
+static const char *const vi_feed_ch_text[] = {"One", "Two"};
 static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
 					  "S32_LE"};
 static char const *ch_text[] = {"Two", "Three", "Four", "Five",
@@ -436,6 +438,7 @@
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
@@ -545,7 +548,6 @@
 static int dmic_0_1_gpio_cnt;
 static int dmic_2_3_gpio_cnt;
 static int dmic_4_5_gpio_cnt;
-static int msm_vi_feed_tx_ch = 2;
 
 static void *def_wcd_mbhc_cal(void);
 
@@ -980,6 +982,23 @@
 	return 1;
 }
 
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
+	pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
+	pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
+	return 1;
+}
+
 static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol)
 {
 	int idx = 0;
@@ -3332,6 +3351,8 @@
 			msm_bt_sample_rate_tx_put),
 	SOC_ENUM_EXT("AFE_LOOPBACK_TX Channels", afe_loopback_tx_chs,
 			afe_loopback_tx_ch_get, afe_loopback_tx_ch_put),
+	SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
+			msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 179a95e..a7b9ff2 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -1779,6 +1779,11 @@
 	atomic_set(&prtd->wait_on_close, 0);
 	atomic_set(&prtd->error, 0);
 
+	init_waitqueue_head(&prtd->eos_wait);
+	init_waitqueue_head(&prtd->drain_wait);
+	init_waitqueue_head(&prtd->close_wait);
+	init_waitqueue_head(&prtd->wait_for_stream_avail);
+
 	runtime->private_data = prtd;
 
 	return 0;
diff --git a/asoc/msm-dai-fe.c b/asoc/msm-dai-fe.c
index c4976a4..6256e8a 100644
--- a/asoc/msm-dai-fe.c
+++ b/asoc/msm-dai-fe.c
@@ -2026,7 +2026,7 @@
 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
 				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 8,
+			.channels_max = 16,
 			.rate_min = 8000,
 			.rate_max = 48000,
 		},
@@ -2042,7 +2042,7 @@
 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
 				    SNDRV_PCM_FMTBIT_S24_LE),
 			.channels_min = 1,
-			.channels_max = 8,
+			.channels_max = 16,
 			.rate_min = 8000,
 			.rate_max = 48000,
 		},
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index fd83b0e..d4f33c7 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -274,6 +274,7 @@
 	struct afe_clk_set clk_set; /* hold LPASS clock config. */
 	union afe_port_group_config group_cfg; /* hold tdm group config */
 	struct afe_tdm_port_config port_cfg; /* hold tdm config */
+	struct afe_param_id_tdm_lane_cfg lane_cfg; /* hold tdm lane config */
 };
 
 /* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
@@ -339,6 +340,11 @@
 
 static atomic_t tdm_group_ref[IDX_GROUP_TDM_MAX];
 
+static struct afe_param_id_tdm_lane_cfg tdm_lane_cfg = {
+	AFE_GROUP_DEVICE_ID_QUINARY_TDM_RX,
+	0x0,
+};
+
 /* cache of group cfg per parent node */
 static struct afe_param_id_group_device_tdm_cfg tdm_group_cfg = {
 	AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG,
@@ -6636,6 +6642,24 @@
 	} else
 		dev_dbg(&pdev->dev, "%s: clk attribute not found\n", __func__);
 
+	/* extract tdm lane cfg to static */
+	tdm_lane_cfg.port_id = tdm_group_cfg.group_id;
+	tdm_lane_cfg.lane_mask = AFE_LANE_MASK_INVALID;
+	if (of_find_property(pdev->dev.of_node,
+			"qcom,msm-cpudai-tdm-lane-mask", NULL)) {
+		rc = of_property_read_u16(pdev->dev.of_node,
+			"qcom,msm-cpudai-tdm-lane-mask",
+			&tdm_lane_cfg.lane_mask);
+		if (rc) {
+			dev_err(&pdev->dev, "%s: value for tdm lane mask not found %s\n",
+				__func__, "qcom,msm-cpudai-tdm-lane-mask");
+			goto rtn;
+		}
+		dev_dbg(&pdev->dev, "%s: tdm lane mask from DT file %d\n",
+			__func__, tdm_lane_cfg.lane_mask);
+	} else
+		dev_dbg(&pdev->dev, "%s: tdm lane mask not found\n", __func__);
+
 	/* extract tdm clk src master/slave info into static */
 	rc = of_property_read_u32(pdev->dev.of_node,
 		"qcom,msm-cpudai-tdm-clk-internal",
@@ -7742,7 +7766,7 @@
 
 		if (atomic_read(group_ref) == 0) {
 			rc = afe_port_group_enable(group_id,
-				NULL, false);
+				NULL, false, NULL);
 			if (rc < 0) {
 				dev_err(dai->dev, "fail to disable AFE group 0x%x\n",
 					group_id);
@@ -8112,7 +8136,17 @@
 	 * NOTE: group config is set to the same as slot config.
 	 */
 	tdm_group->bit_width = tdm_group->slot_width;
-	tdm_group->num_channels = tdm_group->nslots_per_frame;
+
+	/*
+	 * for multi lane scenario
+	 * Total number of active channels = number of active lanes * number of active slots.
+	 */
+	if (dai_data->lane_cfg.lane_mask != AFE_LANE_MASK_INVALID)
+		tdm_group->num_channels = tdm_group->nslots_per_frame
+			* num_of_bits_set(dai_data->lane_cfg.lane_mask);
+	else
+		tdm_group->num_channels = tdm_group->nslots_per_frame;
+
 	tdm_group->sample_rate = dai_data->rate;
 
 	pr_debug("%s: TDM GROUP:\n"
@@ -8137,6 +8171,10 @@
 		tdm_group->port_id[5],
 		tdm_group->port_id[6],
 		tdm_group->port_id[7]);
+	pr_debug("%s: TDM GROUP ID 0x%x lane mask 0x%x:\n",
+		__func__,
+		tdm_group->group_id,
+		dai_data->lane_cfg.lane_mask);
 
 	/*
 	 * update tdm config param
@@ -8292,7 +8330,8 @@
 			 */
 			if (dai_data->num_group_ports > 1) {
 				rc = afe_port_group_enable(group_id,
-					&dai_data->group_cfg, true);
+					&dai_data->group_cfg, true,
+					&dai_data->lane_cfg);
 				if (rc < 0) {
 					dev_err(dai->dev,
 					"%s: fail to enable AFE group 0x%x\n",
@@ -8307,7 +8346,7 @@
 		if (rc < 0) {
 			if (atomic_read(group_ref) == 0) {
 				afe_port_group_enable(group_id,
-					NULL, false);
+					NULL, false, NULL);
 			}
 			if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) {
 				msm_dai_q6_tdm_set_clk(dai_data,
@@ -8364,7 +8403,7 @@
 
 		if (atomic_read(group_ref) == 0) {
 			rc = afe_port_group_enable(group_id,
-				NULL, false);
+				NULL, false, NULL);
 			if (rc < 0) {
 				dev_err(dai->dev, "%s: fail to disable AFE group 0x%x\n",
 					__func__, group_id);
@@ -10269,7 +10308,7 @@
 	dai_data->group_cfg.tdm_cfg = tdm_group_cfg;
 	/* copy static num group ports per parent node */
 	dai_data->num_group_ports = num_tdm_group_ports;
-
+	dai_data->lane_cfg = tdm_lane_cfg;
 
 	dev_set_drvdata(&pdev->dev, dai_data);
 
diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c
index b101b37..3a5707e 100644
--- a/asoc/msm-lsm-client.c
+++ b/asoc/msm-lsm-client.c
@@ -196,7 +196,8 @@
 }
 
 static void lsm_event_handler(uint32_t opcode, uint32_t token,
-			      uint32_t *payload, void *priv)
+			      uint32_t *payload, uint16_t client_size,
+				void *priv)
 {
 	unsigned long flags;
 	struct lsm_priv *prtd = priv;
@@ -279,15 +280,27 @@
 	}
 
 	case LSM_SESSION_EVENT_DETECTION_STATUS:
+                if (client_size < 3 * sizeof(uint8_t)) {
+			dev_err(rtd->dev,
+					"%s: client_size has invalid size[%d]\n",
+					__func__, client_size);
+			return;
+		}
 		status = (uint16_t)((uint8_t *)payload)[0];
 		payload_size = (uint16_t)((uint8_t *)payload)[2];
 		index = 4;
 		dev_dbg(rtd->dev,
 			"%s: event detect status = %d payload size = %d\n",
 			__func__, status, payload_size);
-	break;
+		break;
 
 	case LSM_SESSION_EVENT_DETECTION_STATUS_V2:
+		if (client_size < 2 * sizeof(uint8_t)) {
+			dev_err(rtd->dev,
+					"%s: client_size has invalid size[%d]\n",
+					__func__, client_size);
+			return;
+		}
 		status = (uint16_t)((uint8_t *)payload)[0];
 		payload_size = (uint16_t)((uint8_t *)payload)[1];
 		index = 2;
@@ -297,6 +310,12 @@
 		break;
 
 	case LSM_SESSION_EVENT_DETECTION_STATUS_V3:
+		if (client_size < 2 * (sizeof(uint32_t) + sizeof(uint8_t))) {
+			dev_err(rtd->dev,
+					"%s: client_size has invalid size[%d]\n",
+					__func__, client_size);
+			return;
+		}
 		event_ts_lsw = ((uint32_t *)payload)[0];
 		event_ts_msw = ((uint32_t *)payload)[1];
 		status = (uint16_t)((uint8_t *)payload)[8];
@@ -310,6 +329,13 @@
 
 	case LSM_SESSION_DETECTION_ENGINE_GENERIC_EVENT: {
 		struct snd_lsm_event_status *tmp;
+		if (client_size < 2 * sizeof(uint16_t)) {
+			dev_err(rtd->dev,
+					"%s: client_size has invalid size[%d]\n",
+					__func__, client_size);
+			return;
+		}
+
 
 		status = ((uint16_t *)payload)[0];
 		payload_size = ((uint16_t *)payload)[1];
@@ -332,8 +358,16 @@
 		prtd->det_event = tmp;
 		prtd->det_event->status = status;
 		prtd->det_event->payload_size = payload_size;
-		memcpy(prtd->det_event->payload, &((uint8_t *)payload)[4],
-		       payload_size);
+		if (client_size >= payload_size + 4) {
+			memcpy(prtd->det_event->payload,
+				&((uint8_t *)payload)[4], payload_size);
+		} else {
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			dev_err(rtd->dev,
+				"%s: Failed to copy memory with invalid size = %d\n",
+				__func__, payload_size);
+			return;
+		}
 		prtd->event_avail = 1;
 		spin_unlock_irqrestore(&prtd->event_lock, flags);
 		wake_up(&prtd->event_wait);
@@ -375,12 +409,20 @@
 		prtd->event_status->payload_size = payload_size;
 
 		if (likely(prtd->event_status)) {
-			memcpy(prtd->event_status->payload,
-			       &((uint8_t *)payload)[index],
-			       payload_size);
-			prtd->event_avail = 1;
-			spin_unlock_irqrestore(&prtd->event_lock, flags);
-			wake_up(&prtd->event_wait);
+			if (client_size >= (payload_size + index)) {
+				memcpy(prtd->event_status->payload,
+					&((uint8_t *)payload)[index],
+					payload_size);
+				prtd->event_avail = 1;
+				spin_unlock_irqrestore(&prtd->event_lock, flags);
+				wake_up(&prtd->event_wait);
+			} else {
+				spin_unlock_irqrestore(&prtd->event_lock, flags);
+				dev_err(rtd->dev,
+						"%s: Failed to copy memory with invalid size = %d\n",
+						__func__, payload_size);
+				return;
+			}
 		} else {
 			spin_unlock_irqrestore(&prtd->event_lock, flags);
 			dev_err(rtd->dev,
diff --git a/asoc/msm-pcm-q6-noirq.c b/asoc/msm-pcm-q6-noirq.c
index a317142..3452614 100644
--- a/asoc/msm-pcm-q6-noirq.c
+++ b/asoc/msm-pcm-q6-noirq.c
@@ -663,7 +663,7 @@
 {
 	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
 	struct snd_pcm_substream *substream =
-		vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+		vol->pcm->streams[vol->stream].substream;
 	struct msm_audio *prtd;
 
 	pr_debug("%s\n", __func__);
@@ -687,7 +687,7 @@
 	int rc = 0;
 	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
 	struct snd_pcm_substream *substream =
-		vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+		vol->pcm->streams[vol->stream].substream;
 	struct msm_audio *prtd;
 	int volume = ucontrol->value.integer.value[0];
 
@@ -708,15 +708,16 @@
 	return rc;
 }
 
-static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd,
+				      int stream)
 {
 	int ret = 0;
 	struct snd_pcm *pcm = rtd->pcm;
 	struct snd_pcm_volume *volume_info;
 	struct snd_kcontrol *kctl;
 
-	dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
-	ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+	dev_dbg(rtd->dev, "%s, volume control add\n", __func__);
+	ret = snd_pcm_add_volume_ctls(pcm, stream,
 			NULL, 1, rtd->dai_link->id,
 			&volume_info);
 	if (ret < 0) {
@@ -1223,12 +1224,16 @@
 		pr_err("%s: Could not add pcm Channel Map Control\n",
 			__func__);
 
-	ret = msm_pcm_add_volume_control(rtd);
+	ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_PLAYBACK);
 	if (ret) {
-		pr_err("%s: Could not add pcm Volume Control %d\n",
+		pr_err("%s: Could not add pcm playback volume Control %d\n",
 			__func__, ret);
 	}
-
+	ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE);
+	if (ret) {
+		pr_err("%s: Could not add pcm capture volume Control %d\n",
+			__func__, ret);
+	}
 	ret = msm_pcm_add_fe_topology_control(rtd);
 	if (ret) {
 		pr_err("%s: Could not add pcm topology control %d\n",
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index a087dd8..b010010 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -1391,7 +1391,7 @@
 {
 	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
 	struct snd_pcm_substream *substream =
-		vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+		vol->pcm->streams[vol->stream].substream;
 	struct msm_audio *prtd;
 
 	pr_debug("%s\n", __func__);
@@ -1415,7 +1415,7 @@
 	int rc = 0;
 	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
 	struct snd_pcm_substream *substream =
-		vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+		vol->pcm->streams[vol->stream].substream;
 	struct msm_audio *prtd;
 	int volume = ucontrol->value.integer.value[0];
 
@@ -1436,15 +1436,16 @@
 	return rc;
 }
 
-static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd,
+				      int stream)
 {
 	int ret = 0;
 	struct snd_pcm *pcm = rtd->pcm;
 	struct snd_pcm_volume *volume_info;
 	struct snd_kcontrol *kctl;
 
-	dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
-	ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+	dev_dbg(rtd->dev, "%s, volume control add\n", __func__);
+	ret = snd_pcm_add_volume_ctls(pcm, stream,
 			NULL, 1, rtd->dai_link->id,
 			&volume_info);
 	if (ret < 0) {
@@ -2575,11 +2576,14 @@
 		return ret;
 	}
 
-	ret = msm_pcm_add_volume_control(rtd);
+	ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_PLAYBACK);
 	if (ret)
 		pr_err("%s: Could not add pcm Volume Control %d\n",
 			__func__, ret);
-
+	ret = msm_pcm_add_volume_control(rtd, SNDRV_PCM_STREAM_CAPTURE);
+	if (ret)
+		pr_err("%s: Could not add pcm Volume Control %d\n",
+			__func__, ret);
 	ret = msm_pcm_add_compress_control(rtd);
 	if (ret)
 		pr_err("%s: Could not add pcm Compress Control %d\n",
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index cf56038..d5bad0f 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -1990,6 +1990,10 @@
 	if (!route_check_fe_id_adm_support(val)) {
 		/* ignore adm open if not supported for fe_id */
 		pr_debug("%s: No ADM support for fe id %d\n", __func__, val);
+		if (set)
+			set_bit(val, &msm_bedais[reg].fe_sessions[0]);
+		else
+			clear_bit(val, &msm_bedais[reg].fe_sessions[0]);
 		return;
 	}
 
@@ -12647,6 +12651,14 @@
 	MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -12808,6 +12820,14 @@
 	MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -12828,23 +12848,31 @@
 
 static const struct snd_kcontrol_new pri_mi2s_rx_voice_mixer_controls[] = {
 	SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM,
-MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
-MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM,
-MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
-MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM,
-MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
 };
@@ -12900,6 +12928,14 @@
 	MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -12923,6 +12959,14 @@
 	MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -12946,6 +12990,14 @@
 	MSM_BACKEND_DAI_QUINARY_MI2S_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_QUINARY_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -13408,6 +13460,146 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new pri_tdm_rx_0_voice_mixer_controls[] = {
+	SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_1_voice_mixer_controls[] = {
+	SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_2_voice_mixer_controls[] = {
+	SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_rx_3_voice_mixer_controls[] = {
+	SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
 static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
 	SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_EXTPROC_RX,
@@ -13523,6 +13715,15 @@
 	SOC_DOUBLE_EXT("TX_CDC_DMA_TX_5_MMode1", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TX_CDC_DMA_TX_5, MSM_FRONTEND_DAI_VOICEMMODE1,
 	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QUAT_MI2S_TX_MMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QUIN_MI2S_TX_MMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUINARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("PRI_TDM_TX3_MMode1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_VOICEMMODE1,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = {
@@ -13603,6 +13804,15 @@
 	SOC_DOUBLE_EXT("TX_CDC_DMA_TX_5_MMode2", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TX_CDC_DMA_TX_5, MSM_FRONTEND_DAI_VOICEMMODE2,
 	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QUAT_MI2S_TX_MMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("QUIN_MI2S_TX_MMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUINARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_DOUBLE_EXT("PRI_TDM_TX3_MMode2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_VOICEMMODE1,
+	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
@@ -13697,6 +13907,9 @@
 	SOC_DOUBLE_EXT("TX_CDC_DMA_TX_5_Voip", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_TX_CDC_DMA_TX_5, MSM_FRONTEND_DAI_VOIP,
 	1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3_Voip", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -13867,6 +14080,10 @@
 	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
 	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 	SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_SLIMBUS_7_TX,
 	MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
@@ -16368,6 +16585,14 @@
 		msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new quat_tdm_rx_7_port_mixer_controls[] = {
+	SOC_DOUBLE_EXT("QUAT_TDM_TX_7", SND_SOC_NOPM,
+		MSM_BACKEND_DAI_QUAT_TDM_RX_7,
+		MSM_BACKEND_DAI_QUAT_TDM_TX_7, 1, 0,
+		msm_routing_get_port_mixer,
+		msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new quin_tdm_rx_0_port_mixer_controls[] = {
 	SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM,
 		MSM_BACKEND_DAI_QUIN_TDM_RX_0,
@@ -18122,6 +18347,9 @@
 	} else if (!strcmp(kcontrol->id.name + strlen(prefix),
 					"QUIN_TDM_TX_0")) {
 		*port_id = AFE_PORT_ID_QUINARY_TDM_TX;
+	} else if (!strcmp(kcontrol->id.name + strlen(prefix),
+					"PRIMARY_TDM")) {
+		*port_id = AFE_PORT_ID_PRIMARY_TDM_TX;
 	} else {
 		pr_err("%s: mixer ctl name=%s, could not derive valid port id\n",
 			__func__, kcontrol->id.name);
@@ -18500,6 +18728,21 @@
 		.get	= msm_audio_source_tracking_get,
 	},
 	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name   = "Sound Focus Audio Tx PRIMARY_TDM",
+		.info   = msm_sound_focus_info,
+		.get    = msm_audio_sound_focus_get,
+		.put    = msm_audio_sound_focus_put,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name   = "Source Tracking Audio Tx PRIMARY_TDM",
+		.info   = msm_source_tracking_info,
+		.get    = msm_audio_source_tracking_get,
+	},
+	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name	= "Doa Tracking Monitor Listen VA_CDC_DMA_TX_0",
@@ -19846,6 +20089,22 @@
 				SND_SOC_NOPM, 0, 0,
 				quin_mi2s_rx_voice_mixer_controls,
 				ARRAY_SIZE(quin_mi2s_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_0_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_0_voice_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_0_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_1_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_1_voice_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_1_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_2_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_2_voice_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_2_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_TDM_RX_3_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_3_voice_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_3_voice_mixer_controls)),
 	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2_Voice Mixer",
 				SND_SOC_NOPM, 0, 0,
 				quat_tdm_rx_2_voice_mixer_controls,
@@ -20013,6 +20272,9 @@
 	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_3 Port Mixer", SND_SOC_NOPM, 0, 0,
 	quat_tdm_rx_3_port_mixer_controls,
 	ARRAY_SIZE(quat_tdm_rx_3_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_7 Port Mixer", SND_SOC_NOPM, 0, 0,
+	quat_tdm_rx_7_port_mixer_controls,
+	ARRAY_SIZE(quat_tdm_rx_7_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
 	quin_tdm_rx_0_port_mixer_controls,
 	ARRAY_SIZE(quin_tdm_rx_0_port_mixer_controls)),
@@ -22096,6 +22358,8 @@
 	{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
 
 	{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SEC_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SEC_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
@@ -22195,6 +22459,8 @@
 	{"HDMI", NULL, "HDMI_DL_HL"},
 
 	{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
 	{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
 	{"MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
@@ -22202,6 +22468,8 @@
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
 
 	{"PRI_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"PRI_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
 	{"PRI_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"PRI_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"PRI_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
@@ -22223,6 +22491,8 @@
 	{"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_Voice Mixer"},
 
 	{"TERT_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"TERT_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"TERT_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
 	{"TERT_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"TERT_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"TERT_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
@@ -22230,17 +22500,77 @@
 	{"TERT_MI2S_RX", NULL, "TERT_MI2S_RX_Voice Mixer"},
 
 	{"QUAT_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"QUAT_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"QUAT_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
 	{"QUAT_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"QUAT_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
 	{"QUAT_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
 	{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX_Voice Mixer"},
 
 	{"QUIN_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"QUIN_MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"QUIN_MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
 	{"QUIN_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
 	{"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
 	{"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_Voice Mixer"},
 
+	{"PRI_TDM_RX_0_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"PRI_TDM_RX_0_Voice Mixer", "Voice2", "VOICE2_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "QCHAT", "QCHAT_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+	{"PRI_TDM_RX_0_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+	{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0_Voice Mixer"},
+
+	{"PRI_TDM_RX_1_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"PRI_TDM_RX_1_Voice Mixer", "Voice2", "VOICE2_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "QCHAT", "QCHAT_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+	{"PRI_TDM_RX_1_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+	{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1_Voice Mixer"},
+
+	{"PRI_TDM_RX_2_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"PRI_TDM_RX_2_Voice Mixer", "Voice2", "VOICE2_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "QCHAT", "QCHAT_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+	{"PRI_TDM_RX_2_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+	{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2_Voice Mixer"},
+
+	{"PRI_TDM_RX_3_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"PRI_TDM_RX_3_Voice Mixer", "Voice2", "VOICE2_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "QCHAT", "QCHAT_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+	{"PRI_TDM_RX_3_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+	{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3_Voice Mixer"},
+
 	{"QUAT_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
 	{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_Voice Mixer"},
 
@@ -22379,6 +22709,55 @@
 	{"MM_UL28", NULL, "AUDIO_REF_EC_UL28 MUX"},
 	{"MM_UL29", NULL, "AUDIO_REF_EC_UL29 MUX"},
 
+	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+	{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
+	{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
+	{"Voice_Tx Mixer", "TERT_MI2S_TX_Voice", "TERT_MI2S_TX"},
+	{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
+	{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
+	{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
+	{"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
+	{"Voice_Tx Mixer", "SEC_AUX_PCM_TX_Voice", "SEC_AUX_PCM_TX"},
+	{"Voice_Tx Mixer", "SEC_MI2S_TX_Voice", "SEC_MI2S_TX"},
+	{"Voice_Tx Mixer", "PRI_TDM_TX_3_Voice", "PRI_TDM_TX_3"},
+	{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
+
+	{"Voice2_Tx Mixer", "PRI_TX_Voice2", "PRI_I2S_TX"},
+	{"Voice2_Tx Mixer", "PRI_MI2S_TX_Voice2", "PRI_MI2S_TX"},
+	{"Voice2_Tx Mixer", "MI2S_TX_Voice2", "MI2S_TX"},
+	{"Voice2_Tx Mixer", "TERT_MI2S_TX_Voice2", "TERT_MI2S_TX"},
+	{"Voice2_Tx Mixer", "SLIM_0_TX_Voice2", "SLIMBUS_0_TX"},
+	{"Voice2_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice2", "INT_BT_SCO_TX"},
+	{"Voice2_Tx Mixer", "AFE_PCM_TX_Voice2", "PCM_TX"},
+	{"Voice2_Tx Mixer", "AUX_PCM_TX_Voice2", "AUX_PCM_TX"},
+	{"Voice2_Tx Mixer", "SEC_AUX_PCM_TX_Voice2", "SEC_AUX_PCM_TX"},
+	{"Voice2_Tx Mixer", "PRI_TDM_TX_3_Voice2", "PRI_TDM_TX_3"},
+	{"VOICE2_UL", NULL, "Voice2_Tx Mixer"},
+
+	{"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
+	{"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
+	{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
+	{"VoLTE_Tx Mixer", "AFE_PCM_TX_VoLTE", "PCM_TX"},
+	{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
+	{"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
+	{"VoLTE_Tx Mixer", "MI2S_TX_VoLTE", "MI2S_TX"},
+	{"VoLTE_Tx Mixer", "PRI_MI2S_TX_VoLTE", "PRI_MI2S_TX"},
+	{"VoLTE_Tx Mixer", "TERT_MI2S_TX_VoLTE", "TERT_MI2S_TX"},
+	{"VoLTE_Tx Mixer", "PRI_TDM_TX_3_VoLTE", "PRI_TDM_TX_3"},
+	{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
+
+	{"VoWLAN_Tx Mixer", "PRI_TX_VoWLAN", "PRI_I2S_TX"},
+	{"VoWLAN_Tx Mixer", "SLIM_0_TX_VoWLAN", "SLIMBUS_0_TX"},
+	{"VoWLAN_Tx Mixer", "INTERNAL_BT_SCO_TX_VoWLAN", "INT_BT_SCO_TX"},
+	{"VoWLAN_Tx Mixer", "AFE_PCM_TX_VoWLAN", "PCM_TX"},
+	{"VoWLAN_Tx Mixer", "AUX_PCM_TX_VoWLAN", "AUX_PCM_TX"},
+	{"VoWLAN_Tx Mixer", "SEC_AUX_PCM_TX_VoWLAN", "SEC_AUX_PCM_TX"},
+	{"VoWLAN_Tx Mixer", "MI2S_TX_VoWLAN", "MI2S_TX"},
+	{"VoWLAN_Tx Mixer", "PRI_MI2S_TX_VoWLAN", "PRI_MI2S_TX"},
+	{"VoWLAN_Tx Mixer", "TERT_MI2S_TX_VoWLAN", "TERT_MI2S_TX"},
+	{"VoWLAN_Tx Mixer", "PRI_TDM_TX_3_VoWLAN", "PRI_TDM_TX_3"},
+	{"VoWLAN_UL", NULL, "VoWLAN_Tx Mixer"},
+
 	{"VoiceMMode1_Tx Mixer", "PRI_TX_MMode1", "PRI_I2S_TX"},
 	{"VoiceMMode1_Tx Mixer", "PRI_MI2S_TX_MMode1", "PRI_MI2S_TX"},
 	{"VoiceMMode1_Tx Mixer", "MI2S_TX_MMode1", "MI2S_TX"},
@@ -22402,6 +22781,9 @@
 	{"VoiceMMode1_Tx Mixer", "TX_CDC_DMA_TX_3_MMode1", "TX_CDC_DMA_TX_3"},
 	{"VoiceMMode1_Tx Mixer", "TX_CDC_DMA_TX_4_MMode1", "TX_CDC_DMA_TX_4"},
 	{"VoiceMMode1_Tx Mixer", "TX_CDC_DMA_TX_5_MMode1", "TX_CDC_DMA_TX_5"},
+	{"VoiceMMode1_Tx Mixer", "QUAT_MI2S_TX_MMode1", "QUAT_MI2S_TX"},
+	{"VoiceMMode1_Tx Mixer", "QUIN_MI2S_TX_MMode1", "QUIN_MI2S_TX"},
+	{"VoiceMMode1_Tx Mixer", "PRI_TDM_TX_3_MMode1", "PRI_TDM_TX_3"},
 	{"VOICEMMODE1_UL", NULL, "VoiceMMode1_Tx Mixer"},
 
 	{"VoiceMMode2_Tx Mixer", "PRI_TX_MMode2", "PRI_I2S_TX"},
@@ -22426,6 +22808,9 @@
 	{"VoiceMMode2_Tx Mixer", "TX_CDC_DMA_TX_3_MMode2", "TX_CDC_DMA_TX_3"},
 	{"VoiceMMode2_Tx Mixer", "TX_CDC_DMA_TX_4_MMode2", "TX_CDC_DMA_TX_4"},
 	{"VoiceMMode2_Tx Mixer", "TX_CDC_DMA_TX_5_MMode2", "TX_CDC_DMA_TX_5"},
+	{"VoiceMMode2_Tx Mixer", "QUAT_MI2S_TX_MMode2", "QUAT_MI2S_TX"},
+	{"VoiceMMode2_Tx Mixer", "QUIN_MI2S_TX_MMode2", "QUIN_MI2S_TX"},
+	{"VoiceMMode1_Tx Mixer", "PRI_TDM_TX_3_MMode2", "PRI_TDM_TX_3"},
 	{"VOICEMMODE2_UL", NULL, "VoiceMMode2_Tx Mixer"},
 
 	{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
@@ -22444,6 +22829,7 @@
 	{"Voip_Tx Mixer", "QUAT_AUX_PCM_TX_Voip", "QUAT_AUX_PCM_TX"},
 	{"Voip_Tx Mixer", "QUIN_AUX_PCM_TX_Voip", "QUIN_AUX_PCM_TX"},
 	{"Voip_Tx Mixer", "PRI_MI2S_TX_Voip", "PRI_MI2S_TX"},
+	{"Voip_Tx Mixer", "PRI_TDM_TX_3_Voip", "PRI_TDM_TX_3"},
 	{"VOIP_UL", NULL, "Voip_Tx Mixer"},
 
 	{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -22684,10 +23070,12 @@
 	{"QUAT_TDM_TX_1_UL_HL", NULL, "QUAT_TDM_TX_1"},
 	{"QUAT_TDM_TX_2_UL_HL", NULL, "QUAT_TDM_TX_2"},
 	{"QUAT_TDM_TX_3_UL_HL", NULL, "QUAT_TDM_TX_3"},
+	{"QUAT_TDM_TX_7_UL_HL", NULL, "QUAT_TDM_TX_7"},
 	{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0_DL_HL"},
 	{"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1_DL_HL"},
 	{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_DL_HL"},
 	{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3_DL_HL"},
+	{"QUAT_TDM_RX_7", NULL, "QUAT_TDM_RX_7_DL_HL"},
 	{"QUIN_TDM_TX_0_UL_HL", NULL, "QUIN_TDM_TX_0"},
 	{"QUIN_TDM_TX_1_UL_HL", NULL, "QUIN_TDM_TX_1"},
 	{"QUIN_TDM_TX_2_UL_HL", NULL, "QUIN_TDM_TX_2"},
@@ -23052,6 +23440,9 @@
 	{"QUAT_TDM_RX_3 Port Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
 	{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Port Mixer"},
 
+	{"QUAT_TDM_RX_7 Port Mixer", "QUAT_TDM_TX_7", "QUAT_TDM_TX_7"},
+	{"QUAT_TDM_RX_7", NULL, "QUAT_TDM_RX_7 Port Mixer"},
+
 	{"QUIN_TDM_RX_0 Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"QUIN_TDM_RX_0 Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"QUIN_TDM_RX_0 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -23267,6 +23658,7 @@
 	{"VoLTE Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"VoLTE Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"VoLTE Stub Tx Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"VoLTE Stub Tx Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"VOLTE_STUB_UL", NULL, "VoLTE Stub Tx Mixer"},
 
 	{"Voice2 Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
@@ -23280,6 +23672,7 @@
 	{"Voice2 Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"Voice2 Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"Voice2 Stub Tx Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"Voice2 Stub Tx Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"VOICE2_STUB_UL", NULL, "Voice2 Stub Tx Mixer"},
 
 	{"STUB_RX Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
@@ -23471,6 +23864,7 @@
 	{"BE_OUT", NULL, "QUAT_TDM_RX_1"},
 	{"BE_OUT", NULL, "QUAT_TDM_RX_2"},
 	{"BE_OUT", NULL, "QUAT_TDM_RX_3"},
+	{"BE_OUT", NULL, "QUAT_TDM_RX_7"},
 	{"BE_OUT", NULL, "QUIN_TDM_RX_0"},
 	{"BE_OUT", NULL, "QUIN_TDM_RX_1"},
 	{"BE_OUT", NULL, "QUIN_TDM_RX_2"},
@@ -23555,6 +23949,7 @@
 	{"QUAT_TDM_TX_1", NULL, "BE_IN"},
 	{"QUAT_TDM_TX_2", NULL, "BE_IN"},
 	{"QUAT_TDM_TX_3", NULL, "BE_IN"},
+	{"QUAT_TDM_TX_7", NULL, "BE_IN"},
 	{"AFE_LOOPBACK_TX", NULL, "BE_IN"},
 	{"QUIN_TDM_TX_0", NULL, "BE_IN"},
 	{"QUIN_TDM_TX_1", NULL, "BE_IN"},
@@ -23955,6 +24350,11 @@
 	uint32_t size = 0;
 
 	/* Retrieve cal_info size from cal data*/
+	if (data_size < sizeof(struct audio_cal_type_basic) +
+			sizeof(struct audio_cal_info_adm_top)) {
+		pr_err("%s: Invalid data size: %zd\n", __func__, data_size);
+		goto done;
+	}
 	size = data_size - sizeof(struct audio_cal_type_basic);
 	cal_info = kzalloc(size, GFP_KERNEL);
 
diff --git a/asoc/msm-transcode-loopback-q6-v2.c b/asoc/msm-transcode-loopback-q6-v2.c
index 67bdc75..a311cc1 100644
--- a/asoc/msm-transcode-loopback-q6-v2.c
+++ b/asoc/msm-transcode-loopback-q6-v2.c
@@ -1594,10 +1594,7 @@
 
 static int msm_transcode_dev_probe(struct platform_device *pdev)
 {
-
 	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
-	if (pdev->dev.of_node)
-		dev_set_name(&pdev->dev, "%s", "msm-transcode-loopback");
 
 	return snd_soc_register_component(&pdev->dev,
 					&msm_soc_component,
diff --git a/asoc/sa8155.c b/asoc/sa8155.c
index fedb793..aef8a26 100644
--- a/asoc/sa8155.c
+++ b/asoc/sa8155.c
@@ -253,7 +253,7 @@
 		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
 	},
 	{ /* QUAT TDM */
-		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* TX_0 */
+		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* TX_0 */
 		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
 		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
 		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
@@ -409,7 +409,7 @@
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
-		{0xFFFF}, /* not used */
+		{28,0xFFFF},
 	},
 	{/* QUIN TDM */
 		{0, 4, 0xFFFF},/*STEREO SPKR1*/
@@ -464,7 +464,7 @@
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
-		{0xFFFF}, /* not used */
+		{60,0xFFFF},
 	},
 	{/* QUIN TDM */
 		{0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/
@@ -525,7 +525,7 @@
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
-		{0xFFFF}, /* not used */
+		{0, 0xFFFF},
 	},
 	{/* QUIN TDM */
 		{0xFFFF}, /* not used */
@@ -579,7 +579,7 @@
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
 		{0xFFFF}, /* not used */
-		{0xFFFF}, /* not used */
+		{0, 0xFFFF},
 	},
 	{/* QUIN TDM */
 		{0xFFFF}, /* not used */
@@ -4163,6 +4163,14 @@
 		rate->min = rate->max =
 				tdm_rx_cfg[TDM_QUAT][TDM_3].sample_rate;
 		break;
+	case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+		channels->min = channels->max =
+				tdm_rx_cfg[TDM_QUAT][TDM_7].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				tdm_rx_cfg[TDM_QUAT][TDM_7].bit_format);
+		rate->min = rate->max =
+				tdm_rx_cfg[TDM_QUAT][TDM_7].sample_rate;
+		break;
 	case AFE_PORT_ID_QUATERNARY_TDM_TX:
 		channels->min = channels->max =
 				tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
@@ -4195,6 +4203,14 @@
 		rate->min = rate->max =
 				tdm_tx_cfg[TDM_QUAT][TDM_3].sample_rate;
 		break;
+	case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+		channels->min = channels->max =
+				tdm_tx_cfg[TDM_QUAT][TDM_7].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				tdm_tx_cfg[TDM_QUAT][TDM_7].bit_format);
+		rate->min = rate->max =
+				tdm_tx_cfg[TDM_QUAT][TDM_7].sample_rate;
+		break;
 	case AFE_PORT_ID_QUINARY_TDM_RX:
 		channels->min = channels->max =
 				tdm_rx_cfg[TDM_QUIN][TDM_0].channels;
@@ -4479,6 +4495,11 @@
 		slot_width = tdm_slot[TDM_QUAT].width;
 		slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_3];
 		break;
+	case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+		slots = tdm_slot[TDM_QUAT].num;
+		slot_width = tdm_slot[TDM_QUAT].width;
+		slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_7];
+		break;
 	case AFE_PORT_ID_QUATERNARY_TDM_TX:
 		slots = tdm_slot[TDM_QUAT].num;
 		slot_width = tdm_slot[TDM_QUAT].width;
@@ -4499,6 +4520,11 @@
 		slot_width = tdm_slot[TDM_QUAT].width;
 		slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_3];
 		break;
+	case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+		slots = tdm_slot[TDM_QUAT].num;
+		slot_width = tdm_slot[TDM_QUAT].width;
+		slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_7];
+		break;
 	case AFE_PORT_ID_QUINARY_TDM_RX:
 		slots = tdm_slot[TDM_QUIN].num;
 		slot_width = tdm_slot[TDM_QUIN].width;
@@ -5615,6 +5641,36 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "Quaternary TDM RX 7 Hostless",
+		.stream_name = "Quaternary TDM RX 7 Hostless",
+		.cpu_dai_name = "QUAT_TDM_RX_7_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,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "Quaternary TDM TX 7 Hostless",
+		.stream_name = "Quaternary TDM TX 7 Hostless",
+		.cpu_dai_name = "QUAT_TDM_TX_7_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_custom_fe_dai_links[] = {
@@ -6378,6 +6434,20 @@
 		.ignore_suspend = 1,
 	},
 	{
+		.name = LPASS_BE_QUAT_TDM_RX_7,
+		.stream_name = "Quaternary TDM7 Playback",
+		.cpu_dai_name = "msm-dai-q6-tdm.36926",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_QUAT_TDM_RX_7,
+		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+		.ops = &sa8155_tdm_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
 		.name = LPASS_BE_QUAT_TDM_TX_1,
 		.stream_name = "Quaternary TDM1 Capture",
 		.cpu_dai_name = "msm-dai-q6-tdm.36915",
@@ -6419,6 +6489,20 @@
 		.ops = &sa8155_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
+	{
+		.name = LPASS_BE_QUAT_TDM_TX_7,
+		.stream_name = "Quaternary TDM7 Capture",
+		.cpu_dai_name = "msm-dai-q6-tdm.36927",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_QUAT_TDM_TX_7,
+		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+		.ops = &sa8155_tdm_be_ops,
+		.ignore_suspend = 1,
+	},
 };
 
 static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
diff --git a/asoc/sm6150.c b/asoc/sm6150.c
index 11bb611..6a6597a 100644
--- a/asoc/sm6150.c
+++ b/asoc/sm6150.c
@@ -5150,14 +5150,16 @@
 		__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)) {
-			wsa_macro_set_spkr_mode(component,
-						WSA_MACRO_SPKR_MODE_1);
-			wsa_macro_set_spkr_gain_offset(component,
-					WSA_MACRO_GAIN_OFFSET_M1P5_DB);
+		list_for_each_entry(aux_comp, &rtd->card->aux_comp_list,
+				card_aux_list) {
+			if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
+			    !strcmp(aux_comp->name, WSA8810_NAME_2)) {
+				wsa_macro_set_spkr_mode(component,
+							WSA_MACRO_SPKR_MODE_1);
+				wsa_macro_set_spkr_gain_offset(component,
+						WSA_MACRO_GAIN_OFFSET_M1P5_DB);
+				break;
+			}
 		}
 	}
 	card = rtd->card->snd_card;
diff --git a/asoc/sm8250-port-config.h b/asoc/sm8250-port-config.h
index 0a33c5f..503d514 100644
--- a/asoc/sm8250-port-config.h
+++ b/asoc/sm8250-port-config.h
@@ -29,7 +29,7 @@
 	{3,  0,  0,  0xFF, 0xFF, 1,    0xFF, 0xFF, 1},
 	{31, 0,  0,  3,    6,    7,    0,    0xFF, 0},
 	{31, 11, 11, 0xFF, 0xFF, 4,    1,    0xFF, 0},
-	{3,  1,  0,  0xFF, 0xFF, 0xFF, 0xFF, 1,    0},
+	{7,  1,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},
 	{0,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0,    0},
 };
 
diff --git a/config/litoauto.conf b/config/litoauto.conf
new file mode 100644
index 0000000..8d49fb9
--- /dev/null
+++ b/config/litoauto.conf
@@ -0,0 +1,37 @@
+CONFIG_PINCTRL_LPI=m
+CONFIG_AUDIO_EXT_CLK=m
+CONFIG_SND_SOC_WCD9XXX_V2=m
+CONFIG_SND_SOC_WCD_MBHC=m
+CONFIG_SND_SOC_WSA881X=m
+CONFIG_WCD9XXX_CODEC_CORE_V2=m
+CONFIG_MSM_CDC_PINCTRL=m
+CONFIG_MSM_QDSP6V2_CODECS=m
+CONFIG_MSM_ULTRASOUND=m
+CONFIG_MSM_QDSP6_APRV2_RPMSG=m
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_REGMAP_SWR=m
+CONFIG_MSM_QDSP6_SSR=m
+CONFIG_MSM_QDSP6_PDR=m
+CONFIG_MSM_QDSP6_NOTIFIER=m
+CONFIG_SND_SOC_MSM_HOSTLESS_PCM=m
+CONFIG_SND_SOC_MSM_QDSP6V2_INTF=m
+CONFIG_SOUNDWIRE=m
+CONFIG_SOUNDWIRE_MSTR_CTRL=m
+CONFIG_SND_SOC_QDSP6V2=m
+CONFIG_SND_SOC_WCD_MBHC_ADC=m
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=m
+CONFIG_QTI_PP=m
+CONFIG_SND_HWDEP_ROUTING=m
+CONFIG_SND_SOC_MSM_STUB=m
+CONFIG_MSM_AVTIMER=m
+CONFIG_SND_SOC_BOLERO=m
+CONFIG_WSA_MACRO=m
+CONFIG_VA_MACRO=m
+CONFIG_RX_MACRO=m
+CONFIG_TX_MACRO=m
+CONFIG_SND_SOC_WCD_IRQ=m
+CONFIG_SND_SOC_WCD938X=m
+CONFIG_SND_SOC_WCD938X_SLAVE=m
+CONFIG_SND_SOC_LITO=m
+CONFIG_SND_EVENT=m
+CONFIG_VOICE_MHI=m
diff --git a/config/litoautoconf.h b/config/litoautoconf.h
new file mode 100644
index 0000000..6467c8f
--- /dev/null
+++ b/config/litoautoconf.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#define CONFIG_PINCTRL_LPI 1
+#define CONFIG_AUDIO_EXT_CLK 1
+#define CONFIG_SND_SOC_WCD9XXX_V2 1
+#define CONFIG_SND_SOC_WCD_MBHC 1
+#define CONFIG_SND_SOC_WSA881X 1
+#define CONFIG_WCD9XXX_CODEC_CORE_V2 1
+#define CONFIG_MSM_CDC_PINCTRL 1
+#define CONFIG_MSM_QDSP6V2_CODECS 1
+#define CONFIG_MSM_ULTRASOUND 1
+#define CONFIG_MSM_QDSP6_APRV2_RPMSG 1
+#define CONFIG_SND_SOC_MSM_QDSP6V2_INTF 1
+#define CONFIG_MSM_ADSP_LOADER 1
+#define CONFIG_REGMAP_SWR 1
+#define CONFIG_MSM_QDSP6_SSR 1
+#define CONFIG_MSM_QDSP6_PDR 1
+#define CONFIG_MSM_QDSP6_NOTIFIER 1
+#define CONFIG_SND_SOC_MSM_HOSTLESS_PCM 1
+#define CONFIG_SOUNDWIRE 1
+#define CONFIG_SOUNDWIRE_MSTR_CTRL 1
+#define CONFIG_SND_SOC_WCD_MBHC_ADC 1
+#define CONFIG_SND_SOC_QDSP6V2 1
+#define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1
+#define CONFIG_QTI_PP 1
+#define CONFIG_SND_HWDEP_ROUTING 1
+#define CONFIG_SND_SOC_MSM_STUB 1
+#define CONFIG_MSM_AVTIMER 1
+#define CONFIG_SND_SOC_BOLERO 1
+#define CONFIG_WSA_MACRO 1
+#define CONFIG_VA_MACRO 1
+#define CONFIG_RX_MACRO 1
+#define CONFIG_TX_MACRO 1
+#define CONFIG_SND_SOC_WCD_IRQ 1
+#define CONFIG_SND_SOC_WCD938X 1
+#define CONFIG_SND_SOC_WCD938X_SLAVE 1
+#define CONFIG_SND_SOC_LITO 1
+#define CONFIG_SND_EVENT 1
+#define CONFIG_VOICE_MHI 1
diff --git a/dsp/Android.mk b/dsp/Android.mk
index ddaebe2..42fd4cb 100644
--- a/dsp/Android.mk
+++ b/dsp/Android.mk
@@ -15,9 +15,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform, lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/dsp/Kbuild b/dsp/Kbuild
index daf0b30..cf9de15 100644
--- a/dsp/Kbuild
+++ b/dsp/Kbuild
@@ -29,6 +29,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_SM8150), y)
 		include $(AUDIO_ROOT)/config/sm8150auto.conf
 		export
diff --git a/dsp/codecs/Android.mk b/dsp/codecs/Android.mk
index 25726ac..6550717 100644
--- a/dsp/codecs/Android.mk
+++ b/dsp/codecs/Android.mk
@@ -15,9 +15,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/dsp/codecs/Kbuild b/dsp/codecs/Kbuild
index c80cace..b4be485 100644
--- a/dsp/codecs/Kbuild
+++ b/dsp/codecs/Kbuild
@@ -29,6 +29,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_SM8150), y)
 		include $(AUDIO_ROOT)/config/sm8150auto.conf
 		export
diff --git a/dsp/codecs/audio_utils_aio.c b/dsp/codecs/audio_utils_aio.c
index f221635..62b9455 100644
--- a/dsp/codecs/audio_utils_aio.c
+++ b/dsp/codecs/audio_utils_aio.c
@@ -1157,7 +1157,7 @@
 	/* Write command will populate session_id as token */
 	buf_node->token = ac->session;
 	rc = q6asm_async_read(ac, &param);
-	if (rc < 0)
+	if (rc < 0 && rc != -ENETRESET)
 		pr_err_ratelimited("%s[%pK]:failed\n", __func__, audio);
 	return rc;
 }
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 1833e79..6c188d7 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -350,6 +350,14 @@
 	size_t expected_size =
 		sizeof(u32) + sizeof(struct doa_tracking_mon_param);
 
+	if (payload[0]) {
+		atomic_set(&this_afe.status, payload[0]);
+		atomic_set(&this_afe.state, 0);
+		pr_err("%s: doa_tracking_mon_resp status: %d payload size %d\n",
+			__func__, payload[0], payload_size);
+		return;
+	}
+
 	switch (opcode) {
 	case AFE_PORT_CMDRSP_GET_PARAM_V2:
 		expected_size += sizeof(struct param_hdr_v1);
@@ -383,13 +391,7 @@
 		return;
 	}
 
-	if (!this_afe.doa_tracking_mon_resp.status) {
-		atomic_set(&this_afe.state, 0);
-	} else {
-		pr_debug("%s: doa_tracking_mon_resp status: %d\n", __func__,
-			 this_afe.doa_tracking_mon_resp.status);
-		atomic_set(&this_afe.state, -1);
-	}
+	atomic_set(&this_afe.state, 0);
 }
 
 static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload,
@@ -405,6 +407,11 @@
 	/* Set command specific details */
 	switch (opcode) {
 	case AFE_PORT_CMDRSP_GET_PARAM_V2:
+		if (payload_size < (5 * sizeof(uint32_t))) {
+			pr_err("%s: Error: size %d is less than expected\n",
+				__func__, payload_size);
+			return -EINVAL;
+		}
 		expected_size += sizeof(struct param_hdr_v1);
 		param_hdr.module_id = payload[1];
 		param_hdr.instance_id = INSTANCE_ID_0;
@@ -413,7 +420,17 @@
 		data_start = &payload[4];
 		break;
 	case AFE_PORT_CMDRSP_GET_PARAM_V3:
+		if (payload_size < (6 * sizeof(uint32_t))) {
+			pr_err("%s: Error: size %d is less than expected\n",
+				__func__, payload_size);
+			return -EINVAL;
+		}
 		expected_size += sizeof(struct param_hdr_v3);
+		if (payload_size < expected_size) {
+			pr_err("%s: Error: size %d is less than expected\n",
+				__func__, payload_size);
+			return -EINVAL;
+		}
 		memcpy(&param_hdr, &payload[1], sizeof(struct param_hdr_v3));
 		data_start = &payload[5];
 		break;
@@ -602,6 +619,7 @@
 	    data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V3) {
 		uint32_t *payload = data->payload;
 		uint32_t param_id;
+		uint32_t param_id_pos = 0;
 
 		if (!payload || (data->token >= AFE_MAX_PORTS)) {
 			pr_err("%s: Error: size %d payload %pK token %d\n",
@@ -610,9 +628,23 @@
 			return -EINVAL;
 		}
 
-		param_id = (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V3) ?
-				   payload[3] :
-				   payload[2];
+		if (rtac_make_afe_callback(data->payload,
+					   data->payload_size))
+			return 0;
+
+		if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V3)
+			param_id_pos = 4;
+		else
+			param_id_pos = 3;
+
+		if (data->payload_size >= param_id_pos * sizeof(uint32_t))
+				param_id = payload[param_id_pos - 1];
+		else {
+			pr_err("%s: Error: size %d is less than expected\n",
+				__func__, data->payload_size);
+			return -EINVAL;
+		}
+
 		if (param_id == AUDPROC_PARAM_ID_FFV_DOA_TRACKING_MONITOR) {
 			doa_tracking_mon_afe_cb_handler(data->opcode,
 				data->payload, data->payload_size);
@@ -620,10 +652,6 @@
 			av_dev_drift_afe_cb_handler(data->opcode, data->payload,
 						    data->payload_size);
 		} else {
-			if (rtac_make_afe_callback(data->payload,
-						   data->payload_size))
-				return 0;
-
 			if (sp_make_afe_callback(data->opcode, data->payload,
 						 data->payload_size))
 				return -EINVAL;
@@ -650,6 +678,11 @@
 
 		payload = data->payload;
 		if (data->opcode == APR_BASIC_RSP_RESULT) {
+			if (data->payload_size < (2 * sizeof(uint32_t))) {
+				pr_err("%s: Error: size %d is less than expected\n",
+					__func__, data->payload_size);
+				return -EINVAL;
+			}
 			pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
 				__func__, data->opcode,
 				payload[0], payload[1], data->token);
@@ -5499,18 +5532,67 @@
 }
 
 /**
+ * afe_port_tdm_lane_config -
+ * to configure group TDM lane mask with specified configuration
+ *
+ * @group_id: AFE group id number
+ * @lane_cfg: TDM lane mask configutation
+ *
+ * Returns 0 on success or error value on failure.
+ */
+static int afe_port_tdm_lane_config(u16 group_id,
+	struct afe_param_id_tdm_lane_cfg *lane_cfg)
+{
+	struct param_hdr_v3 param_hdr;
+	int ret = 0;
+
+	if (lane_cfg == NULL ||
+		lane_cfg->lane_mask == AFE_LANE_MASK_INVALID) {
+		pr_debug("%s: lane cfg not supported for group id: 0x%x\n",
+			__func__, group_id);
+		return ret;
+	}
+
+	pr_debug("%s: group id: 0x%x lane mask 0x%x\n", __func__,
+		group_id, lane_cfg->lane_mask);
+
+	memset(&param_hdr, 0, sizeof(param_hdr));
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0) {
+		pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	param_hdr.module_id = AFE_MODULE_GROUP_DEVICE;
+	param_hdr.instance_id = INSTANCE_ID_0;
+	param_hdr.param_id = AFE_PARAM_ID_TDM_LANE_CONFIG;
+	param_hdr.param_size = sizeof(struct afe_param_id_tdm_lane_cfg);
+
+	ret = q6afe_svc_pack_and_set_param_in_band(IDX_GLOBAL_CFG, param_hdr,
+						   (u8 *)lane_cfg);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_TDM_LANE_CONFIG failed %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+/**
  * afe_port_group_enable -
  *         command to enable AFE port group
  *
  * @group_id: group ID for AFE port group
  * @afe_group_config: config for AFE group
  * @enable: flag to indicate enable or disable
+ * @lane_cfg: TDM lane mask configutation
  *
  * Returns 0 on success or error on failure
  */
 int afe_port_group_enable(u16 group_id,
 	union afe_port_group_config *afe_group_config,
-	u16 enable)
+	u16 enable,
+	struct afe_param_id_tdm_lane_cfg *lane_cfg)
 {
 	struct afe_group_device_enable group_enable;
 	struct param_hdr_v3 param_hdr;
@@ -5534,6 +5616,12 @@
 			pr_err("%s: afe send failed %d\n", __func__, ret);
 			return ret;
 		}
+		ret = afe_port_tdm_lane_config(group_id, lane_cfg);
+		if (ret < 0) {
+			pr_err("%s: afe send lane config failed %d\n",
+				__func__, ret);
+			return ret;
+		}
 	}
 
 	param_hdr.module_id = AFE_MODULE_GROUP_DEVICE;
@@ -9074,4 +9162,3 @@
 	return ret;
 }
 EXPORT_SYMBOL(afe_unvote_lpass_core_hw);
-
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index b27163f..66eef64 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -389,6 +389,33 @@
 	.write = audio_input_latency_dbgfs_write
 };
 
+/*
+ * get_monotonic_timeval -
+ *       This method returns a structure in timeval
+ *       format (sec,microsec) by using ktime kernel
+ *       API to get time in nano secs and then converts
+ *       it to timeval format
+ *
+ * ktime_get [nsec]-> ktime_to_timespec [sec,nsec]-> timeval[sec,usec]
+ *
+ * Returns struct timeval
+*/
+static struct timeval get_monotonic_timeval(void)
+{
+	static struct timeval out_tval;
+
+	/* Get time from monotonic clock in nanoseconds */
+	ktime_t kTimeNsec = ktime_get();
+
+	/* Convert it to timespec format and later to timeval as expected by audio HAL */
+	struct timespec temp_tspec = ktime_to_timespec(kTimeNsec);
+
+	/* Time returned above is in sec,nanosec format, needs to convert to sec,microsec */
+	out_tval.tv_usec = temp_tspec.tv_nsec/1000;
+	out_tval.tv_sec = temp_tspec.tv_sec;
+	return out_tval;
+}
+
 static void config_debug_fs_write_cb(void)
 {
 	if (out_enable_flag) {
@@ -396,7 +423,7 @@
 		 * out_cold_index
 		 */
 		if (out_cold_index != 1) {
-			do_gettimeofday(&out_cold_tv);
+			out_cold_tv = get_monotonic_timeval();
 			pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
 				out_cold_tv.tv_sec,
 				out_cold_tv.tv_usec);
@@ -421,7 +448,7 @@
 		 * Hence continuous input latency
 		 */
 		if (in_cont_index == 7) {
-			do_gettimeofday(&in_cont_tv);
+			in_cont_tv = get_monotonic_timeval();
 			pr_info("%s: read buffer at %ld sec %ld microsec\n",
 				__func__,
 				in_cont_tv.tv_sec, in_cont_tv.tv_usec);
@@ -438,7 +465,7 @@
 static void config_debug_fs_run(void)
 {
 	if (out_enable_flag) {
-		do_gettimeofday(&out_cold_tv);
+		out_cold_tv = get_monotonic_timeval();
 		pr_debug("%s: COLD apr_send_pkt at %ld sec %ld microsec\n",
 			__func__, out_cold_tv.tv_sec, out_cold_tv.tv_usec);
 	}
@@ -453,7 +480,7 @@
 		 */
 		if ((strcmp(((char *)ab->data), zero_pattern)) &&
 		(!strcmp(((char *)ab->data + 2), zero_pattern))) {
-			do_gettimeofday(&out_warm_tv);
+			out_warm_tv = get_monotonic_timeval();
 			pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n",
 			 __func__,
 			 out_warm_tv.tv_sec,
@@ -465,7 +492,7 @@
 		 */
 		else if ((!strcmp(((char *)ab->data), zero_pattern))
 		&& (strcmp(((char *)ab->data + 2), zero_pattern))) {
-			do_gettimeofday(&out_cont_tv);
+			out_cont_tv = get_monotonic_timeval();
 			pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n",
 			__func__,
 			out_cont_tv.tv_sec,
@@ -9512,8 +9539,8 @@
 	}
 
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
-	if (rc < 0) {
-		pr_err("%s: read op[0x%x]rc[%d]\n", __func__,
+	if (rc < 0 && rc != -ENETRESET) {
+		pr_err_ratelimited("%s: read op[0x%x]rc[%d]\n", __func__,
 				read.hdr.opcode, rc);
 		goto fail_cmd;
 	}
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index 6af7f69..96671ec 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -153,7 +153,8 @@
 		struct lsm_cmd_read_done read_done;
 
 		token = data->token;
-		if (data->payload_size > sizeof(read_done)) {
+		if (data->payload_size > sizeof(read_done) ||
+				data->payload_size < 6 * sizeof(payload[0])) {
 			pr_err("%s: read done error payload size %d expected size %zd\n",
 				__func__, data->payload_size,
 				sizeof(read_done));
@@ -171,6 +172,7 @@
 		if (client->cb)
 			client->cb(data->opcode, data->token,
 					(void *)&read_done,
+					sizeof(read_done),
 					client->priv);
 		return 0;
 	} else if (data->opcode == APR_BASIC_RSP_RESULT) {
@@ -198,6 +200,11 @@
 					__func__, token, client->session);
 				return -EINVAL;
 			}
+			if (data->payload_size < 2 * sizeof(payload[0])) {
+				pr_err("%s: payload has invalid size[%d]\n",
+					__func__, data->payload_size);
+				return -EINVAL;
+			}
 			client->cmd_err_code = payload[1];
 			if (client->cmd_err_code)
 				pr_err("%s: cmd 0x%x failed status %d\n",
@@ -218,7 +225,7 @@
 
 	if (client->cb)
 		client->cb(data->opcode, data->token, data->payload,
-			   client->priv);
+				data->payload_size, client->priv);
 
 	return 0;
 }
@@ -311,6 +318,11 @@
 		kfree(client);
 		return NULL;
 	}
+
+	init_waitqueue_head(&client->cmd_wait);
+	mutex_init(&client->cmd_lock);
+	atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+
 	pr_debug("%s: Client Session %d\n", __func__, client->session);
 	client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
 				   ((client->session) << 8 | client->session),
@@ -328,9 +340,6 @@
 		goto fail;
 	}
 
-	init_waitqueue_head(&client->cmd_wait);
-	mutex_init(&client->cmd_lock);
-	atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
 	pr_debug("%s: New client allocated\n", __func__);
 	return client;
 fail:
@@ -1791,6 +1800,8 @@
 			 "proc 0x%x SID 0x%x\n", __func__, data->opcode,
 			 data->reset_event, data->reset_proc, sid);
 
+		if (sid < LSM_MIN_SESSION_ID || sid > LSM_MAX_SESSION_ID)
+			pr_err("%s: Invalid session %d\n", __func__, sid);
 		apr_reset(lsm_common.apr);
 		lsm_common.apr = NULL;
 		atomic_set(&lsm_common.apr_users, 0);
@@ -1855,7 +1866,8 @@
 	}
 	if (client->cb)
 		client->cb(data->opcode, data->token,
-			   data->payload, client->priv);
+			   data->payload, data->payload_size,
+			   client->priv);
 	return 0;
 }
 
diff --git a/dsp/q6usm.c b/dsp/q6usm.c
index 70c3a6b..cd024fc 100644
--- a/dsp/q6usm.c
+++ b/dsp/q6usm.c
@@ -628,6 +628,8 @@
 		    (sizeof(uint32_t)*(READDONE_IDX_STATUS + 1))) {
 			pr_err("%s: Invalid payload size for READDONE[%d]\n",
 			       __func__, data->payload_size);
+			spin_unlock_irqrestore(&port->dsp_lock,
+					       dsp_flags);
 			return -EINVAL;
 		}
 		if (payload[READDONE_IDX_STATUS]) {
diff --git a/dsp/sp_params.c b/dsp/sp_params.c
index ed6d2eb..c84f8c7 100644
--- a/dsp/sp_params.c
+++ b/dsp/sp_params.c
@@ -15,8 +15,9 @@
 #define SPK_PARAMS  "spk_params"
 #define CLASS_NAME "cal_data"
 #define BUF_SZ 20
-#define Q27 (1<<27)
 #define Q22 (1<<22)
+#define Q13 (1<<13)
+#define Q7 (1<<7)
 
 struct afe_spk_ctl {
 	struct class *p_class;
@@ -88,11 +89,11 @@
 {
 	ssize_t ret = 0;
 	int32_t ex_val_frac;
-	float ex_val;
 	int32_t ex_q27 = this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_1];
 
-	ex_val = (ex_q27 * 1.0)/Q27;
-	ex_val_frac = ex_val * 100;
+	ex_val_frac = ex_q27/Q13;
+	ex_val_frac = (ex_val_frac * 10000)/(Q7 * Q7);
+	ex_val_frac /= 100;
 	ret = snprintf(buf, BUF_SZ, "%d.%02d\n", 0, ex_val_frac);
 	this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_1] = 0;
 	return ret;
@@ -105,11 +106,11 @@
 {
 	ssize_t ret = 0;
 	int32_t ex_val_frac;
-	float ex_val;
 	int32_t ex_q27 = this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_2];
 
-	ex_val = (ex_q27 * 1.0)/Q27;
-	ex_val_frac = ex_val * 100;
+	ex_val_frac = ex_q27/Q13;
+	ex_val_frac = (ex_val_frac * 10000)/(Q7 * Q7);
+	ex_val_frac /= 100;
 	ret = snprintf(buf, BUF_SZ, "%d.%02d\n", 0, ex_val_frac);
 	this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_2] = 0;
 	return ret;
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index 35cd021..e7c132a 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -1354,6 +1354,8 @@
 #define AFE_LOOPBACK_TX	0x6001
 #define DISPLAY_PORT_RX	0x6020
 
+#define AFE_LANE_MASK_INVALID 0
+
 #define AFE_PORT_INVALID 0xFFFF
 #define SLIMBUS_INVALID AFE_PORT_INVALID
 
@@ -12497,4 +12499,35 @@
 
 #define AFE_PARAM_ID_VAD_CORE_CFG                              0x000102BB
 
+/**
+ * This parameter is should be used to configure the AFE TDM
+ * interface lane configuration.
+ * Regular TDM interface ports:
+ * This parameter ID must be used with module ID
+ * AFE_MODULE_AUDIO_DEV_INTERFACE and set using the AFE_PORT_CMD_SET_PARAM_V3
+ * command for the AFE TDM interface port IDs.
+ * Group device TDM interface ports:
+ * This parameter ID must be used with module ID AFE_MODULE_GROUP_DEVICE
+ * and set using the AFE_SVC_CMD_SET_PARAM_V2 command for the AFE TDM group IDs.
+ */
+#define AFE_PARAM_ID_TDM_LANE_CONFIG                           0x000102C1
+
+/* Payload of the AFE_PARAM_ID_TDM_LANE_CONFIG parameter used by
+ * AFE_MODULE_AUDIO_DEV_INTERFACE.
+ */
+struct afe_param_id_tdm_lane_cfg {
+	uint16_t port_id;
+	/** ID of the TDM interface.
+	 * For regular TDM interfaces value corresponds to valid port ID.
+	 * For group devices TDM interface value corresponds to valid group device ID.
+	 */
+
+	uint16_t lane_mask;
+	/** Position of the active lanes. Bits 0 to N correspond to lanes 0 to N.
+	 * 1 to 2^N-1 When a bit is set, the corresponding lane is active.
+	 * The number of active lanes can be inferred from the number of bits
+	 * set in the mask.
+	 */
+};
+
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index c5b7e3e..1efcb50 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -432,7 +432,8 @@
 int afe_port_group_set_param(u16 group_id,
 	union afe_port_group_config *afe_group_config);
 int afe_port_group_enable(u16 group_id,
-	union afe_port_group_config *afe_group_config, u16 enable);
+	union afe_port_group_config *afe_group_config, u16 enable,
+	struct afe_param_id_tdm_lane_cfg *lane_cfg);
 int afe_unmap_rtac_block(uint32_t *mem_map_handle);
 int afe_map_rtac_block(struct rtac_cal_block_data *cal_block);
 int afe_send_slot_mapping_cfg(
diff --git a/include/dsp/q6lsm.h b/include/dsp/q6lsm.h
index 758bba0..e4a007f 100644
--- a/include/dsp/q6lsm.h
+++ b/include/dsp/q6lsm.h
@@ -21,7 +21,7 @@
 #define LSM_API_VERSION_V3 3
 
 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
-		       uint32_t *payload, void *priv);
+		       uint32_t *payload, uint16_t client_size, void *priv);
 
 struct lsm_sound_model {
 	dma_addr_t      phys;
diff --git a/include/soc/wcd-spi-ac.h b/include/soc/wcd-spi-ac.h
new file mode 100644
index 0000000..5131c49
--- /dev/null
+++ b/include/soc/wcd-spi-ac.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2018-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.
+ */
+
+#ifndef __WCD_SPI_AC_H__
+#define __WCD_SPI_AC_H__
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+enum wcd_spi_acc_req {
+	WCD_SPI_ACCESS_REQUEST,
+	WCD_SPI_ACCESS_RELEASE,
+	WCD_SPI_ACCESS_MAX,
+};
+
+#define WCD_SPI_AC_DATA_TRANSFER	BIT(0)
+#define WCD_SPI_AC_CONCURRENCY		BIT(1)
+#define WCD_SPI_AC_REMOTE_DOWN		BIT(2)
+#define WCD_SPI_AC_SVC_OFFLINE		BIT(3)
+#define WCD_SPI_AC_UNINITIALIZED	BIT(4)
+
+#if IS_ENABLED(CONFIG_WCD_SPI_AC)
+int wcd_spi_access_ctl(struct device *dev,
+		       enum wcd_spi_acc_req req,
+		       u32 reason);
+#else
+int wcd_spi_access_ctl(struct device *dev,
+		       enum wcd_spi_acc_req req,
+		       u32 reason)
+{
+	return 0;
+}
+#endif /* end of CONFIG_WCD_SPI_AC */
+
+#endif /* end of __WCD_SPI_AC_H__ */
diff --git a/ipc/Android.mk b/ipc/Android.mk
index 066c5b8..800d8d4 100644
--- a/ipc/Android.mk
+++ b/ipc/Android.mk
@@ -15,9 +15,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
diff --git a/ipc/Kbuild b/ipc/Kbuild
index 3577623..2da5fbd 100644
--- a/ipc/Kbuild
+++ b/ipc/Kbuild
@@ -30,6 +30,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_SM8150), y)
 		include $(AUDIO_ROOT)/config/sm8150auto.conf
 		export
diff --git a/ipc/apr.c b/ipc/apr.c
index fbb1f32..f1dbc36 100644
--- a/ipc/apr.c
+++ b/ipc/apr.c
@@ -419,8 +419,13 @@
 			rc = -EINVAL;
 		}
 	} else {
-		pr_err("%s: Write APR pkt failed with error %d\n",
+		pr_err_ratelimited("%s: Write APR pkt failed with error %d\n",
 			__func__, rc);
+		if (rc == -ECONNRESET) {
+			pr_err_ratelimited("%s: Received reset error from tal\n",
+					__func__);
+			rc = -ENETRESET;
+		}
 	}
 	spin_unlock_irqrestore(&svc->w_lock, flags);
 
diff --git a/soc/Android.mk b/soc/Android.mk
index 26f18e6..0698221 100644
--- a/soc/Android.mk
+++ b/soc/Android.mk
@@ -15,9 +15,13 @@
 AUDIO_SELECT  := CONFIG_SND_SOC_KONA=m
 endif
 
+ifeq ($(call is-board-platform,lito),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LITO=m
+endif
+
 AUDIO_CHIPSET := audio
 # Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito),true)
 
 LOCAL_PATH := $(call my-dir)
 
@@ -44,7 +48,7 @@
 KBUILD_OPTIONS += $(AUDIO_SELECT)
 
 ###########################################################
-ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona lito),true)
 include $(CLEAR_VARS)
 LOCAL_MODULE              := $(AUDIO_CHIPSET)_pinctrl_lpi.ko
 LOCAL_MODULE_KBUILD_NAME  := pinctrl_lpi_dlkm.ko
@@ -78,7 +82,7 @@
 LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
 include $(DLKM_DIR)/AndroidKernelModule.mk
 ###########################################################
-ifeq ($(call is-board-platform-in-list, $(MSMSTEPPE) kona),true)
+ifeq ($(call is-board-platform-in-list, $(MSMSTEPPE) kona lito),true)
 include $(CLEAR_VARS)
 LOCAL_MODULE              := $(AUDIO_CHIPSET)_snd_event.ko
 LOCAL_MODULE_KBUILD_NAME  := snd_event_dlkm.ko
diff --git a/soc/Kbuild b/soc/Kbuild
index 12d99c3..f5f5c8b 100644
--- a/soc/Kbuild
+++ b/soc/Kbuild
@@ -24,6 +24,11 @@
 		export
 		INCS    +=  -include $(AUDIO_ROOT)/config/konaautoconf.h
 	endif
+	ifeq ($(CONFIG_ARCH_LITO), y)
+		include $(AUDIO_ROOT)/config/litoauto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/litoautoconf.h
+	endif
 	ifeq ($(CONFIG_ARCH_SM6150), y)
 		include $(AUDIO_ROOT)/config/sm6150auto.conf
 		export
@@ -101,6 +106,11 @@
 	SND_EVENT_OBJS += snd_event.o
 endif
 
+ifdef CONFIG_WCD_SPI_AC
+	WCD_SPI_ACC_CTL_OBJS += wcd-spi-ac.o
+	WCD_SPI_ACC_CTL_OBJS += wcd_spi_ctl_v01.o
+endif
+
 LINUX_INC +=	-Iinclude/linux
 
 INCS +=		$(COMMON_INC) \
@@ -159,5 +169,8 @@
 obj-$(CONFIG_SOUNDWIRE_MSTR_CTRL) += swr_ctrl_dlkm.o
 swr_ctrl_dlkm-y := $(SWR_CTRL_OBJS)
 
+obj-$(CONFIG_WCD_SPI_AC) += wcd_spi_acc_ctl_dlkm.o
+wcd_spi_acc_ctl_dlkm-y := $(WCD_SPI_ACC_CTL_OBJS)
+
 # inject some build related information
 DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 722501a..bddf30a 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -1441,6 +1441,8 @@
 	}
 
 	mutex_lock(&swrm->reslock);
+	if (swrm->lpass_core_hw_vote)
+		clk_prepare_enable(swrm->lpass_core_hw_vote);
 	swrm_clk_request(swrm, true);
 	mutex_unlock(&swrm->reslock);
 
@@ -1608,6 +1610,8 @@
 
 	mutex_lock(&swrm->reslock);
 	swrm_clk_request(swrm, false);
+	if (swrm->lpass_core_hw_vote)
+		clk_disable_unprepare(swrm->lpass_core_hw_vote);
 	mutex_unlock(&swrm->reslock);
 	swrm_unlock_sleep(swrm);
 	return ret;
@@ -1897,6 +1901,7 @@
 	u32 i, num_ports, port_num, port_type, ch_mask;
 	u32 *temp, map_size, map_length, ch_iter = 0, old_port_num = 0;
 	int ret = 0;
+	struct clk *lpass_core_hw_vote = NULL;
 
 	/* Allocate soundwire master driver structure */
 	swrm = devm_kzalloc(&pdev->dev, sizeof(struct swr_mstr_ctrl),
@@ -2145,6 +2150,17 @@
 	if (pdev->dev.of_node)
 		of_register_swr_devices(&swrm->master);
 
+	/* Register LPASS core hw vote */
+	lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote");
+	if (IS_ERR(lpass_core_hw_vote)) {
+		ret = PTR_ERR(lpass_core_hw_vote);
+		dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
+			__func__, "lpass_core_hw_vote", ret);
+		lpass_core_hw_vote = NULL;
+		ret = 0;
+	}
+	swrm->lpass_core_hw_vote = lpass_core_hw_vote;
+
 	dbgswrm = swrm;
 	debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
 	if (!IS_ERR(debugfs_swrm_dent)) {
@@ -2257,6 +2273,12 @@
 		__func__, swrm->state);
 	mutex_lock(&swrm->reslock);
 
+	if (swrm->lpass_core_hw_vote)
+		ret = clk_prepare_enable(swrm->lpass_core_hw_vote);
+		if (ret < 0)
+			dev_err(dev, "%s:lpass core hw enable failed\n",
+				__func__);
+
 	if ((swrm->state == SWR_MSTR_DOWN) ||
 	    (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) {
 		if (swrm->clk_stop_mode0_supp) {
@@ -2293,6 +2315,8 @@
 		swrm->state = SWR_MSTR_UP;
 	}
 exit:
+	if (swrm->lpass_core_hw_vote)
+		clk_disable_unprepare(swrm->lpass_core_hw_vote);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
 	mutex_unlock(&swrm->reslock);
 	return ret;
@@ -2313,6 +2337,12 @@
 	mutex_lock(&swrm->force_down_lock);
 	current_state = swrm->state;
 	mutex_unlock(&swrm->force_down_lock);
+	if (swrm->lpass_core_hw_vote)
+		ret = clk_prepare_enable(swrm->lpass_core_hw_vote);
+		if (ret < 0)
+			dev_err(dev, "%s:lpass core hw enable failed\n",
+				__func__);
+
 	if ((current_state == SWR_MSTR_UP) ||
 	    (current_state == SWR_MSTR_SSR)) {
 
@@ -2358,6 +2388,8 @@
 	if (current_state != SWR_MSTR_SSR)
 		swrm->state = SWR_MSTR_DOWN;
 exit:
+	if (swrm->lpass_core_hw_vote)
+		clk_disable_unprepare(swrm->lpass_core_hw_vote);
 	mutex_unlock(&swrm->reslock);
 	return ret;
 }
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index 6ae3feb..4a48571 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -154,6 +154,7 @@
 	int wlock_holders;
 	u32 intr_mask;
 	struct port_params **port_param;
+	struct clk *lpass_core_hw_vote;
 	u8 num_usecase;
 	u32 swr_irq_wakeup_capable;
 };
diff --git a/soc/wcd-spi-ac.c b/soc/wcd-spi-ac.c
new file mode 100644
index 0000000..ee7a7a9
--- /dev/null
+++ b/soc/wcd-spi-ac.c
@@ -0,0 +1,998 @@
+/* Copyright (c) 2018-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/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/wcd-spi-ac-params.h>
+#include <soc/wcd-spi-ac.h>
+#include <soc/qcom/msm_qmi_interface.h>
+
+#include "wcd_spi_ctl_v01.h"
+
+#define WCD_SPI_AC_PFS_ENTRY_MAX_LEN	16
+#define WCD_SPI_AC_WRITE_CMD_MIN_SIZE	\
+	(sizeof(struct wcd_spi_ac_write_cmd))
+#define WCD_SPI_AC_WRITE_CMD_MAX_SIZE		\
+	(WCD_SPI_AC_WRITE_CMD_MIN_SIZE +	\
+	 (WCD_SPI_AC_MAX_BUFFERS *		\
+	  sizeof(struct wcd_spi_ac_buf_data)))
+
+#define WCD_SPI_AC_MUTEX_LOCK(dev, lock)	\
+{						\
+	dev_dbg(dev, "%s: mutex_lock(%s)\n",	\
+		__func__, __stringify_1(lock));	\
+	mutex_lock(&lock);			\
+}
+
+#define WCD_SPI_AC_MUTEX_UNLOCK(dev, lock)	\
+{						\
+	dev_dbg(dev, "%s: mutex_unlock(%s)\n",	\
+		__func__, __stringify_1(lock));	\
+	mutex_unlock(&lock);			\
+}
+
+/*
+ * All bits of status should be cleared for SPI access
+ * to be released.
+ */
+#define WCD_SPI_AC_STATUS_RELEASE_ACCESS	0x00
+#define WCD_SPI_AC_LOCAL_ACCESS	0x00
+#define WCD_SPI_AC_REMOTE_ACCESS 0x01
+#define WCD_SPI_CTL_INS_ID 0
+#define WCD_SPI_AC_QMI_TIMEOUT_MS 100
+
+struct wcd_spi_ac_priv {
+
+	/* Pointer to device for this driver */
+	struct device *dev;
+
+	/* Pointer to parent's device */
+	struct device *parent;
+
+	/* char dev related */
+	struct class *cls;
+	struct device *chardev;
+	struct cdev cdev;
+	dev_t cdev_num;
+
+	/* proc entry related */
+	struct proc_dir_entry *pfs_root;
+	struct proc_dir_entry *pfs_status;
+
+	/* service status related */
+	u8 svc_offline;
+	u8 svc_offline_change;
+	wait_queue_head_t svc_poll_wait;
+	struct mutex status_lock;
+
+	/* state maintenence related */
+	u32 state;
+	struct mutex state_lock;
+	u8 current_access;
+
+	/* qmi related */
+	struct qmi_handle *qmi_hdl;
+	struct work_struct svc_arr_work;
+	struct work_struct svc_exit_work;
+	struct notifier_block nb;
+	struct mutex svc_lock;
+	struct workqueue_struct *qmi_wq;
+	struct work_struct recv_msg_work;
+};
+
+
+static void wcd_spi_ac_status_change(struct wcd_spi_ac_priv *ac,
+				     u8 online)
+{
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
+	ac->svc_offline = !online;
+	/* Make sure the write is complete */
+	wmb();
+	xchg(&ac->svc_offline_change, 1);
+	wake_up_interruptible(&ac->svc_poll_wait);
+	dev_dbg(ac->dev,
+		"%s request %u offline %u off_change %u\n",
+		__func__, online, ac->svc_offline,
+		ac->svc_offline_change);
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
+}
+
+static int wcd_spi_ac_status_open(struct inode *inode,
+				    struct file *file)
+{
+	struct wcd_spi_ac_priv *ac = PDE_DATA(inode);
+
+	file->private_data = ac;
+
+	return 0;
+}
+
+static ssize_t wcd_spi_ac_status_read(struct file *file,
+		char __user *buffer,
+		size_t count, loff_t *offset)
+{
+	struct wcd_spi_ac_priv *ac;
+	char buf[WCD_SPI_AC_PFS_ENTRY_MAX_LEN];
+	int len, ret;
+	u8 offline;
+
+	ac = (struct wcd_spi_ac_priv *) file->private_data;
+	if (!ac) {
+		pr_err("%s: Invalid private data for status\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
+	offline = ac->svc_offline;
+	/* Make sure the read is complete */
+	rmb();
+	dev_dbg(ac->dev, "%s: offline = %sline\n",
+		__func__, offline ? "off" : "on");
+	len = snprintf(buf, sizeof(buf), "%s\n",
+		       offline ? "OFFLINE" : "ONLINE");
+	ret = simple_read_from_buffer(buffer, count, offset, buf, len);
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
+
+	return ret;
+}
+
+static unsigned int wcd_spi_ac_status_poll(struct file *file,
+		poll_table *wait)
+{
+	struct wcd_spi_ac_priv *ac;
+	unsigned int ret = 0;
+
+	ac = (struct wcd_spi_ac_priv *) file->private_data;
+	if (!ac) {
+		pr_err("%s: Invalid private data for status\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(ac->dev, "%s: Poll wait, svc = %s\n",
+		__func__, ac->svc_offline ? "offline" : "online");
+	poll_wait(file, &ac->svc_poll_wait, wait);
+	dev_dbg(ac->dev, "%s: Woken up Poll wait, svc = %s\n",
+		__func__, ac->svc_offline ? "offline" : "online");
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
+	if (xchg(&ac->svc_offline_change, 0))
+		ret = POLLIN | POLLPRI | POLLRDNORM;
+	dev_dbg(ac->dev, "%s: ret (%d) from poll_wait\n",
+		__func__, ret);
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
+
+	return ret;
+}
+
+static const struct file_operations wcd_spi_ac_status_ops = {
+	.owner = THIS_MODULE,
+	.open = wcd_spi_ac_status_open,
+	.read = wcd_spi_ac_status_read,
+	.poll = wcd_spi_ac_status_poll,
+};
+
+static int wcd_spi_ac_procfs_init(struct wcd_spi_ac_priv *ac)
+{
+	int ret = 0;
+
+	ac->pfs_root = proc_mkdir(WCD_SPI_AC_PROCFS_DIR_NAME, NULL);
+	if (!ac->pfs_root) {
+		dev_err(ac->dev, "%s: proc_mkdir failed\n", __func__);
+		return -EINVAL;
+	}
+
+	ac->pfs_status = proc_create_data(WCD_SPI_AC_PROCFS_STATE_NAME,
+					  0444, ac->pfs_root,
+					  &wcd_spi_ac_status_ops,
+					  ac);
+	if (!ac->pfs_status) {
+		dev_err(ac->dev, "%s: proc_create_data failed\n",
+			__func__);
+		ret = -EINVAL;
+		goto rmdir_root;
+	}
+
+	proc_set_size(ac->pfs_status, WCD_SPI_AC_PFS_ENTRY_MAX_LEN);
+
+	return 0;
+
+rmdir_root:
+	proc_remove(ac->pfs_root);
+	return ret;
+}
+
+static void wcd_spi_ac_procfs_deinit(struct wcd_spi_ac_priv *ac)
+{
+	proc_remove(ac->pfs_status);
+	proc_remove(ac->pfs_root);
+}
+
+static int wcd_spi_ac_request_access(struct wcd_spi_ac_priv *ac,
+				     bool is_svc_locked)
+{
+	struct wcd_spi_req_access_msg_v01 req;
+	struct wcd_spi_req_access_resp_v01 rsp;
+	struct msg_desc req_desc, rsp_desc;
+	int ret = 0;
+
+	dev_dbg(ac->dev, "%s: is_svc_locked = %s\n",
+		__func__, is_svc_locked ? "true" : "false");
+
+	memset(&req, 0, sizeof(req));
+	memset(&rsp, 0, sizeof(rsp));
+
+	req.reason_valid = 1;
+	req.reason = ac->state  & 0x03;
+
+	req_desc.max_msg_len = WCD_SPI_REQ_ACCESS_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = WCD_SPI_REQ_ACCESS_MSG_V01;
+	req_desc.ei_array = wcd_spi_req_access_msg_v01_ei;
+
+	rsp_desc.max_msg_len = WCD_SPI_REQ_ACCESS_RESP_V01_MAX_MSG_LEN;
+	rsp_desc.msg_id = WCD_SPI_REQ_ACCESS_RESP_V01;
+	rsp_desc.ei_array = wcd_spi_req_access_resp_v01_ei;
+
+	if (!is_svc_locked)
+		WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
+
+	ret = qmi_send_req_wait(ac->qmi_hdl,
+				&req_desc, &req, sizeof(req),
+				&rsp_desc, &rsp, sizeof(rsp),
+				WCD_SPI_AC_QMI_TIMEOUT_MS);
+	if (ret) {
+		dev_err(ac->dev, "%s: msg send failed %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	if (rsp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		ret = -EIO;
+		dev_err(ac->dev, "%s: qmi resp error %d\n",
+			__func__, rsp.resp.result);
+	}
+done:
+	if (!is_svc_locked)
+		WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
+
+	return ret;
+}
+
+static int wcd_spi_ac_release_access(struct wcd_spi_ac_priv *ac,
+				     bool is_svc_locked)
+{
+	struct wcd_spi_rel_access_msg_v01 req;
+	struct wcd_spi_rel_access_resp_v01 rsp;
+	struct msg_desc req_desc, rsp_desc;
+	int ret = 0;
+
+	dev_dbg(ac->dev, "%s: is_svc_locked = %s\n",
+		__func__, is_svc_locked ? "true" : "false");
+
+	memset(&req, 0, sizeof(req));
+	memset(&rsp, 0, sizeof(rsp));
+
+	req_desc.max_msg_len = WCD_SPI_REL_ACCESS_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = WCD_SPI_REL_ACCESS_MSG_V01;
+	req_desc.ei_array = wcd_spi_rel_access_msg_v01_ei;
+
+	rsp_desc.max_msg_len = WCD_SPI_REL_ACCESS_RESP_V01_MAX_MSG_LEN;
+	rsp_desc.msg_id = WCD_SPI_REL_ACCESS_RESP_V01;
+	rsp_desc.ei_array = wcd_spi_rel_access_resp_v01_ei;
+
+	if (!is_svc_locked)
+		WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
+
+	ret = qmi_send_req_wait(ac->qmi_hdl,
+				&req_desc, &req, sizeof(req),
+				&rsp_desc, &rsp, sizeof(rsp),
+				WCD_SPI_AC_QMI_TIMEOUT_MS);
+	if (ret) {
+		dev_err(ac->dev, "%s: msg send failed %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	if (rsp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		ret = -EIO;
+		dev_err(ac->dev, "%s: qmi resp error %d\n",
+			__func__, rsp.resp.result);
+	}
+done:
+	if (!is_svc_locked)
+		WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
+	return ret;
+}
+
+static int wcd_spi_ac_buf_msg(
+		struct wcd_spi_ac_priv *ac,
+		u8 *data, int data_sz)
+{
+	struct wcd_spi_ac_buf_data *buf_data;
+	struct wcd_spi_buff_msg_v01 req;
+	struct wcd_spi_buff_resp_v01 rsp;
+	struct msg_desc req_desc, rsp_desc;
+	int ret = 0;
+
+	memset(&req, 0, sizeof(req));
+	memset(&rsp, 0, sizeof(rsp));
+
+	buf_data = (struct wcd_spi_ac_buf_data *) data;
+	memcpy(req.buff_addr_1, buf_data,
+	       sizeof(*buf_data));
+
+	if (data_sz - sizeof(*buf_data) != 0) {
+		req.buff_addr_2_valid = 1;
+		buf_data++;
+		memcpy(req.buff_addr_2, buf_data,
+		       sizeof(*buf_data));
+	}
+
+	req_desc.max_msg_len = WCD_SPI_BUFF_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = WCD_SPI_BUFF_MSG_V01;
+	req_desc.ei_array = wcd_spi_buff_msg_v01_ei;
+
+	rsp_desc.max_msg_len = WCD_SPI_BUFF_RESP_V01_MAX_MSG_LEN;
+	rsp_desc.msg_id = WCD_SPI_BUFF_RESP_V01;
+	rsp_desc.ei_array = wcd_spi_buff_resp_v01_ei;
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
+	ret = qmi_send_req_wait(ac->qmi_hdl,
+				&req_desc, &req, sizeof(req),
+				&rsp_desc, &rsp, sizeof(rsp),
+				WCD_SPI_AC_QMI_TIMEOUT_MS);
+
+	if (ret) {
+		dev_err(ac->dev, "%s: msg send failed %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	if (rsp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		ret = -EIO;
+		dev_err(ac->dev, "%s: qmi resp error %d\n",
+			__func__, rsp.resp.result);
+	}
+done:
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
+	return ret;
+
+}
+
+/*
+ * wcd_spi_ac_set_sync: Sets the current status of the SPI
+ *			bus and requests access if not
+ *			already accesible.
+ * @ac: pointer to the drivers private data
+ * @value: value to be set in the status mask
+ * @is_svc_locked: flag to indicate if svc_lock is acquired by caller
+ */
+static int wcd_spi_ac_set_sync(struct wcd_spi_ac_priv *ac,
+			       u32 value, bool is_svc_locked)
+{
+	int ret = 0;
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->state_lock);
+	ac->state |= value;
+	/* any non-zero state indicates us to request SPI access */
+	wmb();
+	dev_dbg(ac->dev, "%s: current state = 0x%x, current access 0x%x\n",
+		__func__, ac->state, ac->current_access);
+	if (ac->current_access == WCD_SPI_AC_REMOTE_ACCESS) {
+		dev_dbg(ac->dev,
+			"%s: requesting access, state = 0x%x\n",
+			__func__, ac->state);
+		ret = wcd_spi_ac_request_access(ac, is_svc_locked);
+		if (!ret)
+			ac->current_access = WCD_SPI_AC_LOCAL_ACCESS;
+	}
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->state_lock);
+
+	return ret;
+}
+
+/*
+ * wcd_spi_ac_clear_sync: Clears the current status of the SPI
+ *			  bus and releases access if applicable
+ * @ac: pointer to the drivers private data
+ * @value: value to be cleared in the status mask
+ * @is_svc_locked: flag to indicate if svc_lock is acquired by caller
+ */
+static int wcd_spi_ac_clear_sync(struct wcd_spi_ac_priv *ac,
+				 u32 value, bool is_svc_locked)
+{
+	int ret = 0;
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->state_lock);
+	ac->state &= ~(value);
+	/* make sure value is written before read */
+	wmb();
+	dev_dbg(ac->dev, "%s: current state = 0x%x, current access 0x%x\n",
+		__func__, ac->state, ac->current_access);
+	/* state should be zero to release SPI access */
+	if (!ac->state &&
+	    ac->current_access == WCD_SPI_AC_LOCAL_ACCESS) {
+		dev_dbg(ac->dev,
+			"%s: releasing access, state = 0x%x\n",
+			__func__, ac->state);
+		ret = wcd_spi_ac_release_access(ac, is_svc_locked);
+		if (!ret)
+			ac->current_access = WCD_SPI_AC_REMOTE_ACCESS;
+	}
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->state_lock);
+
+	return ret;
+
+}
+
+/*
+ * wcd_spi_access_ctl: API to request/release the access
+ *		       to wcd-spi bus.
+ * @dev: handle to the wcd-spi-ac device
+ * @request: enum to indicate access request or access release
+ * @reason: reason for request/release. Must be one of the
+ *	    valid reasons.
+ * Returns success if the access handover was sucessful,
+ * negative error code otherwise.
+ */
+int wcd_spi_access_ctl(struct device *dev,
+		      enum wcd_spi_acc_req request,
+		      u32 reason)
+{
+	struct wcd_spi_ac_priv *ac;
+	int ret = 0;
+
+	if (!dev) {
+		pr_err("%s: invalid device\n", __func__);
+		return -EINVAL;
+	}
+
+	/* only data_transfer and remote_down are valid reasons */
+	if (reason != WCD_SPI_AC_DATA_TRANSFER &&
+	    reason != WCD_SPI_AC_REMOTE_DOWN) {
+		pr_err("%s: Invalid reason 0x%x\n",
+			__func__, reason);
+		return -EINVAL;
+	}
+
+	ac = (struct wcd_spi_ac_priv *) dev_get_drvdata(dev);
+	if (!ac) {
+		dev_err(dev, "%s: invalid driver data\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "%s: request = 0x%x, reason = 0x%x\n",
+		__func__, request, reason);
+
+	switch (request) {
+	case WCD_SPI_ACCESS_REQUEST:
+		ret = wcd_spi_ac_set_sync(ac, reason, false);
+		if (ret)
+			dev_err(dev, "%s: set_sync(0x%x) failed %d\n",
+				__func__, reason, ret);
+		break;
+	case WCD_SPI_ACCESS_RELEASE:
+		ret = wcd_spi_ac_clear_sync(ac, reason, false);
+		if (ret)
+			dev_err(dev, "%s: clear_sync(0x%x) failed %d\n",
+				__func__, reason, ret);
+		break;
+	default:
+		dev_err(dev, "%s: invalid request 0x%x\n",
+			__func__, request);
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd_spi_access_ctl);
+
+static int wcd_spi_ac_cdev_open(struct inode *inode,
+				struct file *file)
+{
+	struct wcd_spi_ac_priv *ac;
+	int ret = 0;
+
+	ac = container_of(inode->i_cdev, struct wcd_spi_ac_priv, cdev);
+	if (!ac) {
+		pr_err("%s: Invalid private data\n", __func__);
+		return -EINVAL;
+	}
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
+	if (ac->svc_offline) {
+		dev_err(ac->dev, "%s: SVC is not online, cannot open driver\n",
+			__func__);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	file->private_data = ac;
+
+done:
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
+	return ret;
+}
+
+static ssize_t wcd_spi_ac_cdev_write(struct file *file,
+				     const char __user *buf,
+				     size_t count,
+				     loff_t *ppos)
+{
+	struct wcd_spi_ac_priv *ac;
+	struct wcd_spi_ac_write_cmd *cmd_buf;
+	int ret = 0;
+	int data_sz;
+
+	ac = (struct wcd_spi_ac_priv *) file->private_data;
+	if (!ac) {
+		pr_err("%s: Invalid private data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (count < WCD_SPI_AC_WRITE_CMD_MIN_SIZE ||
+	    count > WCD_SPI_AC_WRITE_CMD_MAX_SIZE) {
+		dev_err(ac->dev, "%s: Invalid write count %zd\n",
+			__func__, count);
+		return -EINVAL;
+	}
+
+	cmd_buf = kzalloc(count, GFP_KERNEL);
+	if (!cmd_buf)
+		return -ENOMEM;
+
+	if (get_user(cmd_buf->cmd_type, buf)) {
+		dev_err(ac->dev, "%s: get_user failed\n", __func__);
+		ret = -EFAULT;
+		goto free_cmd_buf;
+	}
+
+	dev_dbg(ac->dev, "%s: write cmd type 0x%x\n",
+		__func__, cmd_buf->cmd_type);
+
+	switch (cmd_buf->cmd_type) {
+
+	case WCD_SPI_AC_CMD_CONC_BEGIN:
+		ret = wcd_spi_ac_set_sync(ac, WCD_SPI_AC_CONCURRENCY, false);
+		if (ret) {
+			dev_err(ac->dev, "%s: set_sync(CONC) fail %d\n",
+				__func__, ret);
+			goto free_cmd_buf;
+		}
+
+		break;
+
+	case WCD_SPI_AC_CMD_CONC_END:
+		ret = wcd_spi_ac_clear_sync(ac, WCD_SPI_AC_CONCURRENCY, false);
+		if (ret) {
+			dev_err(ac->dev, "%s: clear_sync(CONC) fail %d\n",
+				__func__, ret);
+			goto free_cmd_buf;
+		}
+
+		break;
+
+	case WCD_SPI_AC_CMD_BUF_DATA:
+
+		/* Read the buffer details and send to service */
+		data_sz = count - sizeof(cmd_buf->cmd_type);
+
+		if (!data_sz ||
+		    (data_sz % sizeof(struct wcd_spi_ac_buf_data))) {
+			dev_err(ac->dev, "%s: size %d not multiple of %ld\n",
+				__func__, data_sz,
+				sizeof(struct wcd_spi_ac_buf_data));
+			goto free_cmd_buf;
+		}
+
+		if (data_sz / sizeof(struct wcd_spi_ac_buf_data) >
+		    WCD_SPI_AC_MAX_BUFFERS) {
+			dev_err(ac->dev, "%s: invalid size %d\n",
+				__func__, data_sz);
+			goto free_cmd_buf;
+		}
+
+		if (copy_from_user(cmd_buf->payload,
+				   buf + sizeof(cmd_buf->cmd_type),
+				   data_sz)) {
+			dev_err(ac->dev, "%s: copy_from_user failed\n",
+				__func__);
+			ret = -EFAULT;
+			goto free_cmd_buf;
+		}
+
+		ret = wcd_spi_ac_buf_msg(ac, cmd_buf->payload, data_sz);
+		if (ret) {
+			dev_err(ac->dev, "%s: _buf_msg failed %d\n",
+				__func__, ret);
+			goto free_cmd_buf;
+		}
+
+		ret = wcd_spi_ac_clear_sync(ac, WCD_SPI_AC_UNINITIALIZED,
+					    false);
+		if (ret) {
+			dev_err(ac->dev, "%s: clear_sync 0x%lx failed %d\n",
+				__func__, WCD_SPI_AC_UNINITIALIZED, ret);
+			goto free_cmd_buf;
+		}
+		break;
+	default:
+		dev_err(ac->dev, "%s: Invalid cmd_type 0x%x\n",
+			__func__, cmd_buf->cmd_type);
+		ret = -EINVAL;
+		goto free_cmd_buf;
+	}
+
+free_cmd_buf:
+
+	kfree(cmd_buf);
+	if (!ret)
+		ret = count;
+
+	return ret;
+}
+
+static int wcd_spi_ac_cdev_release(struct inode *inode,
+				   struct file *file)
+{
+	struct wcd_spi_ac_priv *ac;
+	int ret = 0;
+
+	ac = (struct wcd_spi_ac_priv *) file->private_data;
+	if (!ac) {
+		pr_err("%s: Invalid private data\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = wcd_spi_ac_set_sync(ac, WCD_SPI_AC_UNINITIALIZED, false);
+	if (ret)
+		dev_err(ac->dev, "%s: set_sync(UNINITIALIZED) failed %d\n",
+			__func__, ret);
+	return ret;
+}
+
+static const struct file_operations wcd_spi_ac_cdev_fops = {
+	.owner = THIS_MODULE,
+	.open = wcd_spi_ac_cdev_open,
+	.write = wcd_spi_ac_cdev_write,
+	.release = wcd_spi_ac_cdev_release,
+};
+
+static int wcd_spi_ac_reg_chardev(struct wcd_spi_ac_priv *ac)
+{
+	int ret;
+
+	ret = alloc_chrdev_region(&ac->cdev_num, 0, 1,
+				  WCD_SPI_AC_CLIENT_CDEV_NAME);
+	if (ret) {
+		dev_err(ac->dev, "%s: alloc_chrdev_region failed %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ac->cls = class_create(THIS_MODULE, WCD_SPI_AC_CLIENT_CDEV_NAME);
+	if (IS_ERR(ac->cls)) {
+		ret = PTR_ERR(ac->cls);
+		dev_err(ac->dev, "%s: class_create failed %d\n",
+			__func__, ret);
+		goto unregister_chrdev;
+	}
+
+	ac->chardev = device_create(ac->cls, NULL, ac->cdev_num,
+				      NULL, WCD_SPI_AC_CLIENT_CDEV_NAME);
+	if (IS_ERR(ac->chardev)) {
+		ret = PTR_ERR(ac->chardev);
+		dev_err(ac->dev, "%s: device_create failed %d\n",
+			__func__, ret);
+		goto destroy_class;
+	}
+
+	cdev_init(&ac->cdev, &wcd_spi_ac_cdev_fops);
+	ret = cdev_add(&ac->cdev, ac->cdev_num, 1);
+	if (ret) {
+		dev_err(ac->dev, "%s: cdev_add failed %d\n",
+			__func__, ret);
+		goto destroy_device;
+	}
+
+	return 0;
+
+destroy_device:
+	device_destroy(ac->cls, ac->cdev_num);
+
+destroy_class:
+	class_destroy(ac->cls);
+
+unregister_chrdev:
+	unregister_chrdev_region(0, 1);
+	return ret;
+}
+
+static int wcd_spi_ac_unreg_chardev(struct wcd_spi_ac_priv *ac)
+{
+	cdev_del(&ac->cdev);
+	device_destroy(ac->cls, ac->cdev_num);
+	class_destroy(ac->cls);
+	unregister_chrdev_region(0, 1);
+
+	return 0;
+}
+
+static void wcd_spi_ac_recv_msg(struct work_struct *work)
+{
+	struct wcd_spi_ac_priv *ac;
+	int rc = 0;
+
+	ac = container_of(work, struct wcd_spi_ac_priv,
+			  recv_msg_work);
+	if (!ac) {
+		pr_err("%s: Invalid private data\n", __func__);
+		return;
+	}
+
+	do {
+		dev_dbg(ac->dev, "%s: msg received, rc = %d\n",
+			__func__, rc);
+	} while ((rc = qmi_recv_msg(ac->qmi_hdl)) == 0);
+
+	if (rc != -ENOMSG)
+		dev_err(ac->dev, "%s: qmi_recv_msg failed %d\n",
+			__func__, rc);
+}
+
+static void wcd_spi_ac_clnt_notify(struct qmi_handle *hdl,
+		enum qmi_event_type event, void *priv_data)
+{
+	struct wcd_spi_ac_priv *ac;
+
+	if (!priv_data) {
+		pr_err("%s: Invalid private data\n", __func__);
+		return;
+	}
+
+	ac = (struct wcd_spi_ac_priv *) priv_data;
+
+	switch (event) {
+	case QMI_RECV_MSG:
+		queue_work(ac->qmi_wq, &ac->recv_msg_work);
+		break;
+	default:
+		break;
+	}
+}
+
+static void wcd_spi_ac_svc_arrive(struct work_struct *work)
+{
+	struct wcd_spi_ac_priv *ac;
+	int ret;
+
+	ac = container_of(work, struct wcd_spi_ac_priv,
+			  svc_arr_work);
+	if (!ac) {
+		pr_err("%s: Invalid private data\n",
+			__func__);
+		return;
+	}
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
+	ac->qmi_hdl = qmi_handle_create(wcd_spi_ac_clnt_notify,
+					ac);
+	if (!ac->qmi_hdl) {
+		dev_err(ac->dev, "%s: qmi_handle_create failed\n",
+			__func__);
+		goto done;
+	}
+
+	ret = qmi_connect_to_service(ac->qmi_hdl,
+			WCD_SPI_CTL_SERVICE_ID_V01,
+			WCD_SPI_CTL_SERVICE_VERS_V01,
+			WCD_SPI_CTL_INS_ID);
+	if (ret) {
+		dev_err(ac->dev, "%s, cant connect to service, error %d\n",
+			__func__, ret);
+		qmi_handle_destroy(ac->qmi_hdl);
+		ac->qmi_hdl = NULL;
+		goto done;
+	}
+
+	/* Mark service as online */
+	wcd_spi_ac_status_change(ac, 1);
+
+	/*
+	 * update the state and clear the WCD_SPI_AC_SVC_OFFLINE
+	 * bit to indicate that the service is now online.
+	 */
+	ret = wcd_spi_ac_clear_sync(ac, WCD_SPI_AC_SVC_OFFLINE, true);
+	if (ret)
+		dev_err(ac->dev, "%s: clear_sync(SVC_OFFLINE) failed %d\n",
+			__func__, ret);
+done:
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
+
+}
+
+static void wcd_spi_ac_svc_exit(struct work_struct *work)
+{
+	struct wcd_spi_ac_priv *ac;
+	int ret = 0;
+
+	ac = container_of(work, struct wcd_spi_ac_priv,
+			  svc_exit_work);
+	if (!ac) {
+		pr_err("%s: Invalid private data\n",
+			__func__);
+		return;
+	}
+
+	WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
+	ret = wcd_spi_ac_set_sync(ac, WCD_SPI_AC_SVC_OFFLINE, true);
+	if (ret)
+		dev_err(ac->dev, "%s: set_sync(SVC_OFFLINE) failed %d\n",
+			__func__, ret);
+	qmi_handle_destroy(ac->qmi_hdl);
+	ac->qmi_hdl = NULL;
+	wcd_spi_ac_status_change(ac, 0);
+	WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
+}
+
+static int wcd_spi_ac_svc_event(struct notifier_block *this,
+				unsigned long event,
+				void *data)
+{
+	struct wcd_spi_ac_priv *ac;
+
+	ac = container_of(this, struct wcd_spi_ac_priv, nb);
+	if (!ac) {
+		pr_err("%s: Invalid private data\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(ac->dev, "%s: event = 0x%lx", __func__, event);
+
+	switch (event) {
+	case QMI_SERVER_ARRIVE:
+		schedule_work(&ac->svc_arr_work);
+		break;
+	case QMI_SERVER_EXIT:
+		schedule_work(&ac->svc_exit_work);
+		break;
+	default:
+		dev_err(ac->dev, "%s unhandled event %ld\n",
+			__func__, event);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd_spi_ac_probe(struct platform_device *pdev)
+{
+	struct wcd_spi_ac_priv *ac;
+	struct device *parent = pdev->dev.parent;
+	int ret = 0;
+
+	ac = devm_kzalloc(&pdev->dev, sizeof(*ac),
+			    GFP_KERNEL);
+	if (!ac)
+		return -ENOMEM;
+
+	ac->dev = &pdev->dev;
+	ac->parent = parent;
+
+	ret = wcd_spi_ac_reg_chardev(ac);
+	if (ret)
+		return ret;
+
+	ret = wcd_spi_ac_procfs_init(ac);
+	if (ret)
+		goto unreg_chardev;
+
+	mutex_init(&ac->status_lock);
+	mutex_init(&ac->state_lock);
+	mutex_init(&ac->svc_lock);
+	init_waitqueue_head(&ac->svc_poll_wait);
+	ac->svc_offline = 1;
+	ac->state = (WCD_SPI_AC_SVC_OFFLINE |
+		     WCD_SPI_AC_UNINITIALIZED);
+	ac->current_access = WCD_SPI_AC_LOCAL_ACCESS;
+
+	ac->nb.notifier_call = wcd_spi_ac_svc_event;
+	INIT_WORK(&ac->svc_arr_work, wcd_spi_ac_svc_arrive);
+	INIT_WORK(&ac->svc_exit_work, wcd_spi_ac_svc_exit);
+	INIT_WORK(&ac->recv_msg_work, wcd_spi_ac_recv_msg);
+
+	ac->qmi_wq = create_singlethread_workqueue("qmi_wq");
+	if (!ac->qmi_wq) {
+		dev_err(&pdev->dev,
+			"%s: create_singlethread_workqueue failed\n",
+			__func__);
+		goto deinit_procfs;
+	}
+
+	dev_set_drvdata(&pdev->dev, ac);
+
+	ret = qmi_svc_event_notifier_register(
+			WCD_SPI_CTL_SERVICE_ID_V01,
+			WCD_SPI_CTL_SERVICE_VERS_V01,
+			WCD_SPI_CTL_INS_ID,
+			&ac->nb);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s: qmi_svc_event_notifier_register failed %d\n",
+			__func__, ret);
+		goto destroy_wq;
+	}
+
+	return 0;
+
+destroy_wq:
+	destroy_workqueue(ac->qmi_wq);
+	dev_set_drvdata(&pdev->dev, NULL);
+deinit_procfs:
+	wcd_spi_ac_procfs_deinit(ac);
+	mutex_destroy(&ac->status_lock);
+	mutex_destroy(&ac->state_lock);
+	mutex_destroy(&ac->svc_lock);
+unreg_chardev:
+	wcd_spi_ac_unreg_chardev(ac);
+	return ret;
+}
+
+static int wcd_spi_ac_remove(struct platform_device *pdev)
+{
+	struct wcd_spi_ac_priv *ac;
+
+	ac = dev_get_drvdata(&pdev->dev);
+	qmi_svc_event_notifier_unregister(
+			WCD_SPI_CTL_SERVICE_ID_V01,
+			WCD_SPI_CTL_SERVICE_VERS_V01,
+			WCD_SPI_CTL_INS_ID,
+			&ac->nb);
+	if (ac->qmi_wq)
+		destroy_workqueue(ac->qmi_wq);
+	wcd_spi_ac_unreg_chardev(ac);
+	wcd_spi_ac_procfs_deinit(ac);
+	mutex_destroy(&ac->status_lock);
+	mutex_destroy(&ac->state_lock);
+	mutex_destroy(&ac->svc_lock);
+
+	return 0;
+}
+
+static const struct of_device_id wcd_spi_ac_of_match[] = {
+	{ .compatible = "qcom,wcd-spi-ac" },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, wcd_spi_ac_of_match);
+
+static struct platform_driver wcd_spi_ac_driver = {
+	.driver = {
+		.name = "qcom,wcd-spi-ac",
+		.of_match_table = wcd_spi_ac_of_match,
+	},
+	.probe = wcd_spi_ac_probe,
+	.remove = wcd_spi_ac_remove,
+};
+
+module_platform_driver(wcd_spi_ac_driver);
+
+MODULE_DESCRIPTION("WCD SPI access control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/soc/wcd_spi_ctl_v01.c b/soc/wcd_spi_ctl_v01.c
new file mode 100644
index 0000000..0e59ca3
--- /dev/null
+++ b/soc/wcd_spi_ctl_v01.c
@@ -0,0 +1,138 @@
+/* Copyright (c) 2018-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/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+#include "wcd_spi_ctl_v01.h"
+
+struct elem_info wcd_spi_req_access_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wcd_spi_req_access_msg_v01,
+					   reason_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wcd_spi_req_access_msg_v01,
+					   reason),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wcd_spi_req_access_resp_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wcd_spi_req_access_resp_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wcd_spi_rel_access_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wcd_spi_rel_access_resp_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wcd_spi_rel_access_resp_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wcd_spi_buff_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = WCD_SPI_BUFF_CHANNELS_MAX_V01,
+		.elem_size      = sizeof(u32),
+		.is_array       = STATIC_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wcd_spi_buff_msg_v01,
+					   buff_addr_1),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wcd_spi_buff_msg_v01,
+					   buff_addr_2_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = WCD_SPI_BUFF_CHANNELS_MAX_V01,
+		.elem_size      = sizeof(u32),
+		.is_array       = STATIC_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wcd_spi_buff_msg_v01,
+					   buff_addr_2),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wcd_spi_buff_resp_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wcd_spi_buff_resp_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
diff --git a/soc/wcd_spi_ctl_v01.h b/soc/wcd_spi_ctl_v01.h
new file mode 100644
index 0000000..dd9b1c3
--- /dev/null
+++ b/soc/wcd_spi_ctl_v01.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2018-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.
+ *
+ */
+#ifndef WCD_SPI_CTL_V01_H
+#define WCD_SPI_CTL_V01_H
+
+#define WCD_SPI_CTL_SERVICE_ID_V01 0x421
+#define WCD_SPI_CTL_SERVICE_VERS_V01 0x01
+
+#define WCD_SPI_BUFF_RESP_V01 0x0022
+#define WCD_SPI_REL_ACCESS_RESP_V01 0x0021
+#define WCD_SPI_REQ_ACCESS_MSG_V01 0x0020
+#define WCD_SPI_BUFF_MSG_V01 0x0022
+#define WCD_SPI_REL_ACCESS_MSG_V01 0x0021
+#define WCD_SPI_REQ_ACCESS_RESP_V01 0x0020
+
+#define WCD_SPI_BUFF_CHANNELS_MAX_V01 0x08
+
+#define WCD_SPI_REQ_DATA_TRANSFER_V01 ((u64)0x01ULL)
+#define WCD_SPI_REQ_CONCURRENCY_V01 ((u64)0x02ULL)
+#define WCD_SPI_REQ_REMOTE_DOWN_V01 ((u64)0x04ULL)
+
+struct wcd_spi_req_access_msg_v01 {
+	u8 reason_valid;
+	u64 reason;
+};
+#define WCD_SPI_REQ_ACCESS_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wcd_spi_req_access_msg_v01_ei[];
+
+struct wcd_spi_req_access_resp_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WCD_SPI_REQ_ACCESS_RESP_V01_MAX_MSG_LEN 7
+extern struct elem_info wcd_spi_req_access_resp_v01_ei[];
+
+struct wcd_spi_rel_access_msg_v01 {
+	char placeholder;
+};
+#define WCD_SPI_REL_ACCESS_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wcd_spi_rel_access_msg_v01_ei[];
+
+struct wcd_spi_rel_access_resp_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WCD_SPI_REL_ACCESS_RESP_V01_MAX_MSG_LEN 7
+extern struct elem_info wcd_spi_rel_access_resp_v01_ei[];
+
+struct wcd_spi_buff_msg_v01 {
+	u32 buff_addr_1[WCD_SPI_BUFF_CHANNELS_MAX_V01];
+	u8 buff_addr_2_valid;
+	u32 buff_addr_2[WCD_SPI_BUFF_CHANNELS_MAX_V01];
+};
+#define WCD_SPI_BUFF_MSG_V01_MAX_MSG_LEN 70
+extern struct elem_info wcd_spi_buff_msg_v01_ei[];
+
+struct wcd_spi_buff_resp_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WCD_SPI_BUFF_RESP_V01_MAX_MSG_LEN 7
+extern struct elem_info wcd_spi_buff_resp_v01_ei[];
+
+#endif