Merge "ASoC: mdm9615: Add support for secondary I2S"
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index ed5e2b7..b9da615 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -910,6 +910,8 @@
 	&msm_voip,
 	&msm_i2s_cpudai0,
 	&msm_i2s_cpudai1,
+	&msm_i2s_cpudai4,
+	&msm_i2s_cpudai5,
 	&msm_pcm_hostless,
 	&msm_cpudai_afe_01_rx,
 	&msm_cpudai_afe_01_tx,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 8e8fa83..fe3a4d5 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -571,6 +571,15 @@
 	.name   = "msm-dai-q6",
 	.id     = PRIMARY_I2S_TX,
 };
+struct platform_device msm_i2s_cpudai4 = {
+	.name   = "msm-dai-q6",
+	.id     = SECONDARY_I2S_RX,
+};
+
+struct platform_device msm_i2s_cpudai5 = {
+	.name   = "msm-dai-q6",
+	.id     = SECONDARY_I2S_TX,
+};
 struct platform_device msm_voip = {
 	.name	= "msm-voip-dsp",
 	.id	= -1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 950a1be..8f02050 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -244,7 +244,8 @@
 extern struct platform_device msm_cpudai_incall_record_tx;
 extern struct platform_device msm_i2s_cpudai0;
 extern struct platform_device msm_i2s_cpudai1;
-
+extern struct platform_device msm_i2s_cpudai4;
+extern struct platform_device msm_i2s_cpudai5;
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
 extern struct platform_device msm_pil_tzapps;
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 1000a8b..57b846c 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, 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
@@ -89,6 +89,20 @@
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting audio_sec_i2s[] = {
+	/* Suspend state */
+	{
+		.func = GPIOMUX_FUNC_GPIO,
+		.drv  = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_2,
+		.drv  = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	}
+};
 
 static struct gpiomux_setting cdc_i2s_dout = {
 	.func = GPIOMUX_FUNC_1,
@@ -142,6 +156,42 @@
 	},
 };
 
