Merge "ASoC: codecs: sdm660_cdc: Fix mute if compander is disabled"
diff --git a/asoc/Makefile b/asoc/Makefile
index cc28148..4d3839d 100644
--- a/asoc/Makefile
+++ b/asoc/Makefile
@@ -15,19 +15,9 @@
 snd-soc-msm8998-objs := msm8998.o
 obj-$(CONFIG_SND_SOC_MACHINE_MSM8998) += snd-soc-msm8998.o
 
-# for SDM660 sound card driver
-snd-soc-sdm660-common-objs := sdm660-common.o
-obj-$(CONFIG_SND_SOC_SDM670) += snd-soc-sdm660-common.o
-
-# for SDM660 sound card driver
-snd-soc-int-codec-objs := sdm660-internal.o
-obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-sdm660-common.o
-obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-int-codec.o
-
-# for SDM660 sound card driver
-snd-soc-ext-codec-objs := sdm660-external.o sdm660-ext-dai-links.o
-obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-sdm660-common.o
-obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-ext-codec.o
+# for SDM670 sound card driver
+snd-soc-sdm670-objs := sdm660-common.o sdm660-internal.o sdm660-external.o sdm660-ext-dai-links.o
+obj-$(CONFIG_SND_SOC_SDM670) += snd-soc-sdm670.o
 
 # for SDM845 sound card driver
 snd-soc-sdm845-objs := sdm845.o
diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc.c b/asoc/codecs/sdm660_cdc/msm-digital-cdc.c
index eeaddf6..4ab2037 100644
--- a/asoc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -55,6 +55,11 @@
 	MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
 };
 
+#define SDM660_TX_UNMUTE_DELAY_MS 40
+static int tx_unmute_delay = SDM660_TX_UNMUTE_DELAY_MS;
+module_param(tx_unmute_delay, int, 0664);
+MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 
 struct snd_soc_codec *registered_digcodec;
@@ -924,6 +929,9 @@
 		/* enable HPF */
 		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
 
+		schedule_delayed_work(
+			    &msm_dig_cdc->tx_mute_dwork[decimator - 1].dwork,
+			    msecs_to_jiffies(tx_unmute_delay));
 		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
 				CF_MIN_3DB_150HZ) {
 
@@ -937,20 +945,14 @@
 				  snd_soc_read(codec,
 				  tx_digital_gain_reg[w->shift + offset])
 				  );
-		if (pdata->lb_mode) {
-			pr_debug("%s: loopback mode unmute the DEC\n",
-							__func__);
-			snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
-		}
-				snd_soc_update_bits(codec, tx_vol_ctl_reg,
-						0x01, 0x00);
-
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
 		msleep(20);
 		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
 		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+		cancel_delayed_work_sync(
+			&msm_dig_cdc->tx_mute_dwork[decimator - 1].dwork);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
@@ -1191,6 +1193,35 @@
 }
 EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry);
 
+static void sdm660_tx_mute_update_callback(struct work_struct *work)
+{
+	struct tx_mute_work *tx_mute_dwork;
+	struct snd_soc_codec *codec = NULL;
+	struct msm_dig_priv *dig_cdc;
+	struct delayed_work *delayed_work;
+	u16 tx_vol_ctl_reg = 0;
+	u8 decimator = 0, i;
+
+	delayed_work = to_delayed_work(work);
+	tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork);
+	dig_cdc = tx_mute_dwork->dig_cdc;
+	codec = dig_cdc->codec;
+
+	for (i = 0; i < (NUM_DECIMATORS - 1); i++) {
+		if (dig_cdc->dec_active[i])
+			decimator = i + 1;
+		if (decimator && decimator < NUM_DECIMATORS) {
+			/* unmute decimators corresponding to Tx DAI's*/
+			tx_vol_ctl_reg =
+				MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+					32 * (decimator - 1);
+				snd_soc_update_bits(codec, tx_vol_ctl_reg,
+					0x01, 0x00);
+		}
+		decimator = 0;
+	}
+}
+
 static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec)
 {
 	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
@@ -1207,6 +1238,10 @@
 		tx_hpf_work[i].decimator = i + 1;
 		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
 			tx_hpf_corner_freq_callback);
