Merge "ASoC: wcd938x: Update routing for HDR recording"
diff --git a/asoc/codecs/audio-ext-clk-up.c b/asoc/codecs/audio-ext-clk-up.c
index 0384e71..e6e68ad 100644
--- a/asoc/codecs/audio-ext-clk-up.c
+++ b/asoc/codecs/audio-ext-clk-up.c
@@ -27,6 +27,7 @@
 	AUDIO_EXT_CLK_LPASS6,
 	AUDIO_EXT_CLK_LPASS7,
 	AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE,
+	AUDIO_EXT_CLK_LPASS8,
 	AUDIO_EXT_CLK_LPASS_MAX,
 	AUDIO_EXT_CLK_EXTERNAL_PLL = AUDIO_EXT_CLK_LPASS_MAX,
 	AUDIO_EXT_CLK_MAX,
@@ -326,6 +327,17 @@
 			.mult = 1,
 			.div = 1,
 			.hw.init = &(struct clk_init_data){
+				.name = "audio_lpass_mclk8",
+				.ops = &audio_ext_clk_ops,
+			},
+		},
+	},
+	{
+		.pnctrl_info = {NULL},
+		.fact = {
+			.mult = 1,
+			.div = 1,
+			.hw.init = &(struct clk_init_data){
 				.name = "audio_external_pll_clk",
 				.ops = &audio_ext_clk_ops,
 			},
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 7bf6295..217fa5f 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -1049,13 +1049,11 @@
 {
 	struct bolero_priv *priv = dev_get_drvdata(dev->parent);
 
-	mutex_lock(&priv->clk_lock);
 	if (priv->lpass_core_hw_vote != NULL)
 		clk_disable_unprepare(priv->lpass_core_hw_vote);
 	else
 		dev_dbg(dev, "%s: Invalid lpass core hw node\n",
 			__func__);
-	mutex_unlock(&priv->clk_lock);
 	return 0;
 }
 EXPORT_SYMBOL(bolero_runtime_suspend);
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 58f3689..98ee1e7 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -691,7 +691,7 @@
 							CF_MIN_3DB_150HZ) {
 			schedule_delayed_work(
 					&tx_priv->tx_hpf_work[decimator].dwork,
-					msecs_to_jiffies(300));
+					msecs_to_jiffies(50));
 			snd_soc_component_update_bits(component,
 					hpf_gate_reg, 0x02, 0x02);
 			/*
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index f8df0b7..8789fce 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -595,7 +595,7 @@
 							CF_MIN_3DB_150HZ)
 			schedule_delayed_work(
 					&va_priv->va_hpf_work[decimator].dwork,
-					msecs_to_jiffies(300));
+					msecs_to_jiffies(50));
 		/* apply gain after decimator is enabled */
 		snd_soc_component_write(component, tx_gain_ctl_reg,
 			snd_soc_component_read32(component, tx_gain_ctl_reg));
@@ -1632,7 +1632,7 @@
 	}
 
 	va_io_base = devm_ioremap(&pdev->dev, va_base_addr,
-				  VA_MAX_OFFSET);
+				  VA_MACRO_MAX_OFFSET);
 	if (!va_io_base) {
 		dev_err(&pdev->dev, "%s: ioremap failed\n", __func__);
 		return -EINVAL;
diff --git a/asoc/codecs/wcd-clsh.c b/asoc/codecs/wcd-clsh.c
index fd30148..0f403ac 100644
--- a/asoc/codecs/wcd-clsh.c
+++ b/asoc/codecs/wcd-clsh.c
@@ -219,6 +219,9 @@
 	if ((enable && (++clsh_d->flyback_users == 1)) ||
 	   (!enable && (--clsh_d->flyback_users == 0))) {
 		snd_soc_component_update_bits(component,
+				WCD9XXX_FLYBACK_VNEG_CTRL_1,
+				0xE0, 0xE0);
+		snd_soc_component_update_bits(component,
 				WCD9XXX_ANA_RX_SUPPLIES,
 				(1 << 6), (enable << 6));
 		/*
diff --git a/asoc/codecs/wcd-spi.c b/asoc/codecs/wcd-spi.c
index 35b0d93..145c4df 100644
--- a/asoc/codecs/wcd-spi.c
+++ b/asoc/codecs/wcd-spi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -8,6 +8,7 @@
 #include <linux/of.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/bitops.h>
 #include <linux/spi/spi.h>
 #include <linux/regmap.h>
@@ -152,6 +153,10 @@
 	/* Buffers to hold memory used for transfers */
 	void *tx_buf;
 	void *rx_buf;
+
+	/* DMA handles for transfer buffers */
+	dma_addr_t tx_dma;
+	dma_addr_t rx_dma;
 };
 
 enum xfer_request {
@@ -1371,17 +1376,20 @@
 	spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2);
 
 	/* Pre-allocate the buffers */
-	wcd_spi->tx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
-				  GFP_KERNEL | GFP_DMA);
+	wcd_spi->tx_buf = dma_zalloc_coherent(&spi->dev,
+					      WCD_SPI_RW_MAX_BUF_SIZE,
+					      &wcd_spi->tx_dma, GFP_KERNEL);
 	if (!wcd_spi->tx_buf) {
 		ret = -ENOMEM;
 		goto done;
 	}
 
-	wcd_spi->rx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
-				  GFP_KERNEL | GFP_DMA);
+	wcd_spi->rx_buf = dma_zalloc_coherent(&spi->dev,
+					      WCD_SPI_RW_MAX_BUF_SIZE,
+					      &wcd_spi->rx_dma, GFP_KERNEL);
 	if (!wcd_spi->rx_buf) {
-		kfree(wcd_spi->tx_buf);
+		dma_free_coherent(&spi->dev, WCD_SPI_RW_MAX_BUF_SIZE,
+				  wcd_spi->tx_buf, wcd_spi->tx_dma);
 		wcd_spi->tx_buf = NULL;
 		ret = -ENOMEM;
 		goto done;
@@ -1408,8 +1416,10 @@
 	spi_transfer_del(&wcd_spi->xfer2[0]);
 	spi_transfer_del(&wcd_spi->xfer2[1]);
 
-	kfree(wcd_spi->tx_buf);
-	kfree(wcd_spi->rx_buf);
+	dma_free_coherent(&spi->dev, WCD_SPI_RW_MAX_BUF_SIZE,
+			  wcd_spi->tx_buf, wcd_spi->tx_dma);
+	dma_free_coherent(&spi->dev, WCD_SPI_RW_MAX_BUF_SIZE,
+			  wcd_spi->rx_buf, wcd_spi->rx_dma);
 	wcd_spi->tx_buf = NULL;
 	wcd_spi->rx_buf = NULL;
 }
@@ -1445,6 +1455,7 @@
 	mutex_init(&wcd_spi->xfer_mutex);
 	INIT_DELAYED_WORK(&wcd_spi->clk_dwork, wcd_spi_clk_work);
 	init_completion(&wcd_spi->resume_comp);
+	arch_setup_dma_ops(&spi->dev, 0, 0, NULL, true);
 
 	wcd_spi->spi = spi;
 	spi_set_drvdata(spi, wcd_spi);
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index beb4b17..0836bc0 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -567,6 +567,8 @@
 				WCD937X_DIGITAL_CDC_COMP_CTL_0,
 				0x02, 0x02);
 		usleep_range(5000, 5010);
+		snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN,
+				0x04, 0x00);
 		wcd_cls_h_fsm(component, &wcd937x->clsh_info,
 			     WCD_CLSH_EVENT_PRE_DAC,
 			     WCD_CLSH_STATE_EAR,
@@ -942,6 +944,8 @@
 			     WCD_CLSH_EVENT_POST_PA,
 			     WCD_CLSH_STATE_EAR,
 			     hph_mode);
+		snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN,
+				0x04, 0x04);
 		if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
 			snd_soc_component_update_bits(component,
 					WCD937X_DIGITAL_PDM_WD_CTL2,
diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c
index b7c0230..ec42b0d 100644
--- a/asoc/codecs/wcd938x/wcd938x-slave.c
+++ b/asoc/codecs/wcd938x/wcd938x-slave.c
@@ -22,6 +22,11 @@
 	uint8_t devnum = 0;
 	struct swr_device *pdev = to_swr_device(dev);
 
+	if (!pdev) {
+		pr_err("%s: invalid swr device handle\n", __func__);
+		return -EINVAL;
+	}
+
 	ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
 	if (ret) {
 		dev_dbg(&pdev->dev,
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index fbc745a..8ab4a7c 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -177,7 +177,7 @@
 			u8 *port_type, u8 path)
 {
 	int i, j;
-	u8 num_ports;
+	u8 num_ports = 0;
 	struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT];
 	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
@@ -190,6 +190,10 @@
 		map = &wcd938x->tx_port_mapping;
 		num_ports = wcd938x->num_tx_ports;
 		break;
+	default:
+		dev_err(component->dev, "%s Invalid path selected %u\n",
+					__func__, path);
+		return -EINVAL;
 	}
 
 	for (i = 0; i <= num_ports; i++) {
@@ -217,11 +221,11 @@
 			char *prop, u8 path)
 {
 	u32 *dt_array, map_size, map_length;
-	u32 port_num, ch_mask, ch_rate, old_port_num = 0;
+	u32 port_num = 0, ch_mask, ch_rate, old_port_num = 0;
 	u32 slave_port_type, master_port_type;
 	u32 i, ch_iter = 0;
 	int ret = 0;
-	u8 *num_ports;
+	u8 *num_ports = NULL;
 	struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT];
 	struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
 
@@ -234,6 +238,10 @@
 		map = &wcd938x->tx_port_mapping;
 		num_ports = &wcd938x->num_tx_ports;
 		break;
+	default:
+		dev_err(dev, "%s Invalid path selected %u\n",
+			      __func__, path);
+		return -EINVAL;
 	}
 
 	if (!of_find_property(dev->of_node, prop,
@@ -532,6 +540,8 @@
 				WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x02);
 		/* 5 msec delay as per HW requirement */
 		usleep_range(5000, 5010);
+		snd_soc_component_update_bits(component, WCD938X_FLYBACK_EN,
+				0x04, 0x00);
 		wcd_cls_h_fsm(component, &wcd938x->clsh_info,
 			     WCD_CLSH_EVENT_PRE_DAC,
 			     WCD_CLSH_STATE_EAR,
@@ -824,6 +834,8 @@
 			     WCD_CLSH_EVENT_POST_PA,
 			     WCD_CLSH_STATE_EAR,
 			     hph_mode);
+		snd_soc_component_update_bits(component, WCD938X_FLYBACK_EN,
+				0x04, 0x04);
 		break;
 	};
 	return ret;