+static struct msm_gpiomux_config msm9615_audio_sec_i2s_codec_configs[] = {
+	{
+		.gpio = GPIO_SPKR_I2S_MCLK,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_i2s_mclk,
+		},
+	},
+	{
+		.gpio = GPIO_SEC_I2S_SCK,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_sec_i2s[0],
+			[GPIOMUX_ACTIVE] = &audio_sec_i2s[1],
+		},
+	},
+	{
+		.gpio = GPIO_SEC_I2S_DOUT,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_sec_i2s[0],
+			[GPIOMUX_ACTIVE] = &audio_sec_i2s[1],
+		},
+	},
+	{
+		.gpio = GPIO_SEC_I2S_WS,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_sec_i2s[0],
+			[GPIOMUX_ACTIVE] = &audio_sec_i2s[1],
+		},
+	},
+	{
+		.gpio = GPIO_SEC_I2S_DIN,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_sec_i2s[0],
+			[GPIOMUX_ACTIVE] = &audio_sec_i2s[1],
+		},
+	},
+};
 /* Physical address for LPA CSR
  * LPA SIF mux registers. These are
  * ioremap( ) for Virtual address.
@@ -274,6 +324,9 @@
 static struct platform_device *mdm9615_snd_device_slim;
 static struct platform_device *mdm9615_snd_device_i2s;
 
+static u32 sif_reg_value   = 0x0000;
+static u32 spare_reg_value = 0x0000;
+
 static bool hs_detect_use_gpio;
 module_param(hs_detect_use_gpio, bool, 0444);
 MODULE_PARM_DESC(hs_detect_use_gpio, "Use GPIO for headset detection");
@@ -947,6 +1000,10 @@
 		     msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
 	SOC_ENUM_EXT("PRI_TX Channels", mdm9615_enum[2],
 		     msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
+	SOC_ENUM_EXT("SEC_RX Channels", mdm9615_enum[3],
+			msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
+	SOC_ENUM_EXT("SEC_TX Channels", mdm9615_enum[4],
+			msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
 };
 
 static int msm9615_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -1234,47 +1291,64 @@
 	return ret;
 }
 
-static void msm9615_config_i2s_sif_mux(u8 value)
+static void msm9615_config_i2s_sif_mux(u8 value, u8 i2s_intf)
 {
 	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
-	u32 sif_shadow  = 0x0000;
-	/* Make this variable global if both secondary and
-	 * primary needs to be supported. This is required
-	 * to retain bits in interace and set only specific
-	 * bits in the register. Also set Sec Intf bits.
-	 * Secondary interface bits are 0,1.
-	 **/
-	sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
-		     (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
+	u32 sif_shadow = 0x0000;
+
+	pr_debug("%s() Value = 0x%x intf = 0x%x\n", __func__, value, i2s_intf);
+	if (i2s_intf == MSM_INTF_PRIM) {
+		sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
+			     (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
+		pr_debug("%s() Sif shadow = 0x%x\n", __func__, sif_shadow);
+		sif_reg_value =
+			((sif_reg_value & LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK) |
+			 sif_shadow);
+	}
+	if (i2s_intf == MSM_INTF_SECN) {
+		sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK) |
+				(value << LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT);
+		pr_debug("%s() Sif shadow = 0x%x\n", __func__, sif_shadow);
+		sif_reg_value =
+			((sif_reg_value & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
+			sif_shadow);
+	}
 	if (pintf->sif_virt_addr != NULL)
-		iowrite32(sif_shadow, pintf->sif_virt_addr);
+		iowrite32(sif_reg_value, pintf->sif_virt_addr);
 	/* Dont read SIF register. Device crashes. */
-	pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+	pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_reg_value);
 }
 
 static void msm9615_config_i2s_spare_mux(u8 value, u8 i2s_intf)
 {
 	struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
 	u32 spare_shadow = 0x0000;
-	/* Make this variable global if both secondary and
-	 * primary needs to be supported. This is required
-	 * to retain bits in interace and set only specific
-	 * bits in the register. Also set Sec Intf bits.
-	 **/
+
+	pr_debug("%s() Value = 0x%x intf = 0x%x\n", __func__, value, i2s_intf);
 	if (i2s_intf == MSM_INTF_PRIM) {
 		/* Configure Primary SIF */
-	    spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK
-			   ) | (value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
+		spare_shadow =
+			(spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK) |
+			(value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
+		pr_debug("%s() Spare shadow = 0x%x\n", __func__, spare_shadow);
+		spare_reg_value =
+			((spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK) |
+			spare_shadow);
 	}
 	if (i2s_intf == MSM_INTF_SECN) {
 		/*Secondary interface configuration*/
-	    spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK
-			   ) | (value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
+		spare_shadow =
+			(spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK) |
+			(value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
+		pr_debug("%s() Spare shadow = 0x%x\n", __func__, spare_shadow);
+		spare_reg_value =
+			((spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK) |
+			spare_shadow);
 	}
 	if (pintf->spare_virt_addr != NULL)
-		iowrite32(spare_shadow, pintf->spare_virt_addr);
+		iowrite32(spare_reg_value, pintf->spare_virt_addr);
 	/* Dont read SPARE register. Device crashes. */
-	pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_shadow);
+	pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_reg_value);
 }
 
 static int msm9615_i2s_hw_params(struct snd_pcm_substream *substream,
@@ -1342,7 +1416,8 @@
 					return -EINVAL;
 				}
 				msm9615_config_i2s_sif_mux(
-				       pintf->mux_ctl[MSM_DIR_BOTH].sifconfig);
+				       pintf->mux_ctl[MSM_DIR_BOTH].sifconfig,
+					i2s_intf);
 				msm9615_config_i2s_spare_mux(
 				      pintf->mux_ctl[MSM_DIR_BOTH].spareconfig,
 				      i2s_intf);
@@ -1368,7 +1443,8 @@
 					return -EINVAL;
 				}
 				msm9615_config_i2s_sif_mux(
-					pintf->mux_ctl[MSM_DIR_TX].sifconfig);
+					pintf->mux_ctl[MSM_DIR_TX].sifconfig,
+					i2s_intf);
 				msm9615_config_i2s_spare_mux(
 					pintf->mux_ctl[MSM_DIR_TX].spareconfig,
 					i2s_intf);
@@ -1397,7 +1473,8 @@
 					return -EINVAL;
 				}
 				msm9615_config_i2s_sif_mux(
-					pintf->mux_ctl[MSM_DIR_RX].sifconfig);
+					pintf->mux_ctl[MSM_DIR_RX].sifconfig,
+					i2s_intf);
 				msm9615_config_i2s_spare_mux(
 					pintf->mux_ctl[MSM_DIR_RX].spareconfig,
 					i2s_intf);
@@ -1451,11 +1528,34 @@
 		 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
 }
 