+		msm_dig_cdc->tx_mute_dwork[i].dig_cdc = msm_dig_cdc;
+		msm_dig_cdc->tx_mute_dwork[i].decimator = i + 1;
+		INIT_DELAYED_WORK(&msm_dig_cdc->tx_mute_dwork[i].dwork,
+			sdm660_tx_mute_update_callback);
 	}
 
 	for (i = 0; i < MSM89XX_RX_MAX; i++)
@@ -1891,63 +1926,8 @@
 		MSM89XX_CDC_CORE_TX5_MUX_CTL, 3, 1, 0),
 };
 
-static int msm_dig_cdc_digital_mute(struct snd_soc_dai *dai, int mute)
-{
-	struct snd_soc_codec *codec = NULL;
-	u16 tx_vol_ctl_reg = 0;
-	u8 decimator = 0, i;
-	struct msm_dig_priv *dig_cdc;
-
-	pr_debug("%s: Digital Mute val = %d\n", __func__, mute);
-
-	if (!dai || !dai->codec) {
-		pr_err("%s: Invalid params\n", __func__);
-		return -EINVAL;
-	}
-	codec = dai->codec;
-	dig_cdc = snd_soc_codec_get_drvdata(codec);
-
-	if (dai->id == AIF1_PB) {
-		dev_dbg(codec->dev, "%s: Not capture use case skip\n",
-			__func__);
-		return 0;
-	}
-
-	mute = (mute) ? 1 : 0;
-	if (!mute) {
-		/*
-		 * 15 ms is an emperical value for the mute time
-		 * that was arrived by checking the pop level
-		 * to be inaudible
-		 */
-		usleep_range(15000, 15010);
-	}
-
-	if (dai->id == AIF3_SVA) {
-		snd_soc_update_bits(codec,
-			MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x01, mute);
-		goto ret;
-	}
-	for (i = 0; i < (NUM_DECIMATORS - 1); i++) {
-		if (dig_cdc->dec_active[i])
-			decimator = i + 1;
-		if (decimator && decimator < NUM_DECIMATORS) {
-			/* mute/unmute decimators corresponding to Tx DAI's */
-			tx_vol_ctl_reg =
-			MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
-					32 * (decimator - 1);
-			snd_soc_update_bits(codec, tx_vol_ctl_reg,
-					    0x01, mute);
-		}
-		decimator = 0;
-	}
-ret:
-	return 0;
-}
-
 static struct snd_soc_dai_ops msm_dig_dai_ops = {
 	.hw_params = msm_dig_cdc_hw_params,
-	.digital_mute = msm_dig_cdc_digital_mute,
 };
 
 
diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc.h b/asoc/codecs/sdm660_cdc/msm-digital-cdc.h
index f0e7a9c..42c31d5 100644
--- a/asoc/codecs/sdm660_cdc/msm-digital-cdc.h
+++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc.h
@@ -32,6 +32,12 @@
 	MSM89XX_RX_MAX,
 };
 
+struct tx_mute_work {
+	struct msm_dig_priv *dig_cdc;
+	u32 decimator;
+	struct delayed_work dwork;
+};
+
 struct msm_dig_priv {
 	struct snd_soc_codec *codec;
 	u32 comp_enabled[MSM89XX_RX_MAX];
@@ -54,6 +60,7 @@
 	int (*register_notifier)(void *handle,
 				 struct notifier_block *nblock,
 				 bool enable);
+	struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
 };
 
 struct dig_ctrl_platform_data {
diff --git a/asoc/codecs/wcd9335.c b/asoc/codecs/wcd9335.c
index 19877b9..8ade82b 100644
--- a/asoc/codecs/wcd9335.c
+++ b/asoc/codecs/wcd9335.c
@@ -87,6 +87,8 @@
 #define TASHA_NUM_INTERPOLATORS 9
 #define TASHA_NUM_DECIMATORS 9
 
+#define WCD9335_CHILD_DEVICES_MAX	6
+
 #define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
 #define TASHA_MAD_AUDIO_FIRMWARE_PATH "wcd9335/wcd9335_mad_audio.bin"
 #define TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS (1 << 0)
@@ -829,6 +831,10 @@
 	u32 ref_count;
 	/* Lock to protect mclk enablement */
 	struct mutex mclk_lock;
+
+	struct platform_device *pdev_child_devices
+			[WCD9335_CHILD_DEVICES_MAX];
+	int child_count;
 };
 
 static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