diff --git a/asoc/kona.c b/asoc/kona.c
index fd5c9a7..704951c 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -2297,7 +2297,7 @@
 {
 	int ch_num = cdc_dma_get_port_idx(kcontrol);
 
-	if (ch_num < 0) {
+	if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
 		pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
 		return ch_num;
 	}
@@ -2313,7 +2313,7 @@
 {
 	int ch_num = cdc_dma_get_port_idx(kcontrol);
 
-	if (ch_num < 0) {
+	if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
 		pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
 		return ch_num;
 	}
@@ -2330,7 +2330,7 @@
 {
 	int ch_num = cdc_dma_get_port_idx(kcontrol);
 
-	if (ch_num < 0) {
+	if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
 		pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
 		return ch_num;
 	}
@@ -2363,7 +2363,7 @@
 	int rc = 0;
 	int ch_num = cdc_dma_get_port_idx(kcontrol);
 
-	if (ch_num < 0) {
+	if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
 		pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
 		return ch_num;
 	}
@@ -2498,7 +2498,7 @@
 {
 	int ch_num = cdc_dma_get_port_idx(kcontrol);
 
-	if (ch_num < 0) {
+	if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
 		pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
 		return ch_num;
 	}
@@ -2516,7 +2516,7 @@
 {
 	int ch_num = cdc_dma_get_port_idx(kcontrol);
 
-	if (ch_num < 0) {
+	if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
 		pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
 		return ch_num;
 	}
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index be10bc1..179a95e 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -363,12 +363,17 @@
 	}
 	rtd = cstream->private_data;
 	prtd = cstream->runtime->private_data;
-	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 
-	if (!rtd || !component || !prtd || !prtd->audio_client) {
+	if (!rtd || !prtd || !prtd->audio_client) {
 		pr_err("%s: invalid rtd, prtd or audio client", __func__);
 		return rc;
 	}
+	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: invalid component\n", __func__);
+		return rc;
+	}
+
 	pdata = snd_soc_component_get_drvdata(component);
 
 	if (prtd->compr_passthr != LEGACY_PCM) {
@@ -1810,12 +1815,16 @@
 	}
 	runtime = cstream->runtime;
 	soc_prtd = cstream->private_data;
-	component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
-	if (!runtime || !soc_prtd || !component) {
-		pr_err("%s runtime or soc_prtd or component is null\n",
+	if (!runtime || !soc_prtd) {
+		pr_err("%s runtime or soc_prtd is null\n",
 			__func__);
 		return 0;
 	}
+	component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s component is null\n", __func__);
+		return 0;
+	}
 	prtd = runtime->private_data;
 	if (!prtd) {
 		pr_err("%s prtd is null\n", __func__);
@@ -1913,12 +1922,16 @@
 	}
 	runtime = cstream->runtime;
 	soc_prtd = cstream->private_data;
-	component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
-	if (!runtime || !soc_prtd || !component) {
-		pr_err("%s runtime or soc_prtd or component is null\n",
-			__func__);
+	if (!runtime || !soc_prtd) {
+		pr_err("%s runtime or soc_prtd is null\n", __func__);
 		return 0;
 	}
+	component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s component is null\n", __func__);
+		return 0;
+	}
+
 	prtd = runtime->private_data;
 	if (!prtd) {
 		pr_err("%s prtd is null\n", __func__);
@@ -2687,13 +2700,22 @@
 
 		pr_debug("%s: open_write stream_id %d bits_per_sample %d",
 				__func__, stream_id, bits_per_sample);
-		rc = q6asm_stream_open_write_v4(prtd->audio_client,
+
+		if (q6core_get_avcs_api_version_per_service(
+					APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
+					ADSP_ASM_API_VERSION_V2)
+			rc = q6asm_stream_open_write_v5(prtd->audio_client,
+				prtd->codec, bits_per_sample,
+				stream_id,
+				prtd->gapless_state.use_dsp_gapless_mode);
+		else
+			rc = q6asm_stream_open_write_v4(prtd->audio_client,
 				prtd->codec, bits_per_sample,
 				stream_id,
 				prtd->gapless_state.use_dsp_gapless_mode);
 		if (rc < 0) {
-			pr_err("%s: Session out open failed for gapless\n",
-				 __func__);
+			pr_err("%s: Session out open failed for gapless [%d]\n",
+				__func__, rc);
 			break;
 		}
 
@@ -2788,12 +2810,10 @@
 				rc = q6asm_get_session_time(
 				prtd->audio_client, &prtd->marker_timestamp);
 			if (rc < 0) {
-				pr_err("%s: Get Session Time return =%lld\n",
-					__func__, timestamp);
 				if (atomic_read(&prtd->error))
 					return -ENETRESET;
 				else
-					return -EAGAIN;
+					return rc;
 			}
 		}
 	} else {
@@ -4712,6 +4732,11 @@
 					chmixer_pspd->in_ch_map[i] =
 						pdata->ch_map[fe_id]->channel_map[i];
 			} else {
+				if (chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+					pr_err("%s: Invalid channel count %d\n",
+						__func__, chmixer_pspd->input_channel);
+					return -EINVAL;
+				}
 				q6asm_map_channels(asm_ch_map,
 					chmixer_pspd->input_channel, false);
 				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
@@ -4726,6 +4751,11 @@
 					chmixer_pspd->out_ch_map[i] =
 						pdata->ch_map[fe_id]->channel_map[i];
 			} else {
+				if (chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+					pr_err("%s: Invalid channel count %d\n",
+						__func__, chmixer_pspd->output_channel);
+					return -EINVAL;
+				}
 				q6asm_map_channels(asm_ch_map,
 					chmixer_pspd->output_channel, false);
 				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index ac23857..5803356 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -16,6 +16,7 @@
 #include <sound/pcm_params.h>
 #include <dsp/apr_audio-v2.h>
 #include <dsp/q6afe-v2.h>
+#include <dsp/sp_params.h>
 #include <dsp/q6core.h>
 #include "msm-dai-q6-v2.h"
 #include <asoc/core.h>
@@ -10538,6 +10539,17 @@
 		clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
 }
 
+/* all ports with same WSA requirement can use this digital mute API */
+static int msm_dai_q6_spk_digital_mute(struct snd_soc_dai *dai,
+				       int mute)
+{
+	int port_id = dai->id;
+
+	if (mute)
+		afe_get_sp_xt_logging_data(port_id);
+
+	return 0;
+}
 
 static struct snd_soc_dai_ops msm_dai_q6_cdc_dma_ops = {
 	.prepare          = msm_dai_q6_cdc_dma_prepare,
@@ -10546,6 +10558,14 @@
 	.set_channel_map = msm_dai_q6_cdc_dma_set_channel_map,
 };
 
+static struct snd_soc_dai_ops msm_dai_q6_cdc_wsa_dma_ops = {
+	.prepare          = msm_dai_q6_cdc_dma_prepare,
+	.hw_params        = msm_dai_q6_cdc_dma_hw_params,
+	.shutdown         = msm_dai_q6_cdc_dma_shutdown,
+	.set_channel_map = msm_dai_q6_cdc_dma_set_channel_map,
+	.digital_mute = msm_dai_q6_spk_digital_mute,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_cdc_dma_dai[] = {
 	{
 		.playback = {
@@ -10568,7 +10588,7 @@
 			.rate_max = 384000,
 		},
 		.name = "WSA_CDC_DMA_RX_0",
-		.ops = &msm_dai_q6_cdc_dma_ops,
+		.ops = &msm_dai_q6_cdc_wsa_dma_ops,
 		.id = AFE_PORT_ID_WSA_CODEC_DMA_RX_0,
 		.probe = msm_dai_q6_dai_cdc_dma_probe,
 		.remove = msm_dai_q6_dai_cdc_dma_remove,
@@ -10620,7 +10640,7 @@
 			.rate_max = 384000,
 		},
 		.name = "WSA_CDC_DMA_RX_1",
-		.ops = &msm_dai_q6_cdc_dma_ops,
+		.ops = &msm_dai_q6_cdc_wsa_dma_ops,
 		.id = AFE_PORT_ID_WSA_CODEC_DMA_RX_1,
 		.probe = msm_dai_q6_dai_cdc_dma_probe,
 		.remove = msm_dai_q6_dai_cdc_dma_remove,
diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c
index 379b5e5..b101b37 100644
--- a/asoc/msm-lsm-client.c
+++ b/asoc/msm-lsm-client.c
@@ -1390,8 +1390,8 @@
 		dev_dbg(rtd->dev, "%s: Starting LSM client session\n",
 			__func__);
 		if (!prtd->lsm_client->started) {
-			ret = q6lsm_start(prtd->lsm_client, true);
-			if (!ret) {
+			rc = q6lsm_start(prtd->lsm_client, true);
+			if (!rc) {
 				prtd->lsm_client->started = true;
 				dev_dbg(rtd->dev, "%s: LSM client session started\n",
 					 __func__);
@@ -1407,19 +1407,19 @@
 			if (prtd->lsm_client->lab_enable) {
 				atomic_set(&prtd->read_abort, 1);
 				if (prtd->lsm_client->lab_started) {
-					ret = q6lsm_stop_lab(prtd->lsm_client);
-					if (ret)
+					rc = q6lsm_stop_lab(prtd->lsm_client);
+					if (rc)
 						dev_err(rtd->dev,
-							"%s: stop lab failed ret %d\n",
-							__func__, ret);
+							"%s: stop lab failed rc %d\n",
+							__func__, rc);
 					prtd->lsm_client->lab_started = false;
 				}
 			}
-			ret = q6lsm_stop(prtd->lsm_client, true);
-			if (!ret)
+			rc = q6lsm_stop(prtd->lsm_client, true);
+			if (!rc)
 				dev_dbg(rtd->dev,
 					"%s: LSM client session stopped %d\n",
-					__func__, ret);
+					__func__, rc);
 			prtd->lsm_client->started = false;
 		}
 		break;
@@ -2593,6 +2593,25 @@
 
 	dev_dbg(rtd->dev, "%s\n", __func__);
 	if (prtd->lsm_client->started) {
+		if (prtd->lsm_client->lab_enable) {
+			atomic_set(&prtd->read_abort, 1);
+			if (prtd->lsm_client->lab_started) {
+				ret = q6lsm_stop_lab(prtd->lsm_client);
+				if (ret)
+					dev_err(rtd->dev,
+						"%s: stop lab failed ret %d\n",
+						__func__, ret);
+				prtd->lsm_client->lab_started = false;
+			}
+			if (prtd->lsm_client->lab_buffer) {
+				ret = msm_lsm_lab_buffer_alloc(prtd,
+						LAB_BUFFER_DEALLOC);
+				if (ret)
+					dev_err(rtd->dev,
+						"%s: lab buffer dealloc failed ret %d\n",
+						__func__, ret);
+			}
+		}
 		ret = q6lsm_stop(prtd->lsm_client, true);
 		if (ret)
 			dev_err(rtd->dev,
diff --git a/asoc/msm-pcm-loopback-v2.c b/asoc/msm-pcm-loopback-v2.c
index a686984..4834e81 100644
--- a/asoc/msm-pcm-loopback-v2.c
+++ b/asoc/msm-pcm-loopback-v2.c
@@ -809,6 +809,11 @@
 	if (chmixer_pspd->enable) {
 		if (session_type == SESSION_TYPE_RX &&
 			!chmixer_pspd->override_in_ch_map) {
+			if (chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+				pr_err("%s: Invalid channel count %d\n",
+					__func__, chmixer_pspd->input_channel);
+				return -EINVAL;
+			}
 			q6asm_map_channels(asm_ch_map,
 				chmixer_pspd->input_channel, false);
 			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
@@ -817,6 +822,11 @@
 			reset_override_in_ch_map = true;
 		} else if (session_type == SESSION_TYPE_TX &&
 			!chmixer_pspd->override_out_ch_map) {
+			if (chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+				pr_err("%s: Invalid channel count %d\n",
+					__func__, chmixer_pspd->output_channel);
+				return -EINVAL;
+			}
 			q6asm_map_channels(asm_ch_map,
 				chmixer_pspd->output_channel, false);
 			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index bea58c9..a087dd8 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -1604,7 +1604,7 @@
 	struct snd_soc_pcm_runtime *rtd = NULL;
 	struct msm_plat_data *pdata = NULL;
 	struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
-	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = NULL;
 	u64 fe_id = 0;
 
 	pr_debug("%s", __func__);
@@ -1624,18 +1624,21 @@
 		/* update chmixer_pspd chmap cached with routing driver as well */
 		rtd = substream->private_data;
 		if (rtd) {
-			fe_id = rtd->dai_link->id;
-			pdata = (struct msm_plat_data *)
-					dev_get_drvdata(component->dev);
-			chmixer_pspd = pdata ?
-				pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
+			component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+			if (component) {
+				fe_id = rtd->dai_link->id;
+				pdata = (struct msm_plat_data *)
+						dev_get_drvdata(component->dev);
+				chmixer_pspd = pdata ?
+					pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
 
-			if (chmixer_pspd && chmixer_pspd->enable) {
-				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
-					chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
-				chmixer_pspd->override_in_ch_map = true;
-				msm_pcm_routing_set_channel_mixer_cfg(fe_id,
-						SESSION_TYPE_RX, chmixer_pspd);
+				if (chmixer_pspd && chmixer_pspd->enable) {
+					for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
+						chmixer_pspd->in_ch_map[i] = prtd->channel_map[i];
+					chmixer_pspd->override_in_ch_map = true;
+					msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+							SESSION_TYPE_RX, chmixer_pspd);
+				}
 			}
 		}
 	}
@@ -1939,6 +1942,11 @@
 					chmixer_pspd->in_ch_map[i] =
 						pdata->ch_map[fe_id]->channel_map[i];
 			} else {
+				if (chmixer_pspd->input_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+					pr_err("%s: Invalid channel count %d\n",
+						__func__, chmixer_pspd->input_channel);
+					return -EINVAL;
+				}
 				q6asm_map_channels(asm_ch_map,
 					chmixer_pspd->input_channel, false);
 				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
@@ -1954,6 +1962,11 @@
 					chmixer_pspd->out_ch_map[i] =
 						pdata->ch_map[fe_id]->channel_map[i];
 			} else {
+				if (chmixer_pspd->output_channel > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+					pr_err("%s: Invalid channel count %d\n",
+						__func__, chmixer_pspd->output_channel);
+					return -EINVAL;
+				}
 				q6asm_map_channels(asm_ch_map,
 					chmixer_pspd->output_channel, false);
 				for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index f913c58..5a75609 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -1114,7 +1114,8 @@
 static struct cal_block_data *msm_routing_find_topology(int path,
 							int app_type,
 							int acdb_id,
-							int cal_index)
+							int cal_index,
+							bool exact)
 {
 	struct list_head *ptr, *next;
 	struct cal_block_data *cal_block = NULL;
@@ -1139,9 +1140,29 @@
 			return cal_block;
 		}
 	}
-	pr_debug("%s: Can't find topology for path %d, app %d, acdb_id %d defaulting to search by path\n",
-		__func__, path, app_type, acdb_id);
-	return msm_routing_find_topology_by_path(path, cal_index);
+	pr_debug("%s: Can't find topology for path %d, app %d, "
+		 "acdb_id %d %s\n",  __func__, path, app_type, acdb_id,
+		 exact ? "fail" : "defaulting to search by path");
+	return exact ? NULL : msm_routing_find_topology_by_path(path,
+								cal_index);
+}
+
+static int msm_routing_find_topology_on_index(int session_type, int app_type,
+					      int acdb_dev_id,  int idx,
+					      bool exact)
+{
+	int topology = -EINVAL;
+	struct cal_block_data *cal_block = NULL;
+
+	mutex_lock(&cal_data[idx]->lock);
+	cal_block = msm_routing_find_topology(session_type, app_type,
+					      acdb_dev_id, idx, exact);
+	if (cal_block != NULL) {
+		topology = ((struct audio_cal_info_adm_top *)
+			    cal_block->cal_info)->topology;
+	}
+	mutex_unlock(&cal_data[idx]->lock);
+	return topology;
 }
 
 /*
@@ -1153,7 +1174,6 @@
 					int be_id)
 {
 	int topology = NULL_COPP_TOPOLOGY;
-	struct cal_block_data *cal_block = NULL;
 	int app_type = 0, acdb_dev_id = 0;
 
 	pr_debug("%s: fedai_id %d, session_type %d, be_id %d\n",
@@ -1166,31 +1186,22 @@
 	acdb_dev_id =
 		fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
 
-	mutex_lock(&cal_data[ADM_TOPOLOGY_CAL_TYPE_IDX]->lock);
-	cal_block = msm_routing_find_topology(session_type, app_type,
-					      acdb_dev_id,
-					      ADM_TOPOLOGY_CAL_TYPE_IDX);
-	if (cal_block != NULL) {
-		topology = ((struct audio_cal_info_adm_top *)
-			cal_block->cal_info)->topology;
-		cal_utils_mark_cal_used(cal_block);
-		mutex_unlock(&cal_data[ADM_TOPOLOGY_CAL_TYPE_IDX]->lock);
-	} else {
-		mutex_unlock(&cal_data[ADM_TOPOLOGY_CAL_TYPE_IDX]->lock);
-
-		pr_debug("%s: Check for LSM topology\n", __func__);
-		mutex_lock(&cal_data[ADM_LSM_TOPOLOGY_CAL_TYPE_IDX]->lock);
-		cal_block = msm_routing_find_topology(session_type, app_type,
-						acdb_dev_id,
-						ADM_LSM_TOPOLOGY_CAL_TYPE_IDX);
-		if (cal_block != NULL) {
-			topology = ((struct audio_cal_info_adm_top *)
-				cal_block->cal_info)->topology;
-			cal_utils_mark_cal_used(cal_block);
-		}
-		mutex_unlock(&cal_data[ADM_LSM_TOPOLOGY_CAL_TYPE_IDX]->lock);
+	pr_debug("%s: Check for exact LSM topology\n", __func__);
+	topology = msm_routing_find_topology_on_index(session_type,
+					       app_type,
+					       acdb_dev_id,
+					       ADM_LSM_TOPOLOGY_CAL_TYPE_IDX,
+					       true /*exact*/);
+	if (topology < 0) {
+		pr_debug("%s: Check for compatible topology\n", __func__);
+		topology = msm_routing_find_topology_on_index(session_type,
+						      app_type,
+						      acdb_dev_id,
+						      ADM_TOPOLOGY_CAL_TYPE_IDX,
+						      false /*exact*/);
+		if (topology < 0)
+			topology = NULL_COPP_TOPOLOGY;
 	}
-
 done:
 	pr_debug("%s: Using topology %d\n", __func__, topology);
 	return topology;
diff --git a/asoc/msm-transcode-loopback-q6-v2.c b/asoc/msm-transcode-loopback-q6-v2.c
index 9980874..67bdc75 100644
--- a/asoc/msm-transcode-loopback-q6-v2.c
+++ b/asoc/msm-transcode-loopback-q6-v2.c
@@ -435,7 +435,15 @@
 	mutex_lock(&trans->lock);
 
 	rtd = snd_pcm_substream_chip(cstream);
+	if (!rtd) {
+		pr_err("%s: rtd is NULL\n", __func__);
+		return -EINVAL;
+	}
 	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
 	pdata = snd_soc_component_get_drvdata(component);
 
 	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
@@ -606,7 +614,15 @@
 	}
 
 	rtd = snd_pcm_substream_chip(cstream);
+	if (!rtd) {
+		pr_err("%s: rtd is NULL\n", __func__);
+		return -EINVAL;
+	}
 	component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
 	pdata = snd_soc_component_get_drvdata(component);
 
 	prtd = cstream->runtime->private_data;
diff --git a/asoc/sm6150.c b/asoc/sm6150.c
index 84e05c8..11bb611 100644
--- a/asoc/sm6150.c
+++ b/asoc/sm6150.c
@@ -4760,28 +4760,6 @@
 	afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
 }
 
-static int msm_config_hph_en0_gpio(struct snd_soc_component *component, bool high)
-{
-	struct snd_soc_card *card = component->card;
-	struct msm_asoc_mach_data *pdata;
-	int val;
-
-	if (!card)
-		return 0;
-
-	pdata = snd_soc_card_get_drvdata(card);
-	if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
-		return 0;
-
-	val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
-	if ((!!val) == high)
-		return 0;
-
-	gpio_direction_output(pdata->hph_en0_gpio, (int)high);
-
-	return 1;
-}
-
 static int msm_audrx_tavil_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret = 0;
@@ -5103,7 +5081,6 @@
 		pdata->codec_root = entry;
 	}
 	tasha_codec_info_create_codec_entry(pdata->codec_root, component);
-	tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, component);
 
 	codec_reg_done = true;
 	return 0;
diff --git a/dsp/Kbuild b/dsp/Kbuild
index 195502a..daf0b30 100644
--- a/dsp/Kbuild
+++ b/dsp/Kbuild
@@ -91,11 +91,16 @@
 	Q6_OBJS += msm_audio_ion.o
 	Q6_OBJS += avtimer.o
 	Q6_OBJS += q6_init.o
-
 endif
+
+ifdef CONFIG_XT_LOGGING
+	Q6_OBJS += sp_params.o
+endif
+
 ifdef CONFIG_WCD9XXX_CODEC_CORE
 	Q6_OBJS += audio_slimslave.o
 endif
+
 ifdef CONFIG_DTS_SRS_TM
 	Q6_OBJS += msm-dts-srs-tm-config.o
 endif
diff --git a/dsp/audio_cal_utils.c b/dsp/audio_cal_utils.c
index 19c71fc..7e243e8 100644
--- a/dsp/audio_cal_utils.c
+++ b/dsp/audio_cal_utils.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
  */
 #include <linux/slab.h>
 #include <linux/fs.h>
@@ -16,6 +16,7 @@
 size_t get_cal_info_size(int32_t cal_type)
 {
 	size_t size = 0;
+	size_t size1 = 0, size2 = 0;
 
 	switch (cal_type) {
 	case CVP_VOC_RX_TOPOLOGY_CAL_TYPE:
@@ -93,8 +94,11 @@
 		 * Since get and set parameter structures are different in size
 		 * use the maximum size of get and set parameter structure
 		 */
-		size = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg),
+		size1 = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg),
 			   sizeof(struct audio_cal_info_sp_th_vi_param));
+		size2 = max(sizeof(struct audio_cal_info_sp_th_vi_v_vali_cfg),
+			   sizeof(struct audio_cal_info_sp_th_vi_v_vali_param));
+		size = max(size1, size2);
 		break;
 	case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE:
 		/*
diff --git a/dsp/q6_init.c b/dsp/q6_init.c
index 1078c57..fb18741 100644
--- a/dsp/q6_init.c
+++ b/dsp/q6_init.c
@@ -14,6 +14,7 @@
 	rtac_init();
 	adm_init();
 	afe_init();
+	spk_params_init();
 	q6asm_init();
 	q6lsm_init();
 	voice_init();
@@ -37,6 +38,7 @@
 	q6lsm_exit();
 	q6asm_exit();
 	afe_exit();
+	spk_params_exit();
 	adm_exit();
 	rtac_exit();
 	audio_cal_exit();
diff --git a/dsp/q6_init.h b/dsp/q6_init.h
index e7ad19b..4df2e03 100644
--- a/dsp/q6_init.h
+++ b/dsp/q6_init.h
@@ -30,6 +30,18 @@
 	return;
 }
 #endif
+#ifdef CONFIG_XT_LOGGING
+int spk_params_init(void);
+void spk_params_exit(void);
+#else
+static inline int spk_params_init(void)
+{
+	return 0;
+}
+static inline void spk_params_exit(void)
+{
+}
+#endif
 
 void avtimer_exit(void);
 void msm_audio_ion_exit(void);
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 62d4851..fd66571 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -59,6 +59,16 @@
 	[FBSP_FAILED] = "failed"
 };
 
+enum v_vali_state {
+	V_VALI_FAILED,
+	V_VALI_SUCCESS,
+	V_VALI_INCORRECT_OP_MODE,
+	V_VALI_INACTIVE,
+	V_VALI_WARMUP,
+	V_VALI_IN_PROGRESS,
+	MAX_V_VALI_STATE
+};
+
 enum {
 	USE_CALIBRATED_R0TO,
 	USE_SAFE_R0TO
@@ -72,7 +82,8 @@
 enum {
 	Q6AFE_MSM_SPKR_PROCESSING = 0,
 	Q6AFE_MSM_SPKR_CALIBRATION,
-	Q6AFE_MSM_SPKR_FTM_MODE
+	Q6AFE_MSM_SPKR_FTM_MODE,
+	Q6AFE_MSM_SPKR_V_VALI_MODE
 };
 
 enum {
@@ -124,9 +135,12 @@
 	struct audio_cal_info_spk_prot_cfg	prot_cfg;
 	struct afe_spkr_prot_calib_get_resp	calib_data;
 	struct audio_cal_info_sp_th_vi_ftm_cfg	th_ftm_cfg;
+	struct audio_cal_info_sp_th_vi_v_vali_cfg	v_vali_cfg;
 	struct audio_cal_info_sp_ex_vi_ftm_cfg	ex_ftm_cfg;
 	struct afe_sp_th_vi_get_param_resp	th_vi_resp;
+	struct afe_sp_th_vi_v_vali_get_param_resp	th_vi_v_vali_resp;
 	struct afe_sp_ex_vi_get_param_resp	ex_vi_resp;
+	struct afe_sp_rx_tmax_xmax_logging_resp	xt_logging_resp;
 	struct afe_av_dev_drift_get_param_resp	av_dev_drift_resp;
 	struct afe_doa_tracking_mon_get_param_resp	doa_tracking_mon_resp;
 	int vi_tx_port;
@@ -144,6 +158,9 @@
 	struct vad_config vad_cfg[AFE_MAX_PORTS];
 	struct work_struct afe_dc_work;
 	struct notifier_block event_notifier;
+	/* FTM spk params */
+	uint32_t initial_cal;
+	uint32_t v_vali_flag;
 };
 
 static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -165,6 +182,51 @@
 				struct audio_cal_hw_delay_entry *entry);
 static int remap_cal_data(struct cal_block_data *cal_block, int cal_index);
 
