Merge "ASoC: msm8974: Adding support for AUXPCM"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 032c814..3d022a3 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -97,25 +97,42 @@
 
  - compatible :                           "qcom,msm-auxpcm-resource"
 
- - qcom,msm-cpudai-auxpcm-clk:            clock for auxpcm
+ - qcom,msm-cpudai-auxpcm-clk:            clock for auxpcm. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
 
- - qcom,msm-cpudai-auxpcm-mode:           mode information
+ - qcom,msm-cpudai-auxpcm-mode:           mode information. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
                                           0 - for PCM
 
- - qcom,msm-cpudai-auxpcm-sync:           sync information
+ - qcom,msm-cpudai-auxpcm-sync:           sync information. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
 
- - qcom,msm-cpudai-auxpcm-frame:          No.of bytes per frame
+ - qcom,msm-cpudai-auxpcm-frame:          No.of bytes per frame. The first
+                                          value is for 8khz mode, the second
+                                          is for 16khz
                                           5 - 256BPF
+                                          4 - 128BPF
 
- - qcom,msm-cpudai-auxpcm-quant:          Type of quantization
+ - qcom,msm-cpudai-auxpcm-quant:          Type of quantization. The first
+                                          value is for 8khz mode, the second
+                                          is for 16khz
                                           2 - Linear quantization
 
  - qcom,msm-cpudai-auxpcm-slot:           Slot number for multichannel scenario
+                                          The first value is for 8khz mode the
+                                          second is for 16khz
                                           Value is 1
 
- - qcom,msm-cpudai-auxpcm-data:           Data field - 0
+ - qcom,msm-cpudai-auxpcm-data:           Data field - 0. The first value is
+                                          for 8khz mode, the second is for
+                                          16khz
 
- - qcom,msm-cpudai-auxpcm-pcm-clk-rate:   Clock rate for pcm - 2048000
+ - qcom,msm-cpudai-auxpcm-pcm-clk-rate:   Clock rate for pcm - 2048000. The
+                                          first value is for 8khz mode, the
+                                          second is for auxpcm
 
 [Second Level Nodes]
 
@@ -302,13 +319,13 @@
         qcom,msm-auxpcm {
                 compatible = "qcom,msm-auxpcm-resource";
                 qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
-                qcom,msm-cpudai-auxpcm-mode = <0>;
-                qcom,msm-cpudai-auxpcm-sync = <1>;
-                qcom,msm-cpudai-auxpcm-frame = <5>;
-                qcom,msm-cpudai-auxpcm-quant = <2>;
-                qcom,msm-cpudai-auxpcm-slot = <1>;
-                qcom,msm-cpudai-auxpcm-data = <0>;
-                qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+                qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+                qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+                qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+                qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+                qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+                qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+                qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
 
                 qcom,msm-auxpcm-rx {
                         qcom,msm-auxpcm-dev-id = <4106>;
@@ -357,6 +374,10 @@
 - taiko-mclk-clk : phandle to PMIC8941 clkdiv1 node.
 - qcom,taiko-mclk-clk-freq : Taiko mclk Freq in Hz. currently only 9600000Hz
 				is supported.
+- prim-auxpcm-gpio-clk : GPIO on which AUXPCM clk signal is coming.
+- prim-auxpcm-gpio-sync : GPIO on which AUXPCM SYNC signal is coming.
+- prim-auxpcm-gpio-din : GPIO on which AUXPCM DIN signal is coming.
+- prim-auxpcm-gpio-dout : GPIO on which AUXPCM DOUT signal is coming.
 
 Optional properties:
 - qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
@@ -401,6 +422,11 @@
 	qcom,taiko-mclk-clk-freq = <9600000>;
 
 	qcom,hdmi-audio-rx;
+
+	prim-auxpcm-gpio-clk  = <&msmgpio 65 0>;
+	prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+	prim-auxpcm-gpio-din  = <&msmgpio 67 0>;
+	prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
 };
 
 * msm-dai-mi2s
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b673526..8838953 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -431,6 +431,10 @@
 		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
 		taiko-mclk-clk = <&pm8941_clkdiv1>;
 		qcom,taiko-mclk-clk-freq = <9600000>;
+		prim-auxpcm-gpio-clk  = <&msmgpio 65 0>;
+		prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+		prim-auxpcm-gpio-din  = <&msmgpio 67 0>;
+		prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
 	};
 
 	spmi_bus: qcom,spmi@fc4c0000 {
@@ -823,13 +827,13 @@
 	qcom,msm-auxpcm {
 		compatible = "qcom,msm-auxpcm-resource";
 		qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
-		qcom,msm-cpudai-auxpcm-mode = <0>;
-		qcom,msm-cpudai-auxpcm-sync = <1>;
-		qcom,msm-cpudai-auxpcm-frame = <5>;
-		qcom,msm-cpudai-auxpcm-quant = <2>;
-		qcom,msm-cpudai-auxpcm-slot = <1>;
-		qcom,msm-cpudai-auxpcm-data = <0>;
-		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+		qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+		qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+		qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+		qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+		qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
 
 		qcom,msm-auxpcm-rx {
 			qcom,msm-auxpcm-dev-id = <4106>;
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 6672f49..b1e107d 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -640,6 +640,51 @@
 		},
 	},
 };