@@ -13576,11 +13582,14 @@
 	struct wcd9xxx *control;
 
 	control = dev_get_drvdata(codec->dev->parent);
+	control->num_rx_port = 0;
+	control->num_tx_port = 0;
 	control->rx_chs = NULL;
 	control->tx_chs = NULL;
 
 	tasha_cleanup_irqs(tasha);
 	/* Cleanup MBHC */
+	wcd_mbhc_deinit(&tasha->mbhc);
 	/* Cleanup resmgr */
 
 	return 0;
@@ -13920,6 +13929,7 @@
 	}
 
 	platdata = &tasha->swr_plat_data;
+	tasha->child_count = 0;
 
 	for_each_child_of_node(wcd9xxx->dev->of_node, node) {
 		if (!strcmp(node->name, "swr_master"))
@@ -13980,6 +13990,11 @@
 			tasha->nr = ctrl_num;
 			tasha->swr_ctrl_data = swr_ctrl_data;
 		}
+
+		if (tasha->child_count < WCD9335_CHILD_DEVICES_MAX)
+			tasha->pdev_child_devices[tasha->child_count++] = pdev;
+		else
+			goto err;
 	}
 
 	return;
@@ -14179,17 +14194,25 @@
 static int tasha_remove(struct platform_device *pdev)
 {
 	struct tasha_priv *tasha;
+	int count = 0;
 
 	tasha = platform_get_drvdata(pdev);
 
+	if (!tasha)
+		return -EINVAL;
+
+	for (count = 0; count < tasha->child_count &&
+		count < WCD9335_CHILD_DEVICES_MAX; count++)
+		platform_device_unregister(tasha->pdev_child_devices[count]);
+
 	mutex_destroy(&tasha->codec_mutex);
 	clk_put(tasha->wcd_ext_clk);
 	if (tasha->wcd_native_clk)
 		clk_put(tasha->wcd_native_clk);
 	mutex_destroy(&tasha->mclk_lock);
-	devm_kfree(&pdev->dev, tasha);
-	snd_soc_unregister_codec(&pdev->dev);
 	mutex_destroy(&tasha->sb_clk_gear_lock);
+	snd_soc_unregister_codec(&pdev->dev);
+	devm_kfree(&pdev->dev, tasha);
 	return 0;
 }
 
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 2802a4f..cfe47ed 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -2249,6 +2249,10 @@
 				sizeof(struct asm_aac_enc_cfg_v2_t));
 			break;
 		case ENC_FMT_APTX:
+			memcpy(ucontrol->value.bytes.data + format_size,
+				&dai_data->enc_config.data,
+				sizeof(struct asm_aptx_enc_cfg_t));
+			break;
 		case ENC_FMT_APTX_HD:
 			memcpy(ucontrol->value.bytes.data + format_size,
 				&dai_data->enc_config.data,
@@ -2298,6 +2302,10 @@
 				sizeof(struct asm_aac_enc_cfg_v2_t));
 			break;
 		case ENC_FMT_APTX:
+			memcpy(&dai_data->enc_config.data,
+				ucontrol->value.bytes.data + format_size,
+				sizeof(struct asm_aptx_enc_cfg_t));
+			break;
 		case ENC_FMT_APTX_HD:
 			memcpy(&dai_data->enc_config.data,
 				ucontrol->value.bytes.data + format_size,
@@ -6535,26 +6543,12 @@
 	struct msm_dai_q6_tdm_dai_data *dai_data =
 		dev_get_drvdata(dai->dev);
 
-	switch (dai->id) {
-	case AFE_PORT_ID_QUATERNARY_TDM_RX:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+	if ((dai->id >= AFE_PORT_ID_PRIMARY_TDM_RX) &&
+		(dai->id <= AFE_PORT_ID_QUINARY_TDM_TX_7)) {
 		dai_data->clk_set.clk_freq_in_hz = freq;
-		break;
-	default:
+	} else {
+		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+			__func__, dai->id);
 		return -EINVAL;
 	}
 
diff --git a/asoc/sdm660-common.c b/asoc/sdm660-common.c
index e6b82df..1874cfa 100644
--- a/asoc/sdm660-common.c
+++ b/asoc/sdm660-common.c
@@ -17,6 +17,7 @@
 #include <linux/of_device.h>
 #include <sound/pcm_params.h>
 #include <dsp/q6afe-v2.h>
+#include <dsp/audio_notifier.h>
 #include "msm-pcm-routing-v2.h"
 #include "sdm660-common.h"
 #include "sdm660-internal.h"
@@ -3134,20 +3135,6 @@
 	return ret;
 }
 