+int afe_get_spk_initial_cal(void)
+{
+	return this_afe.initial_cal;
+}
+
+void afe_get_spk_r0(int *spk_r0)
+{
+	uint16_t i = 0;
+
+	for (; i < SP_V2_NUM_MAX_SPKRS; i++)
+		spk_r0[i] = this_afe.prot_cfg.r0[i];
+}
+
+void afe_get_spk_t0(int *spk_t0)
+{
+	uint16_t i = 0;
+
+	for (; i < SP_V2_NUM_MAX_SPKRS; i++)
+		spk_t0[i] = this_afe.prot_cfg.t0[i];
+}
+
+int afe_get_spk_v_vali_flag(void)
+{
+	return this_afe.v_vali_flag;
+}
+
+void afe_get_spk_v_vali_sts(int *spk_v_vali_sts)
+{
+	uint16_t i = 0;
+
+	for (; i < SP_V2_NUM_MAX_SPKRS; i++)
+		spk_v_vali_sts[i] =
+			this_afe.th_vi_v_vali_resp.param.status[i];
+}
+
+void afe_set_spk_initial_cal(int initial_cal)
+{
+	this_afe.initial_cal = initial_cal;
+}
+
+void afe_set_spk_v_vali_flag(int v_vali_flag)
+{
+	this_afe.v_vali_flag = v_vali_flag;
+}
+
 int afe_get_topology(int port_id)
 {
 	int topology;
@@ -364,10 +426,19 @@
 		expected_size += sizeof(struct afe_sp_th_vi_ftm_params);
 		data_dest = (u32 *) &this_afe.th_vi_resp;
 		break;
+	case AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_PARAMS:
+		expected_size += sizeof(struct afe_sp_th_vi_v_vali_params);
+		data_dest = (u32 *) &this_afe.th_vi_v_vali_resp;
+		break;
 	case AFE_PARAM_ID_SP_V2_EX_VI_FTM_PARAMS:
 		expected_size += sizeof(struct afe_sp_ex_vi_ftm_params);
 		data_dest = (u32 *) &this_afe.ex_vi_resp;
 		break;
+	case AFE_PARAM_ID_SP_RX_TMAX_XMAX_LOGGING:
+		expected_size += sizeof(
+				struct afe_sp_rx_tmax_xmax_logging_param);
+		data_dest = (u32 *) &this_afe.xt_logging_resp;
+		break;
 	default:
 		pr_err("%s: Unrecognized param ID %d\n", __func__,
 		       param_hdr.param_id);
@@ -1606,10 +1677,12 @@
 		break;
 	/*
 	 * AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2 is same as
-	 * AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG
+	 * AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG. V_VALI_CFG uses
+	 * same module TH_VI.
 	 */
 	case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG_V2:
 	case AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG:
+	case AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_CFG:
 		param_info.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
 		break;
 	case AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG:
@@ -1737,6 +1810,10 @@
 		if (this_afe.th_ftm_cfg.mode == MSM_SPKR_PROT_IN_FTM_MODE)
 			afe_spk_config.vi_proc_cfg.operation_mode =
 					    Q6AFE_MSM_SPKR_FTM_MODE;
+		else if (this_afe.v_vali_cfg.mode ==
+					MSM_SPKR_PROT_IN_V_VALI_MODE)
+			afe_spk_config.vi_proc_cfg.operation_mode =
+					    Q6AFE_MSM_SPKR_V_VALI_MODE;
 		afe_spk_config.vi_proc_cfg.minor_version = 1;
 		afe_spk_config.vi_proc_cfg.r0_cali_q24[SP_V2_SPKR_1] =
 			(uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_1];
@@ -1789,6 +1866,25 @@
 					 &afe_spk_config))
 			pr_err("%s: th vi ftm cfg failed\n", __func__);
 		this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