+
+static struct gpiomux_setting pri_auxpcm_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct gpiomux_setting pri_auxpcm_sus_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm8974_pri_auxpcm_configs[] __initdata = {
+	{
+		.gpio = 65,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+		},
+	},
+	{
+		.gpio = 66,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+		},
+	},
+	{
+		.gpio = 67,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+		},
+	},
+	{
+		.gpio = 68,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+		},
+	},
+};
+
 static struct msm_gpiomux_config wcnss_5wire_interface[] = {
 	{
 		.gpio = 36,
@@ -902,6 +947,9 @@
 	msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
 	msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_configs));
 
+	msm_gpiomux_install(msm8974_pri_auxpcm_configs,
+				 ARRAY_SIZE(msm8974_pri_auxpcm_configs));
+
 	if (machine_is_msm8974_rumi())
 		msm_gpiomux_install(msm_rumi_blsp_configs,
 				    ARRAY_SIZE(msm_rumi_blsp_configs));
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 435cc7d..ed4e377 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5375,6 +5375,14 @@
 						"msm-dai-q6.4106"),
 	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
 						"msm-dai-q6.4106"),
+	CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
+						"msm-dai-q6.4107"),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
+						"msm-dai-q6.4107"),
+	CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
+						"msm-dai-q6.4107"),
+	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
+						"msm-dai-q6.4107"),
 	CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
 
 	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 4ecd435..c04cbfc 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -26,8 +26,7 @@
 #define MSM_TERT_MI2S 2
 #define MSM_QUAT_MI2S  3
 
-struct msm_dai_auxpcm_pdata {
-	const char *clk;
+struct msm_dai_auxpcm_config {
 	u16 mode;
 	u16 sync;
 	u16 frame;
@@ -40,6 +39,12 @@
 	int pcm_clk_rate;
 };
 
+struct msm_dai_auxpcm_pdata {
+	const char *clk;
+	struct msm_dai_auxpcm_config mode_8k;
+	struct msm_dai_auxpcm_config mode_16k;
+};
+
 struct msm_mi2s_pdata {
 	u16 rx_sd_lines;
 	u16 tx_sd_lines;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 633066f..cc1668e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -28,6 +28,7 @@
 #include <mach/socinfo.h>
 #include <qdsp6v2/msm-pcm-routing-v2.h>
 #include "../codecs/wcd9320.h"
+#include <linux/io.h>
 
 #define DRV_NAME "msm8974-asoc-taiko"
 
@@ -40,15 +41,21 @@
 #define BTSCO_RATE_8KHZ 8000
 #define BTSCO_RATE_16KHZ 16000
 
+static int msm8974_auxpcm_rate = 8000;
 #define LO_1_SPK_AMP	0x1
 #define LO_3_SPK_AMP	0x2
 #define LO_2_SPK_AMP	0x4
 #define LO_4_SPK_AMP	0x8
 
-#define GPIO_AUX_PCM_DOUT 43
-#define GPIO_AUX_PCM_DIN 44
-#define GPIO_AUX_PCM_SYNC 45
-#define GPIO_AUX_PCM_CLK 46
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
 
 #define WCD9XXX_MBHC_DEF_BUTTONS 8
 #define WCD9XXX_MBHC_DEF_RLOADS 5
@@ -57,6 +64,13 @@
 /* It takes about 13ms for Class-D PAs to ramp-up */
 #define EXT_CLASS_D_EN_DELAY 13000
 
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum msm8974_auxpcm_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
 void *def_taiko_mbhc_cal(void);
 static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
 					bool dapm);
@@ -75,11 +89,34 @@
 	.swap_gnd_mic = NULL,
 };
 