-static void msm_free_auxdev_mem(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	int i;
-
-	if (card->num_aux_devs > 0) {
-		for (i = 0; i < card->num_aux_devs; i++) {
-			kfree(msm_aux_dev[i].codec_name);
-			kfree(msm_codec_conf[i].dev_name);
-			kfree(msm_codec_conf[i].name_prefix);
-		}
-	}
-}
-
 static void i2s_auxpcm_init(struct platform_device *pdev)
 {
 	int count;
@@ -3366,10 +3353,22 @@
 	if (pdata->snd_card_val == INT_SND_CARD)
 		mutex_destroy(&pdata->cdc_int_mclk0_mutex);
 
-	msm_free_auxdev_mem(pdev);
-	gpio_free(pdata->us_euro_gpio);
-	gpio_free(pdata->hph_en1_gpio);
-	gpio_free(pdata->hph_en0_gpio);
+	if (gpio_is_valid(pdata->us_euro_gpio)) {
+		gpio_free(pdata->us_euro_gpio);
+		pdata->us_euro_gpio = 0;
+	}
+	if (gpio_is_valid(pdata->hph_en1_gpio)) {
+		gpio_free(pdata->hph_en1_gpio);
+		pdata->hph_en1_gpio = 0;
+	}
+	if (gpio_is_valid(pdata->hph_en0_gpio)) {
+		gpio_free(pdata->hph_en0_gpio);
+		pdata->hph_en0_gpio = 0;
+	}
+
+	if (pdata->snd_card_val != INT_SND_CARD)
+		audio_notifier_deregister("sdm660");
+
 	snd_soc_unregister_card(card);
 	return 0;
 }
diff --git a/asoc/sdm660-ext-dai-links.c b/asoc/sdm660-ext-dai-links.c
index 4777a5f..a331135 100644
--- a/asoc/sdm660-ext-dai-links.c
+++ b/asoc/sdm660-ext-dai-links.c
@@ -1573,7 +1573,7 @@
 	{
 		.name = LPASS_BE_QUIN_TDM_RX_0,
 		.stream_name = "Quinary TDM0 Playback",
-		.cpu_dai_name = "msm-dai-q6-tdm.37184",
+		.cpu_dai_name = "msm-dai-q6-tdm.36928",
 		.platform_name = "msm-pcm-routing",
 		.codec_name = "msm-stub-codec.1",
 		.codec_dai_name = "msm-stub-rx",
@@ -1587,7 +1587,7 @@
 	{
 		.name = LPASS_BE_QUIN_TDM_TX_0,
 		.stream_name = "Quinary TDM0 Capture",
-		.cpu_dai_name = "msm-dai-q6-tdm.37185",
+		.cpu_dai_name = "msm-dai-q6-tdm.36929",
 		.platform_name = "msm-pcm-routing",
 		.codec_name = "msm-stub-codec.1",
 		.codec_dai_name = "msm-stub-tx",
diff --git a/asoc/sdm660-external.h b/asoc/sdm660-external.h
index 0648c01..b81e158 100644
--- a/asoc/sdm660-external.h
+++ b/asoc/sdm660-external.h
@@ -32,7 +32,7 @@
 			       struct snd_pcm_hw_params *params);
 int msm_snd_card_tavil_late_probe(struct snd_soc_card *card);
 int msm_snd_card_tasha_late_probe(struct snd_soc_card *card);
-#ifdef CONFIG_SND_SOC_EXT_CODEC
+#if IS_ENABLED(CONFIG_SND_SOC_EXT_CODEC)
 int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *,
 		     struct snd_soc_card **, struct wcd_mbhc_config *);
 void msm_ext_register_audio_notifier(struct platform_device *pdev);