+	} else if ((this_afe.v_vali_cfg.mode ==
+			MSM_SPKR_PROT_IN_V_VALI_MODE) &&
+		   (this_afe.vi_tx_port == port_id)) {
+		afe_spk_config.th_vi_v_vali_cfg.minor_version = 1;
+		afe_spk_config.th_vi_v_vali_cfg.wait_time_ms[SP_V2_SPKR_1] =
+			this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_1];
+		afe_spk_config.th_vi_v_vali_cfg.wait_time_ms[SP_V2_SPKR_2] =
+			this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_2];
+		afe_spk_config.th_vi_v_vali_cfg.vali_time_ms[SP_V2_SPKR_1] =
+			this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_1];
+		afe_spk_config.th_vi_v_vali_cfg.vali_time_ms[SP_V2_SPKR_2] =
+			this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_2];
+
+		if (afe_spk_prot_prepare(port_id, 0,
+					 AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_CFG,
+					 &afe_spk_config))
+			pr_err("%s: th vi v-vali cfg failed\n", __func__);
+
+		this_afe.v_vali_cfg.mode = MSM_SPKR_PROT_DISABLED;
 	}
 	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 
@@ -7453,6 +7549,46 @@
 }
 EXPORT_SYMBOL(q6afe_check_osr_clk_freq);
 