-static void  mdm9615_install_codec_i2s_gpio(void)
+void msm9615_config_port_select(void)
 {
-	msm_gpiomux_install(msm9615_audio_prim_i2s_codec_configs,
-			ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
+	iowrite32(SEC_PCM_PORT_SLC_VALUE, secpcm_portslc_virt_addr);
+	pr_debug("%s() port select after updating = 0x%x\n",
+		__func__, ioread32(secpcm_portslc_virt_addr));
 }
+static void  mdm9615_install_codec_i2s_gpio(struct snd_pcm_substream *substream)
+{
+	u8 i2s_intf, i2s_dir;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+		pr_debug("%s( ): cpu name = %s intf =%d dir = %d\n",
+			 __func__, cpu_dai->name, i2s_intf, i2s_dir);
+		if (i2s_intf == MSM_INTF_PRIM) {
+			msm_gpiomux_install(
+			msm9615_audio_prim_i2s_codec_configs,
+			ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
+		} else if (i2s_intf == MSM_INTF_SECN) {
+			msm_gpiomux_install(msm9615_audio_sec_i2s_codec_configs,
+			ARRAY_SIZE(msm9615_audio_sec_i2s_codec_configs));
+			msm9615_config_port_select();
+
+		}
+	}
+}
+
 static int msm9615_i2s_prepare(struct snd_pcm_substream *substream)
 {
 	u8 ret = 0;
@@ -1463,7 +1563,7 @@
 	if (wcd9xxx_get_intf_type() < 0)
 		ret = -ENODEV;
 	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-		mdm9615_install_codec_i2s_gpio();
+		mdm9615_install_codec_i2s_gpio(substream);
 
 	return ret;
 }
@@ -1734,15 +1834,6 @@
 	pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
 }
 
-void msm9615_config_port_select(void)
-{
-	pr_debug("%s() port select defualt = 0x%x\n",
-		 __func__, ioread32(secpcm_portslc_virt_addr));
-	iowrite32(SEC_PCM_PORT_SLC_VALUE, secpcm_portslc_virt_addr);
-	pr_debug("%s() port select after updating = 0x%x\n",
-		 __func__, ioread32(secpcm_portslc_virt_addr));
-}
-
 static int mdm9615_auxpcm_startup(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
@@ -2049,6 +2140,30 @@
 		.be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
 		.ops = &msm9615_i2s_be_ops,
 	},
+	{
+		.name = LPASS_BE_SEC_I2S_RX,
+		.stream_name = "Secondary I2S Playback",
+		.cpu_dai_name = "msm-dai-q6.4",
+		.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_SEC_I2S_RX,
+		.be_hw_params_fixup = msm9615_i2s_rx_be_hw_params_fixup,
+		.ops = &msm9615_i2s_be_ops,
+	},
+	{
+		.name = LPASS_BE_SEC_I2S_TX,
+		.stream_name = "Secondary I2S Capture",
+		.cpu_dai_name = "msm-dai-q6.5",
+		.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_SEC_I2S_TX,
+		.be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
+		.ops = &msm9615_i2s_be_ops,
+	},
 };
 
 static struct snd_soc_dai_link mdm9615_dai_slimbus_tabla[] = {
@@ -2097,8 +2212,8 @@
 	},
 	[1] = {
 		.name = "mdm9615-tabla-snd-card-i2s",
-		.controls = tabla_mdm9615_controls,
-		.num_controls = ARRAY_SIZE(tabla_mdm9615_controls),
+		.controls = tabla_msm9615_i2s_controls,
+		.num_controls = ARRAY_SIZE(tabla_msm9615_i2s_controls),
 	},
 };
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index ee1ab79..18c2329 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -674,6 +674,7 @@
 	case PRIMARY_I2S_TX:
 	case PRIMARY_I2S_RX:
 	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
 		rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
 		break;
 
@@ -1379,6 +1380,7 @@
 	case PRIMARY_I2S_TX:
 	case PRIMARY_I2S_RX:
 	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
 		rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
 		break;
 	default:
@@ -1831,6 +1833,7 @@
 		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
 		break;
 	case PRIMARY_I2S_TX:
+	case SECONDARY_I2S_TX:
 		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
 		break;
 	case PCM_RX:
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index f28d01a..5967bb2 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -183,6 +183,7 @@
 	{ MI2S_RX, 0, 0, 0, 0, 0},
 	{ MI2S_TX, 0, 0, 0, 0},
 	{ SECONDARY_I2S_RX, 0, 0, 0, 0, 0},
+	{ SECONDARY_I2S_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_1_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_1_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_4_RX, 0, 0, 0, 0, 0},
@@ -1417,6 +1418,9 @@
 	SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TX", MSM_BACKEND_DAI_SEC_I2S_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