+struct msm_auxpcm_gpio {
+	unsigned gpio_no;
+	const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+	struct msm_auxpcm_gpio *pin_data;
+	u32 cnt;
+};
+
 struct msm8974_asoc_mach_data {
 	int mclk_gpio;
 	u32 mclk_freq;
+	struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
 };
 
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX  1
+
+static char *msm_auxpcm_gpio_name[][2] = {
+	{"PRIM_AUXPCM_CLK",       "prim-auxpcm-gpio-clk"},
+	{"PRIM_AUXPCM_SYNC",      "prim-auxpcm-gpio-sync"},
+	{"PRIM_AUXPCM_DIN",       "prim-auxpcm-gpio-din"},
+	{"PRIM_AUXPCM_DOUT",      "prim-auxpcm-gpio-dout"},
+};
+
+void *lpaif_pri_muxsel_virt_addr;
+
 /* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
 enum {
 	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -471,6 +508,30 @@
 	return 0;
 }
 
+static int msm8974_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = msm8974_auxpcm_rate;
+	return 0;
+}
+
+static int msm8974_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm8974_auxpcm_rate = 8000;
+		break;
+	case 1:
+		msm8974_auxpcm_rate = 16000;
+		break;
+	default:
+		msm8974_auxpcm_rate = 8000;
+		break;
+	}
+	return 0;
+}
+
 static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -480,8 +541,7 @@
 	struct snd_interval *channels =
 	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	/* PCM only supports mono output with 8khz sample rate */
-	rate->min = rate->max = 8000;
+	rate->min = rate->max = msm8974_auxpcm_rate;
 	channels->min = channels->max = 1;
 
 	return 0;
@@ -516,59 +576,86 @@
 	return 0;
 }
 
-static int msm_aux_pcm_get_gpios(void)
+static int msm_aux_pcm_get_gpios(struct snd_pcm_substream *substream)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+	struct msm_auxpcm_gpio *pin_data = NULL;
 	int ret = 0;
+	int i;
+	int j;
 
-	pr_debug("%s\n", __func__);
-
-	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
-				__func__, GPIO_AUX_PCM_DOUT);
-		goto fail_dout;
+	if (pdata == NULL) {
+		pr_err("%s: pdata is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
 	}
 
-	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
-				__func__, GPIO_AUX_PCM_DIN);
-		goto fail_din;
+	auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+	if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+		pr_err("%s: Ctrl pointers are NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	pin_data = auxpcm_ctrl->pin_data;
+	for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+		ret = gpio_request(pin_data->gpio_no,
+				pin_data->gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s\n"
+			"ret = %d\n", __func__,
+			pin_data->gpio_no,
+			pin_data->gpio_name,
+			ret);
+		if (ret) {
+			pr_err("%s: Failed to request gpio %d\n",
+				__func__, pin_data->gpio_no);
+			/* Release all GPIOs on failure */
+			for (j = i; j >= 0; j--)
+				gpio_free(pin_data->gpio_no);
+			goto err;
+		}
 	}
 
-	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
-				__func__, GPIO_AUX_PCM_SYNC);
-		goto fail_sync;
-	}
-	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
-				__func__, GPIO_AUX_PCM_CLK);
-		goto fail_clk;
-	}
-
-	return 0;
-
-fail_clk:
-	gpio_free(GPIO_AUX_PCM_SYNC);
-fail_sync:
-	gpio_free(GPIO_AUX_PCM_DIN);
-fail_din:
-	gpio_free(GPIO_AUX_PCM_DOUT);
-fail_dout:
-
+err:
 	return ret;
 }