+static int afe_get_sp_th_vi_v_vali_data(
+		struct afe_sp_th_vi_v_vali_get_param *th_vi_v_vali)
+{
+	struct param_hdr_v3 param_hdr;
+	int port = SLIMBUS_4_TX;
+	int ret = -EINVAL;
+
+	if (!th_vi_v_vali) {
+		pr_err("%s: Invalid params\n", __func__);
+		goto done;
+	}
+	if (this_afe.vi_tx_port != -1)
+		port = this_afe.vi_tx_port;
+
+	memset(&param_hdr, 0, sizeof(param_hdr));
+
+	param_hdr.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
+	param_hdr.instance_id = INSTANCE_ID_0;
+	param_hdr.param_id = AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_PARAMS;
+	param_hdr.param_size = sizeof(struct afe_sp_th_vi_v_vali_params);
+
+	ret = q6afe_get_params(port, NULL, &param_hdr);
+	if (ret) {
+		pr_err("%s: Failed to get TH VI V-Vali data\n", __func__);
+		goto done;
+	}
+
+	th_vi_v_vali->pdata = param_hdr;
+	memcpy(&th_vi_v_vali->param, &this_afe.th_vi_v_vali_resp.param,
+		sizeof(this_afe.th_vi_v_vali_resp.param));
+	pr_debug("%s:  Vrms %d %d status %d %d\n", __func__,
+		 th_vi_v_vali->param.vrms_q24[SP_V2_SPKR_1],
+		 th_vi_v_vali->param.vrms_q24[SP_V2_SPKR_2],
+		 th_vi_v_vali->param.status[SP_V2_SPKR_1],
+		 th_vi_v_vali->param.status[SP_V2_SPKR_2]);
+	ret = 0;
+done:
+	return ret;
+}
+
 int afe_get_sp_th_vi_ftm_data(struct afe_sp_th_vi_get_param *th_vi)
 {
 	struct param_hdr_v3 param_hdr;
@@ -7539,6 +7675,57 @@
 }
 
 /**
+ * afe_get_sp_rx_tmax_xmax_logging_data -
+ *       command to get excursion logging data from DSP
+ *
+ * @xt_logging: excursion logging params
+ * @port: AFE port ID
+ *
+ * Returns 0 on success or error on failure
+ */
+int afe_get_sp_rx_tmax_xmax_logging_data(
+			struct afe_sp_rx_tmax_xmax_logging_param *xt_logging,
+			u16 port_id)
+{
+	struct param_hdr_v3 param_hdr;
+	int ret = -EINVAL;
+
+	if (!xt_logging) {
+		pr_err("%s: Invalid params\n", __func__);
+		goto done;
+	}
+
+	memset(&param_hdr, 0, sizeof(param_hdr));
+
+	param_hdr.module_id = AFE_MODULE_FB_SPKR_PROT_V2_RX;
+	param_hdr.instance_id = INSTANCE_ID_0;
+	param_hdr.param_id = AFE_PARAM_ID_SP_RX_TMAX_XMAX_LOGGING;
+	param_hdr.param_size = sizeof(struct afe_sp_rx_tmax_xmax_logging_param);
+
+	ret = q6afe_get_params(port_id, NULL, &param_hdr);
+	if (ret < 0) {
+		pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
+		       __func__, port_id, param_hdr.param_id, ret);
+		goto done;
+	}
+
+	memcpy(xt_logging, &this_afe.xt_logging_resp.param,
+		sizeof(this_afe.xt_logging_resp.param));
+	pr_debug("%s: max_excursion %d %d count_exceeded_excursion %d %d max_temperature %d %d count_exceeded_temperature %d %d\n",
+		 __func__, xt_logging->max_excursion[SP_V2_SPKR_1],
+		 xt_logging->max_excursion[SP_V2_SPKR_2],
+		 xt_logging->count_exceeded_excursion[SP_V2_SPKR_1],
+		 xt_logging->count_exceeded_excursion[SP_V2_SPKR_2],
+		 xt_logging->max_temperature[SP_V2_SPKR_1],
+		 xt_logging->max_temperature[SP_V2_SPKR_2],
+		 xt_logging->count_exceeded_temperature[SP_V2_SPKR_1],
+		 xt_logging->count_exceeded_temperature[SP_V2_SPKR_2]);
+done:
+	return ret;
+}
+EXPORT_SYMBOL(afe_get_sp_rx_tmax_xmax_logging_data);
+
+/**
  * afe_get_av_dev_drift -
  *       command to retrieve AV drift
  *
@@ -7654,9 +7841,9 @@
 	memcpy(&calib_resp->res_cfg, &this_afe.calib_data.res_cfg,
 		sizeof(this_afe.calib_data.res_cfg));
 	pr_info("%s: state %s resistance %d %d\n", __func__,
-			 fbsp_state[calib_resp->res_cfg.th_vi_ca_state],
-			 calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_1],
-			 calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_2]);
+		fbsp_state[calib_resp->res_cfg.th_vi_ca_state],
+		calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_1],
+		calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_2]);
 	ret = 0;
 fail_cmd:
 	return ret;
@@ -7952,21 +8139,57 @@
 	return ret;
 }
 
+static int afe_set_cal_sp_th_vi_v_vali_cfg(int32_t cal_type, size_t data_size,
+					void *data)
+{
+	int ret = 0;
+	struct audio_cal_type_sp_th_vi_v_vali_cfg *cal_data = data;
+
+	if (cal_data == NULL || data_size != sizeof(*cal_data))
+		goto done;
+
+	memcpy(&this_afe.v_vali_cfg, &cal_data->cal_info,
+		sizeof(this_afe.v_vali_cfg));
+done:
+	return ret;
+}
+
 static int afe_set_cal_sp_th_vi_ftm_cfg(int32_t cal_type, size_t data_size,
 					void *data)
 {
 	int ret = 0;
 	struct audio_cal_type_sp_th_vi_ftm_cfg *cal_data = data;
 
-	if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
-	    cal_data == NULL ||
-	    data_size != sizeof(*cal_data))
+	if (cal_data == NULL || data_size != sizeof(*cal_data))
 		goto done;
 
-	pr_debug("%s: cal_type = %d\n", __func__, cal_type);
-	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 	memcpy(&this_afe.th_ftm_cfg, &cal_data->cal_info,
 		sizeof(this_afe.th_ftm_cfg));
+done:
+	return ret;
+}
+
+static int afe_set_cal_sp_th_vi_cfg(int32_t cal_type, size_t data_size,
+				    void *data)
+{
+	int ret = 0;
+	struct audio_cal_type_sp_th_vi_ftm_cfg *cal_data = data;
+	uint32_t mode;
+
+	if (cal_data == NULL ||
+	    this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
+		goto done;
+
+	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+	mode = cal_data->cal_info.mode;
+	pr_debug("%s: cal_type = %d, mode = %d\n", __func__, cal_type, mode);
+	if (mode == MSM_SPKR_PROT_IN_FTM_MODE) {
+		ret = afe_set_cal_sp_th_vi_ftm_cfg(cal_type,
+						data_size, data);
+	} else if (mode == MSM_SPKR_PROT_IN_V_VALI_MODE) {
+		ret = afe_set_cal_sp_th_vi_v_vali_cfg(cal_type,
+						data_size, data);
+	}
 	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 done:
 	return ret;
@@ -8017,6 +8240,42 @@
 	return ret;
 }
 
+static int afe_get_cal_sp_th_vi_v_vali_param(int32_t cal_type, size_t data_size,
+					  void *data)
+{
+	int i, ret = 0;
+	struct audio_cal_type_sp_th_vi_v_vali_param *cal_data = data;
+	struct afe_sp_th_vi_v_vali_get_param th_vi_v_vali;
+
+	if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
+	    cal_data == NULL ||
+	    data_size != sizeof(*cal_data))
+		goto done;
+
+	for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+		cal_data->cal_info.status[i] = -EINVAL;
+		cal_data->cal_info.vrms_q24[i] = -1;
+	}
+	if (!afe_get_sp_th_vi_v_vali_data(&th_vi_v_vali)) {
+		for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
+			pr_debug("%s: v-vali param status = %d\n",
+				  __func__, th_vi_v_vali.param.status[i]);
+			if (th_vi_v_vali.param.status[i] ==
+					V_VALI_IN_PROGRESS) {
+				cal_data->cal_info.status[i] = -EAGAIN;
+			} else if (th_vi_v_vali.param.status[i] ==
+					V_VALI_SUCCESS) {
+				cal_data->cal_info.status[i] = V_VALI_SUCCESS;
+				cal_data->cal_info.vrms_q24[i] =
+					th_vi_v_vali.param.vrms_q24[i];
+			}
+		}
+	}
+	this_afe.v_vali_flag = 0;
+done:
+	return ret;
+}
+
 static int afe_get_cal_sp_th_vi_ftm_param(int32_t cal_type, size_t data_size,
 					  void *data)
 {
@@ -8024,13 +8283,11 @@
 	struct audio_cal_type_sp_th_vi_param *cal_data = data;
 	struct afe_sp_th_vi_get_param th_vi;
 
-	pr_debug("%s: cal_type = %d\n", __func__, cal_type);
 	if (this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL ||
 	    cal_data == NULL ||
 	    data_size != sizeof(*cal_data))
 		goto done;
 
-	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 	for (i = 0; i < SP_V2_NUM_MAX_SPKRS; i++) {
 		cal_data->cal_info.status[i] = -EINVAL;
 		cal_data->cal_info.r_dc_q24[i] = -1;
@@ -8051,11 +8308,34 @@
 			}
 		}
 	}
-	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
 done:
 	return ret;
 }
 
+static int afe_get_cal_sp_th_vi_param(int32_t cal_type, size_t data_size,
+				      void *data)
+{
+	struct audio_cal_type_sp_th_vi_param *cal_data = data;
+	uint32_t mode;
+	int ret = 0;
+
+	if (cal_data == NULL ||
+	    this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL] == NULL)
+		return 0;
+
+	mutex_lock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+	mode = cal_data->cal_info.mode;
+	pr_debug("%s: cal_type = %d,mode = %d\n", __func__, cal_type, mode);
+	if (mode == MSM_SPKR_PROT_IN_V_VALI_MODE)
+		ret = afe_get_cal_sp_th_vi_v_vali_param(cal_type,
+						data_size, data);
+	else
+		ret = afe_get_cal_sp_th_vi_ftm_param(cal_type,
+						data_size, data);
+	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_TH_VI_CAL]->lock);
+	return ret;
+}
+
 static int afe_get_cal_sp_ex_vi_ftm_param(int32_t cal_type, size_t data_size,
 					  void *data)
 {
@@ -8154,6 +8434,7 @@
 		cal_data->cal_info.r0[SP_V2_SPKR_1] = -1;
 		cal_data->cal_info.r0[SP_V2_SPKR_2] = -1;
 	}
+	this_afe.initial_cal = 0;
 	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_CAL]->lock);
 	__pm_relax(&wl.ws);
 done:
@@ -8313,8 +8594,8 @@
 		cal_utils_match_buf_num} },
 
 		{{AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE,
-		{NULL, NULL, NULL, afe_set_cal_sp_th_vi_ftm_cfg,
-		afe_get_cal_sp_th_vi_ftm_param, NULL} },
+		{NULL, NULL, NULL, afe_set_cal_sp_th_vi_cfg,
+		afe_get_cal_sp_th_vi_param, NULL} },
 		{NULL, NULL, cal_utils_match_buf_num} },
 
 		{{AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE,
@@ -8546,6 +8827,12 @@
 		return -EINVAL;
 	}
 
+	ret = afe_q6_interface_prepare();
+	if(ret) {
+		pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+		return ret;
+	}
+
 	mutex_lock(&this_afe.afe_cmd_lock);
 
 	memset(cmd_ptr, 0, sizeof(hw_vote_cfg));
@@ -8621,6 +8908,12 @@
 						&hw_vote_cfg;
 	int ret = 0;
 
+	ret = afe_q6_interface_prepare();
+	if(ret) {
+		pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+		return ret;
+	}
+
 	mutex_lock(&this_afe.afe_cmd_lock);
 
 	memset(cmd_ptr, 0, sizeof(hw_vote_cfg));
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 934fc58..6681dcb 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -1950,9 +1950,10 @@
 		data->dest_port);
 	if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
 	    (data->opcode != ASM_DATA_EVENT_EOS) &&
+	    (data->opcode != ASM_SESSION_EVENTX_OVERFLOW) &&
 	    (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
-		if (payload == NULL) {
-			pr_err("%s: payload is null\n", __func__);
+		if (payload == NULL || (data->payload_size < (2 * sizeof(uint32_t)))) {
+			pr_err("%s: payload is null or invalid size[%d]\n", __func__, data->payload_size);
 			spin_unlock_irqrestore(
 				&(session[session_id].session_lock), flags);
 			return -EINVAL;
@@ -2165,6 +2166,16 @@
 			}
 			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
 			buf_index = asm_token._token.buf_index;
+			if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
+				pr_debug("%s: Invalid buffer index %u\n",
+					__func__, buf_index);
+				spin_unlock_irqrestore(&port->dsp_lock,
+								dsp_flags);
+				spin_unlock_irqrestore(
+					&(session[session_id].session_lock),
+					flags);
+				return -EINVAL;
+			}
 			if ( data->payload_size >= 2 * sizeof(uint32_t) &&
 				(lower_32_bits(port->buf[buf_index].phys) !=
 				payload[0] || 
@@ -2267,6 +2278,16 @@
 			}
 			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
 			buf_index = asm_token._token.buf_index;
+			if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
+				pr_debug("%s: Invalid buffer index %u\n",
+					__func__, buf_index);
+				spin_unlock_irqrestore(&port->dsp_lock,
+								dsp_flags);
+				spin_unlock_irqrestore(
+					&(session[session_id].session_lock),
+					flags);
+				return -EINVAL;
+			}
 			port->buf[buf_index].used = 0;
 			if (lower_32_bits(port->buf[buf_index].phys) !=
 			payload[READDONE_IDX_BUFADD_LSW] ||
@@ -4265,6 +4286,12 @@
 		return -EINVAL;
 	}
 
+	if (config->channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__,
+			config->channels);
+		return -EINVAL;
+	}
+
 	bufsz = config->bufsz;
 	bufcnt = config->bufcnt;
 	num_watermarks = 0;
@@ -4664,6 +4691,11 @@
 
 	custom_size = enc_generic->reserved[1];
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d] size[%d] res[2]=[%d] res[3]=[%d]\n",
 		 __func__, ac->session, custom_size, enc_generic->reserved[2],
 		 enc_generic->reserved[3]);
@@ -4882,6 +4914,12 @@
 	u8 *channel_mapping;
 	int rc = 0;
 
+	if (num_channels > MAX_CHAN_MAP_CHANNELS) {
+		pr_err("%s: Invalid channel count %d\n", __func__,
+			num_channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: Session %d, num_channels = %d\n",
 			 __func__, ac->session, num_channels);
 	q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
@@ -4964,6 +5002,12 @@
 		goto fail_cmd;
 	}
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -5066,6 +5110,12 @@
 		goto fail_cmd;
 	}
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -5166,6 +5216,12 @@
 		goto fail_cmd;
 	}
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -5263,6 +5319,11 @@
 		return -EINVAL;
 	}
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
 			 ac->session, rate, channels);
 
@@ -5478,9 +5539,13 @@
 	struct asm_multi_channel_pcm_enc_cfg_v2  enc_cfg;
 	u8 *channel_mapping;
 	u32 frames_per_buf = 0;
-
 	int rc = 0;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
 			 ac->session, rate, channels);
 
@@ -6098,6 +6163,11 @@
 	u8 *channel_mapping;
 	int rc = 0;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
 		channels);
 
@@ -6181,6 +6251,11 @@
 	u8 *channel_mapping;
 	int rc;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -6265,6 +6340,11 @@
 	u8 *channel_mapping;
 	int rc;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -6352,6 +6432,11 @@
 	u8 *channel_mapping;
 	int rc;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -6604,6 +6689,11 @@
 	u8 *channel_mapping;
 	int rc = 0;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
 		channels);
 
@@ -6672,6 +6762,11 @@
 	u8 *channel_mapping;
 	int rc;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -6744,6 +6839,11 @@
 	u8 *channel_mapping;
 	int rc;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -6818,6 +6918,11 @@
 	u8 *channel_mapping;
 	int rc;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
 		 ac->session, rate, channels,
 		 bits_per_sample, sample_word_size);
@@ -7010,6 +7115,11 @@
 	u8 *channel_mapping;
 	int rc = 0;
 
+	if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
+		pr_err("%s: Invalid channel count %d\n", __func__, channels);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
 		 __func__, ac->session, rate,
 		 channels, bits_per_sample);
@@ -9644,16 +9754,17 @@
 		 ac->session, mtmx_params.hdr.opcode);
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
 	if (rc < 0) {
-		pr_err("%s: Commmand 0x%x failed %d\n", __func__,
-		       mtmx_params.hdr.opcode, rc);
-		goto fail_cmd;
+		dev_err_ratelimited(ac->dev, "%s: Get Session Time failed %d\n",
+				    __func__, rc);
+		return rc;
 	}
+
 	rc = wait_event_timeout(ac->time_wait,
 			(atomic_read(&ac->time_flag) == 0),
 			msecs_to_jiffies(TIMEOUT_MS));
 	if (!rc) {
 		pr_err("%s: timeout in getting session time from DSP\n",
-				__func__);
+		       __func__);
 		goto fail_cmd;
 	}
 
diff --git a/dsp/q6voice.c b/dsp/q6voice.c
index bb2bbdf..e36e18b 100644
--- a/dsp/q6voice.c
+++ b/dsp/q6voice.c
@@ -7332,7 +7332,7 @@
 
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
 {
-	uint32_t *ptr = NULL;
+	uint32_t *ptr = NULL, min_payload_size = 0;
 	struct common_data *c = NULL;
 	struct voice_data *v = NULL;
 	struct vss_evt_voice_activity *voice_act_update = NULL;
@@ -7400,7 +7400,7 @@
 	}
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
-		if (data->payload_size) {
+		if (data->payload_size >= sizeof(ptr[0]) * 2) {
 			ptr = data->payload;
 
 			pr_debug("%x %x\n", ptr[0], ptr[1]);
@@ -7470,7 +7470,13 @@
 	} else if (data->opcode == VSS_IMEMORY_RSP_MAP) {
 		pr_debug("%s, Revd VSS_IMEMORY_RSP_MAP response\n", __func__);
 
-		if (data->payload_size && data->token == VOIP_MEM_MAP_TOKEN) {
+		if (data->payload_size < sizeof(ptr[0])) {
+			pr_err("%s: payload has invalid size[%d]\n", __func__,
+			       data->payload_size);
+			return -EINVAL;
+		}
+
+		if (data->token == VOIP_MEM_MAP_TOKEN) {
 			ptr = data->payload;
 			if (ptr[0]) {
 				v->shmem_info.mem_handle = ptr[0];
@@ -7537,10 +7543,13 @@
 		pr_debug("%s: Received VSS_IVERSION_RSP_GET\n", __func__);
 
 		if (data->payload_size) {
+			min_payload_size = min_t(u32, (int)data->payload_size,
+					       CVD_VERSION_STRING_MAX_SIZE);
 			version_rsp =
 				(struct vss_iversion_rsp_get_t *)data->payload;
 			memcpy(common.cvd_version, version_rsp->version,
-			       CVD_VERSION_STRING_MAX_SIZE);
+			       min_payload_size);
+			common.cvd_version[min_payload_size - 1] = '\0';
 			pr_debug("%s: CVD Version = %s\n",
 				 __func__, common.cvd_version);
 
@@ -7740,6 +7749,11 @@
 
 		cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data;
 		if (cvs_voc_pkt != NULL &&  common.mvs_info.ul_cb != NULL) {
+			if (v->shmem_info.sh_buf.buf[1].size <
+			    ((3 * sizeof(uint32_t)) + cvs_voc_pkt[2])) {
+				pr_err("%s: invalid voc pkt size\n", __func__);
+				return -EINVAL;
+			}
 			/* cvs_voc_pkt[0] contains tx timestamp */
 			common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3],
 					      cvs_voc_pkt[2],