diff --git a/asoc/sdm660-internal.c b/asoc/sdm660-internal.c
index 713da55..a1536fe 100644
--- a/asoc/sdm660-internal.c
+++ b/asoc/sdm660-internal.c
@@ -2612,7 +2612,7 @@
 	{
 		.name = LPASS_BE_QUIN_TDM_RX_0,
 		.stream_name = "Quinary TDM0 Playback",
-		.cpu_dai_name = "msm-dai-q6-tdm.37184",
+		.cpu_dai_name = "msm-dai-q6-tdm.36928",
 		.platform_name = "msm-pcm-routing",
 		.codec_name = "msm-stub-codec.1",
 		.codec_dai_name = "msm-stub-rx",
@@ -2626,7 +2626,7 @@
 	{
 		.name = LPASS_BE_QUIN_TDM_TX_0,
 		.stream_name = "Quinary TDM0 Capture",
-		.cpu_dai_name = "msm-dai-q6-tdm.37185",
+		.cpu_dai_name = "msm-dai-q6-tdm.36929",
 		.platform_name = "msm-pcm-routing",
 		.codec_name = "msm-stub-codec.1",
 		.codec_dai_name = "msm-stub-tx",
diff --git a/asoc/sdm660-internal.h b/asoc/sdm660-internal.h
index ccc62b8..6918231 100644
--- a/asoc/sdm660-internal.h
+++ b/asoc/sdm660-internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -15,7 +15,7 @@
 
 #include <sound/soc.h>
 
-#ifdef CONFIG_SND_SOC_INT_CODEC
+#if IS_ENABLED(CONFIG_SND_SOC_INT_CODEC)
 int msm_int_cdc_init(struct platform_device *pdev,
 		     struct msm_asoc_mach_data *pdata,
 		     struct snd_soc_card **card,
diff --git a/asoc/sdm845.c b/asoc/sdm845.c
index 0506636..f8c0444 100644
--- a/asoc/sdm845.c
+++ b/asoc/sdm845.c
@@ -70,7 +70,6 @@
 #define WCN_CDC_SLIM_TX_CH_MAX 3
 
 #define TDM_CHANNEL_MAX 8
-#define TDM_SLOT_OFFSET_MAX 8
 
 #define MSM_HIFI_ON 1
 
@@ -311,17 +310,6 @@
 	}
 };
 
-/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */
-static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
-	{0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */
-	{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */
-};
 
 /* Default configuration of slimbus channels */
 static struct dev_config slim_rx_cfg[] = {
@@ -432,8 +420,8 @@
 				    "Five", "Six", "Seven", "Eight"};
 static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
 static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
-					     "KHZ_44P1", "KHZ_48", "KHZ_96",
-					     "KHZ_192", "KHZ_352P8", "KHZ_384"};
+					     "KHZ_48", "KHZ_176P4",
+					     "KHZ_352P8"};
 static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
 static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
 				      "KHZ_32", "KHZ_44P1", "KHZ_48",
@@ -1620,23 +1608,14 @@
 		sample_rate = SAMPLING_RATE_32KHZ;
 		break;
 	case 3:
-		sample_rate = SAMPLING_RATE_44P1KHZ;
-		break;
-	case 4:
 		sample_rate = SAMPLING_RATE_48KHZ;
 		break;
+	case 4:
+		sample_rate = SAMPLING_RATE_176P4KHZ;
+		break;
 	case 5:
-		sample_rate = SAMPLING_RATE_96KHZ;
-		break;
-	case 6:
-		sample_rate = SAMPLING_RATE_192KHZ;
-		break;
-	case 7:
 		sample_rate = SAMPLING_RATE_352P8KHZ;
 		break;
-	case 8:
-		sample_rate = SAMPLING_RATE_384KHZ;
-		break;
 	default:
 		sample_rate = SAMPLING_RATE_48KHZ;
 		break;