-static int msm_aux_pcm_free_gpios(void)
-{
-	gpio_free(GPIO_AUX_PCM_DIN);
-	gpio_free(GPIO_AUX_PCM_DOUT);
-	gpio_free(GPIO_AUX_PCM_SYNC);
-	gpio_free(GPIO_AUX_PCM_CLK);
 
-	return 0;
+static int msm_aux_pcm_free_gpios(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+	struct msm_auxpcm_gpio *pin_data = NULL;
+	int ret = 0;
+	int i;
+
+	if (pdata == NULL) {
+		pr_err("%s: pdata is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+	if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+		pr_err("%s: Ctrl pointers are NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	pin_data = auxpcm_ctrl->pin_data;
+	for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+		gpio_free(pin_data->gpio_no);
+		pr_debug("%s: gpio = %d, gpio_name = %s\n",
+			__func__, pin_data->gpio_no,
+			pin_data->gpio_name);
+	}
+err:
+	return ret;
 }
 
 static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
@@ -577,8 +664,16 @@
 
 	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
 		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
-	if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
-		ret = msm_aux_pcm_get_gpios();
+
+	if (atomic_inc_return(&auxpcm_rsc_ref) == 1) {
+		if (lpaif_pri_muxsel_virt_addr != NULL)
+			iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+				lpaif_pri_muxsel_virt_addr);
+		else
+			pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+				 __func__);
+		ret = msm_aux_pcm_get_gpios(substream);
+	}
 	if (ret < 0) {
 		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
 		return -EINVAL;
@@ -592,7 +687,7 @@
 	pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
 		__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
 	if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
-		msm_aux_pcm_free_gpios();
+		msm_aux_pcm_free_gpios(substream);
 }
 static struct snd_soc_ops msm_auxpcm_be_ops = {
 	.startup = msm_auxpcm_startup,
@@ -651,11 +746,13 @@
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8974_get_spk,
-		     msm8974_set_spk),
+			msm8974_set_spk),
 	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
-		     msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+			msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
-		     msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+			msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+	SOC_ENUM_EXT("AUX PCM SampleRate", msm8974_auxpcm_enum[0],
+			msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
 };
 
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -867,6 +964,7 @@
 {
 	pr_debug("%s(): substream = %s stream = %d\n", __func__,
 		 substream->name, substream->stream);
+
 }
 
 static struct snd_soc_ops msm8974_be_ops = {
@@ -1363,6 +1461,69 @@
 	.name		= "msm8974-taiko-snd-card",
 };
 