@@ -7908,7 +7922,7 @@
 	}
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
-		if (data->payload_size) {
+		if (data->payload_size >= (2 * sizeof(uint32_t))) {
 			ptr = data->payload;
 
 			pr_debug("%x %x\n", ptr[0], ptr[1]);
diff --git a/dsp/sp_params.c b/dsp/sp_params.c
new file mode 100644
index 0000000..ed6d2eb
--- /dev/null
+++ b/dsp/sp_params.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <dsp/q6audio-v2.h>
+#include <dsp/q6afe-v2.h>
+#include <linux/msm_audio_calibration.h>
+#include <dsp/sp_params.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+/* export or show spk params at /sys/class/spk_params/cal_data */
+#define SPK_PARAMS  "spk_params"
+#define CLASS_NAME "cal_data"
+#define BUF_SZ 20
+#define Q27 (1<<27)
+#define Q22 (1<<22)
+
+struct afe_spk_ctl {
+	struct class *p_class;
+	struct device *p_dev;
+	struct afe_sp_rx_tmax_xmax_logging_param xt_logging;
+	int32_t max_temperature_rd[SP_V2_NUM_MAX_SPKR];
+};
+struct afe_spk_ctl this_afe_spk;
+
+static ssize_t sp_count_exceeded_temperature_l_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	ssize_t ret = 0;
+
+	ret = snprintf(buf, BUF_SZ, "%d\n",
+	this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_1]);
+	this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_1] = 0;
+	return ret;
+}
+static DEVICE_ATTR(count_exceeded_temperature, 0644,
+		sp_count_exceeded_temperature_l_show, NULL);
+
+static ssize_t sp_count_exceeded_temperature_r_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	ssize_t ret = 0;
+
+	ret = snprintf(buf, BUF_SZ, "%d\n",
+	this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_2]);
+	this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_2] = 0;
+	return ret;
+}
+static DEVICE_ATTR(count_exceeded_temperature_r, 0644,
+		sp_count_exceeded_temperature_r_show, NULL);
+
+static ssize_t sp_count_exceeded_excursion_l_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	ssize_t ret = 0;
+
+	ret = snprintf(buf, BUF_SZ, "%d\n",
+		this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_1]);
+	this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_1] = 0;
+	return ret;
+}
+static DEVICE_ATTR(count_exceeded_excursion, 0644,
+		sp_count_exceeded_excursion_l_show, NULL);
+
+static ssize_t sp_count_exceeded_excursion_r_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	ssize_t ret = 0;
+
+	ret = snprintf(buf, BUF_SZ, "%d\n",
+		this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_2]);
+	this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_2] = 0;
+	return ret;
+}
+static DEVICE_ATTR(count_exceeded_excursion_r, 0644,
+		sp_count_exceeded_excursion_r_show, NULL);
+
+static ssize_t sp_max_excursion_l_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	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;
+	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;
+}
+static DEVICE_ATTR(max_excursion, 0644, sp_max_excursion_l_show, NULL);
+
+static ssize_t sp_max_excursion_r_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	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;
+	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;
+}
+static DEVICE_ATTR(max_excursion_r, 0644, sp_max_excursion_r_show, NULL);
+
+static ssize_t sp_max_temperature_l_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	ssize_t ret = 0;
+
+	ret = snprintf(buf, BUF_SZ, "%d\n",
+		this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_1]/Q22);
+	this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_1] = 0;
+	return ret;
+}
+static DEVICE_ATTR(max_temperature, 0644, sp_max_temperature_l_show, NULL);
+
+static ssize_t sp_max_temperature_r_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	ssize_t ret = 0;
+
+	ret = snprintf(buf, BUF_SZ, "%d\n",
+		this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_2]/Q22);
+	this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_2] = 0;
+	return ret;
+}
+static DEVICE_ATTR(max_temperature_r, 0644, sp_max_temperature_r_show, NULL);
+
+static ssize_t sp_max_temperature_rd_l_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return snprintf(buf, BUF_SZ, "%d\n",
+			this_afe_spk.max_temperature_rd[SP_V2_SPKR_1]/Q22);
+}
+static DEVICE_ATTR(max_temperature_rd, 0644,
+		sp_max_temperature_rd_l_show, NULL);
+
+static ssize_t sp_max_temperature_rd_r_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return snprintf(buf, BUF_SZ, "%d\n",
+			this_afe_spk.max_temperature_rd[SP_V2_SPKR_2]/Q22);
+}
+static DEVICE_ATTR(max_temperature_rd_r, 0644,
+		sp_max_temperature_rd_r_show, NULL);
+
+static ssize_t q6afe_initial_cal_show(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return snprintf(buf, BUF_SZ, "%d\n", afe_get_spk_initial_cal());
+}
+
+static ssize_t q6afe_initial_cal_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	int initial_cal = 0;
+
+	if (!kstrtou32(buf, 0, &initial_cal)) {
+		initial_cal = initial_cal > 0 ? 1 : 0;
+		if (initial_cal == afe_get_spk_initial_cal())
+			dev_dbg(dev, "%s: same value already present\n",
+				__func__);
+		else
+			afe_set_spk_initial_cal(initial_cal);
+	}
+	return size;
+}
+
+static DEVICE_ATTR(initial_cal, 0644,
+	q6afe_initial_cal_show, q6afe_initial_cal_store);
+
+static ssize_t q6afe_v_vali_flag_show(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return snprintf(buf, BUF_SZ, "%d\n", afe_get_spk_v_vali_flag());
+}
+
+static ssize_t q6afe_v_vali_flag_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	int v_vali_flag = 0;
+
+	if (!kstrtou32(buf, 0, &v_vali_flag)) {
+		v_vali_flag = v_vali_flag > 0 ? 1 : 0;
+		if (v_vali_flag == afe_get_spk_v_vali_flag())
+			dev_dbg(dev, "%s: same value already present\n",
+				__func__);
+		else
+			afe_set_spk_v_vali_flag(v_vali_flag);
+	}
+	return size;
+}
+
+static DEVICE_ATTR(v_vali_flag, 0644,
+	q6afe_v_vali_flag_show, q6afe_v_vali_flag_store);
+
+static ssize_t q6afe_spk_r0_l_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	int r0[SP_V2_NUM_MAX_SPKRS];
+
+	afe_get_spk_r0(r0);
+	return snprintf(buf, BUF_SZ, "%d\n", r0[SP_V2_SPKR_1]);
+}
+
+static DEVICE_ATTR(spk_r0, 0644, q6afe_spk_r0_l_show, NULL);
+
+static ssize_t q6afe_spk_t0_l_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	int t0[SP_V2_NUM_MAX_SPKRS];
+
+	afe_get_spk_t0(t0);
+	return snprintf(buf, BUF_SZ, "%d\n", t0[SP_V2_SPKR_1]);
+}
+
+static DEVICE_ATTR(spk_t0, 0644, q6afe_spk_t0_l_show, NULL);
+
+static ssize_t q6afe_spk_r0_r_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	int r0[SP_V2_NUM_MAX_SPKRS];
+
+	afe_get_spk_r0(r0);
+	return snprintf(buf, BUF_SZ, "%d\n", r0[SP_V2_SPKR_2]);
+}
+
+static DEVICE_ATTR(spk_r0_r, 0644, q6afe_spk_r0_r_show, NULL);
+
+static ssize_t q6afe_spk_t0_r_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	int t0[SP_V2_NUM_MAX_SPKRS];
+
+	afe_get_spk_t0(t0);
+	return snprintf(buf, BUF_SZ, "%d\n", t0[SP_V2_SPKR_2]);
+}
+
+static DEVICE_ATTR(spk_t0_r, 0644, q6afe_spk_t0_r_show, NULL);
+
+static ssize_t q6afe_spk_v_vali_l_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	int v_vali_sts[SP_V2_NUM_MAX_SPKRS];
+
+	afe_get_spk_v_vali_sts(v_vali_sts);
+	return snprintf(buf, BUF_SZ, "%d\n", v_vali_sts[SP_V2_SPKR_1]);
+}
+
+static DEVICE_ATTR(spk_v_vali_status, 0644, q6afe_spk_v_vali_l_show, NULL);
+
+static ssize_t q6afe_spk_v_vali_r_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	int v_vali_sts[SP_V2_NUM_MAX_SPKRS];
+
+	afe_get_spk_v_vali_sts(v_vali_sts);
+	return snprintf(buf, BUF_SZ, "%d\n", v_vali_sts[SP_V2_SPKR_2]);
+}
+
+static DEVICE_ATTR(spk_v_vali_r_status, 0644, q6afe_spk_v_vali_r_show, NULL);
+
+static struct attribute *afe_spk_cal_attr[] = {
+	&dev_attr_max_excursion.attr,
+	&dev_attr_max_excursion_r.attr,
+	&dev_attr_max_temperature.attr,
+	&dev_attr_max_temperature_r.attr,
+	&dev_attr_count_exceeded_excursion.attr,
+	&dev_attr_count_exceeded_excursion_r.attr,
+	&dev_attr_count_exceeded_temperature.attr,
+	&dev_attr_count_exceeded_temperature_r.attr,
+	&dev_attr_max_temperature_rd.attr,
+	&dev_attr_max_temperature_rd_r.attr,
+	&dev_attr_initial_cal.attr,
+	&dev_attr_spk_r0.attr,
+	&dev_attr_spk_t0.attr,
+	&dev_attr_spk_r0_r.attr,
+	&dev_attr_spk_t0_r.attr,
+	&dev_attr_v_vali_flag.attr,
+	&dev_attr_spk_v_vali_status.attr,
+	&dev_attr_spk_v_vali_r_status.attr,
+	NULL,
+};
+
+static struct attribute_group afe_spk_cal_attr_grp = {
+	.attrs = afe_spk_cal_attr,
+};
+
+
+/**
+ * afe_get_sp_xt_logging_data -
+ *       to get excursion logging data from DSP
+ *
+ * @port: AFE port ID
+ *
+ * Returns 0 on success or error on failure
+ */
+int afe_get_sp_xt_logging_data(u16 port_id)
+{
+	int ret = 0;
+	struct afe_sp_rx_tmax_xmax_logging_param xt_logging_data;
+
+	ret = afe_get_sp_rx_tmax_xmax_logging_data(&xt_logging_data, port_id);
+	if (ret) {
+		pr_err("%s Excursion logging fail\n", __func__);
+		return ret;
+	}
+	/* storing max sp param value */
+	if (this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_1] <
+		xt_logging_data.max_temperature[SP_V2_SPKR_1])
+		this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_1] =
+				xt_logging_data.max_temperature[SP_V2_SPKR_1];
+
+
+	if (this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_2] <
+		xt_logging_data.max_temperature[SP_V2_SPKR_2])
+		this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_2] =
+				xt_logging_data.max_temperature[SP_V2_SPKR_2];
+
+
+	/* update temp for max_temperature_rd node */
+	if (this_afe_spk.max_temperature_rd[SP_V2_SPKR_1] <
+		xt_logging_data.max_temperature[SP_V2_SPKR_1])
+		this_afe_spk.max_temperature_rd[SP_V2_SPKR_1] =
+				xt_logging_data.max_temperature[SP_V2_SPKR_1];
+
+	if (this_afe_spk.max_temperature_rd[SP_V2_SPKR_2] <
+		xt_logging_data.max_temperature[SP_V2_SPKR_2])
+		this_afe_spk.max_temperature_rd[SP_V2_SPKR_2] =
+				xt_logging_data.max_temperature[SP_V2_SPKR_2];
+
+
+	if (this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_1] <
+		xt_logging_data.max_excursion[SP_V2_SPKR_1])
+		this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_1] =
+				xt_logging_data.max_excursion[SP_V2_SPKR_1];
+
+	if (this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_2] <
+		xt_logging_data.max_excursion[SP_V2_SPKR_2])
+		this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_2] =
+				xt_logging_data.max_excursion[SP_V2_SPKR_2];
+
+	if (this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_1] <
+		xt_logging_data.count_exceeded_temperature[SP_V2_SPKR_1])
+		this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_1]
+		+= xt_logging_data.count_exceeded_temperature[SP_V2_SPKR_1];
+
+	if (this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_2] <
+		xt_logging_data.count_exceeded_temperature[SP_V2_SPKR_2])
+		this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_2]
+		+= xt_logging_data.count_exceeded_temperature[SP_V2_SPKR_2];
+
+	if (this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_1] <
+		xt_logging_data.count_exceeded_excursion[SP_V2_SPKR_1])
+		this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_1]
+		+= xt_logging_data.count_exceeded_excursion[SP_V2_SPKR_1];
+
+	if (this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_2] <
+		xt_logging_data.count_exceeded_excursion[SP_V2_SPKR_2])
+		this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_2]
+		+= xt_logging_data.count_exceeded_excursion[SP_V2_SPKR_2];
+
+	return ret;
+}
+EXPORT_SYMBOL(afe_get_sp_xt_logging_data);
+
+int __init spk_params_init(void)
+{
+	/* initialize xt param value with 0 */
+	this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_1] = 0;
+	this_afe_spk.xt_logging.max_temperature[SP_V2_SPKR_2] = 0;
+	this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_1] = 0;
+	this_afe_spk.xt_logging.max_excursion[SP_V2_SPKR_2] = 0;
+	this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_1] = 0;
+	this_afe_spk.xt_logging.count_exceeded_temperature[SP_V2_SPKR_2] = 0;
+	this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_1] = 0;
+	this_afe_spk.xt_logging.count_exceeded_excursion[SP_V2_SPKR_2] = 0;
+
+	this_afe_spk.p_class = class_create(THIS_MODULE, SPK_PARAMS);
+	if (this_afe_spk.p_class) {
+		this_afe_spk.p_dev = device_create(this_afe_spk.p_class, NULL,
+						   1, NULL, CLASS_NAME);
+		if (!IS_ERR(this_afe_spk.p_dev)) {
+			if (sysfs_create_group(&this_afe_spk.p_dev->kobj,
+				&afe_spk_cal_attr_grp))
+				pr_err("%s: Failed to create sysfs group\n",
+					__func__);
+		}
+	}
+	return 0;
+}
+
+void spk_params_exit(void)
+{
+	pr_debug("%s\n", __func__);
+}
diff --git a/include/asoc/wcd9xxx_registers.h b/include/asoc/wcd9xxx_registers.h
index cf3c408..731b72f 100644
--- a/include/asoc/wcd9xxx_registers.h
+++ b/include/asoc/wcd9xxx_registers.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _WCD9XXX_REGISTERS_H
@@ -12,6 +12,7 @@
 #define WCD9XXX_ANA_HPH                             (WCD9XXX_BASE_ADDRESS+0x009)
 #define WCD9XXX_CLASSH_MODE_2                       (WCD9XXX_BASE_ADDRESS+0x098)
 #define WCD9XXX_CLASSH_MODE_3                       (WCD9XXX_BASE_ADDRESS+0x099)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_1                 (WCD9XXX_BASE_ADDRESS+0x0A5)
 #define WCD9XXX_FLYBACK_VNEG_CTRL_4                 (WCD9XXX_BASE_ADDRESS+0x0A8)
 #define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2              (WCD9XXX_BASE_ADDRESS+0x0AF)
 #define WCD9XXX_RX_BIAS_HPH_LOWPOWER                (WCD9XXX_BASE_ADDRESS+0x0BF)
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index d2cab24..62ff28b 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -10408,6 +10408,7 @@
 #define AFE_PARAM_ID_SP_RX_LIMITER_TH 0x000102B1
 #define AFE_PARAM_ID_FBSP_MODE_RX_CFG 0x0001021D
 #define AFE_PARAM_ID_FBSP_PTONE_RAMP_CFG 0x00010260