@@ -1674,26 +1653,17 @@
 	case SAMPLING_RATE_32KHZ:
 		sample_rate_val = 2;
 		break;
-	case SAMPLING_RATE_44P1KHZ:
+	case SAMPLING_RATE_48KHZ:
 		sample_rate_val = 3;
 		break;
-	case SAMPLING_RATE_48KHZ:
+	case SAMPLING_RATE_176P4KHZ:
 		sample_rate_val = 4;
 		break;
-	case SAMPLING_RATE_96KHZ:
-		sample_rate_val = 5;
-		break;
-	case SAMPLING_RATE_192KHZ:
-		sample_rate_val = 6;
-		break;
 	case SAMPLING_RATE_352P8KHZ:
-		sample_rate_val = 7;
-		break;
-	case SAMPLING_RATE_384KHZ:
-		sample_rate_val = 8;
+		sample_rate_val = 5;
 		break;
 	default:
-		sample_rate_val = 4;
+		sample_rate_val = 3;
 		break;
 	}
 	return sample_rate_val;
@@ -4497,15 +4467,46 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int ret = 0;
-	int channels, slot_width, slots;
+	int slot_width = 32;
+	int channels, slots;
 	unsigned int slot_mask, rate, clk_freq;
 	unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
 
-	slot_width = 32;
 	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
+	switch (cpu_dai->id) {
+	case AFE_PORT_ID_PRIMARY_TDM_RX:
+		slots = tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_SECONDARY_TDM_RX:
+		slots = tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_TERTIARY_TDM_RX:
+		slots = tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_QUATERNARY_TDM_RX:
 		slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_PRIMARY_TDM_TX:
+		slots = tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_SECONDARY_TDM_TX:
+		slots = tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_TERTIARY_TDM_TX:
+		slots = tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+		break;
+	case AFE_PORT_ID_QUATERNARY_TDM_TX:
+		slots = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+		break;
+	default:
+		pr_err("%s: dai id 0x%x not supported\n",
+			__func__, cpu_dai->id);
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/*2 slot config - bits 0 and 1 set for the first two slots */
 		slot_mask = 0x0000FFFF >> (16-slots);
 		channels = slots;
@@ -4529,7 +4530,6 @@
 			goto end;
 		}
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		slots = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
 		/*2 slot config - bits 0 and 1 set for the first two slots */
 		slot_mask = 0x0000FFFF >> (16-slots);
 		channels = slots;
@@ -4574,14 +4574,19 @@
 {
 	int ret = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
 
-	ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
-	if (ret)
-		pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
-			__func__, ret);
+	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
+	if ((cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) ||
+		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX)) {
+		ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
+		if (ret)
+			pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
+				__func__, ret);
+	}
 
 	return ret;
 }
@@ -4590,15 +4595,19 @@
 {
 	int ret = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
 
-	ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
-	if (ret)
-		pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
-			__func__, ret);
-
+	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
+	if ((cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) ||
+		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX)) {
+		ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+		if (ret)
+			pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
+				__func__, ret);
+	}
 }
 
 static struct snd_soc_ops sdm845_tdm_be_ops = {
@@ -4732,157 +4741,6 @@
 	.shutdown = msm_aux_pcm_snd_shutdown,
 };
 