@@ -1661,6 +1665,9 @@
 	SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_TX_Voice", MSM_BACKEND_DAI_SEC_I2S_TX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("MI2S_TX_Voice", MSM_BACKEND_DAI_MI2S_TX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -1685,6 +1692,9 @@
 	SOC_SINGLE_EXT("PRI_TX_VoLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_TX_VoLTE", MSM_BACKEND_DAI_SEC_I2S_TX,
+	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("SLIM_0_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_TX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -1706,6 +1716,9 @@
 	SOC_SINGLE_EXT("PRI_TX_SGLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_TX_SGLTE", MSM_BACKEND_DAI_SEC_I2S_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("MI2S_TX_SGLTE", MSM_BACKEND_DAI_MI2S_TX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -1729,6 +1742,9 @@
 	SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_TX_Voip", MSM_BACKEND_DAI_SEC_I2S_TX,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("MI2S_TX_Voip", MSM_BACKEND_DAI_MI2S_TX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -1771,6 +1787,9 @@
 	SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SECONDARY_I2S_TX", MSM_BACKEND_DAI_SEC_I2S_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
@@ -2206,6 +2225,7 @@
 	SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
 	SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_I2S_TX", "Secondary I2S Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
@@ -2442,6 +2462,7 @@
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
+	{"MultiMedia1 Mixer", "SEC_TX", "SEC_I2S_TX"},
 	{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia4 Mixer", "MI2S_TX", "MI2S_TX"},
@@ -2547,6 +2568,7 @@
 	{"HDMI", NULL, "HDMI_DL_HL"},
 
 	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+	{"Voice_Tx Mixer", "SEC_TX_Voice", "SEC_I2S_TX"},
 	{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
 	{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
 	{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
@@ -2555,6 +2577,7 @@
 	{"Voice_Tx Mixer", "SEC_AUX_PCM_TX_Voice", "SEC_AUX_PCM_TX"},
 	{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
 	{"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
+	{"VoLTE_Tx Mixer", "SEC_TX_VoLTE", "SEC_I2S_TX"},
 	{"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
 	{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
 	{"VoLTE_Tx Mixer", "AFE_PCM_TX_VoLTE", "PCM_TX"},
@@ -2562,6 +2585,7 @@
 	{"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
 	{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
 	{"SGLTE_Tx Mixer", "PRI_TX_SGLTE", "PRI_I2S_TX"},
+	{"SGLTE_Tx Mixer", "SEC_TX_SGLTE", "SEC_I2S_TX"},
 	{"SGLTE_Tx Mixer", "MI2S_TX_SGLTE", "MI2S_TX"},
 	{"SGLTE_Tx Mixer", "SLIM_0_TX_SGLTE", "SLIMBUS_0_TX"},
 	{"SGLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_SGLTE", "INT_BT_SCO_TX"},
@@ -2570,6 +2594,7 @@
 	{"SGLTE_Tx Mixer", "SEC_AUX_PCM_TX_SGLTE", "SEC_AUX_PCM_TX"},
 	{"SGLTE_UL", NULL, "SGLTE_Tx Mixer"},
 	{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
+	{"Voip_Tx Mixer", "SEC_TX_Voip", "SEC_I2S_TX"},
 	{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
 	{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
 	{"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
@@ -2609,6 +2634,7 @@
 	{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
 	{"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
 	{"Voice Stub Tx Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
+	{"Voice Stub Tx Mixer", "SECONDARY_I2S_TX", "SEC_I2S_TX"},
 	{"Voice Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
 
@@ -2661,6 +2687,7 @@
 	{"BE_OUT", NULL, "HDMI"},
 	{"BE_OUT", NULL, "MI2S_RX"},
 	{"PRI_I2S_TX", NULL, "BE_IN"},
+	{"SEC_I2S_TX", NULL, "BE_IN"},
 	{"MI2S_TX", NULL, "BE_IN"},
 	{"SLIMBUS_0_TX", NULL, "BE_IN" },
 	{"SLIMBUS_1_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 14f330b..e11133e 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -32,6 +32,7 @@
 #define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_TX"
 #define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_RX"
 #define LPASS_BE_SEC_I2S_RX "SECONDARY_I2S_RX"
+#define LPASS_BE_SEC_I2S_TX "SECONDARY_I2S_TX"
 
 #define LPASS_BE_MI2S_RX "MI2S_RX"
 #define LPASS_BE_MI2S_TX "MI2S_TX"
@@ -93,6 +94,7 @@
 	MSM_BACKEND_DAI_MI2S_RX,
 	MSM_BACKEND_DAI_MI2S_TX,
 	MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_BACKEND_DAI_SEC_I2S_TX,
 	MSM_BACKEND_DAI_SLIMBUS_1_RX,
 	MSM_BACKEND_DAI_SLIMBUS_1_TX,
 	MSM_BACKEND_DAI_SLIMBUS_4_RX,