+#define AFE_PARAM_ID_SP_RX_TMAX_XMAX_LOGGING 0x000102BC
 
 struct asm_fbsp_mode_rx_cfg {
 	uint32_t minor_version;
@@ -10468,6 +10469,8 @@
 #define AFE_PARAM_ID_SP_V2_TH_VI_MODE_CFG	0x0001026B
 #define AFE_PARAM_ID_SP_V2_TH_VI_FTM_CFG	0x0001029F
 #define AFE_PARAM_ID_SP_V2_TH_VI_FTM_PARAMS	0x000102A0
+#define AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_CFG	0x000102BF
+#define AFE_PARAM_ID_SP_V2_TH_VI_V_VALI_PARAMS	0x000102C0
 
 struct afe_sp_th_vi_mode_cfg {
 	uint32_t minor_version;
@@ -10557,6 +10560,51 @@
 	struct afe_sp_th_vi_ftm_params param;
 } __packed;
 
+struct afe_sp_th_vi_v_vali_cfg {
+	uint32_t minor_version;
+	uint32_t wait_time_ms[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Wait time to heat up speaker before collecting statistics
+	 * for V validation mode in ms.
+	 * values 100 to 1000 ms
+	 */
+	uint32_t vali_time_ms[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * duration for which V VALIDATION statistics are collected in ms.
+	 * values 1000 to 3000 ms
+	 */
+} __packed;
+
+struct afe_sp_th_vi_v_vali_params {
+	uint32_t minor_version;
+	uint32_t vrms_q24[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Vrms value in q24 format
+	 * values [0 33554432] Q24 (0 - 2Vrms)
+	 */
+	uint32_t status[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * v-vali packet status
+	 * 0 - Failed.
+	 * 1 - Success.
+	 * 2 - Incorrect operation mode.This status is returned
+	 *     when GET_PARAM is called in non v-vali Mode
+	 * 3 - Inactive mode -- Port is not yet started.
+	 * 4 - Wait state. wait_time_ms has not yet elapsed
+	 * 5 - In progress state. ftm_time_ms has not yet elapsed.
+	 */
+} __packed;
+
+struct afe_sp_th_vi_v_vali_get_param {
+	struct param_hdr_v3 pdata;
+	struct afe_sp_th_vi_v_vali_params param;
+} __packed;
+
+struct afe_sp_th_vi_v_vali_get_param_resp {
+	uint32_t status;
+	struct param_hdr_v3 pdata;
+	struct afe_sp_th_vi_v_vali_params param;
+} __packed;
 
 #define AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI	0x0001026F
 #define AFE_PARAM_ID_SP_V2_EX_VI_MODE_CFG	0x000102A1
@@ -10618,6 +10666,33 @@
 	 */
 } __packed;
 
+struct afe_sp_rx_tmax_xmax_logging_param {
+	/*
+	 * Maximum excursion since the last grasp of xmax in mm.
+	 */
+	int32_t max_excursion[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Number of periods when the monitored excursion exceeds to and
+	 * stays at Xmax during logging_count_period.
+	 */
+	uint32_t count_exceeded_excursion[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Maximum temperature since the last grasp of tmax in C.
+	 */
+	int32_t max_temperature[SP_V2_NUM_MAX_SPKR];
+	/*
+	 * Number of periods when the monitored temperature exceeds to and
+	 * stays at Tmax during logging_count_period
+	 */
+	uint32_t count_exceeded_temperature[SP_V2_NUM_MAX_SPKR];
+} __packed;
+
+struct afe_sp_rx_tmax_xmax_logging_resp {
+	uint32_t status;
+	struct param_hdr_v3 pdata;
+	struct afe_sp_rx_tmax_xmax_logging_param param;
+} __packed;
+
 struct afe_sp_ex_vi_get_param {
 	struct param_hdr_v3 pdata;
 	struct afe_sp_ex_vi_ftm_params param;
@@ -10641,6 +10716,7 @@
 	struct asm_mode_vi_proc_cfg mode_vi_proc_cfg;
 	struct afe_sp_th_vi_mode_cfg th_vi_mode_cfg;
 	struct afe_sp_th_vi_ftm_cfg th_vi_ftm_cfg;
+	struct afe_sp_th_vi_v_vali_cfg th_vi_v_vali_cfg;
 	struct afe_sp_ex_vi_mode_cfg ex_vi_mode_cfg;
 	struct afe_sp_ex_vi_ftm_cfg ex_vi_ftm_cfg;
 	struct afe_sp_rx_limiter_th_param limiter_th_cfg;
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index 413edc1..c5b7e3e 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -446,6 +446,9 @@
 void afe_set_routing_callback(routing_cb cb);
 int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
 		u16 port);
+int afe_get_sp_rx_tmax_xmax_logging_data(
+		struct afe_sp_rx_tmax_xmax_logging_param *xt_logging,
+		u16 port_id);
 int afe_cal_init_hwdep(void *card);
 int afe_send_port_island_mode(u16 port_id);
 int afe_send_cmd_wakeup_register(void *handle, bool enable);
@@ -491,4 +494,11 @@
 int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name,
 			uint32_t *client_handle);
 int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle);
+int afe_get_spk_initial_cal(void);
+void afe_get_spk_r0(int *spk_r0);
+void afe_get_spk_t0(int *spk_t0);
+int afe_get_spk_v_vali_flag(void);
+void afe_get_spk_v_vali_sts(int *spk_v_vali_sts);
+void afe_set_spk_initial_cal(int initial_cal);
+void afe_set_spk_v_vali_flag(int v_vali_flag);
 #endif /* __Q6AFE_V2_H__ */
diff --git a/include/dsp/sp_params.h b/include/dsp/sp_params.h
new file mode 100644
index 0000000..ddc756e
--- /dev/null
+++ b/include/dsp/sp_params.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SP_PARAMS_H__
+#define __SP_PARAMS_H__
+
+#if IS_ENABLED(CONFIG_XT_LOGGING)
+int afe_get_sp_xt_logging_data(u16 port_id);
+#else
+static inline int afe_get_sp_xt_logging_data(u16 port_id)
+{
+	return 0;
+}
+#endif
+
+#endif /* __SP_PARAMS_H__ */
+
diff --git a/include/uapi/Android.mk b/include/uapi/Android.mk
index b8c209a..f19a6c2 100644
--- a/include/uapi/Android.mk
+++ b/include/uapi/Android.mk
@@ -15,6 +15,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE                  := audio_kernel_headers
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_PREBUILT_INT_KERNEL)
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
 GEN := $(addprefix $(UAPI_OUT)/,$(AUDIO_KERNEL_HEADERS))
 $(GEN): $(KERNEL_USR)
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index f6af2bf..9b93abe 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -18,3 +18,4 @@
 header-y += msm_audio_g711.h
 header-y += msm_audio_g711_dec.h
 header-y += mfd/
+header-y += wcd-spi-ac-params.h
diff --git a/include/uapi/linux/msm_audio_calibration.h b/include/uapi/linux/msm_audio_calibration.h
index 9bd64aa..35b5960 100644
--- a/include/uapi/linux/msm_audio_calibration.h
+++ b/include/uapi/linux/msm_audio_calibration.h
@@ -294,9 +294,11 @@
 	MSM_SPKR_PROT_DISABLED,
 	MSM_SPKR_PROT_NOT_CALIBRATED,
 	MSM_SPKR_PROT_PRE_CALIBRATED,
-	MSM_SPKR_PROT_IN_FTM_MODE
+	MSM_SPKR_PROT_IN_FTM_MODE,
+	MSM_SPKR_PROT_IN_V_VALI_MODE
 };
 #define MSM_SPKR_PROT_IN_FTM_MODE MSM_SPKR_PROT_IN_FTM_MODE
+#define MSM_SPKR_PROT_IN_V_VALI_MODE MSM_SPKR_PROT_IN_V_VALI_MODE
 
 enum msm_spkr_count {
 	SP_V2_SPKR_1,
@@ -321,14 +323,37 @@
 };
 
 struct audio_cal_info_sp_th_vi_ftm_cfg {
-	uint32_t	wait_time[SP_V2_NUM_MAX_SPKRS];
-	uint32_t	ftm_time[SP_V2_NUM_MAX_SPKRS];
+	/*
+	 * mode should be first param, add new params later to this.
+	 * we use this mode(first 4 bytes) to differentiate
+	 * whether it is TH_VI FTM or v-validation.
+	 */
 	uint32_t	mode;
 	/*
 	 * 0 - normal running mode
 	 * 1 - Calibration
 	 * 2 - FTM mode
 	 */
+	uint32_t	wait_time[SP_V2_NUM_MAX_SPKRS];
+	uint32_t	ftm_time[SP_V2_NUM_MAX_SPKRS];
+};
+
+struct audio_cal_info_sp_th_vi_v_vali_cfg {
+	/*
+	 * mode should be first param, add new params later to this.
+	 * we use this mode(first 4 bytes) to differentiate
+	 * whether it is TH_VI FTM or v-validation.
+	 */
+	uint32_t	mode;
+	/*
+	 * 0 - normal running mode
+	 * 1 - Calibration
+	 * 2 - FTM mode
+	 * 3 - V-Validation mode
+	 */
+	uint32_t	wait_time[SP_V2_NUM_MAX_SPKRS];
+	uint32_t	vali_time[SP_V2_NUM_MAX_SPKRS];
+
 };
 
 struct audio_cal_info_sp_ex_vi_ftm_cfg {
@@ -349,11 +374,28 @@
 };
 
 struct audio_cal_info_sp_th_vi_param {
+	/*
+	 * mode should be first param, add new params later to this.
+	 * we use this mode(first 4 bytes) to differentiate
+	 * whether it is TH_VI FTM or v-validation.
+	 */
+	uint32_t	mode;
 	int32_t		r_dc_q24[SP_V2_NUM_MAX_SPKRS];
 	int32_t		temp_q22[SP_V2_NUM_MAX_SPKRS];
 	int32_t		status[SP_V2_NUM_MAX_SPKRS];
 };
 
+struct audio_cal_info_sp_th_vi_v_vali_param {
+	/*
+	 * mode should be first param, add new params later to this.
+	 * we use this mode(first 4 bytes) to differentiate
+	 * whether it is TH_VI FTM or v-validation.
+	 */
+	uint32_t	mode;
+	uint32_t	vrms_q24[SP_V2_NUM_MAX_SPKRS];
+	int32_t		status[SP_V2_NUM_MAX_SPKRS];
+};
+
 struct audio_cal_info_msm_spk_prot_status {
 	int32_t		r0[SP_V2_NUM_MAX_SPKRS];
 	int32_t		status;
@@ -589,6 +631,17 @@
 	struct audio_cal_type_sp_th_vi_ftm_cfg	cal_type;
 };
 
+struct audio_cal_type_sp_th_vi_v_vali_cfg {
+	struct audio_cal_type_header		cal_hdr;
+	struct audio_cal_data			cal_data;
+	struct audio_cal_info_sp_th_vi_v_vali_cfg	cal_info;
+};
+
+struct audio_cal_sp_th_vi_v_vali_cfg {
+	struct audio_cal_header			hdr;
+	struct audio_cal_type_sp_th_vi_v_vali_cfg	cal_type;
+};
+
 struct audio_cal_type_sp_ex_vi_ftm_cfg {
 	struct audio_cal_type_header		cal_hdr;
 	struct audio_cal_data			cal_data;
@@ -731,6 +784,17 @@
 	struct audio_cal_header				hdr;
 	struct audio_cal_type_sp_th_vi_param		cal_type;
 };
+
+struct audio_cal_type_sp_th_vi_v_vali_param {
+	struct audio_cal_type_header			cal_hdr;
+	struct audio_cal_data				cal_data;
+	struct audio_cal_info_sp_th_vi_v_vali_param	cal_info;
+};
+
+struct audio_cal_sp_th_vi_v_vali_param {
+	struct audio_cal_header				hdr;
+	struct audio_cal_type_sp_th_vi_v_vali_param	cal_type;
+};
 struct audio_cal_type_sp_ex_vi_param {
 	struct audio_cal_type_header			cal_hdr;
 	struct audio_cal_data				cal_data;
diff --git a/include/uapi/linux/wcd-spi-ac-params.h b/include/uapi/linux/wcd-spi-ac-params.h
new file mode 100644
index 0000000..e397bf2
--- /dev/null
+++ b/include/uapi/linux/wcd-spi-ac-params.h
@@ -0,0 +1,52 @@
+#ifndef __UAPI_WCD_SPI_AC_PARAMS_H__
+#define __UAPI_WCD_SPI_AC_PARAMS_H__
+
+#include <linux/types.h>
+
+#define WCD_SPI_AC_CMD_CONC_BEGIN	0x01
+#define WCD_SPI_AC_CMD_CONC_END		0x02
+#define WCD_SPI_AC_CMD_BUF_DATA		0x03
+
+#define WCD_SPI_AC_MAX_BUFFERS		2
+#define WCD_SPI_AC_MAX_CH_PER_BUF	8
+
+#define WCD_SPI_AC_CLIENT_CDEV_NAME	"wcd-spi-ac-client"
+#define WCD_SPI_AC_PROCFS_DIR_NAME	"wcd-spi-ac"
+#define WCD_SPI_AC_PROCFS_STATE_NAME	"svc-state"
+
+/*
+ * wcd_spi_ac_buf_data:
+ *	Buffer address for one buffer. Should have data
+ *	for all the channels. If channels are unused, the
+ *	value must be NULL.
+ *
+ * @addr:
+ *	Address where each channel of the buffer starts.
+ */
+struct wcd_spi_ac_buf_data {
+	__u32 addr[WCD_SPI_AC_MAX_CH_PER_BUF];
+} __packed;
+
+/*
+ * wcd_spi_ac_write_cmd:
+ *	Data sent to the driver's write interface should
+ *	be packed in this format.
+ *
+ * @cmd_type:
+ *	Indicates the type of command that is sent. Should
+ *	be one of the valid commands defined with
+ *	WCD_SPI_AC_CMD_*
+ * @payload:
+ *	No payload for:
+ *		WCD_SPI_AC_CMD_CONC_BEGIN
+ *		WCD_SPI_AC_CMD_CONC_END
+ *	Upto WCD_SPI_AC_MAX_BUFFERS of type
+ *	struct wcd_spi_ac_buf_data for:
+ *		WCD_SPI_AC_CMD_BUF_DATA
+ */
+struct wcd_spi_ac_write_cmd {
+	__u32 cmd_type;
+	__u8 payload[0];
+} __packed;
+
+#endif /* end of __UAPI_WCD_SPI_AC_PARAMS_H__ */
diff --git a/ipc/apr.c b/ipc/apr.c
index ec05d3b..fbb1f32 100644
--- a/ipc/apr.c
+++ b/ipc/apr.c
@@ -364,7 +364,8 @@
 	unsigned long flags;
 
 	if (!handle || !buf) {
-		pr_err("APR: Wrong parameters\n");
+		pr_err("APR: Wrong parameters for %s\n",
+				!handle ? "handle" : "buf");
 		return -EINVAL;
 	}
 	if (svc->need_reset) {
@@ -636,6 +637,12 @@
 		pr_err("APR: Wrong paket size\n");
 		return;
 	}
+
+	if (hdr->pkt_size < hdr_size) {
+		pr_err("APR: Packet size less than header size\n");
+		return;
+	}
+
 	msg_type = hdr->hdr_field;
 	msg_type = (msg_type >> 0x08) & 0x0003;
 	if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index f9dbc24..8d82ff1 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -448,11 +448,16 @@
 
 	mutex_lock(&swrm->iolock);
 	val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr);
-	/* wait for FIFO RD to complete to avoid overflow */
-	usleep_range(100, 105);
-	swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
-	/* wait for FIFO RD CMD complete to avoid overflow */
-	usleep_range(250, 255);
+	if (swrm->read) {
+		/* skip delay if read is handled in platform driver */
+		swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
+	} else {
+		/* wait for FIFO RD to complete to avoid overflow */
+		usleep_range(100, 105);
+		swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
+		/* wait for FIFO RD CMD complete to avoid overflow */
+		usleep_range(250, 255);
+	}
 retry_read:
 	*cmd_data = swr_master_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR);
 	dev_dbg(swrm->dev, "%s: reg: 0x%x, cmd_id: 0x%x, rcmd_id: 0x%x, \
@@ -496,8 +501,12 @@
 			dev_num: 0x%x, cmd_data: 0x%x\n", __func__,
 			reg_addr, cmd_id, swrm->wcmd_id,dev_addr, cmd_data);
 	swr_master_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
-	/* wait for FIFO WR command to complete to avoid overflow */
-	usleep_range(250, 255);
+	/*
+	 * wait for FIFO WR command to complete to avoid overflow
+	 * skip delay if write is handled in platform driver.
+	 */
+	if(!swrm->write)
+		usleep_range(250, 255);
 	if (cmd_id == 0xF) {
 		/*
 		 * sleep for 10ms for MSM soundwire variant to allow broadcast