-static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
-					    int slots)
-{
-	unsigned int slot_mask = 0;
-	int i, j;
-	unsigned int *slot_offset;
-
-	for (i = TDM_0; i < TDM_PORT_MAX; i++) {
-		slot_offset = tdm_slot_offset[i];
-
-		for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
-			if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
-				slot_mask |=
-				(1 << ((slot_offset[j] * 8) / slot_width));
-			else
-				break;
-		}
-	}
-
-	return slot_mask;
-}
-
-static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
-				     struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int ret = 0;
-	int channels, slot_width, slots;
-	unsigned int slot_mask;
-	unsigned int *slot_offset;
-	int offset_channels = 0;
-	int i;
-
-	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
-
-	channels = params_channels(params);
-	switch (channels) {
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-	case 6:
-	case 7:
-	case 8:
-		switch (params_format(params)) {
-		case SNDRV_PCM_FORMAT_S32_LE:
-		case SNDRV_PCM_FORMAT_S24_LE:
-		case SNDRV_PCM_FORMAT_S16_LE:
-		/*
-		 * Up to 8 channels HW config should
-		 * use 32 bit slot width for max support of
-		 * stream bit width. (slot_width > bit_width)
-		 */
-			slot_width = 32;
-			break;
-		default:
-			pr_err("%s: invalid param format 0x%x\n",
-				__func__, params_format(params));
-			return -EINVAL;
-		}
-		slots = 8;
-		slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
-						    slot_width,
-						    slots);
-		if (!slot_mask) {
-			pr_err("%s: invalid slot_mask 0x%x\n",
-				__func__, slot_mask);
-			return -EINVAL;
-		}
-		break;
-	default:
-		pr_err("%s: invalid param channels %d\n",
-			__func__, channels);
-		return -EINVAL;
-	}
-	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
-	switch (cpu_dai->id) {
-	case AFE_PORT_ID_PRIMARY_TDM_RX:
-	case AFE_PORT_ID_SECONDARY_TDM_RX:
-	case AFE_PORT_ID_TERTIARY_TDM_RX:
-	case AFE_PORT_ID_QUATERNARY_TDM_RX:
-	case AFE_PORT_ID_PRIMARY_TDM_TX:
-	case AFE_PORT_ID_SECONDARY_TDM_TX:
-	case AFE_PORT_ID_TERTIARY_TDM_TX:
-	case AFE_PORT_ID_QUATERNARY_TDM_TX:
-		slot_offset = tdm_slot_offset[TDM_0];
-		break;
-	default:
-		pr_err("%s: dai id 0x%x not supported\n",
-			__func__, cpu_dai->id);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
-		if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
-			offset_channels++;
-		else
-			break;
-	}
-
-	if (offset_channels == 0) {
-		pr_err("%s: slot offset not supported, offset_channels %d\n",
-			__func__, offset_channels);
-		return -EINVAL;
-	}
-
-	if (channels > offset_channels) {
-		pr_err("%s: channels %d exceed offset_channels %d\n",
-			__func__, channels, offset_channels);
-		return -EINVAL;
-	}
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
-					       slots, slot_width);
-		if (ret < 0) {
-			pr_err("%s: failed to set tdm slot, err:%d\n",
-				__func__, ret);
-			goto err;
-		}
-
-		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
-						  channels, slot_offset);
-		if (ret < 0) {
-			pr_err("%s: failed to set channel map, err:%d\n",
-				__func__, ret);
-			goto err;
-		}
-	} else {
-		ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
-					       slots, slot_width);
-		if (ret < 0) {
-			pr_err("%s: failed to set tdm slot, err:%d\n",
-				__func__, ret);
-			goto err;
-		}
-
-		ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
-						  slot_offset, 0, NULL);
-		if (ret < 0) {
-			pr_err("%s: failed to set channel map, err:%d\n",
-				__func__, ret);
-			goto err;
-		}
-	}
-err:
-	return ret;
-}
-
 static struct snd_soc_ops msm_be_ops = {
 	.hw_params = msm_snd_hw_params,
 };
@@ -4895,9 +4753,6 @@
 	.hw_params = msm_wcn_hw_params,
 };
 
-static struct snd_soc_ops msm_tdm_be_ops = {
-	.hw_params = msm_tdm_snd_hw_params
-};
 
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm_common_dai_links[] = {
@@ -5676,7 +5531,7 @@
 		.dpcm_playback = 1,
 		.id = MSM_BACKEND_DAI_PRI_TDM_RX_0,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -5690,7 +5545,7 @@
 		.dpcm_capture = 1,
 		.id = MSM_BACKEND_DAI_PRI_TDM_TX_0,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -5704,7 +5559,7 @@
 		.dpcm_playback = 1,
 		.id = MSM_BACKEND_DAI_SEC_TDM_RX_0,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -5718,7 +5573,7 @@
 		.dpcm_capture = 1,
 		.id = MSM_BACKEND_DAI_SEC_TDM_TX_0,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -5732,7 +5587,7 @@
 		.dpcm_playback = 1,
 		.id = MSM_BACKEND_DAI_TERT_TDM_RX_0,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -5746,7 +5601,7 @@
 		.dpcm_capture = 1,
 		.id = MSM_BACKEND_DAI_TERT_TDM_TX_0,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index a91e119..b6a7aa3 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -2894,6 +2894,24 @@
 		goto exit;
 	}
 
+	if (format == ASM_MEDIA_FMT_APTX) {
+		config.param.payload_size =
+			payload_size + sizeof(config.port.sync_mode_param);
+		pr_debug("%s: sending AFE_PARAM_ID_APTX_SYNC_MODE to DSP",
+			__func__);
+		config.pdata.param_id = AFE_PARAM_ID_APTX_SYNC_MODE;
+		config.pdata.param_size = sizeof(config.port.sync_mode_param);
+		config.port.sync_mode_param.sync_mode =
+			config.port.enc_blk_param.enc_blk_config.aptx_config.
+				aptx_v2_cfg.sync_mode;
+		ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+		if (ret) {
+			pr_err("%s: AFE_PARAM_ID_APTX_SYNC_MODE for port 0x%x failed %d\n",
+				__func__, port_id, ret);
+			goto exit;
+		}
+	}
+
 	config.param.payload_size =
 			payload_size + sizeof(config.port.enc_pkt_id_param);
 	pr_debug("%s:sending AFE_ENCODER_PARAM_ID_PACKETIZER to DSP payload = %d",
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index df635cc..be56d74 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -3074,6 +3074,16 @@
 	u32		topology_id;
 } __packed;
 
+#define AFE_PARAM_ID_APTX_SYNC_MODE  0x00013205
+
+struct afe_param_id_aptx_sync_mode {
+	/*
+	 * sync mode: 0x0 = stereo sync mode (default)
+	 *            0x01 = dual mono sync mode
+	 *            0x02 = dual mono with no sync on either L or R
+	 */
+	uint32_t     sync_mode;
+} __packed;
 
 /*
  * Generic encoder module ID.
@@ -3305,6 +3315,21 @@
 	uint8_t     channel_mapping[8];
 	uint32_t    custom_size;
 } __packed;
+
+struct asm_aptx_v2_enc_cfg_ext_t {
+	/*
+	 * sync mode: 0x0 = stereo sync mode (default)
+	 *            0x01 = dual mono sync mode
+	 *            0x02 = dual mono with no sync on either L or R
+	 */
+	uint32_t     sync_mode;
+} __packed;
+
+struct asm_aptx_enc_cfg_t {
+	struct asm_custom_enc_cfg_t custom_cfg;
+	struct asm_aptx_v2_enc_cfg_ext_t aptx_v2_cfg;
+} __packed;
+
 #define ASM_MEDIA_FMT_CELT 0x00013221
 struct asm_celt_specific_enc_cfg_t {
 	/*
@@ -3421,6 +3446,7 @@
 	struct asm_aac_enc_cfg_v2_t aac_config;
 	struct asm_custom_enc_cfg_t  custom_config;
 	struct asm_celt_enc_cfg_t  celt_config;
+	struct asm_aptx_enc_cfg_t  aptx_config;
 };
 
 struct afe_enc_config {
@@ -3461,6 +3487,7 @@
 	struct afe_param_id_set_topology_cfg      topology;
 	struct afe_param_id_tdm_cfg               tdm;
 	struct afe_param_id_usb_audio_cfg         usb_audio;
+	struct afe_param_id_aptx_sync_mode        sync_mode_param;
 	struct afe_enc_fmt_id_param_t             enc_fmt;
 	struct afe_port_media_type_t              media_type;
 	struct afe_enc_cfg_blk_param_t            enc_blk_param;
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index 1e7ead8..07a582e 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -81,7 +81,7 @@
  * @function: See lpi_gpio_functions[]
  */
 struct lpi_gpio_pad {
-	u16		offset;
+	u32		offset;
 	bool		output_enabled;
 	bool		value;
 	char __iomem	*base;
@@ -622,6 +622,7 @@
 {
 	struct lpi_gpio_state *state = platform_get_drvdata(pdev);
 
+	audio_notifier_deregister("lpi_tlmm");
 	gpiochip_remove(&state->chip);
 	return 0;
 }