Merge "arm: Add support for CONFIG_ENABLE_DMM" into msm-3.0
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 57bf7ac..2e92bb0 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1691,6 +1691,8 @@
 	&apq_cpudai_auxpcm_rx,
 	&apq_cpudai_auxpcm_tx,
 	&apq_cpudai_stub,
+	&apq_cpudai_slimbus_1_rx,
+	&apq_cpudai_slimbus_1_tx,
 	&apq8064_rpm_device,
 	&apq8064_rpm_log_device,
 	&apq8064_rpm_stat_device,
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 6a3a10c..b660906 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -483,6 +483,16 @@
 	.id = -1,
 };
 
+struct platform_device apq_cpudai_slimbus_1_rx = {
+	.name = "msm-dai-q6",
+	.id = 0x4002,
+};
+
+struct platform_device apq_cpudai_slimbus_1_tx = {
+	.name = "msm-dai-q6",
+	.id = 0x4003,
+};
+
 static struct resource resources_ssbi_pmic1[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 2eb716a..ab55a25 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -243,6 +243,8 @@
 extern struct platform_device apq_cpudai_afe_02_tx;
 extern struct platform_device apq_pcm_afe;
 extern struct platform_device apq_cpudai_stub;
+extern struct platform_device apq_cpudai_slimbus_1_rx;
+extern struct platform_device apq_cpudai_slimbus_1_tx;
 
 extern struct platform_device *msm_footswitch_devices[];
 extern unsigned msm_num_footswitch_devices;
diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c
index cffa5c7..bb29279 100644
--- a/arch/arm/mach-msm/vreg.c
+++ b/arch/arm/mach-msm/vreg.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/vreg.c
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012 Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -132,6 +132,8 @@
 {
 	kfree(vreg->name);
 	regulator_put(vreg->reg);
+	list_del(&vreg->list);
+	kfree(vreg);
 }
 
 int vreg_enable(struct vreg *vreg)
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 5ec2932..288ec6d 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -92,6 +92,7 @@
 	/* synchrnous xfr data */
 	unsigned char sync_xfr_regs[XFR_REG_NUM];
 	struct completion sync_xfr_start;
+	struct completion shutdown_done;
 	struct completion sync_req_done;
 	int tune_req;
 	/* internal register status */
@@ -1073,6 +1074,15 @@
 	tavarua_handle_interrupts(radio);
 }
 
+static void fm_shutdown(struct work_struct *work)
+{
+	struct tavarua_device *radio = container_of(work,
+					struct tavarua_device, work.work);
+	radio->pdata->fm_shutdown(radio->pdata);
+	complete(&radio->shutdown_done);
+}
+
+
 /*************************************************************************
  * irq helper functions
  ************************************************************************/
@@ -1100,9 +1110,6 @@
    * is limited to ten characters; it is only used for generating the "command"
    * for the kernel thread(s) (which can be seen in ps or top).
    */
-	radio->wqueue  = create_singlethread_workqueue("kfmradio");
-	if (!radio->wqueue)
-		return -ENOMEM;
   /* allocate an interrupt line */
   /* On success, request_irq() returns 0 if everything goes  as
      planned.  Your interrupt handler will start receiving its
@@ -1156,10 +1163,8 @@
 		return -EINVAL;
 	irq = radio->pdata->irq;
 	disable_irq_wake(irq);
-	cancel_delayed_work_sync(&radio->work);
 	flush_workqueue(radio->wqueue);
 	free_irq(irq, radio);
-	destroy_workqueue(radio->wqueue);
 	return 0;
 }
 
@@ -1805,6 +1810,7 @@
 	char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
 	int bahama_present = -ENODEV;
 
+	INIT_DELAYED_WORK(&radio->work, read_int_stat);
 	if (!atomic_dec_and_test(&radio->users)) {
 		pr_err("%s: Device already in use."
 			"Try again later", __func__);
@@ -2048,11 +2054,15 @@
 		return retval;
 	}
 
+	init_completion(&radio->shutdown_done);
+
 	bahama_present = is_bahama();
 
 	if (bahama_present == -ENODEV)
 		return -ENODEV;
 
+	INIT_DELAYED_WORK(&radio->work, fm_shutdown);
+
 	if (bahama_present)	{
 		/*Write first sequence of bytes to FM_CTL0*/
 		for (i = 0; i < 1; i++) {
@@ -2131,15 +2141,17 @@
 	}
 exit:
 	FMDBG("%s, Calling fm_shutdown\n", __func__);
+	queue_delayed_work(radio->wqueue, &radio->work,
+				msecs_to_jiffies(TAVARUA_DELAY/2));
 	/* teardown gpio and pmic */
-
 	marimba_set_fm_status(radio->marimba, false);
-	radio->pdata->fm_shutdown(radio->pdata);
+	wait_for_completion(&radio->shutdown_done);
 	if (radio->pdata->config_i2s_gpio != NULL)
 		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
 	radio->handle_irq = 1;
 	atomic_inc(&radio->users);
 	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+	flush_workqueue(radio->wqueue);
 	return retval;
 }
 