+static int msm8974_dtparse_auxpcm(struct platform_device *pdev,
+				struct msm8974_asoc_mach_data **pdata)
+{
+	int ret = 0;
+	int i = 0;
+	struct msm_auxpcm_gpio *pin_data = NULL;
+	struct msm_auxpcm_ctrl *ctrl;
+	unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+	enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+	int prim_cnt = 0;
+
+	pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+				sizeof(struct msm_auxpcm_gpio)),
+				GFP_KERNEL);
+	if (!pin_data) {
+		dev_err(&pdev->dev, "No memory for gpio\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+		gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+				msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+				0, &flags);
+
+		if (gpio_no[i] > 0) {
+			pin_data[i].gpio_name =
+				msm_auxpcm_gpio_name[prim_cnt][GPIO_NAME_INDEX];
+			pin_data[i].gpio_no = gpio_no[i];
+			dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+				"0x%x\n", __func__,
+				pin_data[i].gpio_name,
+				pin_data[i].gpio_no);
+			prim_cnt++;
+		} else {
+			dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+				 __func__,
+				msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+				gpio_no[i]);
+			ret = -ENODEV;
+			goto err;
+		}
+	}
+
+	ctrl = devm_kzalloc(&pdev->dev,
+				sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+	if (!ctrl) {
+		dev_err(&pdev->dev, "No memory for gpio\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ctrl->pin_data = pin_data;
+	ctrl->cnt = prim_cnt;
+	(*pdata)->pri_auxpcm_ctrl = ctrl;
+	return ret;
+
+err:
+	if (pin_data)
+		devm_kfree(&pdev->dev, pin_data);
+	return ret;
+}
+
 static int msm8974_prepare_codec_mclk(struct snd_soc_card *card)
 {
 	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
@@ -1413,6 +1574,13 @@
 		goto err;
 	}
 
+	ret = msm8974_dtparse_auxpcm(pdev, &pdata);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, pdata);
@@ -1489,6 +1657,12 @@
 	spdev = pdev;
 	ext_spk_amp_regulator = NULL;
 
+	lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+	if (lpaif_pri_muxsel_virt_addr == NULL) {
+		pr_err("%s Pri muxsel virt addr is null\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
 	return 0;
 err:
 	devm_kfree(&pdev->dev, pdata);
@@ -1506,7 +1680,7 @@
 	gpio_free(pdata->mclk_gpio);
 	if (ext_spk_amp_gpio >= 0)
 		gpio_free(ext_spk_amp_gpio);
-
+	iounmap(lpaif_pri_muxsel_virt_addr);
 	snd_soc_unregister_card(card);
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index a7a80a6..ab92269 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -33,6 +33,12 @@
 	STATUS_MAX
 };
 
+enum {
+	RATE_8KHZ,
+	RATE_16KHZ,
+	RATE_MAX_NUM_OF_AUX_PCM_RATES,
+};
+
 struct msm_dai_q6_dai_data {
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
 	u32 rate;
@@ -92,25 +98,49 @@
 		return -EINVAL;
 	}
 	dai_data->channels = params_channels(params);
-
-	if (params_rate(params) != 8000) {
-		dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
-		return -EINVAL;
-	}
 	dai_data->rate = params_rate(params);
 
-	dai_data->port_config.pcm.pcm_cfg_minor_version =
+	switch (dai_data->rate) {
+	case 8000:
+		dai_data->port_config.pcm.pcm_cfg_minor_version =
 				AFE_API_VERSION_PCM_CONFIG;
-	dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode;
-	dai_data->port_config.pcm.sync_src = auxpcm_pdata->sync;
-	dai_data->port_config.pcm.frame_setting = auxpcm_pdata->frame;
-	dai_data->port_config.pcm.quantype = auxpcm_pdata->quant;
-	dai_data->port_config.pcm.ctrl_data_out_enable = auxpcm_pdata->data;
-	dai_data->port_config.pcm.sample_rate = dai_data->rate;
-	dai_data->port_config.pcm.num_channels = dai_data->channels;
-	dai_data->port_config.pcm.bit_width = 16;
-	dai_data->port_config.pcm.slot_number_mapping[0] = auxpcm_pdata->slot;
-
+		dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode_8k.mode;
+		dai_data->port_config.pcm.sync_src = auxpcm_pdata->mode_8k.sync;
+		dai_data->port_config.pcm.frame_setting =
+					auxpcm_pdata->mode_8k.frame;
+		dai_data->port_config.pcm.quantype =
+					 auxpcm_pdata->mode_8k.quant;
+		dai_data->port_config.pcm.ctrl_data_out_enable =
+					 auxpcm_pdata->mode_8k.data;
+		dai_data->port_config.pcm.sample_rate = dai_data->rate;
+		dai_data->port_config.pcm.num_channels = dai_data->channels;
+		dai_data->port_config.pcm.bit_width = 16;
+		dai_data->port_config.pcm.slot_number_mapping[0] =
+					 auxpcm_pdata->mode_8k.slot;
+		break;
+	case 16000:
+		dai_data->port_config.pcm.pcm_cfg_minor_version =
+				AFE_API_VERSION_PCM_CONFIG;
+		dai_data->port_config.pcm.aux_mode =
+					auxpcm_pdata->mode_16k.mode;
+		dai_data->port_config.pcm.sync_src =
+					auxpcm_pdata->mode_16k.sync;
+		dai_data->port_config.pcm.frame_setting =
+					auxpcm_pdata->mode_16k.frame;
+		dai_data->port_config.pcm.quantype =
+					auxpcm_pdata->mode_16k.quant;
+		dai_data->port_config.pcm.ctrl_data_out_enable =
+					auxpcm_pdata->mode_16k.data;
+		dai_data->port_config.pcm.sample_rate = dai_data->rate;
+		dai_data->port_config.pcm.num_channels = dai_data->channels;
+		dai_data->port_config.pcm.bit_width = 16;
+		dai_data->port_config.pcm.slot_number_mapping[0] =
+					auxpcm_pdata->mode_16k.slot;
+		break;
+	default:
+		dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
+		return -EINVAL;
+	}
 	return 0;
 }
 
@@ -166,6 +196,7 @@
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
 	int rc = 0;
+	unsigned long pcm_clk_rate;
 
 	auxpcm_pdata = dai->dev->platform_data;
 
@@ -210,27 +241,43 @@
 	 * assert/deasset and afe_open sequence is not followed.
 	 */
 
-	rc = clk_set_rate(pcm_src_clk, auxpcm_pdata->pcm_clk_rate);
+	if (dai_data->rate == 8000) {
+		pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+	} else if (dai_data->rate == 16000) {
+		pcm_clk_rate = (auxpcm_pdata->mode_16k.pcm_clk_rate);
+	} else {
+		dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+			dai_data->rate);
+		mutex_unlock(&aux_pcm_mutex);
+		return -EINVAL;
+	}
+
+	rc = clk_set_rate(pcm_src_clk, pcm_clk_rate);
+
 	if (rc < 0) {
 		pr_err("%s: clk_set_rate failed\n", __func__);
+		mutex_unlock(&aux_pcm_mutex);
 		goto fail;
 	}
 
 	rc = clk_prepare_enable(pcm_branch_clk);
 	if (rc) {
 		pr_err("%s: clk enable failed\n", __func__);
+		mutex_unlock(&aux_pcm_mutex);
 		goto fail;
 	}
 
 	rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
 	if (rc < 0) {
 		pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
+		mutex_unlock(&aux_pcm_mutex);
 		goto fail;
 	}
 
 	rc = clk_prepare_enable(pcm_oe_branch_clk);
 	if (rc) {
 		pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
+		mutex_unlock(&aux_pcm_mutex);
 		goto fail;
 	}
 