@@ -4028,7 +4040,9 @@
 	video_set_drvdata(radio->videodev, radio);
     /*Start the worker thread for event handling and register read_int_stat
 	as worker function*/
-	INIT_DELAYED_WORK(&radio->work, read_int_stat);
+	radio->wqueue  = create_singlethread_workqueue("kfmradio");
+	if (!radio->wqueue)
+		return -ENOMEM;
 
 	/* register video device */
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
@@ -4068,6 +4082,8 @@
 	/* disable irq */
 	tavarua_disable_irq(radio);
 
+	destroy_workqueue(radio->wqueue);
+
 	video_unregister_device(radio->videodev);
 
 	/* free internal buffers */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 097ba39..85da871 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -61,6 +61,7 @@
 #define RT_PROXY_PORT_001_TX	0x2001    /* index = 31 */
 
 #define AFE_PORT_INVALID 0xFFFF
+#define SLIMBUS_INVALID AFE_PORT_INVALID
 
 #define AFE_PORT_CMD_START 0x000100ca
 
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index a97bf87..cca0abc 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -58,6 +58,16 @@
 #define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+	SLIM_2_RX_1 = 147, /* HDMI RX */
+	SLIM_3_RX_1 = 148, /* In-call recording RX */
+	SLIM_3_RX_2 = 149, /* In-call recording RX */
+	SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
 static int msm_spk_control;
@@ -743,6 +753,42 @@
 	return 0;
 }
 
+static int msm_slimbus_1_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;
+	unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
+			__func__, rx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
+			__func__, tx_ch);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	}
+
+end:
+	return ret;
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -926,6 +972,7 @@
 
 	return 0;
 }
+
 static int msm_aux_pcm_get_gpios(void)
 {
 	int ret = 0;
@@ -1025,6 +1072,12 @@
 	.shutdown = msm_auxpcm_shutdown,
 };
 
+static struct snd_soc_ops msm_slimbus_1_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_1_hw_params,
+	.shutdown = msm_shutdown,
+};
+
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm_dai[] = {
 	/* FrontEnd DAI Links */
@@ -1125,7 +1178,7 @@
 		.dsp_link = &fe_media,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
-		/* .be_id = do not care */
+		.be_id = MSM_FRONTEND_DAI_VOICE_STUB,
 	},
 	/* Backend DAI Links */
 	{
@@ -1284,6 +1337,31 @@
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm_be_ops,
 	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup =  msm_btsco_be_hw_params_fixup,
+		.ops = &msm_slimbus_1_be_ops,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm = {
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 3d1cea0..cd2d807 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -216,7 +216,6 @@
 	dai_data->channels = params_channels(params);
 	dai_data->rate = params_rate(params);
 
-	dai_data->port_config.slimbus.slimbus_dev_id =  AFE_SLIMBUS_DEVICE_1;
 	/* Q6 only supports 16 as now */
 	dai_data->port_config.slim_sch.bit_width = 16;
 	dai_data->port_config.slim_sch.data_format = 0;
@@ -350,7 +349,9 @@
 		rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
 		break;
 	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
 		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
 				substream->stream);
 		break;
@@ -763,9 +764,11 @@
 							dai->id);
 	switch (dai->id) {
 	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
 		/* channel number to be between 128 and 255. For RX port
 		 * use channel numbers from 138 to 144, for TX port
 		 * use channel numbers from 128 to 137
+		 * For ports between MDM-APQ use channel numbers from 145
 		 */
 		if (!rx_slot)
 			return -EINVAL;
@@ -783,9 +786,11 @@
 
 		break;
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
 		/* channel number to be between 128 and 255. For RX port
 		 * use channel numbers from 138 to 144, for TX port
 		 * use channel numbers from 128 to 137
+		 * For ports between MDM-APQ use channel numbers from 145
 		 */
 		if (!tx_slot)
 			return -EINVAL;
@@ -1041,6 +1046,34 @@
 	.remove = msm_dai_q6_dai_probe,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_min = 8000,
+		.rate_max = 16000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_min = 8000,
+		.rate_max = 16000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 /* To do: change to register DAIs as batch */
 static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
 {
@@ -1075,6 +1108,16 @@
 	case SLIMBUS_0_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_tx_dai);
+		break;
+
+	case SLIMBUS_1_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_1_rx_dai);
+		break;
+	case SLIMBUS_1_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_1_tx_dai);
+		break;
 	case INT_BT_SCO_RX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					&msm_dai_q6_bt_sco_rx_dai);
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4f19160..bce1455 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -120,6 +120,9 @@
 	{ VOICE_RECORD_TX, 0, NULL, 0, 0},
 	{ MI2S_RX, 0, NULL, 0, 0},
 	{ SECONDARY_I2S_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_1_RX, 0, NULL, 0, 0},
+	{ SLIMBUS_1_TX, 0, NULL, 0, 0},
+	{ SLIMBUS_INVALID, 0, NULL, 0, 0},
 };
 
 