@@ -1060,7 +1107,7 @@
 {
 	int rc = 0;
 	struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
-	u32 property_val;
+	uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
 
 	auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
 				GFP_KERNEL);
@@ -1078,62 +1125,81 @@
 			__func__);
 		goto fail_free_plat;
 	}
-	rc = of_property_read_u32(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-mode", &property_val);
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,msm-cpudai-auxpcm-mode",
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-mode missing in DT node\n",
 			__func__);
 		goto fail_free_plat;
 	}
-	auxpcm_pdata->mode = (u16)property_val;
-	rc = of_property_read_u32(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-sync", &property_val);
+	auxpcm_pdata->mode_8k.mode = (u16)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.mode = (u16)val_array[RATE_16KHZ];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,msm-cpudai-auxpcm-sync",
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-sync missing in DT node\n",
 			__func__);
 		goto fail_free_plat;
 	}
-	auxpcm_pdata->sync = (u16)property_val;
-	rc = of_property_read_u32(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-frame", &property_val);
+	auxpcm_pdata->mode_8k.sync = (u16)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.sync = (u16)val_array[RATE_16KHZ];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,msm-cpudai-auxpcm-frame",
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
 	if (rc) {
 		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-frame missing in DT node\n",
 			__func__);
 		goto fail_free_plat;
 	}
-	auxpcm_pdata->frame = (u16)property_val;
-	rc = of_property_read_u32(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-quant", &property_val);
+	auxpcm_pdata->mode_8k.frame = (u16)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.frame = (u16)val_array[RATE_16KHZ];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,msm-cpudai-auxpcm-quant",
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-quant missing in DT node\n",
 			__func__);
 		goto fail_free_plat;
 	}
-	auxpcm_pdata->quant = (u16)property_val;
-	rc = of_property_read_u32(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-slot", &property_val);
+	auxpcm_pdata->mode_8k.quant = (u16)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.quant = (u16)val_array[RATE_16KHZ];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,msm-cpudai-auxpcm-slot",
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-slot missing in DT node\n",
 			__func__);
 		goto fail_free_plat;
 	}
-	auxpcm_pdata->slot = (u16)property_val;
-	rc = of_property_read_u32(pdev->dev.of_node,
-			"qcom,msm-cpudai-auxpcm-data", &property_val);
+	auxpcm_pdata->mode_8k.slot = (u16)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.slot = (u16)val_array[RATE_16KHZ];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,msm-cpudai-auxpcm-data",
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-data missing in DT node\n",
 			__func__);
 		goto fail_free_plat;
 	}
-	auxpcm_pdata->data = (u16)property_val;
-	rc = of_property_read_u32(pdev->dev.of_node,
+	auxpcm_pdata->mode_8k.data = (u16)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.data = (u16)val_array[RATE_16KHZ];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
 			"qcom,msm-cpudai-auxpcm-pcm-clk-rate",
-			&auxpcm_pdata->pcm_clk_rate);
-	if (rc) {
-		dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-pcm-clk-rate missing in DT node\n",
-			__func__);
-		goto fail_free_plat;
-	}
+			val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
+	auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
+	auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
+
 	platform_set_drvdata(pdev, auxpcm_pdata);
 
 	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);