@@ -167,7 +170,7 @@
 
 	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
 		/* bad ID assigned in machine driver */
-		pr_err("%s: bad MM ID\n", __func__);
+		pr_err("%s: bad MM ID %d\n", __func__, fedai_id);
 		return;
 	}
 
@@ -470,6 +473,55 @@
 	return 1;
 }
 
+static int msm_routing_get_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	mutex_lock(&routing_lock);
+
+	if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	mutex_unlock(&routing_lock);
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (ucontrol->value.integer.value[0]) {
+		mutex_lock(&routing_lock);
+		set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		mutex_unlock(&routing_lock);
+
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else {
+		mutex_lock(&routing_lock);
+		clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions);
+		mutex_unlock(&routing_lock);
+
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+		ucontrol->value.integer.value[0]);
+
+	return 1;
+}
+
 static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -911,6 +963,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -920,6 +975,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -929,6 +987,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -940,6 +1001,18 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INVALID,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
 static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -976,6 +1049,18 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
+	SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_INVALID,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -997,6 +1082,18 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new fm_switch_mixer_controls =
 	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
 	0, 1, 0, msm_routing_get_switch_mixer,
@@ -1253,6 +1350,8 @@
 	SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
 
 	/* Switch Definitions */
 	SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1318,12 +1417,24 @@
 	int_fm_rx_mixer_controls, ARRAY_SIZE(int_fm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AFE_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	afe_pcm_rx_mixer_controls, ARRAY_SIZE(afe_pcm_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voice Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+	tx_voice_stub_mixer_controls, ARRAY_SIZE(tx_voice_stub_mixer_controls)),
+	SND_SOC_DAPM_MIXER("STUB_RX Mixer", SND_SOC_NOPM, 0, 0,
+	stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
+	slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
 	ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUXPCM_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, auxpcm_rx_port_mixer_controls,
 	ARRAY_SIZE(auxpcm_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	sbus_1_rx_port_mixer_controls,
+	ARRAY_SIZE(sbus_1_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+	bt_sco_rx_port_mixer_controls,
+	ARRAY_SIZE(bt_sco_rx_port_mixer_controls)),
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -1457,8 +1568,22 @@
 	{"AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_RX Port Mixer"},
-	{"STUB_RX", NULL, "VOICE_STUB_DL"},
-	{"VOICE_STUB_UL", NULL, "STUB_TX"},
+
+	{"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+	{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
+
+	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"STUB_RX", NULL, "STUB_RX Mixer"},
+	{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+
+	{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
+	{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
 };
 
 static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 9515ab3..423ff5f 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -34,6 +34,8 @@
 #define LPASS_BE_MI2S_RX "(Backend) MI2S_RX"
 #define LPASS_BE_STUB_RX "(Backend) STUB_RX"
 #define LPASS_BE_STUB_TX "(Backend) STUB_TX"
+#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
+#define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
 
 /* For multimedia front-ends, asm session is allocated dynamically.
  * Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -50,6 +52,7 @@
 	MSM_FRONTEND_DAI_VOIP,
 	MSM_FRONTEND_DAI_AFE_RX,
 	MSM_FRONTEND_DAI_AFE_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_MAX,
 };
 
@@ -75,6 +78,9 @@
 	MSM_BACKEND_DAI_INCALL_RECORD_TX,
 	MSM_BACKEND_DAI_MI2S_RX,
 	MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_RX,
+	MSM_BACKEND_DAI_SLIMBUS_1_TX,
+	MSM_BACKEND_DAI_INVALID,
 	MSM_BACKEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index be08e25..bac432d 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -145,6 +145,7 @@
 	case MI2S_RX:
 	case HDMI_RX:
 	case SLIMBUS_0_RX:
+	case SLIMBUS_1_RX:
 	case INT_BT_SCO_RX:
 	case INT_BT_A2DP_RX:
 	case INT_FM_RX:
@@ -160,6 +161,7 @@
 	case DIGI_MIC_TX:
 	case VOICE_RECORD_TX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_TX:
 	case INT_FM_TX:
 	case VOICE_RECORD_RX:
 	case INT_BT_SCO_TX:
@@ -168,7 +170,7 @@
 		break;
 
 	default:
-		pr_err("%s: invalid port id\n", __func__);
+		pr_err("%s: invalid port id %d\n", __func__, port_id);
 		ret = -EINVAL;
 	}
 
@@ -197,6 +199,8 @@
 	case VOICE_PLAYBACK_TX:
 	case SLIMBUS_0_RX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
 	case INT_BT_SCO_RX:
 	case INT_BT_SCO_TX:
 	case INT_BT_A2DP_RX:
@@ -257,6 +261,8 @@
 	case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
 	case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
 	case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+	case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
+	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
 	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -286,6 +292,8 @@
 		break;
 	case SLIMBUS_0_RX:
 	case SLIMBUS_0_TX:
+	case SLIMBUS_1_RX:
+	case SLIMBUS_1_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
 		break;
 	case RT_PROXY_PORT_001_RX: