Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 13b95dd..50f6e07 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -6,8 +6,7 @@
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
+ *   the Free Software Foundation; only version 2 of the License.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 0e97248..34712cb 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -5,8 +5,7 @@
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
+ *   the Free Software Foundation; only version 2 of the License.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 8224db5..8dbfdcc 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -57,6 +57,7 @@
 source "sound/soc/sh/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
+source "sound/soc/msm/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0af7016..fff81f2 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -20,3 +20,4 @@
 obj-$(CONFIG_SND_SOC)	+= sh/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
+obj-$(CONFIG_SND_SOC)   += msm/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index 42f699c..f673516 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -18,8 +18,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -509,4 +508,4 @@
 
 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
 MODULE_DESCRIPTION("Atmel PCM module");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 9e59f68..3c8ea9c 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -12,8 +12,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -489,4 +488,4 @@
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index c42fb73..4d6c165 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -12,8 +12,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -328,4 +327,4 @@
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
index c95cc03..3c96242 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -12,8 +12,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -353,4 +352,4 @@
 
 MODULE_AUTHOR("Barry Song");
 MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 922f59f..b923a25 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -96,6 +96,7 @@
 	select SND_SOC_WM9705 if SND_SOC_AC97_BUS
 	select SND_SOC_WM9712 if SND_SOC_AC97_BUS
 	select SND_SOC_WM9713 if SND_SOC_AC97_BUS
+	select SND_SOC_TIMPANI if MARIMBA_CORE
         help
           Normally ASoC codec drivers are only built if a machine driver which
           uses them is also built since they are only usable with a machine
@@ -249,6 +250,9 @@
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WCD9310
+        tristate
+
 config SND_SOC_WL1273
 	tristate
 
@@ -387,3 +391,6 @@
 
 config SND_SOC_WM9090
 	tristate
+
+config SND_SOC_MSM_STUB
+	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index fd85584..78740ab 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -38,6 +38,7 @@
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm8350-objs := wm8350.o
@@ -81,7 +82,8 @@
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-jz4740-codec-objs := jz4740.o
-
+snd-soc-timpani-objs := timpani.o
+snd-soc-msm-stub-objs := msm_stub.o
 # Amp
 snd-soc-lm4857-objs := lm4857.o
 snd-soc-max9877-objs := max9877.o
@@ -130,6 +132,7 @@
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WCD9310)	+= snd-soc-wcd9310.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
@@ -172,6 +175,7 @@
 obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_MSM_STUB)  += snd-soc-msm-stub.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
diff --git a/sound/soc/codecs/msm_stub.c b/sound/soc/codecs/msm_stub.c
new file mode 100644
index 0000000..21691df
--- /dev/null
+++ b/sound/soc/codecs/msm_stub.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+/* A dummy driver useful only to advertise hardware parameters */
+static struct snd_soc_dai_driver msm_stub_dais[] = {
+	{
+		.name = "msm-stub-rx",
+		.playback = { /* Support maximum range */
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+	{
+		.name = "msm-stub-tx",
+		.capture = { /* Support maximum range */
+			.stream_name = "Record",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	}
+};
+
+static struct snd_soc_codec_driver soc_msm_stub = {};
+
+static int __devinit msm_stub_dev_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev,
+	&soc_msm_stub, msm_stub_dais, ARRAY_SIZE(msm_stub_dais));
+}
+
+static int __devexit msm_stub_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_stub_driver = {
+	.driver = {
+		.name = "msm-stub-codec",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_stub_dev_probe,
+	.remove = __devexit_p(msm_stub_dev_remove),
+};
+
+static int __init msm_stub_init(void)
+{
+	return platform_driver_register(&msm_stub_driver);
+}
+module_init(msm_stub_init);
+
+static void __exit msm_stub_exit(void)
+{
+	platform_driver_unregister(&msm_stub_driver);
+}
+module_exit(msm_stub_exit);
+
+MODULE_DESCRIPTION("Generic MSM CODEC driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/timpani.c b/sound/soc/codecs/timpani.c
new file mode 100644
index 0000000..786b2d6
--- /dev/null
+++ b/sound/soc/codecs/timpani.c
@@ -0,0 +1,482 @@
+/* Copyright (c) 2010, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/marimba.h>
+#include <linux/mfd/timpani-audio.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+/* Debug purpose */
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <mach/mpp.h>
+/* End of debug purpose */
+
+#define ADIE_CODEC_MAX 2
+
+struct adie_codec_register {
+	u8 reg;
+	u8 mask;
+	u8 val;
+};
+
+static struct adie_codec_register dmic_on[] = {
+	{0x80, 0x05, 0x05},
+	{0x80, 0x05, 0x00},
+	{0x83, 0x0C, 0x00},
+	{0x8A, 0xF0, 0x30},
+	{0x86, 0xFF, 0xAC},
+	{0x87, 0xFF, 0xAC},
+	{0x8A, 0xF0, 0xF0},
+	{0x82, 0x1F, 0x1E},
+	{0x83, 0x0C, 0x0C},
+	{0x92, 0x3F, 0x21},
+	{0x94, 0x3F, 0x24},
+	{0xA3, 0x39, 0x01},
+	{0xA8, 0x0F, 0x00},
+	{0xAB, 0x3F, 0x00},
+	{0x86, 0xFF, 0x00},
+	{0x87, 0xFF, 0x00},
+	{0x8A, 0xF0, 0xC0},
+};
+
+static struct adie_codec_register dmic_off[] = {
+	{0x8A, 0xF0, 0xF0},
+	{0x83, 0x0C, 0x00},
+	{0x92, 0xFF, 0x00},
+	{0x94, 0xFF, 0x1B},
+};
+
+static struct adie_codec_register spk_on[] = {
+	{0x80, 0x02, 0x02},
+	{0x80, 0x02, 0x00},
+	{0x83, 0x03, 0x00},
+	{0x8A, 0x0F, 0x03},
+	{0xA3, 0x02, 0x02},
+	{0x84, 0xFF, 0x00},
+	{0x85, 0xFF, 0x00},
+	{0x8A, 0x0F, 0x0C},
+	{0x81, 0xFF, 0x0E},
+	{0x83, 0x03, 0x03},
+	{0x24, 0x6F, 0x6C},
+	{0xB7, 0x01, 0x01},
+	{0x31, 0x01, 0x01},
+	{0x32, 0xF8, 0x08},
+	{0x32, 0xF8, 0x48},
+	{0x32, 0xF8, 0xF8},
+	{0xE0, 0xFE, 0xAC},
+	{0xE1, 0xFE, 0xAC},
+	{0x3A, 0x24, 0x24},
+	{0xE0, 0xFE, 0x3C},
+	{0xE1, 0xFE, 0x3C},
+	{0xE0, 0xFE, 0x1C},
+	{0xE1, 0xFE, 0x1C},
+	{0xE0, 0xFE, 0x10},
+	{0xE1, 0xFE, 0x10},
+};
+
+static struct adie_codec_register spk_off[] = {
+	{0x8A, 0x0F, 0x0F},
+	{0xE0, 0xFE, 0x1C},
+	{0xE1, 0xFE, 0x1C},
+	{0xE0, 0xFE, 0x3C},
+	{0xE1, 0xFE, 0x3C},
+	{0xE0, 0xFC, 0xAC},
+	{0xE1, 0xFC, 0xAC},
+	{0x32, 0xF8, 0x00},
+	{0x31, 0x05, 0x00},
+	{0x3A, 0x24, 0x00},
+};
+
+static struct adie_codec_register spk_mute[] = {
+	{0x84, 0xFF, 0xAC},
+	{0x85, 0xFF, 0xAC},
+	{0x8A, 0x0F, 0x0C},
+};
+
+static struct adie_codec_register spk_unmute[] = {
+	{0x84, 0xFF, 0x00},
+	{0x85, 0xFF, 0x00},
+	{0x8A, 0x0F, 0x0C},
+};
+
+struct adie_codec_path {
+	int rate; /* sample rate of path */
+	u32 reg_owner;
+};
+
+struct timpani_drv_data { /* member undecided */
+	struct snd_soc_codec codec;
+	struct adie_codec_path path[ADIE_CODEC_MAX];
+	u32 ref_cnt;
+	struct marimba_codec_platform_data *codec_pdata;
+};
+
+static struct snd_soc_codec *timpani_codec;
+
+enum /* regaccess blk id */
+{
+	RA_BLOCK_RX1 = 0,
+	RA_BLOCK_RX2,
+	RA_BLOCK_TX1,
+	RA_BLOCK_TX2,
+	RA_BLOCK_LB,
+	RA_BLOCK_SHARED_RX_LB,
+	RA_BLOCK_SHARED_TX,
+	RA_BLOCK_TXFE1,
+	RA_BLOCK_TXFE2,
+	RA_BLOCK_PA_COMMON,
+	RA_BLOCK_PA_EAR,
+	RA_BLOCK_PA_HPH,
+	RA_BLOCK_PA_LINE,
+	RA_BLOCK_PA_AUX,
+	RA_BLOCK_ADC,
+	RA_BLOCK_DMIC,
+	RA_BLOCK_TX_I2S,
+	RA_BLOCK_DRV,
+	RA_BLOCK_TEST,
+	RA_BLOCK_RESERVED,
+	RA_BLOCK_NUM,
+};
+
+enum /* regaccess onwer ID */
+{
+	RA_OWNER_NONE = 0,
+	RA_OWNER_PATH_RX1,
+	RA_OWNER_PATH_RX2,
+	RA_OWNER_PATH_TX1,
+	RA_OWNER_PATH_TX2,
+	RA_OWNER_PATH_LB,
+	RA_OWNER_DRV,
+	RA_OWNER_NUM,
+};
+
+struct reg_acc_blk_cfg {
+	u8 valid_owners[RA_OWNER_NUM];
+};
+
+struct timpani_regaccess {
+	u8 reg_addr;
+	u8 blk_mask[RA_BLOCK_NUM];
+	u8 reg_mask;
+	u8 reg_default;
+};
+
+static unsigned int timpani_codec_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	struct marimba *pdrv = codec->control_data;
+	int rc;
+	u8 val;
+
+	rc = marimba_read(pdrv, reg, &val, 1);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: fail to write reg %x\n", __func__, reg);
+		return 0;
+	}
+	return val;
+}
+
+static int timpani_codec_write(struct snd_soc_codec *codec, unsigned int reg,
+			unsigned int value)
+{
+	struct marimba *pdrv = codec->control_data;
+	int rc;
+
+	rc = marimba_write_bit_mask(pdrv, reg,  (u8 *)&value, 1, 0xFF);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: fail to write reg %x\n", __func__, reg);
+		return -EIO;
+	}
+	pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
+	return 0;
+}
+
+static void timpani_codec_bring_up(struct snd_soc_codec *codec)
+{
+	struct timpani_drv_data *timpani = snd_soc_codec_get_drvdata(codec);
+	int rc;
+
+	if (timpani->codec_pdata &&
+	    timpani->codec_pdata->marimba_codec_power) {
+		if (timpani->ref_cnt)
+			return;
+		/* Codec power up sequence */
+		rc = timpani->codec_pdata->marimba_codec_power(1);
+		if (rc)
+			pr_err("%s: could not power up timpani "
+				"codec\n", __func__);
+		else {
+			timpani_codec_write(codec, 0xFF, 0x08);
+			timpani_codec_write(codec, 0xFF, 0x0A);
+			timpani_codec_write(codec, 0xFF, 0x0E);
+			timpani_codec_write(codec, 0xFF, 0x07);
+			timpani_codec_write(codec, 0xFF, 0x17);
+			timpani_codec_write(codec, TIMPANI_A_MREF, 0x22);
+			msleep(15);
+			timpani->ref_cnt++;
+		}
+	}
+}
+
+static void timpani_codec_bring_down(struct snd_soc_codec *codec)
+{
+	struct timpani_drv_data *timpani = snd_soc_codec_get_drvdata(codec);
+	int rc;
+
+	if (timpani->codec_pdata &&
+	    timpani->codec_pdata->marimba_codec_power) {
+		timpani->ref_cnt--;
+		if (timpani->ref_cnt >= 1)
+			return;
+		timpani_codec_write(codec, TIMPANI_A_MREF, TIMPANI_MREF_POR);
+		timpani_codec_write(codec, 0xFF, 0x07);
+		timpani_codec_write(codec, 0xFF, 0x06);
+		timpani_codec_write(codec, 0xFF, 0x0E);
+		timpani_codec_write(codec, 0xFF, 0x08);
+		rc = timpani->codec_pdata->marimba_codec_power(0);
+		if (rc)
+			pr_err("%s: could not power down timpani "
+			"codec\n", __func__);
+	}
+}
+
+static void timpani_dmic_config(struct snd_soc_codec *codec, int on)
+{
+	struct adie_codec_register *regs;
+	int regs_sz, i;
+
+	if (on) {
+		regs = dmic_on;
+		regs_sz = ARRAY_SIZE(dmic_on);
+	} else {
+		regs = dmic_off;
+		regs_sz = ARRAY_SIZE(dmic_off);
+	}
+
+	for (i = 0; i < regs_sz; i++)
+		timpani_codec_write(codec, regs[i].reg,
+				(regs[i].mask & regs[i].val));
+}
+
+static void timpani_spk_config(struct snd_soc_codec *codec, int on)
+{
+	struct adie_codec_register *regs;
+	int regs_sz, i;
+
+	if (on) {
+		regs = spk_on;
+		regs_sz = ARRAY_SIZE(spk_on);
+	} else {
+		regs = spk_off;
+		regs_sz = ARRAY_SIZE(spk_off);
+	}
+
+	for (i = 0; i < regs_sz; i++)
+		timpani_codec_write(codec, regs[i].reg,
+				(regs[i].mask & regs[i].val));
+}
+
+static int timpani_startup(struct snd_pcm_substream *substream,
+		      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	pr_info("%s()\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_info("%s: playback\n", __func__);
+		timpani_codec_bring_up(codec);
+		timpani_spk_config(codec, 1);
+	} else {
+		pr_info("%s: Capture\n", __func__);
+		timpani_codec_bring_up(codec);
+		timpani_dmic_config(codec, 1);
+	}
+	return 0;
+}
+
+static void timpani_shutdown(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	pr_info("%s()\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		timpani_codec_bring_down(codec);
+		timpani_spk_config(codec, 0);
+	} else {
+		timpani_codec_bring_down(codec);
+		timpani_dmic_config(codec, 0);
+	}
+	return;
+}
+
+int digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct adie_codec_register *regs;
+	int regs_sz, i;
+
+	if (mute) {
+		regs = spk_mute;
+		regs_sz = ARRAY_SIZE(spk_mute);
+	} else {
+		regs = spk_unmute;
+		regs_sz = ARRAY_SIZE(spk_unmute);
+	}
+
+	for (i = 0; i < regs_sz; i++) {
+		timpani_codec_write(codec, regs[i].reg,
+			(regs[i].mask & regs[i].val));
+		msleep(10);
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops timpani_dai_ops = {
+	.startup	= timpani_startup,
+	.shutdown	= timpani_shutdown,
+};
+
+struct snd_soc_dai timpani_codec_dai[] = {
+	{
+		.name = "TIMPANI Rx",
+		.playback = {
+			.stream_name = "Handset Playback",
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_max =	96000,
+			.rate_min =	8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &timpani_dai_ops,
+	},
+	{
+		.name = "TIMPANI Tx",
+		.capture = {
+			.stream_name = "Handset Capture",
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_max =	96000,
+			.rate_min =	8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &timpani_dai_ops,
+	}
+};
+
+static int timpani_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (!timpani_codec) {
+		dev_err(&pdev->dev, "core driver not yet probed\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = timpani_codec;
+	codec = timpani_codec;
+
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0)
+		dev_err(codec->dev, "failed to create pcms\n");
+	return ret;
+}
+
+/* power down chip */
+static int timpani_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_timpani = {
+	.probe =	timpani_soc_probe,
+	.remove =	timpani_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_timpani);
+
+static int timpani_codec_probe(struct platform_device *pdev)
+{
+	struct snd_soc_codec *codec;
+	struct timpani_drv_data *priv;
+
+	pr_info("%s()\n", __func__);
+	priv = kzalloc(sizeof(struct timpani_drv_data), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	codec = &priv->codec;
+	snd_soc_codec_set_drvdata(codec, priv);
+	priv->codec_pdata = pdev->dev.platform_data;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->name = "TIMPANI";
+	codec->owner = THIS_MODULE;
+	codec->read = timpani_codec_read;
+	codec->write = timpani_codec_write;
+	codec->dai = timpani_codec_dai;
+	codec->num_dai = ARRAY_SIZE(timpani_codec_dai);
+	codec->control_data = platform_get_drvdata(pdev);
+	timpani_codec = codec;
+
+	snd_soc_register_dais(timpani_codec_dai, ARRAY_SIZE(timpani_codec_dai));
+	snd_soc_register_codec(codec);
+
+	return 0;
+}
+
+static struct platform_driver timpani_codec_driver = {
+	.probe = timpani_codec_probe,
+	.driver = {
+		.name = "timpani_codec",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init timpani_codec_init(void)
+{
+	return platform_driver_register(&timpani_codec_driver);
+}
+
+static void __exit timpani_codec_exit(void)
+{
+	platform_driver_unregister(&timpani_codec_driver);
+}
+
+module_init(timpani_codec_init);
+module_exit(timpani_codec_exit);
+
+MODULE_DESCRIPTION("Timpani codec driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/timpani.h b/sound/soc/codecs/timpani.h
new file mode 100644
index 0000000..bd14eea
--- /dev/null
+++ b/sound/soc/codecs/timpani.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#define NUM_I2S 2
+extern struct snd_soc_dai timpani_codec_dai[NUM_I2S];
+extern struct snd_soc_codec_device soc_codec_dev_timpani;
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
new file mode 100644
index 0000000..bc6bf4f
--- /dev/null
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -0,0 +1,1024 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/wcd9310/registers.h>
+#include "wcd9310.h"
+
+const u8 tabla_reg_readable[TABLA_CACHE_SIZE] = {
+	[TABLA_A_CHIP_CTL] = 1,
+	[TABLA_A_CHIP_STATUS] = 1,
+	[TABLA_A_CHIP_ID_BYTE_0] = 1,
+	[TABLA_A_CHIP_ID_BYTE_1] = 1,
+	[TABLA_A_CHIP_ID_BYTE_2] = 1,
+	[TABLA_A_CHIP_ID_BYTE_3] = 1,
+	[TABLA_A_CHIP_VERSION] = 1,
+	[TABLA_A_SB_VERSION] = 1,
+	[TABLA_A_SLAVE_ID_1] = 1,
+	[TABLA_A_SLAVE_ID_2] = 1,
+	[TABLA_A_SLAVE_ID_3] = 1,
+	[TABLA_A_PIN_CTL_OE0] = 1,
+	[TABLA_A_PIN_CTL_OE1] = 1,
+	[TABLA_A_PIN_CTL_DATA0] = 1,
+	[TABLA_A_PIN_CTL_DATA1] = 1,
+	[TABLA_A_HDRIVE_GENERIC] = 1,
+	[TABLA_A_HDRIVE_OVERRIDE] = 1,
+	[TABLA_A_ANA_CSR_WAIT_STATE] = 1,
+	[TABLA_A_PROCESS_MONITOR_CTL0] = 1,
+	[TABLA_A_PROCESS_MONITOR_CTL1] = 1,
+	[TABLA_A_PROCESS_MONITOR_CTL2] = 1,
+	[TABLA_A_PROCESS_MONITOR_CTL3] = 1,
+	[TABLA_A_QFUSE_CTL] = 1,
+	[TABLA_A_QFUSE_STATUS] = 1,
+	[TABLA_A_QFUSE_DATA_OUT0] = 1,
+	[TABLA_A_QFUSE_DATA_OUT1] = 1,
+	[TABLA_A_QFUSE_DATA_OUT2] = 1,
+	[TABLA_A_QFUSE_DATA_OUT3] = 1,
+	[TABLA_A_CDC_CTL] = 1,
+	[TABLA_A_LEAKAGE_CTL] = 1,
+	[TABLA_A_INTR_MODE] = 1,
+	[TABLA_A_INTR_MASK0] = 1,
+	[TABLA_A_INTR_MASK1] = 1,
+	[TABLA_A_INTR_MASK2] = 1,
+	[TABLA_A_INTR_STATUS0] = 1,
+	[TABLA_A_INTR_STATUS1] = 1,
+	[TABLA_A_INTR_STATUS2] = 1,
+	[TABLA_A_INTR_CLEAR0] = 0,
+	[TABLA_A_INTR_CLEAR1] = 0,
+	[TABLA_A_INTR_CLEAR2] = 0,
+	[TABLA_A_INTR_LEVEL0] = 1,
+	[TABLA_A_INTR_LEVEL1] = 1,
+	[TABLA_A_INTR_LEVEL2] = 1,
+	[TABLA_A_INTR_TEST0] = 1,
+	[TABLA_A_INTR_TEST1] = 1,
+	[TABLA_A_INTR_TEST2] = 1,
+	[TABLA_A_INTR_SET0] = 1,
+	[TABLA_A_INTR_SET1] = 1,
+	[TABLA_A_INTR_SET2] = 1,
+	[TABLA_A_CDC_TX_I2S_SCK_MODE] = 1,
+	[TABLA_A_CDC_TX_I2S_WS_MODE] = 1,
+	[TABLA_A_CDC_DMIC_DATA0_MODE] = 1,
+	[TABLA_A_CDC_DMIC_CLK0_MODE] = 1,
+	[TABLA_A_CDC_DMIC_DATA1_MODE] = 1,
+	[TABLA_A_CDC_DMIC_CLK1_MODE] = 1,
+	[TABLA_A_CDC_RX_I2S_SCK_MODE] = 1,
+	[TABLA_A_CDC_RX_I2S_WS_MODE] = 1,
+	[TABLA_A_CDC_DMIC_DATA2_MODE] = 1,
+	[TABLA_A_CDC_DMIC_CLK2_MODE] = 1,
+	[TABLA_A_CDC_INTR_MODE] = 1,
+	[TABLA_A_BIAS_REF_CTL] = 1,
+	[TABLA_A_BIAS_CENTRAL_BG_CTL] = 1,
+	[TABLA_A_BIAS_PRECHRG_CTL] = 1,
+	[TABLA_A_BIAS_CURR_CTL_1] = 1,
+	[TABLA_A_BIAS_CURR_CTL_2] = 1,
+	[TABLA_A_BIAS_CONFIG_MODE_BG_CTL] = 1,
+	[TABLA_A_BIAS_BG_STATUS] = 1,
+	[TABLA_A_CLK_BUFF_EN1] = 1,
+	[TABLA_A_CLK_BUFF_EN2] = 1,
+	[TABLA_A_LDO_H_MODE_1] = 1,
+	[TABLA_A_LDO_H_MODE_2] = 1,
+	[TABLA_A_LDO_H_LOOP_CTL] = 1,
+	[TABLA_A_LDO_H_COMP_1] = 1,
+	[TABLA_A_LDO_H_COMP_2] = 1,
+	[TABLA_A_LDO_H_BIAS_1] = 1,
+	[TABLA_A_LDO_H_BIAS_2] = 1,
+	[TABLA_A_LDO_H_BIAS_3] = 1,
+	[TABLA_A_LDO_L_MODE_1] = 1,
+	[TABLA_A_LDO_L_MODE_2] = 1,
+	[TABLA_A_LDO_L_LOOP_CTL] = 1,
+	[TABLA_A_LDO_L_COMP_1] = 1,
+	[TABLA_A_LDO_L_COMP_2] = 1,
+	[TABLA_A_LDO_L_BIAS_1] = 1,
+	[TABLA_A_LDO_L_BIAS_2] = 1,
+	[TABLA_A_LDO_L_BIAS_3] = 1,
+	[TABLA_A_MICB_CFILT_1_CTL] = 1,
+	[TABLA_A_MICB_CFILT_1_VAL] = 1,
+	[TABLA_A_MICB_CFILT_1_PRECHRG] = 1,
+	[TABLA_A_MICB_1_CTL] = 1,
+	[TABLA_A_MICB_1_INT_RBIAS] = 1,
+	[TABLA_A_MICB_1_MBHC] = 1,
+	[TABLA_A_MICB_CFILT_2_CTL] = 1,
+	[TABLA_A_MICB_CFILT_2_VAL] = 1,
+	[TABLA_A_MICB_CFILT_2_PRECHRG] = 1,
+	[TABLA_A_MICB_2_CTL] = 1,
+	[TABLA_A_MICB_2_INT_RBIAS] = 1,
+	[TABLA_A_MICB_2_MBHC] = 1,
+	[TABLA_A_MICB_CFILT_3_CTL] = 1,
+	[TABLA_A_MICB_CFILT_3_VAL] = 1,
+	[TABLA_A_MICB_CFILT_3_PRECHRG] = 1,
+	[TABLA_A_MICB_3_CTL] = 1,
+	[TABLA_A_MICB_3_INT_RBIAS] = 1,
+	[TABLA_A_MICB_3_MBHC] = 1,
+	[TABLA_A_MICB_4_CTL] = 1,
+	[TABLA_A_MICB_4_INT_RBIAS] = 1,
+	[TABLA_A_MICB_4_MBHC] = 1,
+	[TABLA_A_TX_COM_BIAS] = 1,
+	[TABLA_A_MBHC_SCALING_MUX_1] = 1,
+	[TABLA_A_MBHC_SCALING_MUX_2] = 1,
+	[TABLA_A_TX_SUP_SWITCH_CTRL_1] = 1,
+	[TABLA_A_TX_SUP_SWITCH_CTRL_2] = 1,
+	[TABLA_A_TX_1_2_EN] = 1,
+	[TABLA_A_TX_1_2_TEST_EN] = 1,
+	[TABLA_A_TX_1_2_ADC_CH1] = 1,
+	[TABLA_A_TX_1_2_ADC_CH2] = 1,
+	[TABLA_A_TX_1_2_ATEST_REFCTRL] = 1,
+	[TABLA_A_TX_1_2_TEST_CTL] = 1,
+	[TABLA_A_TX_1_2_TEST_BLOCK_EN] = 1,
+	[TABLA_A_TX_1_2_TXFE_CLKDIV] = 1,
+	[TABLA_A_TX_1_2_SAR_ERR_CH1] = 1,
+	[TABLA_A_TX_1_2_SAR_ERR_CH2] = 1,
+	[TABLA_A_TX_3_4_EN] = 1,
+	[TABLA_A_TX_3_4_TEST_EN] = 1,
+	[TABLA_A_TX_3_4_ADC_CH3] = 1,
+	[TABLA_A_TX_3_4_ADC_CH4] = 1,
+	[TABLA_A_TX_3_4_ATEST_REFCTRL] = 1,
+	[TABLA_A_TX_3_4_TEST_CTL] = 1,
+	[TABLA_A_TX_3_4_TEST_BLOCK_EN] = 1,
+	[TABLA_A_TX_3_4_TXFE_CKDIV] = 1,
+	[TABLA_A_TX_3_4_SAR_ERR_CH3] = 1,
+	[TABLA_A_TX_3_4_SAR_ERR_CH4] = 1,
+	[TABLA_A_TX_5_6_EN] = 1,
+	[TABLA_A_TX_5_6_TEST_EN] = 1,
+	[TABLA_A_TX_5_6_ADC_CH5] = 1,
+	[TABLA_A_TX_5_6_ADC_CH6] = 1,
+	[TABLA_A_TX_5_6_ATEST_REFCTRL] = 1,
+	[TABLA_A_TX_5_6_TEST_CTL] = 1,
+	[TABLA_A_TX_5_6_TEST_BLOCK_EN] = 1,
+	[TABLA_A_TX_5_6_TXFE_CKDIV] = 1,
+	[TABLA_A_TX_5_6_SAR_ERR_CH5] = 1,
+	[TABLA_A_TX_5_6_SAR_ERR_CH6] = 1,
+	[TABLA_A_TX_7_MBHC_EN] = 1,
+	[TABLA_A_TX_7_MBHC_ATEST_REFCTRL] = 1,
+	[TABLA_A_TX_7_MBHC_ADC] = 1,
+	[TABLA_A_TX_7_MBHC_TEST_CTL] = 1,
+	[TABLA_A_TX_7_MBHC_SAR_ERR] = 1,
+	[TABLA_A_TX_7_TXFE_CLKDIV] = 1,
+	[TABLA_A_AUX_COM_CTL] = 1,
+	[TABLA_A_AUX_COM_ATEST] = 1,
+	[TABLA_A_AUX_L_EN] = 1,
+	[TABLA_A_AUX_L_GAIN] = 1,
+	[TABLA_A_AUX_L_PA_CONN] = 1,
+	[TABLA_A_AUX_L_PA_CONN_INV] = 1,
+	[TABLA_A_AUX_R_EN] = 1,
+	[TABLA_A_AUX_R_GAIN] = 1,
+	[TABLA_A_AUX_R_PA_CONN] = 1,
+	[TABLA_A_AUX_R_PA_CONN_INV] = 1,
+	[TABLA_A_CP_EN] = 1,
+	[TABLA_A_CP_CLK] = 1,
+	[TABLA_A_CP_STATIC] = 1,
+	[TABLA_A_CP_DCC1] = 1,
+	[TABLA_A_CP_DCC3] = 1,
+	[TABLA_A_CP_ATEST] = 1,
+	[TABLA_A_CP_DTEST] = 1,
+	[TABLA_A_RX_COM_TIMER_DIV] = 1,
+	[TABLA_A_RX_COM_OCP_CTL] = 1,
+	[TABLA_A_RX_COM_OCP_COUNT] = 1,
+	[TABLA_A_RX_COM_DAC_CTL] = 1,
+	[TABLA_A_RX_COM_BIAS] = 1,
+	[TABLA_A_RX_HPH_BIAS_PA] = 1,
+	[TABLA_A_RX_HPH_BIAS_LDO] = 1,
+	[TABLA_A_RX_HPH_BIAS_CNP] = 1,
+	[TABLA_A_RX_HPH_BIAS_WG] = 1,
+	[TABLA_A_RX_HPH_OCP_CTL] = 1,
+	[TABLA_A_RX_HPH_CNP_EN] = 1,
+	[TABLA_A_RX_HPH_CNP_WG_CTL] = 1,
+	[TABLA_A_RX_HPH_CNP_WG_TIME] = 1,
+	[TABLA_A_RX_HPH_L_GAIN] = 1,
+	[TABLA_A_RX_HPH_L_TEST] = 1,
+	[TABLA_A_RX_HPH_L_PA_CTL] = 1,
+	[TABLA_A_RX_HPH_L_DAC_CTL] = 1,
+	[TABLA_A_RX_HPH_L_ATEST] = 1,
+	[TABLA_A_RX_HPH_L_STATUS] = 1,
+	[TABLA_A_RX_HPH_R_GAIN] = 1,
+	[TABLA_A_RX_HPH_R_TEST] = 1,
+	[TABLA_A_RX_HPH_R_PA_CTL] = 1,
+	[TABLA_A_RX_HPH_R_DAC_CTL] = 1,
+	[TABLA_A_RX_HPH_R_ATEST] = 1,
+	[TABLA_A_RX_HPH_R_STATUS] = 1,
+	[TABLA_A_RX_EAR_BIAS_PA] = 1,
+	[TABLA_A_RX_EAR_BIAS_CMBUFF] = 1,
+	[TABLA_A_RX_EAR_EN] = 1,
+	[TABLA_A_RX_EAR_GAIN] = 1,
+	[TABLA_A_RX_EAR_CMBUFF] = 1,
+	[TABLA_A_RX_EAR_ICTL] = 1,
+	[TABLA_A_RX_EAR_CCOMP] = 1,
+	[TABLA_A_RX_EAR_VCM] = 1,
+	[TABLA_A_RX_EAR_CNP] = 1,
+	[TABLA_A_RX_EAR_ATEST] = 1,
+	[TABLA_A_RX_EAR_STATUS] = 1,
+	[TABLA_A_RX_LINE_BIAS_PA] = 1,
+	[TABLA_A_RX_LINE_BIAS_DAC] = 1,
+	[TABLA_A_RX_LINE_BIAS_CNP] = 1,
+	[TABLA_A_RX_LINE_COM] = 1,
+	[TABLA_A_RX_LINE_CNP_EN] = 1,
+	[TABLA_A_RX_LINE_CNP_WG_CTL] = 1,
+	[TABLA_A_RX_LINE_CNP_WG_TIME] = 1,
+	[TABLA_A_RX_LINE_1_GAIN] = 1,
+	[TABLA_A_RX_LINE_1_TEST] = 1,
+	[TABLA_A_RX_LINE_1_DAC_CTL] = 1,
+	[TABLA_A_RX_LINE_1_STATUS] = 1,
+	[TABLA_A_RX_LINE_2_GAIN] = 1,
+	[TABLA_A_RX_LINE_2_TEST] = 1,
+	[TABLA_A_RX_LINE_2_DAC_CTL] = 1,
+	[TABLA_A_RX_LINE_2_STATUS] = 1,
+	[TABLA_A_RX_LINE_3_GAIN] = 1,
+	[TABLA_A_RX_LINE_3_TEST] = 1,
+	[TABLA_A_RX_LINE_3_DAC_CTL] = 1,
+	[TABLA_A_RX_LINE_3_STATUS] = 1,
+	[TABLA_A_RX_LINE_4_GAIN] = 1,
+	[TABLA_A_RX_LINE_4_TEST] = 1,
+	[TABLA_A_RX_LINE_4_DAC_CTL] = 1,
+	[TABLA_A_RX_LINE_4_STATUS] = 1,
+	[TABLA_A_RX_LINE_5_GAIN] = 1,
+	[TABLA_A_RX_LINE_5_TEST] = 1,
+	[TABLA_A_RX_LINE_5_DAC_CTL] = 1,
+	[TABLA_A_RX_LINE_5_STATUS] = 1,
+	[TABLA_A_RX_LINE_CNP_DBG] = 1,
+	[TABLA_A_MBHC_HPH] = 1,
+	[TABLA_A_CONFIG_MODE_FREQ] = 1,
+	[TABLA_A_CONFIG_MODE_TEST] = 1,
+	[TABLA_A_CONFIG_MODE_STATUS] = 1,
+	[TABLA_A_CONFIG_MODE_TUNER] = 1,
+	[TABLA_A_CDC_TX1_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX2_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX3_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX4_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX5_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX6_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX7_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX8_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX9_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX10_VOL_CTL_TIMER] = 1,
+	[TABLA_A_CDC_TX1_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX2_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX3_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX4_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX5_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX6_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX7_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX8_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX9_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX10_VOL_CTL_GAIN] = 1,
+	[TABLA_A_CDC_TX1_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX2_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX3_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX4_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX5_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX6_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX7_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX8_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX9_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX10_VOL_CTL_CFG] = 1,
+	[TABLA_A_CDC_TX1_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX2_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX3_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX4_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX5_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX6_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX7_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX8_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX9_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX10_MUX_CTL] = 1,
+	[TABLA_A_CDC_TX1_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX2_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX3_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX4_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX5_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX6_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX7_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX8_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX9_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX10_CLK_FS_CTL] = 1,
+	[TABLA_A_CDC_TX1_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX2_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX3_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX4_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX5_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX6_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX7_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX8_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX9_DMIC_CTL] = 1,
+	[TABLA_A_CDC_TX10_DMIC_CTL] = 1,
+	[TABLA_A_CDC_SRC1_PDA_CFG] = 1,
+	[TABLA_A_CDC_SRC2_PDA_CFG] = 1,
+	[TABLA_A_CDC_SRC1_FS_CTL] = 1,
+	[TABLA_A_CDC_SRC2_FS_CTL] = 1,
+	[TABLA_A_CDC_RX1_B1_CTL] = 1,
+	[TABLA_A_CDC_RX2_B1_CTL] = 1,
+	[TABLA_A_CDC_RX3_B1_CTL] = 1,
+	[TABLA_A_CDC_RX4_B1_CTL] = 1,
+	[TABLA_A_CDC_RX5_B1_CTL] = 1,
+	[TABLA_A_CDC_RX6_B1_CTL] = 1,
+	[TABLA_A_CDC_RX7_B1_CTL] = 1,
+	[TABLA_A_CDC_RX1_B2_CTL] = 1,
+	[TABLA_A_CDC_RX2_B2_CTL] = 1,
+	[TABLA_A_CDC_RX3_B2_CTL] = 1,
+	[TABLA_A_CDC_RX4_B2_CTL] = 1,
+	[TABLA_A_CDC_RX5_B2_CTL] = 1,
+	[TABLA_A_CDC_RX6_B2_CTL] = 1,
+	[TABLA_A_CDC_RX7_B2_CTL] = 1,
+	[TABLA_A_CDC_RX1_B3_CTL] = 1,
+	[TABLA_A_CDC_RX2_B3_CTL] = 1,
+	[TABLA_A_CDC_RX3_B3_CTL] = 1,
+	[TABLA_A_CDC_RX4_B3_CTL] = 1,
+	[TABLA_A_CDC_RX5_B3_CTL] = 1,
+	[TABLA_A_CDC_RX6_B3_CTL] = 1,
+	[TABLA_A_CDC_RX7_B3_CTL] = 1,
+	[TABLA_A_CDC_RX1_B4_CTL] = 1,
+	[TABLA_A_CDC_RX2_B4_CTL] = 1,
+	[TABLA_A_CDC_RX3_B4_CTL] = 1,
+	[TABLA_A_CDC_RX4_B4_CTL] = 1,
+	[TABLA_A_CDC_RX5_B4_CTL] = 1,
+	[TABLA_A_CDC_RX6_B4_CTL] = 1,
+	[TABLA_A_CDC_RX7_B4_CTL] = 1,
+	[TABLA_A_CDC_RX1_B5_CTL] = 1,
+	[TABLA_A_CDC_RX2_B5_CTL] = 1,
+	[TABLA_A_CDC_RX3_B5_CTL] = 1,
+	[TABLA_A_CDC_RX4_B5_CTL] = 1,
+	[TABLA_A_CDC_RX5_B5_CTL] = 1,
+	[TABLA_A_CDC_RX6_B5_CTL] = 1,
+	[TABLA_A_CDC_RX7_B5_CTL] = 1,
+	[TABLA_A_CDC_RX1_B6_CTL] = 1,
+	[TABLA_A_CDC_RX2_B6_CTL] = 1,
+	[TABLA_A_CDC_RX3_B6_CTL] = 1,
+	[TABLA_A_CDC_RX4_B6_CTL] = 1,
+	[TABLA_A_CDC_RX5_B6_CTL] = 1,
+	[TABLA_A_CDC_RX6_B6_CTL] = 1,
+	[TABLA_A_CDC_RX7_B6_CTL] = 1,
+	[TABLA_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX2_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX3_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX4_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX5_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX6_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX7_VOL_CTL_B1_CTL] = 1,
+	[TABLA_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_RX2_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_RX3_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_RX4_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_RX5_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_RX6_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_RX7_VOL_CTL_B2_CTL] = 1,
+	[TABLA_A_CDC_CLK_RX_RESET_CTL] = 1,
+	[TABLA_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
+	[TABLA_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
+	[TABLA_A_CDC_CLK_DMIC_CTL] = 1,
+	[TABLA_A_CDC_CLK_RX_I2S_CTL] = 1,
+	[TABLA_A_CDC_CLK_TX_I2S_CTL] = 1,
+	[TABLA_A_CDC_CLK_OTHR_RESET_CTL] = 1,
+	[TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
+	[TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL] = 1,
+	[TABLA_A_CDC_CLK_OTHR_CTL] = 1,
+	[TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL] = 1,
+	[TABLA_A_CDC_CLK_RX_B1_CTL] = 1,
+	[TABLA_A_CDC_CLK_RX_B2_CTL] = 1,
+	[TABLA_A_CDC_CLK_MCLK_CTL] = 1,
+	[TABLA_A_CDC_CLK_PDM_CTL] = 1,
+	[TABLA_A_CDC_CLK_SD_CTL] = 1,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B1_CTL] = 1,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B2_CTL] = 1,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL] = 1,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B4_CTL] = 1,
+	[TABLA_A_CDC_CLSG_GAIN_THRESH_CTL] = 1,
+	[TABLA_A_CDC_CLSG_TIMER_B1_CFG] = 1,
+	[TABLA_A_CDC_CLSG_TIMER_B2_CFG] = 1,
+	[TABLA_A_CDC_CLSG_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B1_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B1_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B2_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B2_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B3_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B3_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B4_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B4_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B5_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B5_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B6_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B6_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B7_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B7_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_B8_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_B8_CTL] = 1,
+	[TABLA_A_CDC_IIR1_CTL] = 1,
+	[TABLA_A_CDC_IIR2_CTL] = 1,
+	[TABLA_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
+	[TABLA_A_CDC_IIR2_GAIN_TIMER_CTL] = 1,
+	[TABLA_A_CDC_IIR1_COEF_B1_CTL] = 1,
+	[TABLA_A_CDC_IIR2_COEF_B1_CTL] = 1,
+	[TABLA_A_CDC_IIR1_COEF_B2_CTL] = 1,
+	[TABLA_A_CDC_IIR2_COEF_B2_CTL] = 1,
+	[TABLA_A_CDC_IIR1_COEF_B3_CTL] = 1,
+	[TABLA_A_CDC_IIR2_COEF_B3_CTL] = 1,
+	[TABLA_A_CDC_IIR1_COEF_B4_CTL] = 1,
+	[TABLA_A_CDC_IIR2_COEF_B4_CTL] = 1,
+	[TABLA_A_CDC_IIR1_COEF_B5_CTL] = 1,
+	[TABLA_A_CDC_IIR2_COEF_B5_CTL] = 1,
+	[TABLA_A_CDC_TOP_GAIN_UPDATE] = 1,
+	[TABLA_A_CDC_DEBUG_B1_CTL] = 1,
+	[TABLA_A_CDC_DEBUG_B2_CTL] = 1,
+	[TABLA_A_CDC_DEBUG_B3_CTL] = 1,
+	[TABLA_A_CDC_DEBUG_B4_CTL] = 1,
+	[TABLA_A_CDC_DEBUG_B5_CTL] = 1,
+	[TABLA_A_CDC_DEBUG_B6_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX1_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX1_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX1_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX2_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX2_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX2_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX3_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX3_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX3_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX4_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX4_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX5_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX5_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX6_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX6_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX7_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX7_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_B4_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ1_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ1_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ1_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ1_B4_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ2_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ2_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ2_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_EQ2_B4_CTL] = 1,
+	[TABLA_A_CDC_CONN_SRC1_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_SRC1_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_SRC2_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_SRC2_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B3_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B4_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B5_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B6_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B7_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B8_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B9_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B10_CTL] = 1,
+	[TABLA_A_CDC_CONN_TX_SB_B11_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX_SB_B1_CTL] = 1,
+	[TABLA_A_CDC_CONN_RX_SB_B2_CTL] = 1,
+	[TABLA_A_CDC_CONN_CLSG_CTL] = 1,
+	[TABLA_A_CDC_CONN_SPARE] = 1,
+	[TABLA_A_CDC_MBHC_EN_CTL] = 1,
+	[TABLA_A_CDC_MBHC_FEATURE_B1_CFG] = 1,
+	[TABLA_A_CDC_MBHC_FEATURE_B2_CFG] = 1,
+	[TABLA_A_CDC_MBHC_TIMER_B1_CTL] = 1,
+	[TABLA_A_CDC_MBHC_TIMER_B2_CTL] = 1,
+	[TABLA_A_CDC_MBHC_TIMER_B3_CTL] = 1,
+	[TABLA_A_CDC_MBHC_TIMER_B4_CTL] = 1,
+	[TABLA_A_CDC_MBHC_TIMER_B5_CTL] = 1,
+	[TABLA_A_CDC_MBHC_TIMER_B6_CTL] = 1,
+	[TABLA_A_CDC_MBHC_B1_STATUS] = 1,
+	[TABLA_A_CDC_MBHC_B2_STATUS] = 1,
+	[TABLA_A_CDC_MBHC_B3_STATUS] = 1,
+	[TABLA_A_CDC_MBHC_B4_STATUS] = 1,
+	[TABLA_A_CDC_MBHC_B5_STATUS] = 1,
+	[TABLA_A_CDC_MBHC_B1_CTL] = 1,
+	[TABLA_A_CDC_MBHC_B2_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B1_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B2_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B3_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B4_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B5_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B6_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B7_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B8_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B9_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B10_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B11_CTL] = 1,
+	[TABLA_A_CDC_MBHC_VOLT_B12_CTL] = 1,
+	[TABLA_A_CDC_MBHC_CLK_CTL] = 1,
+	[TABLA_A_CDC_MBHC_INT_CTL] = 1,
+	[TABLA_A_CDC_MBHC_DEBUG_CTL] = 1,
+	[TABLA_A_CDC_MBHC_SPARE] = 1,
+};
+
+const u8 tabla_reg_defaults[TABLA_CACHE_SIZE] = {
+	[TABLA_A_CHIP_CTL] = TABLA_A_CHIP_CTL__POR,
+	[TABLA_A_CHIP_STATUS] = TABLA_A_CHIP_STATUS__POR,
+	[TABLA_A_CHIP_ID_BYTE_0] = TABLA_A_CHIP_ID_BYTE_0__POR,
+	[TABLA_A_CHIP_ID_BYTE_1] = TABLA_A_CHIP_ID_BYTE_1__POR,
+	[TABLA_A_CHIP_ID_BYTE_2] = TABLA_A_CHIP_ID_BYTE_2__POR,
+	[TABLA_A_CHIP_ID_BYTE_3] = TABLA_A_CHIP_ID_BYTE_3__POR,
+	[TABLA_A_CHIP_VERSION] = TABLA_A_CHIP_VERSION__POR,
+	[TABLA_A_SB_VERSION] = TABLA_A_SB_VERSION__POR,
+	[TABLA_A_SLAVE_ID_1] = TABLA_A_SLAVE_ID_1__POR,
+	[TABLA_A_SLAVE_ID_2] = TABLA_A_SLAVE_ID_2__POR,
+	[TABLA_A_SLAVE_ID_3] = TABLA_A_SLAVE_ID_3__POR,
+	[TABLA_A_PIN_CTL_OE0] = TABLA_A_PIN_CTL_OE0__POR,
+	[TABLA_A_PIN_CTL_OE1] = TABLA_A_PIN_CTL_OE1__POR,
+	[TABLA_A_PIN_CTL_DATA0] = TABLA_A_PIN_CTL_DATA0__POR,
+	[TABLA_A_PIN_CTL_DATA1] = TABLA_A_PIN_CTL_DATA1__POR,
+	[TABLA_A_HDRIVE_GENERIC] = TABLA_A_HDRIVE_GENERIC__POR,
+	[TABLA_A_HDRIVE_OVERRIDE] = TABLA_A_HDRIVE_OVERRIDE__POR,
+	[TABLA_A_ANA_CSR_WAIT_STATE] = TABLA_A_ANA_CSR_WAIT_STATE__POR,
+	[TABLA_A_PROCESS_MONITOR_CTL0] = TABLA_A_PROCESS_MONITOR_CTL0__POR,
+	[TABLA_A_PROCESS_MONITOR_CTL1] = TABLA_A_PROCESS_MONITOR_CTL1__POR,
+	[TABLA_A_PROCESS_MONITOR_CTL2] = TABLA_A_PROCESS_MONITOR_CTL2__POR,
+	[TABLA_A_PROCESS_MONITOR_CTL3] = TABLA_A_PROCESS_MONITOR_CTL3__POR,
+	[TABLA_A_QFUSE_CTL] = TABLA_A_QFUSE_CTL__POR,
+	[TABLA_A_QFUSE_STATUS] = TABLA_A_QFUSE_STATUS__POR,
+	[TABLA_A_QFUSE_DATA_OUT0] = TABLA_A_QFUSE_DATA_OUT0__POR,
+	[TABLA_A_QFUSE_DATA_OUT1] = TABLA_A_QFUSE_DATA_OUT1__POR,
+	[TABLA_A_QFUSE_DATA_OUT2] = TABLA_A_QFUSE_DATA_OUT2__POR,
+	[TABLA_A_QFUSE_DATA_OUT3] = TABLA_A_QFUSE_DATA_OUT3__POR,
+	[TABLA_A_CDC_CTL] = TABLA_A_CDC_CTL__POR,
+	[TABLA_A_LEAKAGE_CTL] = TABLA_A_LEAKAGE_CTL__POR,
+	[TABLA_A_INTR_MODE] = TABLA_A_INTR_MODE__POR,
+	[TABLA_A_INTR_MASK0] = TABLA_A_INTR_MASK0__POR,
+	[TABLA_A_INTR_MASK1] = TABLA_A_INTR_MASK1__POR,
+	[TABLA_A_INTR_MASK2] = TABLA_A_INTR_MASK2__POR,
+	[TABLA_A_INTR_STATUS0] = TABLA_A_INTR_STATUS0__POR,
+	[TABLA_A_INTR_STATUS1] = TABLA_A_INTR_STATUS1__POR,
+	[TABLA_A_INTR_STATUS2] = TABLA_A_INTR_STATUS2__POR,
+	[TABLA_A_INTR_CLEAR0] = TABLA_A_INTR_CLEAR0__POR,
+	[TABLA_A_INTR_CLEAR1] = TABLA_A_INTR_CLEAR1__POR,
+	[TABLA_A_INTR_CLEAR2] = TABLA_A_INTR_CLEAR2__POR,
+	[TABLA_A_INTR_LEVEL0] = TABLA_A_INTR_LEVEL0__POR,
+	[TABLA_A_INTR_LEVEL1] = TABLA_A_INTR_LEVEL1__POR,
+	[TABLA_A_INTR_LEVEL2] = TABLA_A_INTR_LEVEL2__POR,
+	[TABLA_A_INTR_TEST0] = TABLA_A_INTR_TEST0__POR,
+	[TABLA_A_INTR_TEST1] = TABLA_A_INTR_TEST1__POR,
+	[TABLA_A_INTR_TEST2] = TABLA_A_INTR_TEST2__POR,
+	[TABLA_A_INTR_SET0] = TABLA_A_INTR_SET0__POR,
+	[TABLA_A_INTR_SET1] = TABLA_A_INTR_SET1__POR,
+	[TABLA_A_INTR_SET2] = TABLA_A_INTR_SET2__POR,
+	[TABLA_A_CDC_TX_I2S_SCK_MODE] = TABLA_A_CDC_TX_I2S_SCK_MODE__POR,
+	[TABLA_A_CDC_TX_I2S_WS_MODE] = TABLA_A_CDC_TX_I2S_WS_MODE__POR,
+	[TABLA_A_CDC_DMIC_DATA0_MODE] = TABLA_A_CDC_DMIC_DATA0_MODE__POR,
+	[TABLA_A_CDC_DMIC_CLK0_MODE] = TABLA_A_CDC_DMIC_CLK0_MODE__POR,
+	[TABLA_A_CDC_DMIC_DATA1_MODE] = TABLA_A_CDC_DMIC_DATA1_MODE__POR,
+	[TABLA_A_CDC_DMIC_CLK1_MODE] = TABLA_A_CDC_DMIC_CLK1_MODE__POR,
+	[TABLA_A_CDC_RX_I2S_SCK_MODE] = TABLA_A_CDC_RX_I2S_SCK_MODE__POR,
+	[TABLA_A_CDC_RX_I2S_WS_MODE] = TABLA_A_CDC_RX_I2S_WS_MODE__POR,
+	[TABLA_A_CDC_DMIC_DATA2_MODE] = TABLA_A_CDC_DMIC_DATA2_MODE__POR,
+	[TABLA_A_CDC_DMIC_CLK2_MODE] = TABLA_A_CDC_DMIC_CLK2_MODE__POR,
+	[TABLA_A_CDC_INTR_MODE] = TABLA_A_CDC_INTR_MODE__POR,
+	[TABLA_A_BIAS_REF_CTL] = TABLA_A_BIAS_REF_CTL__POR,
+	[TABLA_A_BIAS_CENTRAL_BG_CTL] = TABLA_A_BIAS_CENTRAL_BG_CTL__POR,
+	[TABLA_A_BIAS_PRECHRG_CTL] = TABLA_A_BIAS_PRECHRG_CTL__POR,
+	[TABLA_A_BIAS_CURR_CTL_1] = TABLA_A_BIAS_CURR_CTL_1__POR,
+	[TABLA_A_BIAS_CURR_CTL_2] = TABLA_A_BIAS_CURR_CTL_2__POR,
+	[TABLA_A_BIAS_CONFIG_MODE_BG_CTL] =
+		TABLA_A_BIAS_CONFIG_MODE_BG_CTL__POR,
+	[TABLA_A_BIAS_BG_STATUS] = TABLA_A_BIAS_BG_STATUS__POR,
+	[TABLA_A_CLK_BUFF_EN1] = TABLA_A_CLK_BUFF_EN1__POR,
+	[TABLA_A_CLK_BUFF_EN2] = TABLA_A_CLK_BUFF_EN2__POR,
+	[TABLA_A_LDO_H_MODE_1] = TABLA_A_LDO_H_MODE_1__POR,
+	[TABLA_A_LDO_H_MODE_2] = TABLA_A_LDO_H_MODE_2__POR,
+	[TABLA_A_LDO_H_LOOP_CTL] = TABLA_A_LDO_H_LOOP_CTL__POR,
+	[TABLA_A_LDO_H_COMP_1] = TABLA_A_LDO_H_COMP_1__POR,
+	[TABLA_A_LDO_H_COMP_2] = TABLA_A_LDO_H_COMP_2__POR,
+	[TABLA_A_LDO_H_BIAS_1] = TABLA_A_LDO_H_BIAS_1__POR,
+	[TABLA_A_LDO_H_BIAS_2] = TABLA_A_LDO_H_BIAS_2__POR,
+	[TABLA_A_LDO_H_BIAS_3] = TABLA_A_LDO_H_BIAS_3__POR,
+	[TABLA_A_LDO_L_MODE_1] = TABLA_A_LDO_L_MODE_1__POR,
+	[TABLA_A_LDO_L_MODE_2] = TABLA_A_LDO_L_MODE_2__POR,
+	[TABLA_A_LDO_L_LOOP_CTL] = TABLA_A_LDO_L_LOOP_CTL__POR,
+	[TABLA_A_LDO_L_COMP_1] = TABLA_A_LDO_L_COMP_1__POR,
+	[TABLA_A_LDO_L_COMP_2] = TABLA_A_LDO_L_COMP_2__POR,
+	[TABLA_A_LDO_L_BIAS_1] = TABLA_A_LDO_L_BIAS_1__POR,
+	[TABLA_A_LDO_L_BIAS_2] = TABLA_A_LDO_L_BIAS_2__POR,
+	[TABLA_A_LDO_L_BIAS_3] = TABLA_A_LDO_L_BIAS_3__POR,
+	[TABLA_A_MICB_CFILT_1_CTL] = TABLA_A_MICB_CFILT_1_CTL__POR,
+	[TABLA_A_MICB_CFILT_1_VAL] = TABLA_A_MICB_CFILT_1_VAL__POR,
+	[TABLA_A_MICB_CFILT_1_PRECHRG] = TABLA_A_MICB_CFILT_1_PRECHRG__POR,
+	[TABLA_A_MICB_1_CTL] = TABLA_A_MICB_1_CTL__POR,
+	[TABLA_A_MICB_1_INT_RBIAS] = TABLA_A_MICB_1_INT_RBIAS__POR,
+	[TABLA_A_MICB_1_MBHC] = TABLA_A_MICB_1_MBHC__POR,
+	[TABLA_A_MICB_CFILT_2_CTL] = TABLA_A_MICB_CFILT_2_CTL__POR,
+	[TABLA_A_MICB_CFILT_2_VAL] = TABLA_A_MICB_CFILT_2_VAL__POR,
+	[TABLA_A_MICB_CFILT_2_PRECHRG] = TABLA_A_MICB_CFILT_2_PRECHRG__POR,
+	[TABLA_A_MICB_2_CTL] = TABLA_A_MICB_2_CTL__POR,
+	[TABLA_A_MICB_2_INT_RBIAS] = TABLA_A_MICB_2_INT_RBIAS__POR,
+	[TABLA_A_MICB_2_MBHC] = TABLA_A_MICB_2_MBHC__POR,
+	[TABLA_A_MICB_CFILT_3_CTL] = TABLA_A_MICB_CFILT_3_CTL__POR,
+	[TABLA_A_MICB_CFILT_3_VAL] = TABLA_A_MICB_CFILT_3_VAL__POR,
+	[TABLA_A_MICB_CFILT_3_PRECHRG] = TABLA_A_MICB_CFILT_3_PRECHRG__POR,
+	[TABLA_A_MICB_3_CTL] = TABLA_A_MICB_3_CTL__POR,
+	[TABLA_A_MICB_3_INT_RBIAS] = TABLA_A_MICB_3_INT_RBIAS__POR,
+	[TABLA_A_MICB_3_MBHC] = TABLA_A_MICB_3_MBHC__POR,
+	[TABLA_A_MICB_4_CTL] = TABLA_A_MICB_4_CTL__POR,
+	[TABLA_A_MICB_4_INT_RBIAS] = TABLA_A_MICB_4_INT_RBIAS__POR,
+	[TABLA_A_MICB_4_MBHC] = TABLA_A_MICB_4_MBHC__POR,
+	[TABLA_A_TX_COM_BIAS] = TABLA_A_TX_COM_BIAS__POR,
+	[TABLA_A_MBHC_SCALING_MUX_1] = TABLA_A_MBHC_SCALING_MUX_1__POR,
+	[TABLA_A_MBHC_SCALING_MUX_2] = TABLA_A_MBHC_SCALING_MUX_2__POR,
+	[TABLA_A_TX_SUP_SWITCH_CTRL_1] = TABLA_A_TX_SUP_SWITCH_CTRL_1__POR,
+	[TABLA_A_TX_SUP_SWITCH_CTRL_2] = TABLA_A_TX_SUP_SWITCH_CTRL_2__POR,
+	[TABLA_A_TX_1_2_EN] = TABLA_A_TX_1_2_EN__POR,
+	[TABLA_A_TX_1_2_TEST_EN] = TABLA_A_TX_1_2_TEST_EN__POR,
+	[TABLA_A_TX_1_2_ADC_CH1] = TABLA_A_TX_1_2_ADC_CH1__POR,
+	[TABLA_A_TX_1_2_ADC_CH2] = TABLA_A_TX_1_2_ADC_CH2__POR,
+	[TABLA_A_TX_1_2_ATEST_REFCTRL] = TABLA_A_TX_1_2_ATEST_REFCTRL__POR,
+	[TABLA_A_TX_1_2_TEST_CTL] = TABLA_A_TX_1_2_TEST_CTL__POR,
+	[TABLA_A_TX_1_2_TEST_BLOCK_EN] = TABLA_A_TX_1_2_TEST_BLOCK_EN__POR,
+	[TABLA_A_TX_1_2_TXFE_CLKDIV] = TABLA_A_TX_1_2_TXFE_CLKDIV__POR,
+	[TABLA_A_TX_1_2_SAR_ERR_CH1] = TABLA_A_TX_1_2_SAR_ERR_CH1__POR,
+	[TABLA_A_TX_1_2_SAR_ERR_CH2] = TABLA_A_TX_1_2_SAR_ERR_CH2__POR,
+	[TABLA_A_TX_3_4_EN] = TABLA_A_TX_3_4_EN__POR,
+	[TABLA_A_TX_3_4_TEST_EN] = TABLA_A_TX_3_4_TEST_EN__POR,
+	[TABLA_A_TX_3_4_ADC_CH3] = TABLA_A_TX_3_4_ADC_CH3__POR,
+	[TABLA_A_TX_3_4_ADC_CH4] = TABLA_A_TX_3_4_ADC_CH4__POR,
+	[TABLA_A_TX_3_4_ATEST_REFCTRL] = TABLA_A_TX_3_4_ATEST_REFCTRL__POR,
+	[TABLA_A_TX_3_4_TEST_CTL] = TABLA_A_TX_3_4_TEST_CTL__POR,
+	[TABLA_A_TX_3_4_TEST_BLOCK_EN] = TABLA_A_TX_3_4_TEST_BLOCK_EN__POR,
+	[TABLA_A_TX_3_4_TXFE_CKDIV] = TABLA_A_TX_3_4_TXFE_CKDIV__POR,
+	[TABLA_A_TX_3_4_SAR_ERR_CH3] = TABLA_A_TX_3_4_SAR_ERR_CH3__POR,
+	[TABLA_A_TX_3_4_SAR_ERR_CH4] = TABLA_A_TX_3_4_SAR_ERR_CH4__POR,
+	[TABLA_A_TX_5_6_EN] = TABLA_A_TX_5_6_EN__POR,
+	[TABLA_A_TX_5_6_TEST_EN] = TABLA_A_TX_5_6_TEST_EN__POR,
+	[TABLA_A_TX_5_6_ADC_CH5] = TABLA_A_TX_5_6_ADC_CH5__POR,
+	[TABLA_A_TX_5_6_ADC_CH6] = TABLA_A_TX_5_6_ADC_CH6__POR,
+	[TABLA_A_TX_5_6_ATEST_REFCTRL] = TABLA_A_TX_5_6_ATEST_REFCTRL__POR,
+	[TABLA_A_TX_5_6_TEST_CTL] = TABLA_A_TX_5_6_TEST_CTL__POR,
+	[TABLA_A_TX_5_6_TEST_BLOCK_EN] = TABLA_A_TX_5_6_TEST_BLOCK_EN__POR,
+	[TABLA_A_TX_5_6_TXFE_CKDIV] = TABLA_A_TX_5_6_TXFE_CKDIV__POR,
+	[TABLA_A_TX_5_6_SAR_ERR_CH5] = TABLA_A_TX_5_6_SAR_ERR_CH5__POR,
+	[TABLA_A_TX_5_6_SAR_ERR_CH6] = TABLA_A_TX_5_6_SAR_ERR_CH6__POR,
+	[TABLA_A_TX_7_MBHC_EN] = TABLA_A_TX_7_MBHC_EN__POR,
+	[TABLA_A_TX_7_MBHC_ATEST_REFCTRL] =
+		TABLA_A_TX_7_MBHC_ATEST_REFCTRL__POR,
+	[TABLA_A_TX_7_MBHC_ADC] = TABLA_A_TX_7_MBHC_ADC__POR,
+	[TABLA_A_TX_7_MBHC_TEST_CTL] = TABLA_A_TX_7_MBHC_TEST_CTL__POR,
+	[TABLA_A_TX_7_MBHC_SAR_ERR] = TABLA_A_TX_7_MBHC_SAR_ERR__POR,
+	[TABLA_A_TX_7_TXFE_CLKDIV] = TABLA_A_TX_7_TXFE_CLKDIV__POR,
+	[TABLA_A_AUX_COM_CTL] = TABLA_A_AUX_COM_CTL__POR,
+	[TABLA_A_AUX_COM_ATEST] = TABLA_A_AUX_COM_ATEST__POR,
+	[TABLA_A_AUX_L_EN] = TABLA_A_AUX_L_EN__POR,
+	[TABLA_A_AUX_L_GAIN] = TABLA_A_AUX_L_GAIN__POR,
+	[TABLA_A_AUX_L_PA_CONN] = TABLA_A_AUX_L_PA_CONN__POR,
+	[TABLA_A_AUX_L_PA_CONN_INV] = TABLA_A_AUX_L_PA_CONN_INV__POR,
+	[TABLA_A_AUX_R_EN] = TABLA_A_AUX_R_EN__POR,
+	[TABLA_A_AUX_R_GAIN] = TABLA_A_AUX_R_GAIN__POR,
+	[TABLA_A_AUX_R_PA_CONN] = TABLA_A_AUX_R_PA_CONN__POR,
+	[TABLA_A_AUX_R_PA_CONN_INV] = TABLA_A_AUX_R_PA_CONN_INV__POR,
+	[TABLA_A_CP_EN] = TABLA_A_CP_EN__POR,
+	[TABLA_A_CP_CLK] = TABLA_A_CP_CLK__POR,
+	[TABLA_A_CP_STATIC] = TABLA_A_CP_STATIC__POR,
+	[TABLA_A_CP_DCC1] = TABLA_A_CP_DCC1__POR,
+	[TABLA_A_CP_DCC3] = TABLA_A_CP_DCC3__POR,
+	[TABLA_A_CP_ATEST] = TABLA_A_CP_ATEST__POR,
+	[TABLA_A_CP_DTEST] = TABLA_A_CP_DTEST__POR,
+	[TABLA_A_RX_COM_TIMER_DIV] = TABLA_A_RX_COM_TIMER_DIV__POR,
+	[TABLA_A_RX_COM_OCP_CTL] = TABLA_A_RX_COM_OCP_CTL__POR,
+	[TABLA_A_RX_COM_OCP_COUNT] = TABLA_A_RX_COM_OCP_COUNT__POR,
+	[TABLA_A_RX_COM_DAC_CTL] = TABLA_A_RX_COM_DAC_CTL__POR,
+	[TABLA_A_RX_COM_BIAS] = TABLA_A_RX_COM_BIAS__POR,
+	[TABLA_A_RX_HPH_BIAS_PA] = TABLA_A_RX_HPH_BIAS_PA__POR,
+	[TABLA_A_RX_HPH_BIAS_LDO] = TABLA_A_RX_HPH_BIAS_LDO__POR,
+	[TABLA_A_RX_HPH_BIAS_CNP] = TABLA_A_RX_HPH_BIAS_CNP__POR,
+	[TABLA_A_RX_HPH_BIAS_WG] = TABLA_A_RX_HPH_BIAS_WG__POR,
+	[TABLA_A_RX_HPH_OCP_CTL] = TABLA_A_RX_HPH_OCP_CTL__POR,
+	[TABLA_A_RX_HPH_CNP_EN] = TABLA_A_RX_HPH_CNP_EN__POR,
+	[TABLA_A_RX_HPH_CNP_WG_CTL] = TABLA_A_RX_HPH_CNP_WG_CTL__POR,
+	[TABLA_A_RX_HPH_CNP_WG_TIME] = TABLA_A_RX_HPH_CNP_WG_TIME__POR,
+	[TABLA_A_RX_HPH_L_GAIN] = TABLA_A_RX_HPH_L_GAIN__POR,
+	[TABLA_A_RX_HPH_L_TEST] = TABLA_A_RX_HPH_L_TEST__POR,
+	[TABLA_A_RX_HPH_L_PA_CTL] = TABLA_A_RX_HPH_L_PA_CTL__POR,
+	[TABLA_A_RX_HPH_L_DAC_CTL] = TABLA_A_RX_HPH_L_DAC_CTL__POR,
+	[TABLA_A_RX_HPH_L_ATEST] = TABLA_A_RX_HPH_L_ATEST__POR,
+	[TABLA_A_RX_HPH_L_STATUS] = TABLA_A_RX_HPH_L_STATUS__POR,
+	[TABLA_A_RX_HPH_R_GAIN] = TABLA_A_RX_HPH_R_GAIN__POR,
+	[TABLA_A_RX_HPH_R_TEST] = TABLA_A_RX_HPH_R_TEST__POR,
+	[TABLA_A_RX_HPH_R_PA_CTL] = TABLA_A_RX_HPH_R_PA_CTL__POR,
+	[TABLA_A_RX_HPH_R_DAC_CTL] = TABLA_A_RX_HPH_R_DAC_CTL__POR,
+	[TABLA_A_RX_HPH_R_ATEST] = TABLA_A_RX_HPH_R_ATEST__POR,
+	[TABLA_A_RX_HPH_R_STATUS] = TABLA_A_RX_HPH_R_STATUS__POR,
+	[TABLA_A_RX_EAR_BIAS_PA] = TABLA_A_RX_EAR_BIAS_PA__POR,
+	[TABLA_A_RX_EAR_BIAS_CMBUFF] = TABLA_A_RX_EAR_BIAS_CMBUFF__POR,
+	[TABLA_A_RX_EAR_EN] = TABLA_A_RX_EAR_EN__POR,
+	[TABLA_A_RX_EAR_GAIN] = TABLA_A_RX_EAR_GAIN__POR,
+	[TABLA_A_RX_EAR_CMBUFF] = TABLA_A_RX_EAR_CMBUFF__POR,
+	[TABLA_A_RX_EAR_ICTL] = TABLA_A_RX_EAR_ICTL__POR,
+	[TABLA_A_RX_EAR_CCOMP] = TABLA_A_RX_EAR_CCOMP__POR,
+	[TABLA_A_RX_EAR_VCM] = TABLA_A_RX_EAR_VCM__POR,
+	[TABLA_A_RX_EAR_CNP] = TABLA_A_RX_EAR_CNP__POR,
+	[TABLA_A_RX_EAR_ATEST] = TABLA_A_RX_EAR_ATEST__POR,
+	[TABLA_A_RX_EAR_STATUS] = TABLA_A_RX_EAR_STATUS__POR,
+	[TABLA_A_RX_LINE_BIAS_PA] = TABLA_A_RX_LINE_BIAS_PA__POR,
+	[TABLA_A_RX_LINE_BIAS_DAC] = TABLA_A_RX_LINE_BIAS_DAC__POR,
+	[TABLA_A_RX_LINE_BIAS_CNP] = TABLA_A_RX_LINE_BIAS_CNP__POR,
+	[TABLA_A_RX_LINE_COM] = TABLA_A_RX_LINE_COM__POR,
+	[TABLA_A_RX_LINE_CNP_EN] = TABLA_A_RX_LINE_CNP_EN__POR,
+	[TABLA_A_RX_LINE_CNP_WG_CTL] = TABLA_A_RX_LINE_CNP_WG_CTL__POR,
+	[TABLA_A_RX_LINE_CNP_WG_TIME] = TABLA_A_RX_LINE_CNP_WG_TIME__POR,
+	[TABLA_A_RX_LINE_1_GAIN] = TABLA_A_RX_LINE_1_GAIN__POR,
+	[TABLA_A_RX_LINE_1_TEST] = TABLA_A_RX_LINE_1_TEST__POR,
+	[TABLA_A_RX_LINE_1_DAC_CTL] = TABLA_A_RX_LINE_1_DAC_CTL__POR,
+	[TABLA_A_RX_LINE_1_STATUS] = TABLA_A_RX_LINE_1_STATUS__POR,
+	[TABLA_A_RX_LINE_2_GAIN] = TABLA_A_RX_LINE_2_GAIN__POR,
+	[TABLA_A_RX_LINE_2_TEST] = TABLA_A_RX_LINE_2_TEST__POR,
+	[TABLA_A_RX_LINE_2_DAC_CTL] = TABLA_A_RX_LINE_2_DAC_CTL__POR,
+	[TABLA_A_RX_LINE_2_STATUS] = TABLA_A_RX_LINE_2_STATUS__POR,
+	[TABLA_A_RX_LINE_3_GAIN] = TABLA_A_RX_LINE_3_GAIN__POR,
+	[TABLA_A_RX_LINE_3_TEST] = TABLA_A_RX_LINE_3_TEST__POR,
+	[TABLA_A_RX_LINE_3_DAC_CTL] = TABLA_A_RX_LINE_3_DAC_CTL__POR,
+	[TABLA_A_RX_LINE_3_STATUS] = TABLA_A_RX_LINE_3_STATUS__POR,
+	[TABLA_A_RX_LINE_4_GAIN] = TABLA_A_RX_LINE_4_GAIN__POR,
+	[TABLA_A_RX_LINE_4_TEST] = TABLA_A_RX_LINE_4_TEST__POR,
+	[TABLA_A_RX_LINE_4_DAC_CTL] = TABLA_A_RX_LINE_4_DAC_CTL__POR,
+	[TABLA_A_RX_LINE_4_STATUS] = TABLA_A_RX_LINE_4_STATUS__POR,
+	[TABLA_A_RX_LINE_5_GAIN] = TABLA_A_RX_LINE_5_GAIN__POR,
+	[TABLA_A_RX_LINE_5_TEST] = TABLA_A_RX_LINE_5_TEST__POR,
+	[TABLA_A_RX_LINE_5_DAC_CTL] = TABLA_A_RX_LINE_5_DAC_CTL__POR,
+	[TABLA_A_RX_LINE_5_STATUS] = TABLA_A_RX_LINE_5_STATUS__POR,
+	[TABLA_A_RX_LINE_CNP_DBG] = TABLA_A_RX_LINE_CNP_DBG__POR,
+	[TABLA_A_MBHC_HPH] = TABLA_A_MBHC_HPH__POR,
+	[TABLA_A_CONFIG_MODE_FREQ] = TABLA_A_CONFIG_MODE_FREQ__POR,
+	[TABLA_A_CONFIG_MODE_TEST] = TABLA_A_CONFIG_MODE_TEST__POR,
+	[TABLA_A_CONFIG_MODE_STATUS] = TABLA_A_CONFIG_MODE_STATUS__POR,
+	[TABLA_A_CONFIG_MODE_TUNER] = TABLA_A_CONFIG_MODE_TUNER__POR,
+	[TABLA_A_CDC_TX1_VOL_CTL_TIMER] = TABLA_A_CDC_TX1_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX2_VOL_CTL_TIMER] = TABLA_A_CDC_TX2_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX3_VOL_CTL_TIMER] = TABLA_A_CDC_TX3_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX4_VOL_CTL_TIMER] = TABLA_A_CDC_TX4_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX5_VOL_CTL_TIMER] = TABLA_A_CDC_TX5_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX6_VOL_CTL_TIMER] = TABLA_A_CDC_TX6_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX7_VOL_CTL_TIMER] = TABLA_A_CDC_TX7_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX8_VOL_CTL_TIMER] = TABLA_A_CDC_TX8_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX9_VOL_CTL_TIMER] = TABLA_A_CDC_TX9_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX10_VOL_CTL_TIMER] = TABLA_A_CDC_TX10_VOL_CTL_TIMER__POR,
+	[TABLA_A_CDC_TX1_VOL_CTL_GAIN] = TABLA_A_CDC_TX1_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX2_VOL_CTL_GAIN] = TABLA_A_CDC_TX2_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX3_VOL_CTL_GAIN] = TABLA_A_CDC_TX3_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX4_VOL_CTL_GAIN] = TABLA_A_CDC_TX4_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX5_VOL_CTL_GAIN] = TABLA_A_CDC_TX5_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX6_VOL_CTL_GAIN] = TABLA_A_CDC_TX6_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX7_VOL_CTL_GAIN] = TABLA_A_CDC_TX7_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX8_VOL_CTL_GAIN] = TABLA_A_CDC_TX8_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX9_VOL_CTL_GAIN] = TABLA_A_CDC_TX9_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX10_VOL_CTL_GAIN] = TABLA_A_CDC_TX10_VOL_CTL_GAIN__POR,
+	[TABLA_A_CDC_TX1_VOL_CTL_CFG] = TABLA_A_CDC_TX1_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX2_VOL_CTL_CFG] = TABLA_A_CDC_TX2_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX3_VOL_CTL_CFG] = TABLA_A_CDC_TX3_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX4_VOL_CTL_CFG] = TABLA_A_CDC_TX4_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX5_VOL_CTL_CFG] = TABLA_A_CDC_TX5_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX6_VOL_CTL_CFG] = TABLA_A_CDC_TX6_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX7_VOL_CTL_CFG] = TABLA_A_CDC_TX7_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX8_VOL_CTL_CFG] = TABLA_A_CDC_TX8_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX9_VOL_CTL_CFG] = TABLA_A_CDC_TX9_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX10_VOL_CTL_CFG] = TABLA_A_CDC_TX10_VOL_CTL_CFG__POR,
+	[TABLA_A_CDC_TX1_MUX_CTL] = TABLA_A_CDC_TX1_MUX_CTL__POR,
+	[TABLA_A_CDC_TX2_MUX_CTL] = TABLA_A_CDC_TX2_MUX_CTL__POR,
+	[TABLA_A_CDC_TX3_MUX_CTL] = TABLA_A_CDC_TX3_MUX_CTL__POR,
+	[TABLA_A_CDC_TX4_MUX_CTL] = TABLA_A_CDC_TX4_MUX_CTL__POR,
+	[TABLA_A_CDC_TX5_MUX_CTL] = TABLA_A_CDC_TX5_MUX_CTL__POR,
+	[TABLA_A_CDC_TX6_MUX_CTL] = TABLA_A_CDC_TX6_MUX_CTL__POR,
+	[TABLA_A_CDC_TX7_MUX_CTL] = TABLA_A_CDC_TX7_MUX_CTL__POR,
+	[TABLA_A_CDC_TX8_MUX_CTL] = TABLA_A_CDC_TX8_MUX_CTL__POR,
+	[TABLA_A_CDC_TX9_MUX_CTL] = TABLA_A_CDC_TX9_MUX_CTL__POR,
+	[TABLA_A_CDC_TX10_MUX_CTL] = TABLA_A_CDC_TX10_MUX_CTL__POR,
+	[TABLA_A_CDC_TX1_CLK_FS_CTL] = TABLA_A_CDC_TX1_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX2_CLK_FS_CTL] = TABLA_A_CDC_TX2_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX3_CLK_FS_CTL] = TABLA_A_CDC_TX3_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX4_CLK_FS_CTL] = TABLA_A_CDC_TX4_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX5_CLK_FS_CTL] = TABLA_A_CDC_TX5_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX6_CLK_FS_CTL] = TABLA_A_CDC_TX6_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX7_CLK_FS_CTL] = TABLA_A_CDC_TX7_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX8_CLK_FS_CTL] = TABLA_A_CDC_TX8_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX9_CLK_FS_CTL] = TABLA_A_CDC_TX9_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX10_CLK_FS_CTL] = TABLA_A_CDC_TX10_CLK_FS_CTL__POR,
+	[TABLA_A_CDC_TX1_DMIC_CTL] = TABLA_A_CDC_TX1_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX2_DMIC_CTL] = TABLA_A_CDC_TX2_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX3_DMIC_CTL] = TABLA_A_CDC_TX3_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX4_DMIC_CTL] = TABLA_A_CDC_TX4_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX5_DMIC_CTL] = TABLA_A_CDC_TX5_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX6_DMIC_CTL] = TABLA_A_CDC_TX6_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX7_DMIC_CTL] = TABLA_A_CDC_TX7_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX8_DMIC_CTL] = TABLA_A_CDC_TX8_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX9_DMIC_CTL] = TABLA_A_CDC_TX9_DMIC_CTL__POR,
+	[TABLA_A_CDC_TX10_DMIC_CTL] = TABLA_A_CDC_TX10_DMIC_CTL__POR,
+	[TABLA_A_CDC_SRC1_PDA_CFG] = TABLA_A_CDC_SRC1_PDA_CFG__POR,
+	[TABLA_A_CDC_SRC2_PDA_CFG] = TABLA_A_CDC_SRC2_PDA_CFG__POR,
+	[TABLA_A_CDC_SRC1_FS_CTL] = TABLA_A_CDC_SRC1_FS_CTL__POR,
+	[TABLA_A_CDC_SRC2_FS_CTL] = TABLA_A_CDC_SRC2_FS_CTL__POR,
+	[TABLA_A_CDC_RX1_B1_CTL] = TABLA_A_CDC_RX1_B1_CTL__POR,
+	[TABLA_A_CDC_RX2_B1_CTL] = TABLA_A_CDC_RX2_B1_CTL__POR,
+	[TABLA_A_CDC_RX3_B1_CTL] = TABLA_A_CDC_RX3_B1_CTL__POR,
+	[TABLA_A_CDC_RX4_B1_CTL] = TABLA_A_CDC_RX4_B1_CTL__POR,
+	[TABLA_A_CDC_RX5_B1_CTL] = TABLA_A_CDC_RX5_B1_CTL__POR,
+	[TABLA_A_CDC_RX6_B1_CTL] = TABLA_A_CDC_RX6_B1_CTL__POR,
+	[TABLA_A_CDC_RX7_B1_CTL] = TABLA_A_CDC_RX7_B1_CTL__POR,
+	[TABLA_A_CDC_RX1_B2_CTL] = TABLA_A_CDC_RX1_B2_CTL__POR,
+	[TABLA_A_CDC_RX2_B2_CTL] = TABLA_A_CDC_RX2_B2_CTL__POR,
+	[TABLA_A_CDC_RX3_B2_CTL] = TABLA_A_CDC_RX3_B2_CTL__POR,
+	[TABLA_A_CDC_RX4_B2_CTL] = TABLA_A_CDC_RX4_B2_CTL__POR,
+	[TABLA_A_CDC_RX5_B2_CTL] = TABLA_A_CDC_RX5_B2_CTL__POR,
+	[TABLA_A_CDC_RX6_B2_CTL] = TABLA_A_CDC_RX6_B2_CTL__POR,
+	[TABLA_A_CDC_RX7_B2_CTL] = TABLA_A_CDC_RX7_B2_CTL__POR,
+	[TABLA_A_CDC_RX1_B3_CTL] = TABLA_A_CDC_RX1_B3_CTL__POR,
+	[TABLA_A_CDC_RX2_B3_CTL] = TABLA_A_CDC_RX2_B3_CTL__POR,
+	[TABLA_A_CDC_RX3_B3_CTL] = TABLA_A_CDC_RX3_B3_CTL__POR,
+	[TABLA_A_CDC_RX4_B3_CTL] = TABLA_A_CDC_RX4_B3_CTL__POR,
+	[TABLA_A_CDC_RX5_B3_CTL] = TABLA_A_CDC_RX5_B3_CTL__POR,
+	[TABLA_A_CDC_RX6_B3_CTL] = TABLA_A_CDC_RX6_B3_CTL__POR,
+	[TABLA_A_CDC_RX7_B3_CTL] = TABLA_A_CDC_RX7_B3_CTL__POR,
+	[TABLA_A_CDC_RX1_B4_CTL] = TABLA_A_CDC_RX1_B4_CTL__POR,
+	[TABLA_A_CDC_RX2_B4_CTL] = TABLA_A_CDC_RX2_B4_CTL__POR,
+	[TABLA_A_CDC_RX3_B4_CTL] = TABLA_A_CDC_RX3_B4_CTL__POR,
+	[TABLA_A_CDC_RX4_B4_CTL] = TABLA_A_CDC_RX4_B4_CTL__POR,
+	[TABLA_A_CDC_RX5_B4_CTL] = TABLA_A_CDC_RX5_B4_CTL__POR,
+	[TABLA_A_CDC_RX6_B4_CTL] = TABLA_A_CDC_RX6_B4_CTL__POR,
+	[TABLA_A_CDC_RX7_B4_CTL] = TABLA_A_CDC_RX7_B4_CTL__POR,
+	[TABLA_A_CDC_RX1_B5_CTL] = TABLA_A_CDC_RX1_B5_CTL__POR,
+	[TABLA_A_CDC_RX2_B5_CTL] = TABLA_A_CDC_RX2_B5_CTL__POR,
+	[TABLA_A_CDC_RX3_B5_CTL] = TABLA_A_CDC_RX3_B5_CTL__POR,
+	[TABLA_A_CDC_RX4_B5_CTL] = TABLA_A_CDC_RX4_B5_CTL__POR,
+	[TABLA_A_CDC_RX5_B5_CTL] = TABLA_A_CDC_RX5_B5_CTL__POR,
+	[TABLA_A_CDC_RX6_B5_CTL] = TABLA_A_CDC_RX6_B5_CTL__POR,
+	[TABLA_A_CDC_RX7_B5_CTL] = TABLA_A_CDC_RX7_B5_CTL__POR,
+	[TABLA_A_CDC_RX1_B6_CTL] = TABLA_A_CDC_RX1_B6_CTL__POR,
+	[TABLA_A_CDC_RX2_B6_CTL] = TABLA_A_CDC_RX2_B6_CTL__POR,
+	[TABLA_A_CDC_RX3_B6_CTL] = TABLA_A_CDC_RX3_B6_CTL__POR,
+	[TABLA_A_CDC_RX4_B6_CTL] = TABLA_A_CDC_RX4_B6_CTL__POR,
+	[TABLA_A_CDC_RX5_B6_CTL] = TABLA_A_CDC_RX5_B6_CTL__POR,
+	[TABLA_A_CDC_RX6_B6_CTL] = TABLA_A_CDC_RX6_B6_CTL__POR,
+	[TABLA_A_CDC_RX7_B6_CTL] = TABLA_A_CDC_RX7_B6_CTL__POR,
+	[TABLA_A_CDC_RX1_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX2_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX2_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX3_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX3_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX4_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX4_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX5_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX5_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX6_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX6_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX7_VOL_CTL_B1_CTL] = TABLA_A_CDC_RX7_VOL_CTL_B1_CTL__POR,
+	[TABLA_A_CDC_RX1_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_RX2_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX2_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_RX3_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX3_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_RX4_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX4_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_RX5_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX5_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_RX6_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX6_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_RX7_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX7_VOL_CTL_B2_CTL__POR,
+	[TABLA_A_CDC_CLK_RX_RESET_CTL] = TABLA_A_CDC_CLK_RX_RESET_CTL__POR,
+	[TABLA_A_CDC_CLK_TX_RESET_B1_CTL] =
+		TABLA_A_CDC_CLK_TX_RESET_B1_CTL__POR,
+	[TABLA_A_CDC_CLK_TX_RESET_B2_CTL] =
+		TABLA_A_CDC_CLK_TX_RESET_B2_CTL__POR,
+	[TABLA_A_CDC_CLK_DMIC_CTL] = TABLA_A_CDC_CLK_DMIC_CTL__POR,
+	[TABLA_A_CDC_CLK_RX_I2S_CTL] = TABLA_A_CDC_CLK_RX_I2S_CTL__POR,
+	[TABLA_A_CDC_CLK_TX_I2S_CTL] = TABLA_A_CDC_CLK_TX_I2S_CTL__POR,
+	[TABLA_A_CDC_CLK_OTHR_RESET_CTL] = TABLA_A_CDC_CLK_OTHR_RESET_CTL__POR,
+	[TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
+		TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
+	[TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL] =
+		TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR,
+	[TABLA_A_CDC_CLK_OTHR_CTL] = TABLA_A_CDC_CLK_OTHR_CTL__POR,
+	[TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL] =
+		TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL__POR,
+	[TABLA_A_CDC_CLK_RX_B1_CTL] = TABLA_A_CDC_CLK_RX_B1_CTL__POR,
+	[TABLA_A_CDC_CLK_RX_B2_CTL] = TABLA_A_CDC_CLK_RX_B2_CTL__POR,
+	[TABLA_A_CDC_CLK_MCLK_CTL] = TABLA_A_CDC_CLK_MCLK_CTL__POR,
+	[TABLA_A_CDC_CLK_PDM_CTL] = TABLA_A_CDC_CLK_PDM_CTL__POR,
+	[TABLA_A_CDC_CLK_SD_CTL] = TABLA_A_CDC_CLK_SD_CTL__POR,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B1_CTL] =
+		TABLA_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B2_CTL] =
+		TABLA_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL] =
+		TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR,
+	[TABLA_A_CDC_CLSG_FREQ_THRESH_B4_CTL] =
+		TABLA_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR,
+	[TABLA_A_CDC_CLSG_GAIN_THRESH_CTL] =
+		TABLA_A_CDC_CLSG_GAIN_THRESH_CTL__POR,
+	[TABLA_A_CDC_CLSG_TIMER_B1_CFG] = TABLA_A_CDC_CLSG_TIMER_B1_CFG__POR,
+	[TABLA_A_CDC_CLSG_TIMER_B2_CFG] = TABLA_A_CDC_CLSG_TIMER_B2_CFG__POR,
+	[TABLA_A_CDC_CLSG_CTL] = TABLA_A_CDC_CLSG_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B1_CTL] = TABLA_A_CDC_IIR1_GAIN_B1_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B1_CTL] = TABLA_A_CDC_IIR2_GAIN_B1_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B2_CTL] = TABLA_A_CDC_IIR1_GAIN_B2_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B2_CTL] = TABLA_A_CDC_IIR2_GAIN_B2_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B3_CTL] = TABLA_A_CDC_IIR1_GAIN_B3_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B3_CTL] = TABLA_A_CDC_IIR2_GAIN_B3_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B4_CTL] = TABLA_A_CDC_IIR1_GAIN_B4_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B4_CTL] = TABLA_A_CDC_IIR2_GAIN_B4_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B5_CTL] = TABLA_A_CDC_IIR1_GAIN_B5_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B5_CTL] = TABLA_A_CDC_IIR2_GAIN_B5_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B6_CTL] = TABLA_A_CDC_IIR1_GAIN_B6_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B6_CTL] = TABLA_A_CDC_IIR2_GAIN_B6_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B7_CTL] = TABLA_A_CDC_IIR1_GAIN_B7_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B7_CTL] = TABLA_A_CDC_IIR2_GAIN_B7_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_B8_CTL] = TABLA_A_CDC_IIR1_GAIN_B8_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_B8_CTL] = TABLA_A_CDC_IIR2_GAIN_B8_CTL__POR,
+	[TABLA_A_CDC_IIR1_CTL] = TABLA_A_CDC_IIR1_CTL__POR,
+	[TABLA_A_CDC_IIR2_CTL] = TABLA_A_CDC_IIR2_CTL__POR,
+	[TABLA_A_CDC_IIR1_GAIN_TIMER_CTL] =
+		TABLA_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
+	[TABLA_A_CDC_IIR2_GAIN_TIMER_CTL] =
+		TABLA_A_CDC_IIR2_GAIN_TIMER_CTL__POR,
+	[TABLA_A_CDC_IIR1_COEF_B1_CTL] = TABLA_A_CDC_IIR1_COEF_B1_CTL__POR,
+	[TABLA_A_CDC_IIR2_COEF_B1_CTL] = TABLA_A_CDC_IIR2_COEF_B1_CTL__POR,
+	[TABLA_A_CDC_IIR1_COEF_B2_CTL] = TABLA_A_CDC_IIR1_COEF_B2_CTL__POR,
+	[TABLA_A_CDC_IIR2_COEF_B2_CTL] = TABLA_A_CDC_IIR2_COEF_B2_CTL__POR,
+	[TABLA_A_CDC_IIR1_COEF_B3_CTL] = TABLA_A_CDC_IIR1_COEF_B3_CTL__POR,
+	[TABLA_A_CDC_IIR2_COEF_B3_CTL] = TABLA_A_CDC_IIR2_COEF_B3_CTL__POR,
+	[TABLA_A_CDC_IIR1_COEF_B4_CTL] = TABLA_A_CDC_IIR1_COEF_B4_CTL__POR,
+	[TABLA_A_CDC_IIR2_COEF_B4_CTL] = TABLA_A_CDC_IIR2_COEF_B4_CTL__POR,
+	[TABLA_A_CDC_IIR1_COEF_B5_CTL] = TABLA_A_CDC_IIR1_COEF_B5_CTL__POR,
+	[TABLA_A_CDC_IIR2_COEF_B5_CTL] = TABLA_A_CDC_IIR2_COEF_B5_CTL__POR,
+	[TABLA_A_CDC_TOP_GAIN_UPDATE] = TABLA_A_CDC_TOP_GAIN_UPDATE__POR,
+	[TABLA_A_CDC_DEBUG_B1_CTL] = TABLA_A_CDC_DEBUG_B1_CTL__POR,
+	[TABLA_A_CDC_DEBUG_B2_CTL] = TABLA_A_CDC_DEBUG_B2_CTL__POR,
+	[TABLA_A_CDC_DEBUG_B3_CTL] = TABLA_A_CDC_DEBUG_B3_CTL__POR,
+	[TABLA_A_CDC_DEBUG_B4_CTL] = TABLA_A_CDC_DEBUG_B4_CTL__POR,
+	[TABLA_A_CDC_DEBUG_B5_CTL] = TABLA_A_CDC_DEBUG_B5_CTL__POR,
+	[TABLA_A_CDC_DEBUG_B6_CTL] = TABLA_A_CDC_DEBUG_B6_CTL__POR,
+	[TABLA_A_CDC_CONN_RX1_B1_CTL] = TABLA_A_CDC_CONN_RX1_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX1_B2_CTL] = TABLA_A_CDC_CONN_RX1_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_RX1_B3_CTL] = TABLA_A_CDC_CONN_RX1_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_RX2_B1_CTL] = TABLA_A_CDC_CONN_RX2_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX2_B2_CTL] = TABLA_A_CDC_CONN_RX2_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_RX2_B3_CTL] = TABLA_A_CDC_CONN_RX2_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_RX3_B1_CTL] = TABLA_A_CDC_CONN_RX3_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX3_B2_CTL] = TABLA_A_CDC_CONN_RX3_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_RX3_B3_CTL] = TABLA_A_CDC_CONN_RX3_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_RX4_B1_CTL] = TABLA_A_CDC_CONN_RX4_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX4_B2_CTL] = TABLA_A_CDC_CONN_RX4_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_RX5_B1_CTL] = TABLA_A_CDC_CONN_RX5_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX5_B2_CTL] = TABLA_A_CDC_CONN_RX5_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_RX6_B1_CTL] = TABLA_A_CDC_CONN_RX6_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX6_B2_CTL] = TABLA_A_CDC_CONN_RX6_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_RX7_B1_CTL] = TABLA_A_CDC_CONN_RX7_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX7_B2_CTL] = TABLA_A_CDC_CONN_RX7_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_B1_CTL] = TABLA_A_CDC_CONN_TX_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_B2_CTL] = TABLA_A_CDC_CONN_TX_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_B3_CTL] = TABLA_A_CDC_CONN_TX_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_B4_CTL] = TABLA_A_CDC_CONN_TX_B4_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ1_B1_CTL] = TABLA_A_CDC_CONN_EQ1_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ1_B2_CTL] = TABLA_A_CDC_CONN_EQ1_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ1_B3_CTL] = TABLA_A_CDC_CONN_EQ1_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ1_B4_CTL] = TABLA_A_CDC_CONN_EQ1_B4_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ2_B1_CTL] = TABLA_A_CDC_CONN_EQ2_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ2_B2_CTL] = TABLA_A_CDC_CONN_EQ2_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ2_B3_CTL] = TABLA_A_CDC_CONN_EQ2_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_EQ2_B4_CTL] = TABLA_A_CDC_CONN_EQ2_B4_CTL__POR,
+	[TABLA_A_CDC_CONN_SRC1_B1_CTL] = TABLA_A_CDC_CONN_SRC1_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_SRC1_B2_CTL] = TABLA_A_CDC_CONN_SRC1_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_SRC2_B1_CTL] = TABLA_A_CDC_CONN_SRC2_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_SRC2_B2_CTL] = TABLA_A_CDC_CONN_SRC2_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B1_CTL] = TABLA_A_CDC_CONN_TX_SB_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B2_CTL] = TABLA_A_CDC_CONN_TX_SB_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B3_CTL] = TABLA_A_CDC_CONN_TX_SB_B3_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B4_CTL] = TABLA_A_CDC_CONN_TX_SB_B4_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B5_CTL] = TABLA_A_CDC_CONN_TX_SB_B5_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B6_CTL] = TABLA_A_CDC_CONN_TX_SB_B6_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B7_CTL] = TABLA_A_CDC_CONN_TX_SB_B7_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B8_CTL] = TABLA_A_CDC_CONN_TX_SB_B8_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B9_CTL] = TABLA_A_CDC_CONN_TX_SB_B9_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B10_CTL] = TABLA_A_CDC_CONN_TX_SB_B10_CTL__POR,
+	[TABLA_A_CDC_CONN_TX_SB_B11_CTL] = TABLA_A_CDC_CONN_TX_SB_B11_CTL__POR,
+	[TABLA_A_CDC_CONN_RX_SB_B1_CTL] = TABLA_A_CDC_CONN_RX_SB_B1_CTL__POR,
+	[TABLA_A_CDC_CONN_RX_SB_B2_CTL] = TABLA_A_CDC_CONN_RX_SB_B2_CTL__POR,
+	[TABLA_A_CDC_CONN_CLSG_CTL] = TABLA_A_CDC_CONN_CLSG_CTL__POR,
+	[TABLA_A_CDC_CONN_SPARE] = TABLA_A_CDC_CONN_SPARE__POR,
+	[TABLA_A_CDC_MBHC_EN_CTL] = TABLA_A_CDC_MBHC_EN_CTL__POR,
+	[TABLA_A_CDC_MBHC_FEATURE_B1_CFG] =
+		TABLA_A_CDC_MBHC_FEATURE_B1_CFG__POR,
+	[TABLA_A_CDC_MBHC_FEATURE_B2_CFG] =
+		TABLA_A_CDC_MBHC_FEATURE_B2_CFG__POR,
+	[TABLA_A_CDC_MBHC_TIMER_B1_CTL] = TABLA_A_CDC_MBHC_TIMER_B1_CTL__POR,
+	[TABLA_A_CDC_MBHC_TIMER_B2_CTL] = TABLA_A_CDC_MBHC_TIMER_B2_CTL__POR,
+	[TABLA_A_CDC_MBHC_TIMER_B3_CTL] = TABLA_A_CDC_MBHC_TIMER_B3_CTL__POR,
+	[TABLA_A_CDC_MBHC_TIMER_B4_CTL] = TABLA_A_CDC_MBHC_TIMER_B4_CTL__POR,
+	[TABLA_A_CDC_MBHC_TIMER_B5_CTL] = TABLA_A_CDC_MBHC_TIMER_B5_CTL__POR,
+	[TABLA_A_CDC_MBHC_TIMER_B6_CTL] = TABLA_A_CDC_MBHC_TIMER_B6_CTL__POR,
+	[TABLA_A_CDC_MBHC_B1_STATUS] = TABLA_A_CDC_MBHC_B1_STATUS__POR,
+	[TABLA_A_CDC_MBHC_B2_STATUS] = TABLA_A_CDC_MBHC_B2_STATUS__POR,
+	[TABLA_A_CDC_MBHC_B3_STATUS] = TABLA_A_CDC_MBHC_B3_STATUS__POR,
+	[TABLA_A_CDC_MBHC_B4_STATUS] = TABLA_A_CDC_MBHC_B4_STATUS__POR,
+	[TABLA_A_CDC_MBHC_B5_STATUS] = TABLA_A_CDC_MBHC_B5_STATUS__POR,
+	[TABLA_A_CDC_MBHC_B1_CTL] = TABLA_A_CDC_MBHC_B1_CTL__POR,
+	[TABLA_A_CDC_MBHC_B2_CTL] = TABLA_A_CDC_MBHC_B2_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B1_CTL] = TABLA_A_CDC_MBHC_VOLT_B1_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B2_CTL] = TABLA_A_CDC_MBHC_VOLT_B2_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B3_CTL] = TABLA_A_CDC_MBHC_VOLT_B3_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B4_CTL] = TABLA_A_CDC_MBHC_VOLT_B4_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B5_CTL] = TABLA_A_CDC_MBHC_VOLT_B5_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B6_CTL] = TABLA_A_CDC_MBHC_VOLT_B6_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B7_CTL] = TABLA_A_CDC_MBHC_VOLT_B7_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B8_CTL] = TABLA_A_CDC_MBHC_VOLT_B8_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B9_CTL] = TABLA_A_CDC_MBHC_VOLT_B9_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B10_CTL] = TABLA_A_CDC_MBHC_VOLT_B10_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B11_CTL] = TABLA_A_CDC_MBHC_VOLT_B11_CTL__POR,
+	[TABLA_A_CDC_MBHC_VOLT_B12_CTL] = TABLA_A_CDC_MBHC_VOLT_B12_CTL__POR,
+	[TABLA_A_CDC_MBHC_CLK_CTL] = TABLA_A_CDC_MBHC_CLK_CTL__POR,
+	[TABLA_A_CDC_MBHC_INT_CTL] = TABLA_A_CDC_MBHC_INT_CTL__POR,
+	[TABLA_A_CDC_MBHC_DEBUG_CTL] = TABLA_A_CDC_MBHC_DEBUG_CTL__POR,
+	[TABLA_A_CDC_MBHC_SPARE] = TABLA_A_CDC_MBHC_SPARE__POR,
+};
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
new file mode 100644
index 0000000..de1b199
--- /dev/null
+++ b/sound/soc/codecs/wcd9310.c
@@ -0,0 +1,1598 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9310/registers.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include "wcd9310.h"
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+enum tabla_bandgap_type {
+	TABLA_BANDGAP_OFF = 0,
+	TABLA_BANDGAP_AUDIO_MODE,
+	TABLA_BANDGAP_MBHC_MODE,
+};
+
+struct tabla_priv { /* member undecided */
+	struct snd_soc_codec *codec;
+	u32 ref_cnt;
+	u32 adc_count;
+	u32 dec_count;
+	enum tabla_bandgap_type bandgap_type;
+	bool clock_active;
+	bool config_mode_active;
+	bool mbhc_polling_active;
+
+	struct tabla_mbhc_calibration *calibration;
+
+	struct snd_soc_jack *jack;
+};
+
+static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if ((tabla->bandgap_type != TABLA_BANDGAP_AUDIO_MODE) ||
+			(!tabla->clock_active)) {
+			pr_err("%s: Error, Tabla must have clocks enabled for "
+				"charge pump\n", __func__);
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x01);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
+			0x01);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
+		usleep_range(200, 200);
+		snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
+			0x10);
+		usleep_range(20, 20);
+		snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
+		snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
+			0x00);
+		snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_kcontrol_new tabla_snd_controls[] = {
+	SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
+		line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
+		line_gain),
+
+	SOC_SINGLE_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL, 0,
+		100, 0, digital_gain),
+	SOC_SINGLE_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL, 0,
+		100, 0, digital_gain),
+
+	SOC_SINGLE_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, 100, 0,
+		digital_gain),
+	SOC_SINGLE_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, 100, 0,
+		digital_gain),
+
+	SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+
+	SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
+};
+
+static const char *rx_mix1_text[] = {
+	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+		"RX5", "RX6", "RX7"
+};
+
+static const char *sb_tx1_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC1"
+};
+
+static const char *sb_tx5_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC5"
+};
+
+static const char *sb_tx6_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC6"
+};
+
+static const char const *sb_tx7_to_tx10_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+		"DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+		"DEC9", "DEC10"
+};
+
+static const char *dec1_mux_text[] = {
+	"ZERO", "DMIC1", "ADC6",
+};
+
+static const char *dec5_mux_text[] = {
+	"ZERO", "DMIC5", "ADC2",
+};
+
+static const char *dec6_mux_text[] = {
+	"ZERO", "DMIC6", "ADC1",
+};
+
+static const char const *dec7_mux_text[] = {
+	"ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
+};
+
+static const char *iir1_inp1_text[] = {
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx4_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx5_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx6_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
+
+static const struct soc_enum sb_tx7_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
+			sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx8_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
+			sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+
+static const struct soc_enum dec1_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
+
+static const struct soc_enum dec5_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
+
+static const struct soc_enum dec6_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
+
+static const struct soc_enum dec7_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx6_mux =
+	SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx7_mux =
+	SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx8_mux =
+	SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new dec1_mux =
+	SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec5_mux =
+	SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
+
+static const struct snd_kcontrol_new dec6_mux =
+	SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
+
+static const struct snd_kcontrol_new dec7_mux =
+	SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new dac1_control =
+	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0);
+
+static const struct snd_kcontrol_new hphl_switch =
+	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new hphr_switch =
+	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new lineout1_switch =
+	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new lineout3_switch =
+	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
+
+static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %d\n", __func__, enable);
+
+	if (enable) {
+		tabla->adc_count++;
+		snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
+	} else {
+		tabla->adc_count--;
+		if (!tabla->adc_count) {
+			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
+				0x2, 0x0);
+			if (!tabla->mbhc_polling_active)
+				snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
+					0xE0, 0x0);
+		}
+	}
+}
+
+static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 adc_reg;
+
+	pr_debug("%s %d\n", __func__, event);
+
+	if (w->reg == TABLA_A_TX_1_2_EN)
+		adc_reg = TABLA_A_TX_1_2_TEST_CTL;
+	else if (w->reg == TABLA_A_TX_3_4_EN)
+		adc_reg = TABLA_A_TX_3_4_TEST_CTL;
+	else if (w->reg == TABLA_A_TX_5_6_EN)
+		adc_reg = TABLA_A_TX_5_6_TEST_CTL;
+	else {
+		pr_err("%s: Error, invalid adc register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tabla_codec_enable_adc_block(codec, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
+			1 << w->shift);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
+		usleep_range(1000, 1000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tabla_codec_enable_adc_block(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 lineout_gain_reg;
+
+	pr_debug("%s %d\n", __func__, event);
+
+	switch (w->shift) {
+	case 0:
+		lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
+		break;
+	case 1:
+		lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
+		break;
+	case 2:
+		lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
+		break;
+	case 3:
+		lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
+		break;
+	case 4:
+		lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
+		break;
+	default:
+		pr_err("%s: Error, incorrect lineout register value\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(40000, 40000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_enable_dmic1(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_CDC_TX1_MUX_CTL, 0x1, 0x1);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x2, 0x2);
+		snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x1, 0x1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x3, 0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 micb_cfilt_reg, micb_int_reg;
+	char *internal_text = "Internal";
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (w->reg) {
+	case TABLA_A_MICB_1_CTL:
+		micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
+		micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
+		break;
+	case TABLA_A_MICB_2_CTL:
+		micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
+		micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
+		break;
+	case TABLA_A_MICB_3_CTL:
+		micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
+		micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
+		break;
+	default:
+		pr_err("%s: Error, invalid micbias register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
+		if (strnstr(w->name, internal_text, 20))
+			snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (strnstr(w->name, internal_text, 20))
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+		snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static void tabla_codec_enable_dec_clock(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		tabla->dec_count++;
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x4, 0x4);
+	} else {
+		tabla->dec_count--;
+		if (!tabla->dec_count)
+			snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
+				0x4, 0x0);
+	}
+}
+
+static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 dec_reset_reg;
+
+	pr_debug("%s %d\n", __func__, event);
+
+	if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
+		dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
+	else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
+		dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
+	else {
+		pr_err("%s: Error, incorrect dec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tabla_codec_enable_dec_clock(codec, 1);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+			1 << w->shift);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tabla_codec_enable_dec_clock(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_reset_interpolator_1(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x1,
+			0x1);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x1,
+			0x0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_reset_interpolator_2(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x2,
+			0x2);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x2,
+			0x0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_reset_interpolator_3(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x4,
+			0x4);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x4,
+			0x0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_reset_interpolator_4(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x8,
+			0x8);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x8,
+			0x0);
+		break;
+	}
+	return 0;
+}
+
+static int tabla_codec_reset_interpolator_5(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x10,
+			0x10);
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL, 0x10,
+			0x0);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
+	/*RX stuff */
+	SND_SOC_DAPM_OUTPUT("EAR"),
+
+	SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
+		tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("DAC1", TABLA_A_RX_EAR_EN, 6, 0, &dac1_control),
+	SND_SOC_DAPM_PGA_E("RX1 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA("RX BIAS", TABLA_A_RX_COM_BIAS, 7, 0, NULL, 0),
+	SND_SOC_DAPM_MUX_E("RX1 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0,
+		&rx_mix1_inp1_mux, tabla_codec_reset_interpolator_1,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0,
+		TABLA_A_CDC_RX1_B6_CTL, 5, 0),
+
+	/* RX 2 path */
+	SND_SOC_DAPM_PGA_E("RX2 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("RX2 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0,
+		&rx2_mix1_inp1_mux, tabla_codec_reset_interpolator_2,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0,
+		TABLA_A_CDC_RX2_B6_CTL, 5, 0),
+
+	/* Headphone */
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
+		&hphl_switch),
+
+	SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
+		&hphr_switch),
+
+	/* Speaker */
+	SND_SOC_DAPM_OUTPUT("LINEOUT"),
+	SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
+		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
+		&lineout1_switch),
+	SND_SOC_DAPM_MUX_E("RX3 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0,
+		&rx3_mix1_inp1_mux, tabla_codec_reset_interpolator_3,
+		SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
+		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
+		&lineout3_switch),
+	SND_SOC_DAPM_MUX_E("RX4 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
+		&rx4_mix1_inp1_mux, tabla_codec_reset_interpolator_4,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX_E("RX5 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0,
+		&rx5_mix1_inp1_mux, tabla_codec_reset_interpolator_5,
+		SND_SOC_DAPM_PRE_PMU),
+
+	/* TX */
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
+		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal", TABLA_A_MICB_1_CTL, 7, 0,
+		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
+		tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+		&dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
+		&dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
+		&dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
+		&dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
+		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal", TABLA_A_MICB_2_CTL, 7, 0,
+		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
+		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal", TABLA_A_MICB_3_CTL, 7, 0,
+		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
+		tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			0, 0),
+
+	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			4, 0),
+
+	SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			5, 0),
+
+	SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			0, 0),
+
+	SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			0, 0),
+
+	/* Digital Mic */
+	SND_SOC_DAPM_INPUT("DMIC1 IN"),
+	SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic1),
+
+	/* Sidetone */
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* SLIMBUS Connections */
+	{"RX BIAS", NULL, "SLIM RX1"},
+	{"RX BIAS", NULL, "SLIM RX2"},
+
+	{"SLIM TX1", NULL, "SLIM TX1 MUX"},
+	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+
+	{"SLIM TX5", NULL, "SLIM TX5 MUX"},
+	{"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
+
+	{"SLIM TX6", NULL, "SLIM TX6 MUX"},
+	{"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
+
+	{"SLIM TX7", NULL, "SLIM TX7 MUX"},
+	{"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
+	{"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
+	{"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
+
+	{"SLIM TX8", NULL, "SLIM TX8 MUX"},
+	{"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
+	{"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
+
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR PA"},
+	{"EAR PA", NULL, "EAR PA Input"},
+	{"EAR PA Input", NULL, "DAC1"},
+	{"DAC1", "Switch", "RX1 CP"},
+	{"RX1 CP", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1 INP1", "RX1", "RX BIAS"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL"},
+	{"HPHL", NULL, "HPHL DAC"},
+	{"HPHL DAC", "Switch", "RX1 MIX1 INP1"},
+
+	{"HEADPHONE", NULL, "HPHR"},
+	{"HPHR", NULL, "HPHR DAC"},
+	{"HPHR DAC", "Switch", "RX2 CP"},
+	{"RX2 CP", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1 INP1", "RX2", "RX BIAS"},
+
+	/* Speaker (RX MIX3 and RX MIX4) */
+	{"LINEOUT", NULL, "LINEOUT1"},
+	{"LINEOUT1", NULL, "LINEOUT1 DAC"},
+	{"LINEOUT1 DAC", "Switch", "RX3 MIX1 INP1"},
+	{"RX3 MIX1 INP1", "RX1", "RX BIAS"},
+
+	{"LINEOUT", NULL, "LINEOUT3"},
+	{"LINEOUT3", NULL, "LINEOUT3 DAC"},
+	{"LINEOUT3 DAC", "Switch", "RX5 MIX1 INP1"},
+	{"RX4 MIX1 INP1", "RX2", "RX BIAS"},
+	{"RX5 MIX1 INP1", "RX2", "RX BIAS"},
+
+	/* Handset TX */
+	{"DEC5 MUX", "ADC2", "ADC2"},
+	{"DEC6 MUX", "ADC1", "ADC1"},
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+
+	/* Digital Mic */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC7 MUX", "DMIC1", "DMIC1"},
+	{"DMIC1", NULL, "DMIC1 IN"},
+
+	/* Sidetone (IIR1) */
+	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
+
+};
+
+static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	return tabla_reg_readable[reg];
+}
+
+static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+{
+	/* Registers lower than 0x100 are top level registers which can be
+	 * written by the Tabla core driver.
+	 */
+
+	if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
+		return 1;
+
+	return 0;
+}
+
+#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	int ret;
+	pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
+
+	BUG_ON(reg > TABLA_MAX_REGISTER);
+
+	if (!tabla_volatile(codec, reg)) {
+		pr_debug("writing to cache\n");
+		ret = snd_soc_cache_write(codec, reg, value);
+		if (ret != 0)
+			dev_err(codec->dev, "Cache write to %x failed: %d\n",
+				reg, ret);
+	}
+
+	return tabla_reg_write(codec->control_data, reg, value);
+}
+static unsigned int tabla_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	unsigned int val;
+	int ret;
+
+	BUG_ON(reg > TABLA_MAX_REGISTER);
+
+	if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
+		reg < codec->driver->reg_cache_size) {
+		pr_debug("reading from cache\n");
+		ret = snd_soc_cache_read(codec, reg, &val);
+		if (ret >= 0) {
+			pr_debug("register %d, value %d\n", reg, val);
+			return val;
+		} else
+			dev_err(codec->dev, "Cache read from %x failed: %d\n",
+				reg, ret);
+	}
+
+	val = tabla_reg_read(codec->control_data, reg);
+	pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
+	return val;
+}
+
+static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x80);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
+		0x04);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
+		0x01);
+	usleep_range(1000, 1000);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x00);
+}
+
+static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
+	enum tabla_bandgap_type choice)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	/* TODO lock resources accessed by audio streams and threaded
+	 * interrupt handlers
+	 */
+
+	pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
+		tabla->bandgap_type);
+
+	if (tabla->bandgap_type == choice)
+		return;
+
+	if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
+		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
+		tabla_codec_enable_audio_mode_bandgap(codec);
+	} else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
+		(choice == TABLA_BANDGAP_MBHC_MODE)) {
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
+			0x2);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
+			0x4);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x00);
+	} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
+		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		usleep_range(100, 100);
+		tabla_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == TABLA_BANDGAP_OFF) {
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+	} else {
+		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+	}
+	tabla->bandgap_type = choice;
+}
+
+static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
+		usleep_range(5, 5);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
+			0x80);
+		usleep_range(10, 10);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
+		usleep_range(20, 20);
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
+	} else {
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
+			0);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
+	}
+	tabla->config_mode_active = enable ? true : false;
+
+	return 0;
+}
+
+static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
+	int config_mode)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s\n", __func__);
+
+	if (config_mode) {
+		tabla_codec_enable_config_mode(codec, 1);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
+		usleep_range(1000, 1000);
+	} else
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+	if (!config_mode && tabla->mbhc_polling_active) {
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+		tabla_codec_enable_config_mode(codec, 0);
+
+	}
+
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
+	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	usleep_range(50, 50);
+	tabla->clock_active = true;
+	return 0;
+}
+static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	pr_debug("%s\n", __func__);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
+	ndelay(160);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+	tabla->clock_active = false;
+}
+
+static int tabla_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	pr_debug("%s()\n", __func__);
+
+	if (!codec) {
+		pr_err("Error, no codec found\n");
+		return -EINVAL;
+	}
+	tabla->ref_cnt++;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		/* Enable LDO */
+		snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
+			0xA0);
+		snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
+		usleep_range(1000, 1000);
+	}
+
+	if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
+		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
+		tabla_codec_enable_clock_block(codec, 0);
+	}
+
+	return ret;
+}
+
+static void tabla_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s()\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		/* Disable LDO */
+		snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x00);
+		usleep_range(1000, 1000);
+	}
+
+	if (!tabla->ref_cnt) {
+		pr_err("Error, trying to shutdown codec when already down\n");
+		return;
+	}
+	tabla->ref_cnt--;
+
+	if (tabla->mbhc_polling_active) {
+		if (!tabla->ref_cnt) {
+			tabla_codec_enable_bandgap(codec,
+				TABLA_BANDGAP_MBHC_MODE);
+			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
+				0x80);
+			tabla_codec_enable_clock_block(codec, 1);
+		}
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
+	}
+}
+
+static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	pr_debug("%s %d\n", __func__, mute);
+
+	/* TODO mute TX */
+	if (mute)
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
+	else
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
+
+	return 0;
+}
+
+static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int tabla_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+	return 0;
+}
+
+static struct snd_soc_dai_ops tabla_dai_ops = {
+	.startup = tabla_startup,
+	.shutdown = tabla_shutdown,
+	.hw_params = tabla_hw_params,
+	.set_sysclk = tabla_set_dai_sysclk,
+	.set_fmt = tabla_set_dai_fmt,
+	.digital_mute = tabla_digital_mute,
+};
+
+static struct snd_soc_dai_driver tabla_dai[] = {
+	{
+		.name = "tabla_rx1",
+		.id = 1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = TABLA_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tabla_dai_ops,
+	},
+	{
+		.name = "tabla_tx1",
+		.id = 2,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = TABLA_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tabla_dai_ops,
+	},
+};
+
+static void tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct tabla_mbhc_calibration *calibration = tabla->calibration;
+	int micbias_ctl_reg, micbias_cfilt_val_reg, micbias_cfilt_ctl_reg;
+
+	if (!calibration) {
+		pr_err("Error, no tabla calibration\n");
+		return;
+	}
+
+	tabla->mbhc_polling_active = true;
+
+	if (!tabla->ref_cnt) {
+		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
+		snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
+		tabla_codec_enable_clock_block(codec, 1);
+	}
+
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
+
+	/* TODO store register values in calibration */
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x09);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+
+	snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0F, 0x0D);
+	snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+	/* TODO select cfilt separately from the micbias line inside the machine
+	 * driver
+	 */
+	switch (calibration->bias) {
+	case TABLA_MICBIAS1:
+		micbias_ctl_reg = TABLA_A_MICB_1_CTL;
+		micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
+		micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_1_VAL;
+		break;
+	case TABLA_MICBIAS2:
+		micbias_ctl_reg = TABLA_A_MICB_2_CTL;
+		micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
+		micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_2_VAL;
+		break;
+	case TABLA_MICBIAS3:
+		micbias_ctl_reg = TABLA_A_MICB_3_CTL;
+		micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
+		micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_3_VAL;
+		break;
+	case TABLA_MICBIAS4:
+		pr_err("%s: Error, microphone bias 4 not supported\n",
+			__func__);
+		return;
+	default:
+		pr_err("Error, invalid mic bias line\n");
+		return;
+	}
+	snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
+
+	snd_soc_write(codec, micbias_ctl_reg, 0x36);
+
+	snd_soc_write(codec, micbias_cfilt_val_reg, 0x68);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x4);
+
+	snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
+	snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
+	snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
+
+	snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x80, 0x80);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x80, 0x00);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+
+	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
+	/* TODO check if we need to maintain the other register bits */
+}
+
+static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
+		int insertion)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct tabla_mbhc_calibration *calibration = tabla->calibration;
+	int central_bias_enabled = 0;
+	int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
+
+	if (!calibration) {
+		pr_err("Error, no tabla calibration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
+
+	if (insertion)
+		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
+	else
+		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
+
+	if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
+		if (!(tabla->clock_active)) {
+			tabla_codec_enable_config_mode(codec, 1);
+			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
+				0x04, 0);
+			usleep_range(calibration->shutdown_plug_removal,
+				calibration->shutdown_plug_removal);
+			tabla_codec_enable_config_mode(codec, 0);
+		} else
+			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
+				0x04, 0);
+	}
+
+	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
+		calibration->hph_current << 2);
+
+	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
+
+	switch (calibration->bias) {
+	case TABLA_MICBIAS1:
+		micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
+		micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
+		micbias_ctl_reg = TABLA_A_MICB_1_CTL;
+		break;
+	case TABLA_MICBIAS2:
+		micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
+		micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
+		micbias_ctl_reg = TABLA_A_MICB_2_CTL;
+		break;
+	case TABLA_MICBIAS3:
+		micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
+		micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
+		micbias_ctl_reg = TABLA_A_MICB_3_CTL;
+		break;
+	case TABLA_MICBIAS4:
+		micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
+		micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
+		micbias_ctl_reg = TABLA_A_MICB_4_CTL;
+		break;
+	default:
+		pr_err("Error, invalid mic bias line\n");
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
+	snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
+
+	/* If central bandgap disabled */
+	if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
+		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
+		usleep_range(calibration->bg_fast_settle,
+			calibration->bg_fast_settle);
+		central_bias_enabled = 1;
+	}
+
+	/* If LDO_H disabled */
+	if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
+		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
+		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
+		usleep_range(calibration->tldoh, calibration->tldoh);
+		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
+
+		if (central_bias_enabled)
+			snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
+	}
+	snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
+		calibration->mic_current << 5);
+	snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
+	usleep_range(calibration->mic_pid, calibration->mic_pid);
+	snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
+
+	snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
+
+	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+	return 0;
+}
+
+int tabla_hs_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+	struct tabla_mbhc_calibration *calibration)
+{
+	struct tabla_priv *tabla;
+	if (!codec || !calibration) {
+		pr_err("Error: no codec or calibration\n");
+		return -EINVAL;
+	}
+	tabla = snd_soc_codec_get_drvdata(codec);
+	tabla->jack = jack;
+	tabla->calibration = calibration;
+
+	return tabla_codec_enable_hs_detect(codec, 1);
+}
+EXPORT_SYMBOL_GPL(tabla_hs_detect);
+
+static irqreturn_t tabla_dummy_handler(int irq, void *data)
+{
+	struct tabla_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
+{
+	struct tabla_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+
+	if (priv->jack) {
+		pr_debug("reporting insertion %d\n", SND_JACK_HEADSET);
+		snd_soc_jack_report(priv->jack, SND_JACK_HEADSET,
+			SND_JACK_HEADSET);
+	}
+	usleep_range(priv->calibration->setup_plug_removal_delay,
+		priv->calibration->setup_plug_removal_delay);
+
+	tabla_codec_setup_hs_polling(codec);
+
+	return IRQ_HANDLED;
+}
+
+static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	if (!tabla->ref_cnt) {
+		snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
+		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
+		tabla_codec_enable_clock_block(codec, 0);
+	}
+
+	tabla->mbhc_polling_active = false;
+}
+
+static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
+{
+	struct tabla_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+
+	usleep_range(priv->calibration->shutdown_plug_removal,
+		priv->calibration->shutdown_plug_removal);
+
+	if (priv->jack) {
+		pr_debug("reporting removal\n");
+		snd_soc_jack_report(priv->jack, 0, SND_JACK_HEADSET);
+	}
+	tabla_codec_shutdown_hs_polling(codec);
+
+	tabla_codec_enable_hs_detect(codec, 1);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned long slimbus_value;
+
+static irqreturn_t tabla_slimbus_irq(int irq, void *data)
+{
+	struct tabla_priv *priv = data;
+	struct snd_soc_codec *codec = priv->codec;
+	int i, j;
+	u8 val;
+
+	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
+		slimbus_value = tabla_interface_reg_read(codec->control_data,
+			TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
+		for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
+			val = tabla_interface_reg_read(codec->control_data,
+				TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
+			if (val & 0x1)
+				pr_err_ratelimited("overflow error on port %x,"
+					" value %x\n", i*8 + j, val);
+			if (val & 0x2)
+				pr_err_ratelimited("underflow error on port %x,"
+					" value %x\n", i*8 + j, val);
+		}
+		tabla_interface_reg_write(codec->control_data,
+			TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int tabla_codec_probe(struct snd_soc_codec *codec)
+{
+	struct tabla *control;
+	struct tabla_priv *tabla;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret = 0;
+	int i;
+	int tx_channel;
+
+	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	control = codec->control_data;
+
+	tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
+	if (!tabla) {
+		dev_err(codec->dev, "Failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	snd_soc_codec_set_drvdata(codec, tabla);
+
+	tabla->ref_cnt = 0;
+	tabla->bandgap_type = TABLA_BANDGAP_OFF;
+	tabla->clock_active = false;
+	tabla->config_mode_active = false;
+	tabla->mbhc_polling_active = false;
+	tabla->codec = codec;
+
+	/* TODO only enable bandgap when necessary in order to save power */
+	tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
+	tabla_codec_enable_clock_block(codec, 0);
+
+	/* Initialize gain registers to use register gain */
+	snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
+	snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
+	snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
+	snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
+
+	/* Initialize mic biases to differential mode */
+	snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
+	snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
+	snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
+	snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
+
+	/* Set headset CFILT to fast mode */
+	snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_CTL, 0x00, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_CTL, 0x00, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_CTL, 0x00, 0x00);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
+
+	/* Use 16 bit sample size for now */
+	for (tx_channel = 0; tx_channel < 6; tx_channel++) {
+		snd_soc_update_bits(codec,
+			TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
+		snd_soc_update_bits(codec,
+			TABLA_A_CDC_TX1_MUX_CTL + tx_channel, 0x8, 0x0);
+
+	}
+	for (tx_channel = 6; tx_channel < 10; tx_channel++) {
+		snd_soc_update_bits(codec,
+			TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
+		snd_soc_update_bits(codec,
+			TABLA_A_CDC_TX1_MUX_CTL + tx_channel, 0x8, 0x0);
+	}
+	snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
+	snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
+
+	snd_soc_add_controls(codec, tabla_snd_controls,
+		ARRAY_SIZE(tabla_snd_controls));
+	snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
+		ARRAY_SIZE(tabla_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+	snd_soc_dapm_sync(dapm);
+
+	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
+		tabla_hs_insert_irq, "Headset insert detect", tabla);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			TABLA_IRQ_MBHC_INSERTION);
+		goto err_insert_irq;
+	}
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+
+	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
+		tabla_hs_remove_irq, "Headset remove detect", tabla);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			TABLA_IRQ_MBHC_REMOVAL);
+		goto err_remove_irq;
+	}
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+
+	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
+		tabla_dummy_handler, "DC Estimation detect", tabla);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			TABLA_IRQ_MBHC_POTENTIAL);
+		goto err_potential_irq;
+	}
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+
+	ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
+		tabla_slimbus_irq, "SLIMBUS Slave", tabla);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			TABLA_IRQ_SLIMBUS);
+		goto err_slimbus_irq;
+	}
+
+	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
+		tabla_interface_reg_write(codec->control_data,
+			TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+
+	return ret;
+
+err_slimbus_irq:
+	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+err_potential_irq:
+	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+err_remove_irq:
+	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+err_insert_irq:
+	kfree(tabla);
+	return ret;
+}
+static int tabla_codec_remove(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+	tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+	tabla_codec_disable_clock_block(codec);
+	tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
+	kfree(tabla);
+	return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_tabla = {
+	.probe	= tabla_codec_probe,
+	.remove	= tabla_codec_remove,
+	.read = tabla_read,
+	.write = tabla_write,
+
+	.readable_register = tabla_readable,
+	.volatile_register = tabla_volatile,
+
+	.reg_cache_size = TABLA_CACHE_SIZE,
+	.reg_cache_default = tabla_reg_defaults,
+	.reg_word_size = 1,
+};
+static int __devinit tabla_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
+		tabla_dai, ARRAY_SIZE(tabla_dai));
+}
+static int __devexit tabla_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+static struct platform_driver tabla_codec_driver = {
+	.probe = tabla_probe,
+	.remove = tabla_remove,
+	.driver = {
+		.name = "tabla_codec",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init tabla_codec_init(void)
+{
+	return platform_driver_register(&tabla_codec_driver);
+}
+
+static void __exit tabla_codec_exit(void)
+{
+	platform_driver_unregister(&tabla_codec_driver);
+}
+
+module_init(tabla_codec_init);
+module_exit(tabla_codec_exit);
+
+MODULE_DESCRIPTION("Tabla codec driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
new file mode 100644
index 0000000..9b4faef
--- /dev/null
+++ b/sound/soc/codecs/wcd9310.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <sound/soc.h>
+
+#define TABLA_NUM_REGISTERS 0x400
+#define TABLA_MAX_REGISTER (TABLA_NUM_REGISTERS-1)
+#define TABLA_CACHE_SIZE TABLA_NUM_REGISTERS
+
+extern const u8 tabla_reg_readable[TABLA_CACHE_SIZE];
+extern const u8 tabla_reg_defaults[TABLA_CACHE_SIZE];
+
+enum tabla_micbias_num {
+	TABLA_MICBIAS1,
+	TABLA_MICBIAS2,
+	TABLA_MICBIAS3,
+	TABLA_MICBIAS4,
+};
+
+enum tabla_pid_current {
+	TABLA_PID_MIC_2P5_UA,
+	TABLA_PID_MIC_5_UA,
+	TABLA_PID_MIC_10_UA,
+	TABLA_PID_MIC_20_UA,
+};
+
+struct tabla_mbhc_calibration {
+	enum tabla_micbias_num bias;
+	int tldoh;
+	int bg_fast_settle;
+	enum tabla_pid_current mic_current;
+	int mic_pid;
+	enum tabla_pid_current hph_current;
+	int setup_plug_removal_delay;
+	int shutdown_plug_removal;
+};
+
+extern int tabla_hs_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *jack, struct tabla_mbhc_calibration *calibration);
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 309c59e..25e9e62 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -8,8 +8,7 @@
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
+ *  Free Software Foundation;  only version 2 of the  License.
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
index a7c9578..81153b1 100644
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -3,8 +3,7 @@
  *
  *  This program is free software; you can redistribute	 it and/or modify it
  *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
+ *  Free Software Foundation;  only version 2 of the License.
  *
  *  You should have received a copy of the  GNU General Public License along
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
@@ -370,4 +369,4 @@
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index cd33de1..b21a5e4 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -6,8 +6,7 @@
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
+ *  Free Software Foundation;  only version 2 of the  License.
  */
 
 #include <linux/init.h>
@@ -402,5 +401,5 @@
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:kirkwood-pcm-audio");
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
new file mode 100644
index 0000000..485d3db5
--- /dev/null
+++ b/sound/soc/msm/Kconfig
@@ -0,0 +1,134 @@
+menu "MSM SoC Audio support"
+
+#7201 7625 variants
+config SND_MSM_DAI_SOC
+	tristate
+
+config SND_MSM_SOC_MSM7K
+	 tristate
+
+config SND_MSM_SOC
+	tristate "SoC Audio for the MSM series chips"
+	depends on ARCH_MSM_ARM11 && SND_SOC && MSM_ADSP
+	select SND_MSM_DAI_SOC
+	select SND_MSM_SOC_MSM7K
+	default n
+	help
+	  To add support for ALSA PCM driver for MSM board.
+
+#7630 Variants
+config SND_MSM7KV2_DAI_SOC
+	tristate
+
+config SND_MSM_SOC_MSM7KV2
+	tristate
+
+config SND_MSM7KV2_SOC
+	tristate "SoC Audio for the MSM7KV2 chip"
+	depends on ARCH_MSM7X30 && SND_SOC && MSM7KV2_AUDIO
+	select SND_MSM_SOC_MSM7KV2
+	select SND_MSM7KV2_DAI_SOC
+	default n
+	help
+	  To add support for ALSA PCM driver for QSD8k board.
+
+config SND_MSM_MVS7x30_SOC
+	tristate
+
+config SND_MSM_MVS_DAI_SOC
+	tristate
+
+config SND_MVS_SOC
+	tristate "SoC Mvs support for MSM7X30"
+	depends on SND_MSM7KV2_SOC
+	select SND_MSM_MVS7x30_SOC
+	select SND_MSM_MVS_DAI_SOC
+	default n
+	help
+	To support Mvs packet capture/playback
+
+#8660 Variants
+config SND_SOC_MSM8X60_PCM
+	tristate
+
+config SND_SOC_MSM8X60_DAI
+	tristate
+
+config SND_SOC_MSM8X60
+	tristate "SoC Audio over DSP support for MSM8660"
+	depends on ARCH_MSM8X60 && SND_SOC && MSM8X60_AUDIO
+	select SND_SOC_MSM8X60_PCM
+	select SND_SOC_MSM8X60_DAI
+	select SND_SOC_MSM_QDSP6_INTF
+	default y
+	help
+	 To add support for SoC audio on MSM8X60. This driver
+	 Adds support for audio over DSP. The driver adds Kcontrols
+	 to do device switch/routing and volume control support for all
+	 audio sessions. The kcontols also does sesion management for
+	 voice calls
+
+config SND_SOC_MSM_HOSTLESS_PCM
+	tristate
+
+config SND_SOC_MSM8660_PCM
+	tristate
+
+config SND_SOC_MSM8660_LPAIF
+	tristate
+
+config SND_SOC_MSM8660
+	tristate "SoC Machine driver for MSM8660"
+	depends on !SND_SOC_MSM8X60 && ARCH_MSM8X60
+	select SND_SOC_MSM8660_PCM
+	select SND_SOC_MSM8660_LPAIF
+	select SND_SOC_TIMPANI
+	select MARIMBA_CORE
+	select SND_SOC_MSM_QDSP6_INTF
+	default n
+	help
+	 To add support for SoC audio on MSM8660 for direct playback
+	 to LPA buffer over DMA.The interface bypasses DSP and hence
+	 does not support any post/pre processing features.The driver
+	 would support full duplex playback/record sessions.
+
+config SND_VOIP_PCM
+	tristate
+
+config MSM_8x60_VOIP
+	tristate "SoC Machine driver for voip"
+	depends on SND_SOC_MSM8X60
+	select SND_MSM_MVS_DAI_SOC
+	select SND_VOIP_PCM
+	default n
+	help
+	 To support ALSA VOIP driver for MSM8x60 target.
+	 This driver communicates with QDSP6, for getting
+	 uplink and downlink voice packets.
+
+config SND_SOC_MSM_QDSP6_INTF
+	bool "SoC Q6 audio driver for MSM8960"
+	depends on MSM_QDSP6_APR
+	default n
+	help
+	 To add support for SoC audio on MSM8960.
+
+config SND_SOC_QDSP6
+	tristate "SoC ALSA audio driver for QDSP6"
+	select SND_SOC_MSM_QDSP6_INTF
+	default n
+	help
+	 To add support for MSM QDSP6 Soc Audio.
+
+config SND_SOC_MSM8960
+	tristate "SoC Machine driver for MSM8960 boards"
+	depends on ARCH_MSM8960
+	select SND_SOC_QDSP6
+	select SND_SOC_MSM_STUB
+	select SND_SOC_WCD9310
+	select SND_SOC_MSM_HOSTLESS_PCM
+	default n
+	help
+	 To add support for SoC audio on MSM8960 boards
+
+endmenu
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
new file mode 100644
index 0000000..92b008d
--- /dev/null
+++ b/sound/soc/msm/Makefile
@@ -0,0 +1,71 @@
+# MSM CPU/CODEC DAI Support
+snd-soc-msm-dai-objs := msm-dai.o
+obj-$(CONFIG_SND_MSM_DAI_SOC) += snd-soc-msm-dai.o
+
+snd-soc-msm7kv2-dai-objs := msm7kv2-dai.o
+obj-$(CONFIG_SND_MSM7KV2_DAI_SOC) += snd-soc-msm7kv2-dai.o
+
+# MSM Platform Support
+snd-soc-msm-objs := msm-pcm.o msm7k-pcm.o
+obj-$(CONFIG_SND_MSM_SOC) += snd-soc-msm.o
+
+snd-soc-msmv2-objs := msm7kv2-dsp.o msm7kv2-pcm.o
+obj-$(CONFIG_SND_MSM7KV2_SOC) += snd-soc-msmv2.o
+
+# MSM Machine Support
+snd-soc-msm7k-objs := msm7201.o
+obj-$(CONFIG_SND_MSM_SOC_MSM7K) += snd-soc-msm7k.o
+
+snd-soc-msm7kv2-objs := msm7x30.o
+obj-$(CONFIG_SND_MSM_SOC_MSM7KV2) += snd-soc-msm7kv2.o
+
+# 8660 ALSA Support
+snd-soc-msm8x60-dai-objs := msm8x60-dai.o
+obj-$(CONFIG_SND_SOC_MSM8X60_DAI) += snd-soc-msm8x60-dai.o
+
+snd-soc-msm8x60-pcm-objs := msm8x60-pcm.o
+obj-$(CONFIG_SND_SOC_MSM8X60_PCM) += snd-soc-msm8x60-pcm.o
+
+snd-soc-msm8x60-objs := msm8x60.o
+obj-$(CONFIG_SND_SOC_MSM8X60) += snd-soc-msm8x60.o
+
+
+#MVS Support
+snd-soc-msm-mvs-dai-objs := mvs-dai.o
+obj-$(CONFIG_SND_MSM_MVS_DAI_SOC) += snd-soc-msm-mvs-dai.o
+
+snd-soc-msm-mvs-objs := msm-mvs.o
+obj-$(CONFIG_SND_MVS_SOC) += snd-soc-msm-mvs.o
+
+# 8660 ALSA Support
+snd-soc-msm8660-lpa-objs := msm8660-i2s.o msm8660-dma.o
+obj-$(CONFIG_SND_SOC_MSM8660_LPAIF) += snd-soc-msm8660-lpa.o
+
+snd-soc-msm8660-pcm-objs := msm8660-pcm.o
+obj-$(CONFIG_SND_SOC_MSM8660_PCM) += snd-soc-msm8660-pcm.o
+
+snd-soc-msm8660-objs := msm8660.o
+obj-$(CONFIG_SND_SOC_MSM8660) += snd-soc-msm8660.o
+
+#8660 VOIP Driver Support
+
+snd-soc-msm-voip-objs := msm-voip.o
+obj-$(CONFIG_SND_VOIP_PCM) += snd-soc-msm-voip.o
+
+snd-soc-msm8660-dma-objs := msm8660-dma.o
+obj-$(CONFIG_SND_SOC_MSM8X60) += snd-soc-msm8660-dma.o
+
+# for MSM 8960 sound card driver
+
+obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
+
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-pcm-voice.o msm-pcm-voip.o
+snd-soc-qdsp6-objs += msm-pcm-lpa.o
+obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
+
+snd-soc-msm8960-objs := msm8960.o
+obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
+
+# Generic MSM drivers
+snd-soc-hostless-pcm-objs := msm-pcm-hostless.o
+obj-$(CONFIG_SND_SOC_MSM_HOSTLESS_PCM) += snd-soc-hostless-pcm.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
new file mode 100644
index 0000000..c937a5a
--- /dev/null
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+static struct snd_soc_dai_ops msm_fe_dai_ops = {};
+
+static struct snd_soc_dai_driver msm_fe_dais[] = {
+	{
+		.playback = {
+			.stream_name = "Multimedia1 Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
+		.capture = {
+			.stream_name = "Multimedia1 Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "MultiMedia1",
+	},
+	{
+		.playback = {
+			.stream_name = "Multimedia2 Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
+		.capture = {
+			.stream_name = "Multimedia2 Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "MultiMedia2",
+	},
+	{
+		.playback = {
+			.stream_name = "Voice Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "Voice Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "CS-VOICE",
+	},
+	{
+		.playback = {
+			.stream_name = "VoIP Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =	8000,
+			.rate_max = 48000,
+		},
+		.capture = {
+			.stream_name = "VoIP Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =	8000,
+			.rate_max = 48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "VoIP",
+	},
+	{
+		.playback = {
+			.stream_name = "MultiMedia3 Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =	8000,
+			.rate_max = 48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "MultiMedia3",
+	},
+	/* FE DAIs created for hostless operation purpose */
+	{
+		.playback = {
+			.stream_name = "SLIMBUS0 Hostless Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "SLIMBUS0 Hostless Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SLIMBUS0_HOSTLESS",
+	},
+	{
+		.playback = {
+			.stream_name = "INT_FM Hostless Playback",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "INT_FM Hostless Capture",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "INT_FM_HOSTLESS",
+	},
+};
+
+static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "%s: dev name %s\n", __func__,
+	dev_name(&pdev->dev));
+	return snd_soc_register_dais(&pdev->dev, msm_fe_dais,
+		ARRAY_SIZE(msm_fe_dais));
+}
+
+static __devexit int msm_fe_dai_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_fe_dai_driver = {
+	.probe  = msm_fe_dai_dev_probe,
+	.remove = msm_fe_dai_dev_remove,
+	.driver = {
+		.name = "msm-dai-fe",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_fe_dai_init(void)
+{
+	return platform_driver_register(&msm_fe_dai_driver);
+}
+module_init(msm_fe_dai_init);
+
+static void __exit msm_fe_dai_exit(void)
+{
+	platform_driver_unregister(&msm_fe_dai_driver);
+}
+module_exit(msm_fe_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Frontend DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
new file mode 100644
index 0000000..9cdd1d6
--- /dev/null
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -0,0 +1,555 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wcd9310/core.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+#include <sound/q6adm.h>
+
+enum {
+	STATUS_PORT_STARTED, /* track if AFE port has started */
+	STATUS_MAX
+};
+
+struct msm_dai_q6_dai_data {
+	DECLARE_BITMAP(status_mask, STATUS_MAX);
+	u32 rate;
+	u32 channels;
+	union afe_port_config port_config;
+};
+
+static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->channels = params_channels(params);
+	switch (dai_data->channels) {
+	case 2:
+		dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
+		break;
+	case 1:
+		dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+	dai_data->rate = params_rate(params);
+
+	dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
+	dai_data->channels, dai_data->rate);
+
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.mi2s.bitwidth = 16;
+	dai_data->port_config.mi2s.line = 1;
+	dai_data->port_config.mi2s.ws = 1; /* I2S master mode for now */
+
+	return 0;
+}
+
+static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s start HDMI port\n", __func__);
+
+	dai_data->channels = params_channels(params);
+	switch (dai_data->channels) {
+	case 2:
+		dai_data->port_config.hdmi.channel_mode = 0; /* Put in macro */
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.hdmi.bitwidth = 16;
+	dai_data->port_config.hdmi.data_type = 0;
+	dai_data->rate = params_rate(params);
+
+	return 0;
+}
+
+static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	u8 pgd_la, inf_la;
+
+	memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
+		sizeof(dai_data->port_config.slimbus.slave_port_mapping));
+
+	dai_data->channels = params_channels(params);
+	switch (dai_data->channels) {
+	case 2:
+		if (dai->id == SLIMBUS_0_RX) {
+			dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
+			dai_data->port_config.slimbus.slave_port_mapping[1] = 2;
+		} else {
+			dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
+			dai_data->port_config.slimbus.slave_port_mapping[1] = 8;
+		}
+		break;
+	case 1:
+		if (dai->id == SLIMBUS_0_RX)
+			dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
+		else
+			dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+	dai_data->rate = params_rate(params);
+	tabla_get_logical_addresses(&pgd_la, &inf_la);
+
+	dai_data->port_config.slimbus.slimbus_dev_id =  AFE_SLIMBUS_DEVICE_1;
+	dai_data->port_config.slimbus.slave_dev_pgd_la = pgd_la;
+	dai_data->port_config.slimbus.slave_dev_intfdev_la = inf_la;
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.slimbus.bit_width = 16;
+	dai_data->port_config.slimbus.data_format = 0;
+	dai_data->port_config.slimbus.num_channels = dai_data->channels;
+	dai_data->port_config.slimbus.reserved = 0;
+
+	dev_dbg(dai->dev, "slimbus_dev_id  %hu  slave_dev_pgd_la 0x%hx\n"
+		"slave_dev_intfdev_la 0x%hx   bit_width %hu   data_format %hu\n"
+		"num_channel %hu  slave_port_mapping[0]  %hu\n"
+		"slave_port_mapping[1]  %hu slave_port_mapping[2]  %hu\n"
+		"sample_rate %d\n",
+		dai_data->port_config.slimbus.slimbus_dev_id,
+		dai_data->port_config.slimbus.slave_dev_pgd_la,
+		dai_data->port_config.slimbus.slave_dev_intfdev_la,
+		dai_data->port_config.slimbus.bit_width,
+		dai_data->port_config.slimbus.data_format,
+		dai_data->port_config.slimbus.num_channels,
+		dai_data->port_config.slimbus.slave_port_mapping[0],
+		dai_data->port_config.slimbus.slave_port_mapping[1],
+		dai_data->port_config.slimbus.slave_port_mapping[2],
+		dai_data->rate);
+
+	return 0;
+}
+
+static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->channels = params_channels(params);
+	dai_data->rate = params_rate(params);
+
+	dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
+		dai_data->channels, dai_data->rate);
+
+	memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
+
+	return 0;
+}
+
+/* Current implementation assumes hw_param is called once
+ * This may not be the case but what to do when ADM and AFE
+ * port are already opened and parameter changes
+ */
+static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	int rc = 0;
+
+	switch (dai->id) {
+	case PRIMARY_I2S_TX:
+	case PRIMARY_I2S_RX:
+		rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
+		break;
+	case HDMI_RX:
+		rc = msm_dai_q6_hdmi_hw_params(params, dai);
+		break;
+
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
+				substream->stream);
+		break;
+	case INT_BT_SCO_RX:
+	case INT_BT_SCO_TX:
+	case INT_FM_RX:
+	case INT_FM_TX:
+		rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
+		break;
+	default:
+		dev_err(dai->dev, "invalid AFE port ID\n");
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc;
+
+	rc = adm_close(dai->id);
+
+	if (IS_ERR_VALUE(rc))
+		dev_err(dai->dev, "fail to close ADM COPP\n");
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		rc = afe_close(dai->id); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	}
+};
+
+static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc = 0;
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		/* if AFE port is already started, this means
+		 * application wishes to restore hardware to
+		 * fresh state. This logic anticipates prepare is not
+		 * called right after TRIGGER_START before Q6 AFE
+		 * has enough time to respond to port start command.
+		 */
+		rc = afe_close(dai->id); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	} else {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			rc = adm_open_mixer(dai->id, 1, dai_data->rate,
+				dai_data->channels, DEFAULT_COPP_TOPOLOGY);
+		else
+			rc = adm_open_mixer(dai->id, 2, dai_data->rate,
+				dai_data->channels, DEFAULT_COPP_TOPOLOGY);
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to open ADM\n");
+	}
+
+	return rc;
+
+}
+
+static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc = 0;
+
+	/* Start/stop port without waiting for Q6 AFE response. Need to have
+	 * native q6 AFE driver propagates AFE response in order to handle
+	 * port start/stop command error properly if error does arise.
+	 */
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+			afe_port_start_nowait(dai->id, &dai_data->port_config,
+				dai_data->rate);
+			set_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+		}
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+			afe_port_stop_nowait(dai->id);
+			clear_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc = 0;
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
+		GFP_KERNEL);
+
+	if (!dai_data) {
+		dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+		dai->id);
+		rc = -ENOMEM;
+	} else
+		dev_set_drvdata(dai->dev, dai_data);
+
+	return rc;
+}
+
+static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data;
+	int rc;
+
+	dai_data = dev_get_drvdata(dai->dev);
+
+	/* If AFE port is still up, close it */
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		rc = afe_close(dai->id); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+	}
+	kfree(dai_data);
+	snd_soc_unregister_dai(dai->dev);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_ops = {
+	/*
+	 * DSP only handles 16-bit and support only I2S
+	 * master mode for now. leave set_fmt function
+	 * unimplemented for now.
+	 */
+	.prepare	= msm_dai_q6_prepare,
+	.trigger	= msm_dai_q6_trigger,
+	.hw_params	= msm_dai_q6_hw_params,
+	.shutdown	= msm_dai_q6_shutdown,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.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_i2s_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.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_hdmi_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 2,
+		.channels_max = 2,
+		.rate_max =     48000,
+		.rate_min =	48000,
+	},
+	.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_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.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_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.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_bt_sco_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_max = 16000,
+		.rate_min = 8000,
+	},
+	.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_bt_sco_tx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 16000,
+		.rate_min = 8000,
+	},
+	.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_fm_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 2,
+		.channels_max = 2,
+		.rate_max = 48000,
+		.rate_min = 8000,
+	},
+	.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_fm_tx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 2,
+		.channels_max = 2,
+		.rate_max = 48000,
+		.rate_min = 8000,
+	},
+	.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)
+{
+	int rc = 0;
+
+	dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+	switch (pdev->id) {
+	case PRIMARY_I2S_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
+		break;
+	case PRIMARY_I2S_TX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
+		break;
+	case HDMI_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_hdmi_rx_dai);
+		break;
+	case SLIMBUS_0_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_rx_dai);
+		break;
+	case SLIMBUS_0_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_tx_dai);
+	case INT_BT_SCO_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_bt_sco_rx_dai);
+		break;
+	case INT_BT_SCO_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_bt_sco_tx_dai);
+		break;
+	case INT_FM_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
+		break;
+	case INT_FM_TX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
+		break;
+	default:
+		rc = -ENODEV;
+		break;
+	}
+	return rc;
+}
+
+static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_dai_q6_driver = {
+	.probe  = msm_dai_q6_dev_probe,
+	.remove = msm_dai_q6_dev_remove,
+	.driver = {
+		.name = "msm-dai-q6",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_dai_q6_init(void)
+{
+	return platform_driver_register(&msm_dai_q6_driver);
+}
+module_init(msm_dai_q6_init);
+
+static void __exit msm_dai_q6_exit(void)
+{
+	platform_driver_unregister(&msm_dai_q6_driver);
+}
+module_exit(msm_dai_q6_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM DSP DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-dai.c b/sound/soc/msm/msm-dai.c
new file mode 100644
index 0000000..6ebee51
--- /dev/null
+++ b/sound/soc/msm/msm-dai.c
@@ -0,0 +1,154 @@
+/* sound/soc/msm/msm-dai.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * Derived from msm-pcm.c and msm7201.c.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#ifdef CONFIG_ARCH_MSM_ARM11
+#include "msm-pcm.h"
+#else
+#include "qsd-pcm.h"
+#endif
+
+static struct snd_soc_dai_driver msm_pcm_codec_dais[] = {
+{
+	.name = "msm-codec-dai",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_max = USE_CHANNELS_MAX,
+		.rates = USE_RATE,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.formats = USE_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rates = USE_RATE,
+		.formats = USE_FORMATS,
+	},
+},
+};
+
+static struct snd_soc_dai_driver msm_pcm_cpu_dais[] = {
+{
+	.name = "msm-cpu-dai",
+	.playback = {
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rates = USE_RATE,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.formats = USE_FORMATS,
+	},
+	.capture = {
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rates = USE_RATE,
+		.formats = USE_FORMATS,
+	},
+},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_msm = {
+        .compress_type = SND_SOC_FLAT_COMPRESSION,
+};
+
+static __devinit int asoc_msm_codec_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm,
+                        msm_pcm_codec_dais, ARRAY_SIZE(msm_pcm_codec_dais));
+}
+
+static int __devexit asoc_msm_codec_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static __devinit int asoc_pcm_cpu_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_dai(&pdev->dev, msm_pcm_cpu_dais);
+}
+
+static int __devexit asoc_pcm_cpu_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_codec_dai_driver = {
+	.probe = asoc_msm_codec_probe,
+	.remove = __devexit_p(asoc_msm_codec_remove),
+	.driver = {
+			.name = "msm-codec-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_driver asoc_cpu_dai_driver = {
+	.probe = asoc_pcm_cpu_probe,
+	.remove = __devexit_p(asoc_pcm_cpu_remove),
+	.driver = {
+			.name = "msm-cpu-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_codec_dai_init(void)
+{
+	return platform_driver_register(&asoc_codec_dai_driver);
+}
+
+static void __exit msm_codec_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_codec_dai_driver);
+}
+
+static int __init msm_cpu_dai_init(void)
+{
+	return platform_driver_register(&asoc_cpu_dai_driver);
+}
+
+static void __exit msm_cpu_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_cpu_dai_driver);
+}
+
+module_init(msm_codec_dai_init);
+module_exit(msm_codec_dai_exit);
+module_init(msm_cpu_dai_init);
+module_exit(msm_cpu_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Codec/Cpu Dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-mvs.c b/sound/soc/msm/msm-mvs.c
new file mode 100644
index 0000000..2e7114c
--- /dev/null
+++ b/sound/soc/msm/msm-mvs.c
@@ -0,0 +1,936 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/wakelock.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/debug_mm.h>
+#include "msm_audio_mvs.h"
+
+
+static struct audio_mvs_info_type audio_mvs_info;
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= (SNDRV_PCM_RATE_8000),
+	.rate_min		= 8000,
+	.rate_max		= 8000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= MVS_MAX_VOC_PKT_SIZE * MVS_MAX_Q_LEN,
+	.period_bytes_min	= MVS_MAX_VOC_PKT_SIZE,
+	.period_bytes_max	= MVS_MAX_VOC_PKT_SIZE,
+	.periods_min		= MVS_MAX_Q_LEN,
+	.periods_max		= MVS_MAX_Q_LEN,
+	.fifo_size		= 0,
+};
+
+static void snd_pcm_mvs_timer(unsigned long data)
+{
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+	MM_DBG("%s\n", __func__);
+	if (audio->playback_start) {
+		if (audio->ack_dl_count) {
+			audio->pcm_playback_irq_pos += audio->pcm_count;
+			audio->ack_dl_count--;
+			snd_pcm_period_elapsed(audio->playback_substream);
+		}
+	}
+
+	if (audio->capture_start) {
+		if (audio->ack_ul_count) {
+			audio->pcm_capture_irq_pos += audio->pcm_capture_count;
+			audio->ack_ul_count--;
+			snd_pcm_period_elapsed(audio->capture_substream);
+		}
+	}
+	audio->timer.expires +=  audio->expiry_delta;
+	add_timer(&audio->timer);
+}
+
+static int audio_mvs_setup_mvs(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_enable_msg enable_msg;
+	MM_DBG("%s\n", __func__);
+
+	/* Enable MVS. */
+
+	memset(&enable_msg, 0, sizeof(enable_msg));
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	enable_msg.enable_args.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+	enable_msg.enable_args.mode = cpu_to_be32(MVS_MODE_LINEAR_PCM);
+	enable_msg.enable_args.ul_cb_func_id = (int) NULL;
+	enable_msg.enable_args.dl_cb_func_id = (int) NULL;
+	enable_msg.enable_args.context = cpu_to_be32(MVS_PKT_CONTEXT_ISR);
+
+	msm_rpc_setup_req(&enable_msg.rpc_hdr, MVS_PROG,
+			MVS_VERS, MVS_ENABLE_PROC);
+
+	rc = msm_rpc_write(audio->rpc_endpt,
+				&enable_msg, sizeof(enable_msg));
+
+	if (rc >= 0) {
+		MM_DBG("RPC write for enable done\n");
+
+		rc = wait_event_timeout(audio->wait,
+					(audio->rpc_status !=
+					 RPC_STATUS_FAILURE), 1 * HZ);
+
+		if (rc > 0) {
+			MM_DBG("Wait event for enable succeeded\n");
+
+			mutex_lock(&audio->lock);
+			audio->mvs_mode = MVS_MODE_LINEAR_PCM;
+			audio->frame_mode = MVS_FRAME_MODE_PCM_DL;
+			audio->pcm_frame = 0;
+			mutex_unlock(&audio->lock);
+			rc = 0;
+
+		} else
+			MM_ERR("Wait event for enable failed %d\n", rc);
+	} else
+		MM_ERR("RPC write for enable failed %d\n", rc);
+	return rc;
+}
+
+static void audio_mvs_rpc_reply(struct msm_rpc_endpoint *endpoint,
+					uint32_t xid)
+{
+	int rc = 0;
+	struct rpc_reply_hdr reply_hdr;
+	MM_DBG("%s\n", __func__);
+
+	memset(&reply_hdr, 0, sizeof(reply_hdr));
+	reply_hdr.xid = cpu_to_be32(xid);
+	reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+	reply_hdr.reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+	reply_hdr.data.acc_hdr.accept_stat =
+	    cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
+	reply_hdr.data.acc_hdr.verf_flavor = 0;
+	reply_hdr.data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(endpoint, &reply_hdr, sizeof(reply_hdr));
+
+	if (rc < 0)
+		MM_ERR("RPC write for response failed %d\n", rc);
+}
+
+static void audio_mvs_process_rpc_request(uint32_t procedure, uint32_t xid,
+					  void *data, uint32_t length,
+					  struct audio_mvs_info_type *audio)
+{
+
+	int rc = 0;
+	uint32_t index;
+	MM_DBG("%s\n", __func__);
+	switch (procedure) {
+	case MVS_EVENT_CB_TYPE_PROC:{
+		struct audio_mvs_cb_func_args *args = data;
+		uint32_t event_type = be32_to_cpu(args->event);
+		uint32_t cmd_status =
+			be32_to_cpu(args->
+				event_data.mvs_ev_command_type.cmd_status);
+		uint32_t mode_status =
+			be32_to_cpu(args->
+				event_data.mvs_ev_mode_type.mode_status);
+		audio_mvs_rpc_reply(audio->rpc_endpt, xid);
+		if (be32_to_cpu(args->valid_ptr)) {
+			if (event_type == AUDIO_MVS_COMMAND) {
+				if (cmd_status == AUDIO_MVS_CMD_SUCCESS)
+					audio->rpc_status = RPC_STATUS_SUCCESS;
+				wake_up(&audio->wait);
+			} else if (event_type == AUDIO_MVS_MODE) {
+				if (mode_status != AUDIO_MVS_MODE_NOT_AVAIL) {
+					audio->rpc_status =
+					    RPC_STATUS_SUCCESS;
+				}
+				audio->prepare_ack++;
+				wake_up(&audio->wait);
+				wake_up(&audio->prepare_wait);
+			} else {
+				/*nothing to do */
+			}
+		} else
+			MM_ERR("ALSA: CB event pointer not valid\n");
+		break;
+	}
+	case MVS_PACKET_UL_FN_TYPE_PROC:{
+			uint32_t *cb_data = data;
+			uint32_t pkt_len ;
+			struct audio_mvs_ul_reply ul_reply;
+			MM_DBG("MVS_PACKET_UL_FN_TYPE_PROC\n");
+
+			memset(&ul_reply, 0, sizeof(ul_reply));
+			cb_data++;
+			pkt_len = be32_to_cpu(*cb_data);
+			cb_data++;
+			if (audio->capture_enable) {
+				audio_mvs_info.ack_ul_count++;
+				mutex_lock(&audio->out_lock);
+				index = audio->out_write % MVS_MAX_Q_LEN;
+				memcpy(audio->out[index].voc_pkt, cb_data,
+							pkt_len);
+				audio->out[index].len = pkt_len;
+				audio->out_write++;
+				mutex_unlock(&audio->out_lock);
+			}
+			MM_DBG(" audio->out_read = %d audio->out write = %d\n",
+				audio->out_read, audio->out_write);
+			ul_reply.reply_hdr.xid = cpu_to_be32(xid);
+			ul_reply.reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+			ul_reply.reply_hdr.reply_stat =
+				cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+			ul_reply.reply_hdr.data.acc_hdr.accept_stat =
+				cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
+			ul_reply.reply_hdr.data.acc_hdr.verf_flavor = 0;
+			ul_reply.reply_hdr.data.acc_hdr.verf_length = 0;
+			ul_reply.valid_pkt_status_ptr = cpu_to_be32(0x00000001);
+			ul_reply.pkt_status = cpu_to_be32(0x00000000);
+			rc = msm_rpc_write(audio->rpc_endpt, &ul_reply,
+				sizeof(ul_reply));
+			wake_up(&audio->out_wait);
+			if (rc < 0)
+				MM_ERR("RPC write for UL response failed %d\n",
+				rc);
+			break;
+	}
+	case MVS_PACKET_DL_FN_TYPE_PROC:{
+			struct audio_mvs_dl_reply dl_reply;
+			MM_DBG("MVS_PACKET_DL_FN_TYPE_PROC\n");
+			memset(&dl_reply, 0, sizeof(dl_reply));
+			dl_reply.reply_hdr.xid = cpu_to_be32(xid);
+			dl_reply.reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+			dl_reply.reply_hdr.reply_stat =
+				cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+			dl_reply.reply_hdr.data.acc_hdr.accept_stat =
+				cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
+			dl_reply.reply_hdr.data.acc_hdr.verf_flavor = 0;
+			dl_reply.reply_hdr.data.acc_hdr.verf_length = 0;
+			mutex_lock(&audio->in_lock);
+			if (audio->in_read < audio->in_write
+					&& audio->dl_play) {
+				index = audio->in_read % MVS_MAX_Q_LEN;
+				memcpy(&dl_reply.voc_pkt,
+						audio->in[index].voc_pkt,
+						audio->in[index].len);
+				audio->in_read++;
+				audio_mvs_info.ack_dl_count++;
+				dl_reply.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+				wake_up(&audio->in_wait);
+			} else {
+				dl_reply.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_SLOW);
+			}
+			mutex_unlock(&audio->in_lock);
+			MM_DBG(" audio->in_read = %d audio->in write = %d\n",
+					audio->in_read, audio->in_write);
+			dl_reply.valid_frame_info_ptr = cpu_to_be32(0x00000001);
+			dl_reply.frame_mode = cpu_to_be32(audio->frame_mode);
+			dl_reply.frame_mode_again =
+				cpu_to_be32(audio->frame_mode);
+			dl_reply.frame_info_hdr.frame_mode =
+				cpu_to_be32(audio->frame_mode);
+			dl_reply.frame_info_hdr.mvs_mode =
+				cpu_to_be32(audio->mvs_mode);
+			dl_reply.frame_info_hdr.buf_free_cnt = 0;
+			dl_reply.pcm_frame = cpu_to_be32(audio->pcm_frame);
+			dl_reply.pcm_mode = cpu_to_be32(audio->pcm_mode);
+			dl_reply.valid_pkt_status_ptr = cpu_to_be32(0x00000001);
+			rc = msm_rpc_write(audio->rpc_endpt, &dl_reply,
+					sizeof(dl_reply));
+			if (rc < 0)
+				MM_ERR("RPC write for DL response failed %d\n",
+				rc);
+			break;
+	}
+	default:
+		MM_ERR("Unknown CB type %d\n", procedure);
+	}
+}
+
+static int audio_mvs_thread(void *data)
+{
+	struct audio_mvs_info_type *audio =  &audio_mvs_info;
+	struct rpc_request_hdr *rpc_hdr = NULL;
+	struct rpc_reply_hdr *rpc_reply = NULL;
+	uint32_t reply_status = 0;
+	uint32_t rpc_type;
+	int rpc_hdr_len;
+	MM_DBG("%s\n", __func__);
+
+	while (!kthread_should_stop()) {
+		rpc_hdr_len =
+		    msm_rpc_read(audio->rpc_endpt, (void **)&rpc_hdr, -1, -1);
+		if (rpc_hdr_len < 0) {
+			MM_ERR("RPC read failed %d\n", rpc_hdr_len);
+			break;
+		} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ)
+			continue;
+		else {
+			rpc_type = be32_to_cpu(rpc_hdr->type);
+			if (rpc_type == RPC_TYPE_REPLY) {
+				if (rpc_hdr_len < RPC_REPLY_HDR_SZ)
+					continue;
+				rpc_reply = (void *)rpc_hdr;
+				reply_status = be32_to_cpu(rpc_reply->
+							reply_stat);
+				if (reply_status != RPCMSG_REPLYSTAT_ACCEPTED) {
+					/* If the command is not accepted,
+					 * there will be no response callback.
+					 * Wake the caller and report error. */
+					audio->rpc_status =  RPC_STATUS_REJECT;
+					wake_up(&audio->wait);
+					MM_ERR("RPC reply status denied\n");
+				}
+			} else if (rpc_type == RPC_TYPE_REQUEST) {
+				if (rpc_hdr_len < RPC_REQUEST_HDR_SZ)
+					continue;
+				MM_DBG("ALSA: kthread call procedure\n");
+				audio_mvs_process_rpc_request(
+					be32_to_cpu(rpc_hdr->procedure),
+					be32_to_cpu(rpc_hdr->xid),
+					(void *)(rpc_hdr + 1),
+					(rpc_hdr_len - sizeof(*rpc_hdr)),
+					audio);
+			} else
+				MM_ERR("Unexpected RPC type %d\n", rpc_type);
+		}
+		kfree(rpc_hdr);
+		rpc_hdr = NULL;
+	}
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+	MM_DBG("%s\n", __func__);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
+			audio->playback_start = 1;
+		else
+			audio->capture_start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
+			audio->playback_start = 0;
+		else
+			audio->capture_start = 0;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+
+	MM_DBG("%s\n", __func__);
+	mutex_lock(&audio->lock);
+	if (audio->state < AUDIO_MVS_OPENED) {
+		audio->rpc_endpt =
+			msm_rpc_connect_compatible(MVS_PROG,
+					MVS_VERS,
+					MSM_RPC_UNINTERRUPTIBLE);
+		audio->state = AUDIO_MVS_OPENED;
+	}
+
+	if (IS_ERR(audio->rpc_endpt)) {
+		MM_ERR("ALSA MVS RPC connect failed with version 0x%x\n",
+			MVS_VERS);
+		ret = PTR_ERR(audio->rpc_endpt);
+		audio->rpc_endpt = NULL;
+		goto err;
+	} else {
+		MM_DBG("ALSA MVS RPC connect succeeded\n");
+		if (audio->playback_substream == NULL ||
+			audio->capture_substream == NULL) {
+				if (substream->stream ==
+					SNDRV_PCM_STREAM_PLAYBACK) {
+					audio->playback_substream =
+						substream;
+					runtime->hw = msm_pcm_hardware;
+				} else if (substream->stream ==
+					SNDRV_PCM_STREAM_CAPTURE) {
+					audio->capture_substream =
+						substream;
+					runtime->hw = msm_pcm_hardware;
+				}
+		} else {
+			ret  = -EPERM;
+			goto err;
+		}
+		ret = snd_pcm_hw_constraint_integer(runtime,
+				SNDRV_PCM_HW_PARAM_PERIODS);
+		if (ret < 0) {
+			MM_ERR("snd_pcm_hw_constraint_integer failed\n");
+			if (!audio->instance) {
+				msm_rpc_close(audio->rpc_endpt);
+				audio->rpc_endpt = NULL;
+			}
+			goto err;
+		}
+			audio->instance++;
+	}
+err:
+	mutex_unlock(&audio->lock);
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+				 snd_pcm_uframes_t hwoff, void __user *buf,
+				 snd_pcm_uframes_t frames)
+{
+	int rc = 0;
+	int count = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+	uint32_t index;
+	MM_DBG("%s\n", __func__);
+	if (audio->dl_play  == 1) {
+		rc = wait_event_interruptible_timeout(audio->in_wait,
+			(audio->in_write - audio->in_read  <= 3),
+			100 * HZ);
+		if (!rc) {
+			MM_ERR("MVS: write time out\n");
+			return -ETIMEDOUT;
+		} else if (rc < 0) {
+			MM_ERR("MVS: write was interrupted\n");
+			return  -ERESTARTSYS;
+		}
+	}
+	mutex_lock(&audio->in_lock);
+	if (audio->state == AUDIO_MVS_ENABLED) {
+		index = audio->in_write % MVS_MAX_Q_LEN;
+		count = frames_to_bytes(runtime, frames);
+		if (count <= MVS_MAX_VOC_PKT_SIZE) {
+			rc = copy_from_user(audio->in[index].voc_pkt, buf,
+						 count);
+		 } else
+			rc = -ENOMEM;
+		if (!rc) {
+			audio->in[index].len = count;
+			audio->in_write++;
+			rc = count;
+			if (audio->in_write >= 3)
+				audio->dl_play  = 1;
+		} else {
+			MM_ERR("Copy from user returned %d\n", rc);
+			rc = -EFAULT;
+		}
+
+	} else {
+		MM_ERR("Write performed in invalid state %d\n",
+					audio->state);
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->in_lock);
+	return rc;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+			int channel, snd_pcm_uframes_t hwoff,
+			void __user *buf, snd_pcm_uframes_t frames)
+{
+	int rc = 0;
+	int count = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+	uint32_t index = 0;
+
+	MM_DBG("%s\n", __func__);
+
+	/* Ensure the driver has been enabled. */
+	if (audio->state != AUDIO_MVS_ENABLED) {
+		MM_ERR("Read performed in invalid state %d\n", audio->state);
+		return -EPERM;
+	}
+	rc = wait_event_interruptible_timeout(audio->out_wait,
+		(audio->out_read < audio->out_write ||
+		audio->state == AUDIO_MVS_CLOSING ||
+		audio->state == AUDIO_MVS_CLOSED),
+		100 * HZ);
+	if (!rc) {
+		MM_ERR("MVS: No UL data available\n");
+		return -ETIMEDOUT;
+	} else if (rc < 0) {
+		MM_ERR("MVS: Read was interrupted\n");
+		return  -ERESTARTSYS;
+	}
+
+	mutex_lock(&audio->out_lock);
+	if (audio->state  == AUDIO_MVS_CLOSING
+		|| audio->state == AUDIO_MVS_CLOSED) {
+		rc = -EBUSY;
+	} else {
+		count = frames_to_bytes(runtime, frames);
+		index = audio->out_read % MVS_MAX_Q_LEN;
+		if (audio->out[index].len <= count) {
+				rc = copy_to_user(buf,
+				audio->out[index].voc_pkt,
+				audio->out[index].len);
+				if (rc == 0) {
+					rc = audio->out[index].len;
+					audio->out_read++;
+				} else {
+					MM_ERR("Copy to user %d\n", rc);
+					rc = -EFAULT;
+				}
+		} else
+			rc = -ENOMEM;
+	}
+	mutex_unlock(&audio->out_lock);
+	return rc;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+			snd_pcm_uframes_t hwoff, void __user *buf,
+			snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	MM_DBG("%s\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int rc = 0;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+	struct audio_mvs_release_msg release_msg;
+	MM_DBG("%s\n", __func__);
+	memset(&release_msg, 0, sizeof(release_msg));
+	mutex_lock(&audio->lock);
+
+	audio->instance--;
+	wake_up(&audio->out_wait);
+
+	if (!audio->instance) {
+		if (audio->state == AUDIO_MVS_ENABLED) {
+			audio->state = AUDIO_MVS_CLOSING;
+			/* Release MVS. */
+			release_msg.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+			msm_rpc_setup_req(&release_msg.rpc_hdr, audio->rpc_prog,
+						 audio->rpc_ver,
+						 MVS_RELEASE_PROC);
+			audio->rpc_status = RPC_STATUS_FAILURE;
+			rc = msm_rpc_write(audio->rpc_endpt, &release_msg,
+					sizeof(release_msg));
+			if (rc >= 0) {
+				MM_DBG("RPC write for release done\n");
+				rc = wait_event_timeout(audio->wait,
+						(audio->rpc_status !=
+						 RPC_STATUS_FAILURE), 1 * HZ);
+				if (rc != 0) {
+					MM_DBG
+					("Wait event for release succeeded\n");
+					rc = 0;
+					kthread_stop(audio->task);
+					audio->prepare_ack = 0;
+					audio->task = NULL;
+					del_timer_sync(&audio->timer);
+				} else {
+					MM_ERR
+					("Wait event for release failed %d\n",
+						 rc);
+				}
+			} else	{
+				MM_ERR("RPC write for release failed %d\n", rc);
+			}
+		}
+		audio->state = AUDIO_MVS_CLOSED;
+		msm_rpc_close(audio->rpc_endpt);
+		audio->rpc_endpt = NULL;
+	}
+
+	mutex_unlock(&audio->lock);
+
+		wake_unlock(&audio->suspend_lock);
+		wake_unlock(&audio->idle_lock);
+		/* Release the IO buffers. */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mutex_lock(&audio->in_lock);
+		audio->in_write = 0;
+		audio->in_read = 0;
+		audio->playback_enable = 0;
+		audio->dl_play  = 0;
+		audio->ack_dl_count = 0;
+		memset(audio->in[0].voc_pkt, 0,
+			 MVS_MAX_VOC_PKT_SIZE * MVS_MAX_Q_LEN);
+		audio->in->len = 0;
+		audio->playback_substream = NULL;
+		mutex_unlock(&audio->in_lock);
+	} else {
+		mutex_lock(&audio->out_lock);
+		audio->out_write = 0;
+		audio->out_read = 0;
+		audio->capture_enable = 0;
+		audio->ack_ul_count = 0;
+		memset(audio->out[0].voc_pkt, 0,
+			 MVS_MAX_VOC_PKT_SIZE * MVS_MAX_Q_LEN);
+		audio->out->len = 0;
+		audio->capture_substream = NULL;
+		mutex_unlock(&audio->out_lock);
+	}
+	return rc;
+}
+
+static int msm_mvs_pcm_setup(struct snd_pcm_substream *substream)
+{
+	int rc = 0;
+	struct audio_mvs_acquire_msg acquire_msg;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+	memset(&acquire_msg, 0, sizeof(acquire_msg));
+
+	/*Create an Kthread */
+	MM_DBG("ALSA MVS thread creating\n");
+	if (!IS_ERR(audio->rpc_endpt)) {
+		audio->task =
+		    kthread_run(audio_mvs_thread, audio,
+				"audio_alsa_mvs_thread");
+		if (!IS_ERR(audio->task)) {
+			MM_DBG("ALSA MVS thread create succeeded\n");
+			audio->rpc_prog = MVS_PROG;
+			audio->rpc_ver = MVS_VERS;
+			/* Acquire MVS. */
+			acquire_msg.acquire_args.client_id =
+			    cpu_to_be32(MVS_CLIENT_ID_VOIP);
+			acquire_msg.acquire_args.cb_func_id =
+			    cpu_to_be32(MVS_CB_FUNC_ID);
+			msm_rpc_setup_req(&acquire_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_ACQUIRE_PROC);
+			audio->rpc_status = RPC_STATUS_FAILURE;
+			rc = msm_rpc_write(audio->rpc_endpt,
+					   &acquire_msg, sizeof(acquire_msg));
+			if (rc >= 0) {
+				MM_DBG("RPC write for acquire done\n");
+
+				rc = wait_event_timeout(audio->wait,
+							(audio->rpc_status !=
+							 RPC_STATUS_FAILURE),
+							1 * HZ);
+				if (rc != 0) {
+					audio->state =
+						AUDIO_MVS_ACQUIRE;
+					rc = 0;
+					MM_DBG
+					    ("MVS driver in acquire state\n");
+				} else {
+					MM_ERR
+					    ("acquire Wait event failed %d\n",
+						rc);
+					rc = -EBUSY;
+				}
+			} else {
+				MM_ERR("RPC write for acquire failed %d\n",
+				       rc);
+				rc = -EBUSY;
+			}
+		} else {
+			MM_ERR("ALSA MVS thread create failed\n");
+			rc = PTR_ERR(audio->task);
+			audio->task = NULL;
+			msm_rpc_close(audio->rpc_endpt);
+			audio->rpc_endpt = NULL;
+		}
+	} else {
+		MM_ERR("RPC connect is not setup with version 0x%x\n",
+			MVS_VERS);
+		rc = PTR_ERR(audio->rpc_endpt);
+		audio->rpc_endpt = NULL;
+	}
+	/*mvs mode setup */
+	if (audio->state == AUDIO_MVS_ACQUIRE)
+		rc =  audio_mvs_setup_mvs(audio);
+	else
+		rc = -EBUSY;
+	return rc;
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct  audio_mvs_info_type *prtd = &audio_mvs_info;
+	MM_DBG("%s\n", __func__);
+	prtd->pcm_playback_irq_pos = 0;
+	prtd->pcm_playback_buf_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->playback_enable = 1;
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct  audio_mvs_info_type *prtd = &audio_mvs_info;
+	prtd->pcm_capture_size  = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_capture_irq_pos = 0;
+	prtd->pcm_capture_buf_pos = 0;
+	prtd->capture_enable = 1;
+	return 0;
+}
+
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int rc = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_mvs_info_type *prtd = &audio_mvs_info;
+	unsigned long expiry = 0;
+	MM_DBG("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+
+	mutex_lock(&prtd->prepare_lock);
+	if (prtd->state == AUDIO_MVS_ENABLED)
+		goto enabled;
+	else if (prtd->state == AUDIO_MVS_PREPARING)
+		goto prepairing;
+	else if (prtd->state == AUDIO_MVS_OPENED) {
+		prtd->state = AUDIO_MVS_PREPARING;
+		rc = msm_mvs_pcm_setup(substream);
+	}
+	if (!rc) {
+		expiry = ((unsigned long)((prtd->pcm_count * 1000)
+			/(runtime->rate * runtime->channels * 2)));
+		expiry -= (expiry % 10);
+		prtd->timer.expires = jiffies + (msecs_to_jiffies(expiry));
+		prtd->expiry_delta = (msecs_to_jiffies(expiry));
+		if (prtd->expiry_delta <= 2)
+			prtd->expiry_delta = 1;
+		setup_timer(&prtd->timer, snd_pcm_mvs_timer,
+				 (unsigned long)prtd);
+		prtd->ack_ul_count = 0;
+		prtd->ack_dl_count = 0;
+		add_timer(&prtd->timer);
+
+	} else {
+		MM_ERR("ALSA MVS setup is not done");
+		rc =  -EPERM;
+		prtd->state = AUDIO_MVS_OPENED;
+		goto err;
+	}
+
+prepairing:
+	rc = wait_event_interruptible(prtd->prepare_wait,
+			(prtd->prepare_ack == 2));
+	if (rc < 0) {
+		MM_ERR("Wait event for prepare faild  rc  %d", rc);
+		rc = -EINTR;
+		prtd->state = AUDIO_MVS_OPENED;
+		goto err;
+	} else
+		MM_DBG("Wait event for prepare succeeded\n");
+
+	prtd->state = AUDIO_MVS_ENABLED;
+enabled:
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		rc = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		rc =  msm_pcm_capture_prepare(substream);
+err:
+	mutex_unlock(&prtd->prepare_lock);
+	return rc;
+}
+
+int msm_mvs_pcm_hw_params(struct snd_pcm_substream *substream,
+			  struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	MM_DBG("%s\n", __func__);
+	if (substream->pcm->device & 1) {
+		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
+		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
+	}
+	return 0;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+
+	if (audio->pcm_playback_irq_pos >= audio->pcm_size)
+		audio->pcm_playback_irq_pos = 0;
+	return bytes_to_frames(runtime, (audio->pcm_playback_irq_pos));
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_mvs_info_type *audio = &audio_mvs_info;
+
+	if (audio->pcm_capture_irq_pos >= audio->pcm_capture_size)
+		audio->pcm_capture_irq_pos = 0;
+	return bytes_to_frames(runtime, (audio->pcm_capture_irq_pos));
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+	MM_DBG("%s\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_pointer(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_pointer(substream);
+	return ret;
+}
+
+static struct snd_pcm_ops msm_mvs_pcm_ops = {
+	.open = msm_pcm_open,
+	.copy = msm_pcm_copy,
+	.hw_params = msm_mvs_pcm_hw_params,
+	.close = msm_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.prepare = msm_pcm_prepare,
+	.trigger = msm_pcm_trigger,
+	.pointer = msm_pcm_pointer,
+
+};
+
+static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int   i, ret, offset = 0;
+	struct snd_pcm *pcm = rtd->pcm;
+
+	audio_mvs_info.mem_chunk = kmalloc(
+		2 * MVS_MAX_VOC_PKT_SIZE * MVS_MAX_Q_LEN, GFP_KERNEL);
+	if (audio_mvs_info.mem_chunk != NULL) {
+		audio_mvs_info.in_read = 0;
+		audio_mvs_info.in_write = 0;
+		audio_mvs_info.out_read = 0;
+		audio_mvs_info.out_write = 0;
+		for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			audio_mvs_info.in[i].voc_pkt =
+			audio_mvs_info.mem_chunk + offset;
+			offset = offset + MVS_MAX_VOC_PKT_SIZE;
+		}
+		for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			audio_mvs_info.out[i].voc_pkt =
+				audio_mvs_info.mem_chunk + offset;
+			offset = offset + MVS_MAX_VOC_PKT_SIZE;
+		}
+		audio_mvs_info.playback_substream = NULL;
+		audio_mvs_info.capture_substream = NULL;
+	} else {
+		MM_ERR("MSM MVS kmalloc failed\n");
+		return -ENODEV;
+	}
+
+
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+	if (ret)
+		return ret;
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+	if (ret)
+		return ret;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_mvs_pcm_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_mvs_pcm_ops);
+
+	return 0;
+}
+
+struct snd_soc_platform_driver msm_mvs_soc_platform = {
+	.ops		= &msm_mvs_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+};
+EXPORT_SYMBOL(msm_mvs_soc_platform);
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_mvs_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-mvs-audio",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_mvs_soc_platform_init(void)
+{
+	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+	mutex_init(&audio_mvs_info.lock);
+	mutex_init(&audio_mvs_info.prepare_lock);
+	mutex_init(&audio_mvs_info.in_lock);
+	mutex_init(&audio_mvs_info.out_lock);
+	init_waitqueue_head(&audio_mvs_info.wait);
+	init_waitqueue_head(&audio_mvs_info.prepare_wait);
+	init_waitqueue_head(&audio_mvs_info.out_wait);
+	init_waitqueue_head(&audio_mvs_info.in_wait);
+	wake_lock_init(&audio_mvs_info.suspend_lock, WAKE_LOCK_SUSPEND,
+				"audio_mvs_suspend");
+	wake_lock_init(&audio_mvs_info.idle_lock, WAKE_LOCK_IDLE,
+				"audio_mvs_idle");
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_mvs_soc_platform_init);
+
+static void __exit msm_mvs_soc_platform_exit(void)
+{
+	 platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_mvs_soc_platform_exit);
+
+MODULE_DESCRIPTION("MVS PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-hostless.c b/sound/soc/msm/msm-pcm-hostless.c
new file mode 100644
index 0000000..c61511d
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-hostless.c
@@ -0,0 +1,61 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+
+static struct snd_pcm_ops msm_pcm_hostless_ops = {};
+
+static struct snd_soc_platform_driver msm_soc_hostless_platform = {
+	.ops		= &msm_pcm_hostless_ops,
+};
+
+static __devinit int msm_pcm_hostless_probe(struct platform_device *pdev)
+{
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_hostless_platform);
+}
+
+static int msm_pcm_hostless_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_hostless_driver = {
+	.driver = {
+		.name = "msm-pcm-hostless",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_hostless_probe,
+	.remove = __devexit_p(msm_pcm_hostless_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_hostless_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_hostless_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Hostless platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
new file mode 100644
index 0000000..10546fb
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -0,0 +1,464 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     2 * 1024 * 1024,
+/* TODO: Check on the lowest period size we can support */
+	.period_bytes_min =	128 * 1024,
+	.period_bytes_max =     512 * 1024,
+	.periods_min =          4,
+	.periods_max =          16,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_aio_write_param param;
+	struct audio_buffer *buf = prtd->audio_client->port[IN].buf;
+	int i = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE: {
+		uint32_t *ptrmem = (uint32_t *)&param;
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+				__func__, prtd->pcm_count);
+
+		param.paddr = (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		param.len = prtd->pcm_count;
+		param.msw_ts = 0;
+		param.lsw_ts = 0;
+		param.flags = NO_TIMESTAMP;
+		param.uid =  (unsigned long)buf[0].phys
+				+ (prtd->out_head * prtd->pcm_count);
+		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+					i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		if (q6asm_async_write(prtd->audio_client,
+					&param) < 0)
+			pr_err("%s:q6asm_async_write failed\n",
+				__func__);
+		else
+			prtd->out_head =
+				(prtd->out_head + 1) & (runtime->periods - 1);
+		break;
+	}
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN: {
+			pr_debug("%s:writing %d bytes"
+				" of buffer to dsp\n",
+				__func__, prtd->pcm_count);
+			param.paddr = (unsigned long)buf[prtd->out_head].data;
+			param.len = prtd->pcm_count;
+			param.msw_ts = 0;
+			param.lsw_ts = 0;
+			param.flags = NO_TIMESTAMP;
+			param.uid =  (unsigned long)buf[prtd->out_head].data;
+			if (q6asm_async_write(prtd->audio_client,
+						&param) < 0)
+				pr_err("%s:q6asm_async_write failed\n",
+					__func__);
+			else
+				prtd->out_head =
+					(prtd->out_head + 1)
+					& (runtime->periods - 1);
+		}
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
+				runtime->channels);
+	if (ret < 0)
+		pr_debug("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	pr_debug("%s\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("SNDRV_PCM_TRIGGER_START\n");
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		atomic_set(&prtd->start, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	runtime->hw = msm_pcm_hardware;
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_debug("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+		ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+		if (ret < 0) {
+			pr_err("%s: Set IO mode failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		return -EPERM;
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		prtd->session_id, substream->stream);
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	pr_debug("%s\n", __func__);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+		SNDRV_PCM_STREAM_PLAYBACK);
+	pr_debug("%s\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+	pr_debug("%s: pcm_irq_pos = %d\n", __func__, prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		return -EPERM;
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed \
+					rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+	if (!buf && !buf[0].data)
+		return -ENOMEM;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n",
+			__func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-lpa",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
new file mode 100644
index 0000000..0535693
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -0,0 +1,689 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     4096 * 8,
+	.period_bytes_min =	4096,
+	.period_bytes_max =     4096,
+	.periods_min =          8,
+	.periods_max =          8,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[8][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	uint32_t *ptrmem = (uint32_t *)payload;
+	int i = 0;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE: {
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		if (!prtd->mmap_flag)
+			break;
+		if (q6asm_is_cpu_buf_avail(IN,
+				prtd->audio_client,
+				&size, &idx)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+					__func__, prtd->pcm_count);
+			q6asm_write(prtd->audio_client,
+				prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		}
+		break;
+	}
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case ASM_DATA_EVENT_READ_DONE: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("token = 0x%08x\n", token);
+		for (i = 0; i < 8; i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		in_frame_info[token][0] = payload[2];
+		in_frame_info[token][1] = payload[3];
+		prtd->pcm_irq_pos += in_frame_info[token][0];
+		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		if (atomic_read(&prtd->in_count) <= prtd->periods)
+			atomic_inc(&prtd->in_count);
+		wake_up(&the_locks.read_wait);
+		if (prtd->mmap_flag
+			&& q6asm_is_cpu_buf_avail(OUT,
+				prtd->audio_client,
+				&size, &idx))
+			q6asm_read(prtd->audio_client);
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		if (!prtd->mmap_flag
+			&& !atomic_read(&prtd->out_needed))
+			break;
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN:
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK)
+				break;
+			if (prtd->mmap_flag) {
+				pr_debug("%s:writing %d bytes"
+					" of buffer to dsp\n",
+					__func__,
+					prtd->pcm_count);
+				q6asm_write(prtd->audio_client,
+					prtd->pcm_count,
+					0, 0, NO_TIMESTAMP);
+			} else {
+				while (atomic_read(&prtd->out_needed)) {
+					pr_debug("%s:writing %d bytes"
+						 " of buffer to dsp\n",
+						__func__,
+						prtd->pcm_count);
+					q6asm_write(prtd->audio_client,
+						prtd->pcm_count,
+						0, 0, NO_TIMESTAMP);
+					atomic_dec(&prtd->out_needed);
+					wake_up(&the_locks.write_wait);
+				};
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
+				runtime->channels);
+	if (ret < 0)
+		pr_info("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	int i = 0;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return 0;
+
+	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+	pr_debug("Channel = %d\n", prtd->channel_mode);
+	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
+					prtd->channel_mode);
+	if (ret < 0)
+		pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+	for (i = 0; i < runtime->periods; i++)
+		q6asm_read(prtd->audio_client);
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: Trigger start\n", __func__);
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		atomic_set(&prtd->start, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	runtime->hw = msm_pcm_hardware;
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_info("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm in open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+
+	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->cmd_ack = 1;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer = 0;
+	char *bufptr = NULL;
+	void *data = NULL;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	pr_debug("%s: prtd->out_count = %d\n",
+				__func__, atomic_read(&prtd->out_count));
+	ret = wait_event_timeout(the_locks.write_wait,
+			(atomic_read(&prtd->out_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_err("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+
+	if (!atomic_read(&prtd->out_count)) {
+		pr_err("%s: pcm stopped out_count 0\n", __func__);
+		return 0;
+	}
+
+	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	if (bufptr) {
+		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+					__func__, fbytes, xfer, size);
+		xfer = fbytes;
+		if (copy_from_user(bufptr, buf, xfer)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		fbytes -= xfer;
+		pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+		if (atomic_read(&prtd->start)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
+					__func__, xfer);
+			ret = q6asm_write(prtd->audio_client, xfer,
+						0, 0, NO_TIMESTAMP);
+			if (ret < 0) {
+				ret = -EFAULT;
+				goto fail;
+			}
+		} else
+			atomic_inc(&prtd->out_needed);
+		atomic_dec(&prtd->out_count);
+	}
+fail:
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer;
+	char *bufptr;
+	void *data = NULL;
+	static uint32_t idx;
+	static uint32_t size;
+	uint32_t offset = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+
+	pr_debug("%s\n", __func__);
+	fbytes = frames_to_bytes(runtime, frames);
+
+	pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+	pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+	pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+	ret = wait_event_timeout(the_locks.read_wait,
+			(atomic_read(&prtd->in_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+	if (!atomic_read(&prtd->in_count)) {
+		pr_debug("%s: pcm stopped in_count 0\n", __func__);
+		return 0;
+	}
+	pr_debug("Checking if valid buffer is available...%08x\n",
+						(unsigned int) data);
+	data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	pr_debug("Size = %d\n", size);
+	pr_debug("fbytes = %d\n", fbytes);
+	pr_debug("idx = %d\n", idx);
+	if (bufptr) {
+		xfer = fbytes;
+		if (xfer > size)
+			xfer = size;
+		offset = in_frame_info[idx][1];
+		pr_debug("Offset value = %d\n", offset);
+		if (copy_to_user(buf, bufptr+offset, xfer)) {
+			pr_err("Failed to copy buf to user\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+		fbytes -= xfer;
+		size -= xfer;
+		in_frame_info[idx][1] += xfer;
+		pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+					__func__, fbytes, size, xfer);
+		pr_debug(" Sending next buffer to dsp\n");
+		memset(&in_frame_info[idx], 0,
+			sizeof(uint32_t) * 2);
+		atomic_dec(&prtd->in_count);
+		ret = q6asm_read(prtd->audio_client);
+		if (ret < 0) {
+			pr_err("q6asm read failed\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+	} else
+		pr_err("No valid buffer\n");
+
+	pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+	SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed \
+					rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
new file mode 100644
index 0000000..6a0635b
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+
+extern int copy_count;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t eos_wait;
+	wait_queue_head_t enable_wait;
+};
+
+struct msm_audio {
+	struct snd_pcm_substream *substream;
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	uint16_t source; /* Encoding source bit mask */
+
+	struct audio_client *audio_client;
+
+	uint16_t session_id;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t dsp_cnt;
+
+	int abort; /* set when error, like sample rate mismatch */
+
+	int enabled;
+	int close_ack;
+	int cmd_ack;
+	atomic_t start;
+	atomic_t out_count;
+	atomic_t in_count;
+	atomic_t out_needed;
+	int out_head;
+	int periods;
+	int mmap_flag;
+};
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
new file mode 100644
index 0000000..06f72b7
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -0,0 +1,688 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6adm.h>
+#include <sound/q6afe.h>
+
+#include "msm-pcm-routing.h"
+#include "qdsp6/q6voice.h"
+
+struct audio_mixer_data {
+	u32 port_id; /* AFE port ID for Rx, FE DAI ID for TX */
+	unsigned long dai_sessions; /* Rx: FE DAIs Tx: BE DAI */
+	u32 mixer_type; /* playback or capture */
+};
+
+#define INVALID_SESSION -1
+
+enum {
+	AUDIO_MIXER_PRI_I2S_RX = 0,
+	AUDIO_MIXER_SLIMBUS_0_RX,
+	AUDIO_MIXER_HDMI_RX,
+	AUDIO_MIXER_MM_UL1,
+	AUDIO_MIXER_INT_BT_SCO_RX,
+	AUDIO_MIXER_INT_FM_RX,
+	AUDIO_MIXER_MAX,
+};
+
+enum {
+	AUDIO_PORT_MIXER_SLIM_0_RX = 0,
+	AUDIO_PORT_MIXER_MAX,
+};
+
+/* Tx mixer session is stored based on BE DAI ID
+ * Need to map to actual AFE port ID since AFE port
+ * ID can get really large.
+ * The table convert DAI back to AFE port ID
+ */
+static int bedai_port_map[MSM_BACKEND_DAI_MAX] = {
+	PRIMARY_I2S_RX,
+	PRIMARY_I2S_TX,
+	SLIMBUS_0_RX,
+	SLIMBUS_0_TX,
+	HDMI_RX,
+	INT_BT_SCO_RX,
+	INT_BT_SCO_TX,
+	INT_FM_RX,
+	INT_FM_TX,
+};
+
+/* Track ASM playback & capture sessions of DAI */
+static int fe_dai_map[MSM_FRONTEND_DAI_MAX][2] = {
+	/* MULTIMEDIA1 */
+	{INVALID_SESSION, INVALID_SESSION},
+	/* MULTIMEDIA2 */
+	{INVALID_SESSION, INVALID_SESSION},
+	/* MULTIMEDIA3 */
+	{INVALID_SESSION, INVALID_SESSION},
+};
+
+static struct audio_mixer_data audio_mixers[AUDIO_MIXER_MAX] = {
+	/* AUDIO_MIXER_PRI_I2S_RX */
+	{PRIMARY_I2S_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* AUDIO_MIXER_SLIMBUS_0_RX */
+	{SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* AUDIO_MIXER_HDMI_RX */
+	{HDMI_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* AUDIO_MIXER_MM_UL1 */
+	{MSM_FRONTEND_DAI_MULTIMEDIA1, 0, SNDRV_PCM_STREAM_CAPTURE},
+	/* AUDIO_MIXER_INT_BT_SCO_RX */
+	{INT_BT_SCO_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* AUDIO_MIXER_INT_FM_RX */
+	{INT_FM_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+};
+static struct voice_mixer_data voice_mixers[VOICE_MIXER_MAX] = {
+	/* VOICE_MIXER_PRI_I2S_RX */
+	{VOICE_PRI_I2S_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* VOICE_MIXER_SLIMBUS_0_RX */
+	{VOICE_SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* VOICE_MIXER_PRI_I2S_TX */
+	{VOICE_PRI_I2S_TX, 0, SNDRV_PCM_STREAM_CAPTURE},
+	/* VOICE_MIXER_SLIMBUS_0_TX */
+	{VOICE_SLIMBUS_0_TX, 0, SNDRV_PCM_STREAM_CAPTURE},
+	/* VOICE_MIXER_INT_BT_SCO_RX */
+	{VOICE_INT_BT_SCO_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+	/* VOICE_MIXER_INT_BT_SCO_TX */
+	{VOICE_INT_BT_SCO_TX, 0, SNDRV_PCM_STREAM_CAPTURE}
+};
+
+/* Reuse audio_mixer_data struct but ignore mixer type field
+ * unless there is use case for RX -> TX
+ */
+static struct audio_mixer_data audio_port_mixers[AUDIO_PORT_MIXER_MAX] = {
+	/* AUDIO_PORT_MIXER_SLIM_0_RX */
+	{SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
+};
+
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+{
+	int i, be_id;
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		fe_dai_map[fedai_id][0] = dspst_id;
+		for (i = 0; i < AUDIO_MIXER_MAX; i++) {
+			if ((audio_mixers[i].mixer_type == stream_type) &&
+			(test_bit(fedai_id, &audio_mixers[i].dai_sessions)))
+				/* To do: multiple devices case */
+				adm_route_session(audio_mixers[i].port_id,
+				dspst_id, 1);
+		}
+	} else {
+		fe_dai_map[fedai_id][1] = dspst_id;
+		for (i = 0; i < AUDIO_MIXER_MAX; i++) {
+			if ((audio_mixers[i].mixer_type == stream_type) &&
+				(fedai_id == audio_mixers[i].port_id)) {
+				/* To-do: Handle mixing of inputs */
+				be_id = find_next_bit(
+					&audio_mixers[i].dai_sessions,
+					MSM_BACKEND_DAI_MAX, 0);
+				if (be_id < MSM_BACKEND_DAI_MAX)
+					adm_route_session(bedai_port_map[be_id],
+					dspst_id, 1);
+				else
+					pr_err("%s: no routing\n", __func__);
+			}
+		}
+	}
+}
+
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
+{
+	int i, be_id;
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < AUDIO_MIXER_MAX; i++) {
+			if ((audio_mixers[i].mixer_type == stream_type) &&
+			(test_bit(fedai_id, &audio_mixers[i].dai_sessions))) {
+				/* To do: multiple devices case */
+				adm_route_session(audio_mixers[i].port_id,
+				fe_dai_map[fedai_id][0], 0);
+			}
+		}
+		fe_dai_map[fedai_id][0] = INVALID_SESSION;
+	} else {
+		for (i = 0; i < AUDIO_MIXER_MAX; i++) {
+			if ((audio_mixers[i].mixer_type == stream_type) &&
+				(fedai_id == audio_mixers[i].port_id)) {
+				/* To-do: Handle mixing of inputs */
+				be_id = find_next_bit(
+					&audio_mixers[i].dai_sessions,
+					MSM_BACKEND_DAI_MAX, 0);
+				if (be_id < MSM_BACKEND_DAI_MAX)
+					adm_route_session(bedai_port_map[be_id],
+					fe_dai_map[fedai_id][1], 0);
+				else
+					pr_err("%s: no routing\n", __func__);
+			}
+		}
+		fe_dai_map[fedai_id][1] = INVALID_SESSION;
+	}
+}
+
+static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
+{
+
+	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
+
+	if (set)
+		set_bit(val, &audio_mixers[reg].dai_sessions);
+	 else
+		clear_bit(val, &audio_mixers[reg].dai_sessions);
+
+	if (audio_mixers[reg].mixer_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (fe_dai_map[val][0] != INVALID_SESSION)
+			adm_route_session(audio_mixers[reg].port_id,
+			fe_dai_map[val][0], set);
+	} else {
+		int fe_id = audio_mixers[reg].port_id;
+		if (fe_dai_map[fe_id][1] != INVALID_SESSION)
+			adm_route_session(bedai_port_map[val],
+			fe_dai_map[fe_id][1], set);
+	}
+}
+
+static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (test_bit(mc->shift, &audio_mixers[mc->reg].dai_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	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_audio_mixer(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+
+	if (ucontrol->value.integer.value[0]) {
+		msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else {
+		msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+
+	return 1;
+}
+
+static void msm_pcm_routing_process_voice(u16 reg, u16 val, int set)
+{
+
+	u32 port_map_id;
+
+	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
+
+	port_map_id = voice_mixers[reg].port_id;
+
+	if (set)
+		set_bit(val, &voice_mixers[reg].dai_sessions);
+	else
+		clear_bit(val, &voice_mixers[reg].dai_sessions);
+
+	if (voice_mixers[reg].mixer_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		voc_set_route_flag(RX_PATH, set);
+		if (set) {
+			voc_set_rxtx_port(bedai_port_map[port_map_id], DEV_RX);
+
+			if (voc_get_route_flag(RX_PATH) &&
+						voc_get_route_flag(TX_PATH))
+				voc_enable_cvp();
+		} else {
+			voc_disable_cvp();
+		}
+	} else {
+		voc_set_route_flag(TX_PATH, set);
+		if (set) {
+			voc_set_rxtx_port(bedai_port_map[port_map_id], DEV_TX);
+
+			if (voc_get_route_flag(RX_PATH) &&
+						voc_get_route_flag(TX_PATH))
+				voc_enable_cvp();
+		} else {
+			voc_disable_cvp();
+		}
+	}
+}
+
+static int msm_routing_get_voice_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (test_bit(mc->shift, &voice_mixers[mc->reg].dai_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	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_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (ucontrol->value.integer.value[0]) {
+		msm_pcm_routing_process_voice(mc->reg, mc->shift, 1);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+	} else {
+		msm_pcm_routing_process_voice(mc->reg, mc->shift, 0);
+		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+	}
+
+	return 1;
+}
+
+static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+	(struct soc_mixer_control *)kcontrol->private_value;
+
+	if (test_bit(mc->shift, &audio_port_mixers[mc->reg].dai_sessions))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	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_port_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+
+	pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg,
+		mc->shift, ucontrol->value.integer.value[0]);
+
+	if (ucontrol->value.integer.value[0]) {
+		afe_loopback(1, audio_port_mixers[mc->reg].port_id,
+			     bedai_port_map[mc->shift]);
+		set_bit(mc->shift,
+		&audio_port_mixers[mc->reg].dai_sessions);
+	} else {
+		afe_loopback(0, audio_port_mixers[mc->reg].port_id,
+			     bedai_port_map[mc->shift]);
+		clear_bit(mc->shift,
+		&audio_port_mixers[mc->reg].dai_sessions);
+	}
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_PRI_I2S_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_HDMI_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_INT_FM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX", AUDIO_MIXER_MM_UL1,
+	MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", AUDIO_MIXER_MM_UL1,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", AUDIO_MIXER_MM_UL1,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_MIXER_MM_UL1,
+	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", VOICE_MIXER_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", VOICE_MIXER_PRI_I2S_RX ,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", VOICE_MIXER_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", VOICE_MIXER_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("CSVoice", VOICE_MIXER_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voip", VOICE_MIXER_INT_BT_SCO_RX ,
+	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_Voice", VOICE_MIXER_PRI_I2S_TX,
+	MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_Voice", VOICE_MIXER_SLIMBUS_0_TX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice", VOICE_MIXER_INT_BT_SCO_TX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_Voip", VOICE_MIXER_PRI_I2S_TX,
+	MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_Voip", VOICE_MIXER_SLIMBUS_0_TX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voip", VOICE_MIXER_INT_BT_SCO_TX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_PORT_MIXER_SLIM_0_RX,
+	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", AUDIO_PORT_MIXER_SLIM_0_RX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
+static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
+	/* Frontend AIF */
+	/* Widget name equals to Front-End DAI name<Need confirmation>,
+	 * Stream name must contains substring of front-end dai name
+	 */
+	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIM0_UL_HL", "SLIMBUS0_HOSTLESS Capture",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
+		0, 0, 0, 0),
+	/* Backend AIF */
+	/* Stream name equals to backend dai link stream name
+	 */
+	SND_SOC_DAPM_AIF_OUT("PRI_I2S_RX", "Primary I2S Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI 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("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("INT_BT_SCO_TX", "Internal BT-SCO Capture",
+				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INT_FM_RX", "Internal FM Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("INT_FM_TX", "Internal FM Capture",
+				0, 0, 0, 0),
+
+	/* Mixer definitions */
+	SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
+	hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
+	/* Voice Mixer */
+	SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
+				ARRAY_SIZE(pri_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				slimbus_rx_voice_mixer_controls,
+				ARRAY_SIZE(slimbus_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX_Voice Mixer",
+				SND_SOC_NOPM, 0, 0,
+				bt_sco_rx_voice_mixer_controls,
+				ARRAY_SIZE(bt_sco_rx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
+				SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
+				ARRAY_SIZE(tx_voice_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
+				SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
+				ARRAY_SIZE(tx_voip_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+	int_fm_rx_mixer_controls, ARRAY_SIZE(int_fm_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)),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"PRI_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
+
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
+
+	{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
+	{"HDMI Mixer", "MultiMedia2", "MM_DL2"},
+	{"HDMI", NULL, "HDMI Mixer"},
+
+	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
+	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
+
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
+
+	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
+
+	{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
+
+	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
+
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
+
+	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+	{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
+	{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
+	{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
+	{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
+	{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
+	{"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
+	{"VOIP_UL", NULL, "Voip_Tx Mixer"},
+	{"SLIMBUS_0_RX", NULL, "SLIM0_DL_HL"},
+	{"SLIM0_UL_HL", NULL, "SLIMBUS_0_TX"},
+	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
+	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+	{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
+};
+
+static struct snd_pcm_ops msm_routing_pcm_ops = {};
+
+static unsigned int msm_routing_read(struct snd_soc_platform *platform,
+				 unsigned int reg)
+{
+	dev_dbg(platform->dev, "reg %x\n", reg);
+	return 0;
+}
+
+/* Not used but frame seems to require it */
+static int msm_routing_write(struct snd_soc_platform *platform,
+	unsigned int reg, unsigned int val)
+{
+	dev_dbg(platform->dev, "reg %x val %x\n", reg, val);
+	return 0;
+}
+
+/* Not used but frame seems to require it */
+static int msm_routing_probe(struct snd_soc_platform *platform)
+{
+	snd_soc_dapm_new_controls(&platform->dapm, msm_qdsp6_widgets,
+			    ARRAY_SIZE(msm_qdsp6_widgets));
+	snd_soc_dapm_add_routes(&platform->dapm, intercon,
+		ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(&platform->dapm);
+
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_routing_platform = {
+	.ops		= &msm_routing_pcm_ops,
+	.probe		= msm_routing_probe,
+	.read		= msm_routing_read,
+	.write		= msm_routing_write,
+};
+
+static __devinit int msm_routing_pcm_probe(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_routing_platform);
+}
+
+static int msm_routing_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_routing_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-routing",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_routing_pcm_probe,
+	.remove = __devexit_p(msm_routing_pcm_remove),
+};
+
+static int __init msm_soc_routing_platform_init(void)
+{
+	return platform_driver_register(&msm_routing_pcm_driver);
+}
+module_init(msm_soc_routing_platform_init);
+
+static void __exit msm_soc_routing_platform_exit(void)
+{
+	platform_driver_unregister(&msm_routing_pcm_driver);
+}
+module_exit(msm_soc_routing_platform_exit);
+
+MODULE_DESCRIPTION("MSM routing platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
new file mode 100644
index 0000000..c45f95b
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_ROUTING_H
+#define _MSM_PCM_ROUTING_H
+#include <sound/apr_audio.h>
+
+#define LPASS_BE_PRI_I2S_RX "(Backend) PRIMARY_I2S_RX"
+#define LPASS_BE_PRI_I2S_TX "(Backend) PRIMARY_I2S_TX"
+#define LPASS_BE_SLIMBUS_0_RX "(Backend) SLIMBUS_0_RX"
+#define LPASS_BE_SLIMBUS_0_TX "(Backend) SLIMBUS_0_TX"
+#define LPASS_BE_HDMI "(Backend) HDMI"
+#define LPASS_BE_INT_BT_SCO_RX "(Backend) INT_BT_SCO_RX"
+#define LPASS_BE_INT_BT_SCO_TX "(Backend) INT_BT_SCO_TX"
+#define LPASS_BE_INT_FM_RX "(Backend) INT_FM_RX"
+#define LPASS_BE_INT_FM_TX "(Backend) INT_FM_TX"
+
+enum {
+	MSM_FRONTEND_DAI_MULTIMEDIA1 = 0,
+	MSM_FRONTEND_DAI_MULTIMEDIA2,
+	MSM_FRONTEND_DAI_CS_VOICE,
+	MSM_FRONTEND_DAI_VOIP,
+	MSM_FRONTEND_DAI_MULTIMEDIA3,
+	MSM_FRONTEND_DAI_MAX,
+};
+
+enum {
+	MSM_BACKEND_DAI_PRI_I2S_RX = 0,
+	MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_BACKEND_DAI_HDMI_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_BACKEND_DAI_INT_FM_RX,
+	MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_BACKEND_DAI_MAX,
+};
+
+struct voice_mixer_data {
+	u32 port_id;
+	unsigned long dai_sessions;
+	u32 mixer_type;
+};
+
+enum {
+	VOICE_MIXER_PRI_I2S_RX = 0,
+	VOICE_MIXER_SLIMBUS_0_RX,
+	VOICE_MIXER_PRI_I2S_TX,
+	VOICE_MIXER_SLIMBUS_0_TX,
+	VOICE_MIXER_INT_BT_SCO_RX,
+	VOICE_MIXER_INT_BT_SCO_TX,
+	VOICE_MIXER_MAX,
+};
+
+enum {
+	VOICE_PRI_I2S_RX = 0,
+	VOICE_PRI_I2S_TX,
+	VOICE_SLIMBUS_0_RX,
+	VOICE_SLIMBUS_0_TX,
+	VOICE_INT_BT_SCO_RX = 5,
+	VOICE_INT_BT_SCO_TX,
+};
+
+/* dai_id: front-end ID,
+ * dspst_id:  DSP audio stream ID
+ * stream_type: playback or capture
+ */
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
+	int stream_type);
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
new file mode 100644
index 0000000..1f581562
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -0,0 +1,319 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-voice.h"
+#include "qdsp6/q6voice.h"
+
+static struct msm_voice voice_info;
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+	.rate_min =             8000,
+	.rate_max =             16000,
+	.channels_min =         1,
+	.channels_max =         1,
+
+	.buffer_bytes_max =     4096 * 2,
+	.period_bytes_min =     4096,
+	.period_bytes_max =     4096,
+	.periods_min =          2,
+	.periods_max =          2,
+
+	.fifo_size =            0,
+};
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+
+	if (!prtd->playback_start)
+		prtd->playback_start = 1;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+
+	if (!prtd->capture_start)
+		prtd->capture_start = 1;
+
+	return 0;
+}
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *voice = &voice_info;
+
+	mutex_lock(&voice->lock);
+
+	runtime->hw = msm_pcm_hardware;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		voice->playback_substream = substream;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		voice->capture_substream = substream;
+
+	voice->instance++;
+	pr_debug(" %s: instance: %d\n", __func__ , voice->instance);
+	runtime->private_data = voice;
+
+	mutex_unlock(&voice->lock);
+
+	return 0;
+}
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+
+	if (prtd->playback_start)
+		prtd->playback_start = 0;
+
+	prtd->playback_substream = NULL;
+
+	return 0;
+}
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+
+	if (prtd->capture_start)
+		prtd->capture_start = 0;
+	prtd->capture_substream = NULL;
+
+	return 0;
+}
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+	int ret;
+
+	mutex_lock(&prtd->lock);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+
+	prtd->instance--;
+	if (!prtd->playback_start && !prtd->capture_start) {
+		pr_debug("end voice call\n");
+		voc_end_voice_call();
+	}
+	mutex_unlock(&prtd->lock);
+
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+
+	mutex_lock(&prtd->lock);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+
+	if (prtd->playback_start && prtd->capture_start)
+		voc_start_voice_call();
+
+	mutex_unlock(&prtd->lock);
+
+	return ret;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+
+	pr_debug("%s, Voice\n", __func__);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static int msm_voice_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2; /* Volume */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 5;
+
+	return 0;
+}
+
+static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_voice_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dir = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+
+	pr_debug(" dir: %d, volume: %d\n", dir, volume);
+
+	voc_set_rx_vol_index(dir, volume);
+	return 0;
+}
+
+static int msm_voice_mute_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 2;
+
+	return 0;
+}
+
+static int msm_voice_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_voice_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dir = ucontrol->value.integer.value[0];
+	int mute = ucontrol->value.integer.value[1];
+
+	pr_debug("%s: dir=%d, mute=%d\n", __func__, dir, mute);
+
+	voc_set_tx_mute(dir, mute);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new msm_voice_controls[] = {
+	MSM_EXT("VoiceVolume", msm_voice_volume_info, msm_voice_volume_get, \
+		msm_voice_volume_put, 0),
+	MSM_EXT("VoiceMute", msm_voice_mute_info, msm_voice_mute_get, \
+		msm_voice_mute_put, 0),
+};
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static int msm_pcm_voice_probe(struct snd_soc_platform *platform)
+{
+	snd_soc_add_platform_controls(platform, msm_voice_controls,
+					ARRAY_SIZE(msm_voice_controls));
+
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+	.probe		= msm_pcm_voice_probe,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-voice",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	memset(&voice_info, 0, sizeof(voice_info));
+	mutex_init(&voice_info.lock);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Voice PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-voice.h b/sound/soc/msm/msm-pcm-voice.h
new file mode 100644
index 0000000..2c1f5ca
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-voice.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_VOICE_H
+#define _MSM_PCM_VOICE_H
+#include <sound/apr_audio.h>
+
+
+struct msm_voice {
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	int instance;
+
+	struct mutex lock;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	int playback_start;
+	int capture_start;
+};
+
+#define MSM_EXT(xname, fp_info, fp_get, fp_put, addr) \
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.name = xname, \
+	.info = fp_info,\
+	.get = fp_get, .put = fp_put, \
+	.private_value = addr, \
+	}
+
+#endif /*_MSM_PCM_VOICE_H*/
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
new file mode 100644
index 0000000..2f2ab79
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -0,0 +1,721 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+#include "qdsp6/q6voice.h"
+
+#define VOIP_MAX_Q_LEN 10
+#define VOIP_MAX_VOC_PKT_SIZE 320
+
+enum voip_state {
+	VOIP_STOPPED,
+	VOIP_STARTED,
+};
+
+struct voip_frame {
+	uint32_t len;
+	uint8_t voc_pkt[VOIP_MAX_VOC_PKT_SIZE];
+};
+
+struct voip_buf_node {
+	struct list_head list;
+	struct voip_frame frame;
+};
+
+struct voip_drv_info {
+	enum  voip_state state;
+
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	struct list_head in_queue;
+	struct list_head free_in_queue;
+
+	struct list_head out_queue;
+	struct list_head free_out_queue;
+
+	wait_queue_head_t out_wait;
+
+	struct mutex lock;
+	struct mutex in_lock;
+	struct mutex out_lock;
+
+	spinlock_t dsp_lock;
+
+
+	uint8_t capture_start;
+	uint8_t playback_start;
+
+	uint8_t playback_instance;
+	uint8_t capture_instance;
+
+	unsigned int play_samp_rate;
+	unsigned int cap_samp_rate;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_playback_irq_pos;      /* IRQ position */
+	unsigned int pcm_playback_buf_pos;      /* position in buffer */
+
+	unsigned int pcm_capture_size;
+	unsigned int pcm_capture_count;
+	unsigned int pcm_capture_irq_pos;       /* IRQ position */
+	unsigned int pcm_capture_buf_pos;       /* position in buffer */
+};
+
+static struct voip_drv_info voip_info;
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+	.rate_min =             8000,
+	.rate_max =             16000,
+	.channels_min =         1,
+	.channels_max =         1,
+	.buffer_bytes_max =	VOIP_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN,
+	.period_bytes_min =	VOIP_MAX_VOC_PKT_SIZE,
+	.period_bytes_max =	VOIP_MAX_VOC_PKT_SIZE,
+	.periods_min =		VOIP_MAX_Q_LEN,
+	.periods_max =		VOIP_MAX_Q_LEN,
+	.fifo_size =            0,
+};
+
+
+/* sample rate supported */
+static unsigned int supported_sample_rates[] = {8000, 16000};
+
+/* capture path */
+static void voip_process_ul_pkt(uint8_t *voc_pkt,
+					uint32_t pkt_len,
+					void *private_data)
+{
+	struct voip_buf_node *buf_node = NULL;
+	struct voip_drv_info *prtd = private_data;
+	unsigned long dsp_flags;
+
+	if (prtd->capture_substream == NULL)
+		return;
+
+	/* Copy up-link packet into out_queue. */
+	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+
+	/* discarding UL packets till start is received */
+	if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
+		buf_node = list_first_entry(&prtd->free_out_queue,
+					struct voip_buf_node, list);
+		list_del(&buf_node->list);
+
+		buf_node->frame.len = pkt_len;
+		memcpy(&buf_node->frame.voc_pkt[0], voc_pkt,
+					buf_node->frame.len);
+
+		list_add_tail(&buf_node->list, &prtd->out_queue);
+		prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		snd_pcm_period_elapsed(prtd->capture_substream);
+	} else {
+		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		pr_err("UL data dropped\n");
+	}
+
+	wake_up(&prtd->out_wait);
+}
+
+/* playback path */
+static void voip_process_dl_pkt(uint8_t *voc_pkt,
+					uint32_t *pkt_len,
+					void *private_data)
+{
+	struct voip_buf_node *buf_node = NULL;
+	struct voip_drv_info *prtd = private_data;
+	unsigned long dsp_flags;
+
+
+	if (prtd->playback_substream == NULL)
+		return;
+
+	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+
+	if (!list_empty(&prtd->in_queue) && prtd->playback_start) {
+		buf_node = list_first_entry(&prtd->in_queue,
+				struct voip_buf_node, list);
+		list_del(&buf_node->list);
+
+		*pkt_len = buf_node->frame.len;
+
+		memcpy(voc_pkt,
+			&buf_node->frame.voc_pkt[0],
+			buf_node->frame.len);
+
+		list_add_tail(&buf_node->list, &prtd->free_in_queue);
+
+		prtd->pcm_playback_irq_pos += prtd->pcm_count;
+		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		snd_pcm_period_elapsed(prtd->playback_substream);
+	} else {
+		*pkt_len = 0;
+		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		pr_err("DL data not available\n");
+	}
+}
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	prtd->play_samp_rate = runtime->rate;
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_playback_irq_pos = 0;
+	prtd->pcm_playback_buf_pos = 0;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+	int ret = 0;
+
+	prtd->cap_samp_rate = runtime->rate;
+	prtd->pcm_capture_size  = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_capture_irq_pos = 0;
+	prtd->pcm_capture_buf_pos = 0;
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		pr_debug("%s: Trigger start\n", __func__);
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			prtd->capture_start = 1;
+		else
+			prtd->playback_start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			prtd->playback_start = 0;
+		else
+			prtd->capture_start = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = &voip_info;
+	int ret = 0;
+
+	pr_debug("%s, VoIP\n", __func__);
+	mutex_lock(&prtd->lock);
+
+	runtime->hw = msm_pcm_hardware;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+					SNDRV_PCM_HW_PARAM_RATE,
+					&constraints_sample_rates);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_list failed\n");
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		pr_debug("snd_pcm_hw_constraint_integer failed\n");
+		goto err;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->playback_substream = substream;
+		prtd->playback_instance++;
+	} else {
+		prtd->capture_substream = substream;
+		prtd->capture_instance++;
+	}
+	runtime->private_data = prtd;
+err:
+	mutex_unlock(&prtd->lock);
+
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	struct voip_buf_node *buf_node = NULL;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	int count = frames_to_bytes(runtime, frames);
+	pr_debug("%s: count = %d\n", __func__, count);
+
+	mutex_lock(&prtd->in_lock);
+
+	if (count == VOIP_MAX_VOC_PKT_SIZE) {
+		if (!list_empty(&prtd->free_in_queue)) {
+			buf_node =
+				list_first_entry(&prtd->free_in_queue,
+						struct voip_buf_node, list);
+			list_del(&buf_node->list);
+
+			ret = copy_from_user(&buf_node->frame.voc_pkt,
+						buf, count);
+			buf_node->frame.len = count;
+			list_add_tail(&buf_node->list, &prtd->in_queue);
+		} else
+			pr_err("%s: No free DL buffs\n", __func__);
+	} else {
+		pr_err("%s: Write count %d is not  VOIP_MAX_VOC_PKT_SIZE\n",
+			__func__, count);
+		ret = -ENOMEM;
+	}
+
+	mutex_unlock(&prtd->in_lock);
+
+	return  ret;
+}
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int count = 0;
+	struct voip_buf_node *buf_node = NULL;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	count = frames_to_bytes(runtime, frames);
+
+	pr_debug("%s: count = %d\n", __func__, count);
+
+	ret = wait_event_interruptible_timeout(prtd->out_wait,
+				(!list_empty(&prtd->out_queue) ||
+				prtd->state == VOIP_STOPPED),
+				1 * HZ);
+
+	if (ret > 0) {
+		mutex_lock(&prtd->out_lock);
+
+		if (count == VOIP_MAX_VOC_PKT_SIZE) {
+			buf_node = list_first_entry(&prtd->out_queue,
+					struct voip_buf_node, list);
+			list_del(&buf_node->list);
+
+			ret = copy_to_user(buf,
+					&buf_node->frame.voc_pkt,
+					buf_node->frame.len);
+
+			if (ret) {
+				pr_err("%s: Copy to user retuned %d\n",
+					__func__, ret);
+				ret = -EFAULT;
+			}
+			list_add_tail(&buf_node->list,
+						&prtd->free_out_queue);
+		} else {
+				pr_err("%s: Read count %d < VOIP_MAX_VOC_PKT_SIZE\n",
+						__func__, count);
+				ret = -ENOMEM;
+		}
+
+		mutex_unlock(&prtd->out_lock);
+
+	} else if (ret == 0) {
+		pr_err("%s: No UL data available\n", __func__);
+		ret = -ETIMEDOUT;
+	} else {
+		pr_err("%s: Read was interrupted\n", __func__);
+		ret = -ERESTARTSYS;
+	}
+	return ret;
+}
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+	struct voip_buf_node *buf_node = NULL;
+	struct snd_dma_buffer *p_dma_buf, *c_dma_buf;
+	struct snd_pcm_substream *p_substream, *c_substream;
+	struct snd_pcm_runtime *runtime;
+	struct voip_drv_info *prtd;
+
+	if (substream == NULL) {
+		pr_err("substream is NULL\n");
+		return -EINVAL;
+	}
+	runtime = substream->runtime;
+	prtd = runtime->private_data;
+
+	wake_up(&prtd->out_wait);
+
+	mutex_lock(&prtd->lock);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->playback_instance--;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		prtd->capture_instance--;
+
+	if (!prtd->playback_instance && !prtd->capture_instance) {
+		if (prtd->state == VOIP_STARTED) {
+			prtd->state = VOIP_STOPPED;
+			voc_end_voice_call();
+			voc_set_voc_path_full(0);
+			voc_register_mvs_cb(NULL, NULL, prtd);
+		}
+		/* release all buffer */
+		/* release in_queue and free_in_queue */
+		pr_debug("release all buffer\n");
+		p_substream = prtd->playback_substream;
+		if (p_substream == NULL) {
+			pr_debug("p_substream is NULL\n");
+			goto capt;
+		}
+		p_dma_buf = &p_substream->dma_buffer;
+		if (p_dma_buf == NULL) {
+			pr_debug("p_dma_buf is NULL\n");
+			goto capt;
+		}
+		if (p_dma_buf->area != NULL) {
+			mutex_lock(&prtd->in_lock);
+			list_for_each_safe(ptr, next, &prtd->in_queue) {
+				buf_node = list_entry(ptr,
+						struct voip_buf_node, list);
+				list_del(&buf_node->list);
+			}
+			list_for_each_safe(ptr, next, &prtd->free_in_queue) {
+				buf_node = list_entry(ptr,
+						struct voip_buf_node, list);
+				list_del(&buf_node->list);
+			}
+			dma_free_coherent(p_substream->pcm->card->dev,
+				runtime->hw.buffer_bytes_max, p_dma_buf->area,
+				p_dma_buf->addr);
+			p_dma_buf->area = NULL;
+			mutex_unlock(&prtd->in_lock);
+		}
+		/* release out_queue and free_out_queue */
+capt:		c_substream = prtd->capture_substream;
+		if (c_substream == NULL) {
+			pr_debug("c_substream is NULL\n");
+			goto done;
+		}
+		c_dma_buf = &c_substream->dma_buffer;
+		if (c_substream == NULL) {
+			pr_debug("c_dma_buf is NULL.\n");
+			goto done;
+		}
+		if (c_dma_buf->area != NULL) {
+			mutex_lock(&prtd->out_lock);
+			list_for_each_safe(ptr, next, &prtd->out_queue) {
+				buf_node = list_entry(ptr,
+						struct voip_buf_node, list);
+				list_del(&buf_node->list);
+			}
+			list_for_each_safe(ptr, next, &prtd->free_out_queue) {
+				buf_node = list_entry(ptr,
+						struct voip_buf_node, list);
+				list_del(&buf_node->list);
+			}
+			dma_free_coherent(c_substream->pcm->card->dev,
+				runtime->hw.buffer_bytes_max, c_dma_buf->area,
+				c_dma_buf->addr);
+			c_dma_buf->area = NULL;
+			mutex_unlock(&prtd->out_lock);
+		}
+done:
+		prtd->capture_substream = NULL;
+		prtd->playback_substream = NULL;
+	}
+	mutex_unlock(&prtd->lock);
+
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	mutex_lock(&prtd->lock);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+
+	if (prtd->playback_instance && prtd->capture_instance
+				&& (prtd->state != VOIP_STARTED)) {
+
+		voc_set_voc_path_full(1);
+
+		if ((prtd->play_samp_rate == 8000) &&
+					(prtd->cap_samp_rate == 8000))
+			voc_config_vocoder(VSS_MEDIA_ID_PCM_NB,
+						0, VSS_NETWORK_ID_VOIP_NB);
+		else if ((prtd->play_samp_rate == 16000) &&
+					(prtd->cap_samp_rate == 16000))
+			voc_config_vocoder(VSS_MEDIA_ID_PCM_WB,
+						0, VSS_NETWORK_ID_VOIP_WB);
+		else {
+			pr_err(" sample rate are not set properly\n");
+			goto err;
+		}
+		voc_register_mvs_cb(voip_process_ul_pkt,
+					voip_process_dl_pkt, prtd);
+		voc_start_voice_call();
+
+		prtd->state = VOIP_STARTED;
+	}
+err:
+	mutex_unlock(&prtd->lock);
+
+	return ret;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	if (prtd->pcm_playback_irq_pos >= prtd->pcm_size)
+		prtd->pcm_playback_irq_pos = 0;
+	return bytes_to_frames(runtime, (prtd->pcm_playback_irq_pos));
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
+
+	if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
+		prtd->pcm_capture_irq_pos = 0;
+	return bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+	 pr_debug("%s\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_pointer(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_pointer(substream);
+	return ret;
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+			struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	pr_debug("%s\n", __func__);
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct voip_buf_node *buf_node = NULL;
+	int i = 0, offset = 0;
+
+	pr_debug("%s: voip\n", __func__);
+
+	mutex_lock(&voip_info.lock);
+
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+
+	dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+			runtime->hw.buffer_bytes_max,
+			&dma_buf->addr, GFP_KERNEL);
+	if (!dma_buf->area) {
+		pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
+			buf_node = (void *)dma_buf->area + offset;
+
+			mutex_lock(&voip_info.in_lock);
+			list_add_tail(&buf_node->list,
+					&voip_info.free_in_queue);
+			mutex_unlock(&voip_info.in_lock);
+			offset = offset + sizeof(struct voip_buf_node);
+		}
+	} else {
+		for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
+			buf_node = (void *) dma_buf->area + offset;
+			mutex_lock(&voip_info.out_lock);
+			list_add_tail(&buf_node->list,
+					&voip_info.free_out_queue);
+			mutex_unlock(&voip_info.out_lock);
+			offset = offset + sizeof(struct voip_buf_node);
+		}
+	}
+
+	mutex_unlock(&voip_info.lock);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	pr_debug("msm_asoc_pcm_new\n");
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-voip-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	memset(&voip_info, 0, sizeof(voip_info));
+
+	mutex_init(&voip_info.lock);
+	mutex_init(&voip_info.in_lock);
+	mutex_init(&voip_info.out_lock);
+
+	spin_lock_init(&voip_info.dsp_lock);
+
+	init_waitqueue_head(&voip_info.out_wait);
+
+	INIT_LIST_HEAD(&voip_info.in_queue);
+	INIT_LIST_HEAD(&voip_info.free_in_queue);
+	INIT_LIST_HEAD(&voip_info.out_queue);
+	INIT_LIST_HEAD(&voip_info.free_out_queue);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm.c b/sound/soc/msm/msm-pcm.c
new file mode 100644
index 0000000..bea528f
--- /dev/null
+++ b/sound/soc/msm/msm-pcm.c
@@ -0,0 +1,645 @@
+/* sound/soc/msm/msm-pcm.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+
+#define MAX_DATA_SIZE 496
+#define AUDPP_ALSA_DECODER	(-1)
+
+#define DB_TABLE_INDEX		(50)
+
+#define audio_send_queue_recbs(prtd, cmd, len) \
+	msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
+#define audio_send_queue_rec(prtd, cmd, len) \
+	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
+
+int intcnt;
+static int audio_dsp_send_buffer(struct msm_audio *prtd,
+			unsigned idx, unsigned len);
+
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __attribute__ ((packed));
+
+/* Table contains dB to raw value mapping */
+static const unsigned decoder_db_table[] = {
+
+      31 , /* -50 dB */
+      35 ,      39 ,      44 ,      50 ,      56 ,
+      63 ,      70 ,      79 ,      89 ,      99 ,
+     112 ,     125 ,     141 ,     158 ,     177 ,
+     199 ,     223 ,     251 ,     281 ,     316 ,
+     354 ,     398 ,     446 ,     501 ,     562 ,
+     630 ,     707 ,     794 ,     891 ,     999 ,
+    1122 ,    1258 ,    1412 ,    1584 ,    1778 ,
+    1995 ,    2238 ,    2511 ,    2818 ,    3162 ,
+    3548 ,    3981 ,    4466 ,    5011 ,    5623 ,
+    6309 ,    7079 ,    7943 ,    8912 ,   10000 ,
+   11220 ,   12589 ,   14125 ,   15848 ,   17782 ,
+   19952 ,   22387 ,   25118 ,   28183 ,   31622 ,
+   35481 ,   39810 ,   44668 ,   50118 ,   56234 ,
+   63095 ,   70794 ,   79432 ,   89125 ,  100000 ,
+  112201 ,  125892 ,  141253 ,  158489 ,  177827 ,
+  199526 ,  223872 ,  251188 ,  281838 ,  316227 ,
+  354813 ,  398107 ,  446683 ,  501187 ,  562341 ,
+  630957 ,  707945 ,  794328 ,  891250 , 1000000 ,
+ 1122018 , 1258925 , 1412537 , 1584893 , 1778279 ,
+ 1995262 , 2238721 , 2511886 , 2818382 , 3162277 ,
+ 3548133   /*  51 dB */
+
+};
+
+static unsigned compute_db_raw(int db)
+{
+	unsigned reg_val = 0;        /* Computed result for correspondent db */
+	/* Check if the given db is out of range */
+	if (db <= MIN_DB)
+		return 0;
+	else if (db > MAX_DB)
+		db = MAX_DB;       /* If db is too high then set to max    */
+	reg_val = decoder_db_table[DB_TABLE_INDEX+db];
+	return reg_val;
+}
+
+int msm_audio_volume_update(unsigned id,
+				int volume, int pan)
+{
+	unsigned vol_raw;
+
+	vol_raw = compute_db_raw(volume);
+	printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
+	return audpp_set_volume_and_pan(id, vol_raw, pan);
+}
+EXPORT_SYMBOL(msm_audio_volume_update);
+
+void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
+{
+	struct msm_audio *prtd = data;
+	struct buffer *frame;
+	unsigned long flag;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:
+		break;
+	case AUDPP_MSG_SPA_BANDS:
+		break;
+	case AUDPP_MSG_HOST_PCM_INTF_MSG:{
+			unsigned id = msg[2];
+			unsigned idx = msg[3] - 1;
+			if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+				printk(KERN_ERR "bogus id\n");
+				break;
+			}
+			if (idx > 1) {
+				printk(KERN_ERR "bogus buffer idx\n");
+				break;
+			}
+			/* Update with actual sent buffer size */
+			if (prtd->out[idx].used != BUF_INVALID_LEN)
+				prtd->pcm_irq_pos += prtd->out[idx].used;
+
+			if (prtd->pcm_irq_pos > prtd->pcm_size)
+				prtd->pcm_irq_pos = prtd->pcm_count;
+
+			if (prtd->ops->playback)
+				prtd->ops->playback(prtd);
+
+			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+			if (prtd->running) {
+				prtd->out[idx].used = 0;
+				frame = prtd->out + prtd->out_tail;
+				if (frame->used) {
+					audio_dsp_send_buffer(prtd,
+							      prtd->out_tail,
+							      frame->used);
+					prtd->out_tail ^= 1;
+				} else {
+					prtd->out_needed++;
+				}
+				wake_up(&the_locks.write_wait);
+			}
+			spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+			break;
+		}
+	case AUDPP_MSG_PCMDMAMISSED:
+		pr_info("alsa_dsp_event: PCMDMAMISSED %d\n", msg[0]);
+		prtd->eos_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			prtd->out_needed = 0;
+			prtd->running = 1;
+			audio_dsp_out_enable(prtd, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			prtd->running = 0;
+		} else {
+			printk(KERN_ERR "alsa_dsp_event:CFG_MSG=%d\n", msg[0]);
+		}
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"alsa_dsp_event: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "alsa_dsp_event: UNKNOWN (%d)\n", id);
+	}
+}
+
+void alsa_audpre_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	uint16_t msg[MAX_DATA_SIZE/2];
+
+	if (len > MAX_DATA_SIZE) {
+		printk(KERN_ERR"audpre: event too large(%d bytes)\n", len);
+		return;
+	}
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		printk(KERN_ERR "audpre: err_index %d\n", msg[0]);
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"audpre: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "audpre: unknown event %d\n", id);
+	}
+}
+
+void audrec_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	struct msm_audio *prtd = data;
+	unsigned long flag;
+	uint16_t msg[MAX_DATA_SIZE/2];
+
+	if (len > MAX_DATA_SIZE) {
+		printk(KERN_ERR"audrec: event/msg too large(%d bytes)\n", len);
+		return;
+	}
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG:
+		if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) {
+			if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA)
+				audrec_encoder_config(prtd);
+			else
+				prtd->running = 0;
+		}
+		break;
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG:{
+			prtd->running = 1;
+			break;
+		}
+	case AUDREC_MSG_FATAL_ERR_MSG:
+		printk(KERN_ERR "audrec: ERROR %x\n", msg[0]);
+		break;
+	case AUDREC_MSG_PACKET_READY_MSG:
+		alsa_get_dsp_frames(prtd);
+		++intcnt;
+		if (prtd->channel_mode == 1) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			prtd->pcm_irq_pos += prtd->pcm_count;
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		} else if ((prtd->channel_mode == 0) && (intcnt % 2 == 0)) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			prtd->pcm_irq_pos += prtd->pcm_count;
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		}
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"audrec: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "audrec: unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops aud_pre_adsp_ops = {
+	.event = alsa_audpre_dsp_event,
+};
+
+struct msm_adsp_ops aud_rec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+int alsa_adsp_configure(struct msm_audio *prtd)
+{
+	int ret, i;
+
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->data = prtd->playback_substream->dma_buffer.area;
+		prtd->phys = prtd->playback_substream->dma_buffer.addr;
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->data = prtd->capture_substream->dma_buffer.area;
+		prtd->phys = prtd->capture_substream->dma_buffer.addr;
+	}
+	if (!prtd->data) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	ret = audmgr_open(&prtd->audmgr);
+	if (ret)
+		goto err2;
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->out_buffer_size = PLAYBACK_DMASZ;
+		prtd->out_sample_rate = 44100;
+		prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+		prtd->out_weight = 100;
+
+		prtd->out[0].data = prtd->data + 0;
+		prtd->out[0].addr = prtd->phys + 0;
+		prtd->out[0].size = BUFSZ;
+		prtd->out[1].data = prtd->data + BUFSZ;
+		prtd->out[1].addr = prtd->phys + BUFSZ;
+		prtd->out[1].size = BUFSZ;
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_44100;
+		prtd->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_44100;
+		prtd->channel_mode = AUDREC_CMD_STEREO_MODE_STEREO;
+		prtd->buffer_size = STEREO_DATA_SIZE;
+		prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+		prtd->tx_agc_cfg.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+		prtd->ns_cfg.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+		prtd->iir_cfg.cmd_id =
+		    AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+		ret = msm_adsp_get("AUDPREPROCTASK",
+				   &prtd->audpre, &aud_pre_adsp_ops, prtd);
+		if (ret)
+			goto err3;
+		ret = msm_adsp_get("AUDRECTASK",
+				   &prtd->audrec, &aud_rec_adsp_ops, prtd);
+		if (ret) {
+			msm_adsp_put(prtd->audpre);
+			goto err3;
+		}
+		prtd->dsp_cnt = 0;
+		prtd->in_head = 0;
+		prtd->in_tail = 0;
+		prtd->in_count = 0;
+		for (i = 0; i < FRAME_NUM; i++) {
+			prtd->in[i].size = 0;
+			prtd->in[i].read = 0;
+		}
+	}
+
+	return 0;
+
+err3:
+	audmgr_close(&prtd->audmgr);
+
+err2:
+	prtd->data = NULL;
+err1:
+	return ret;
+}
+EXPORT_SYMBOL(alsa_adsp_configure);
+
+int alsa_audio_configure(struct msm_audio *prtd)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (prtd->enabled)
+		return 0;
+
+	/* refuse to start if we're not ready with first buffer */
+	if (!prtd->out[0].used)
+		return -EIO;
+
+	cfg.tx_rate = 0;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+	rc = audmgr_enable(&prtd->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (audpp_enable(AUDPP_ALSA_DECODER, alsa_dsp_event, prtd)) {
+		printk(KERN_ERR "audio: audpp_enable() failed\n");
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+
+	prtd->enabled = 1;
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_configure);
+
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	mutex_lock(&the_locks.write_lock);
+	while (count > 0) {
+		frame = prtd->out + prtd->out_head;
+		rc = wait_event_interruptible(the_locks.write_wait,
+					      (frame->used == 0)
+					      || (prtd->stopped));
+		if (rc < 0)
+			break;
+		if (prtd->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		prtd->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		frame = prtd->out + prtd->out_tail;
+		if (frame->used && prtd->out_needed) {
+			audio_dsp_send_buffer(prtd, prtd->out_tail,
+					      frame->used);
+			prtd->out_tail ^= 1;
+			prtd->out_needed--;
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+	}
+	mutex_unlock(&the_locks.write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+EXPORT_SYMBOL(alsa_send_buffer);
+
+int alsa_audio_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		audio_dsp_out_enable(prtd, 0);
+		wake_up(&the_locks.write_wait);
+		audpp_disable(AUDPP_ALSA_DECODER, prtd);
+		audmgr_disable(&prtd->audmgr);
+		prtd->out_needed = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_disable);
+
+int alsa_audrec_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		alsa_rec_dsp_enable(prtd, 0);
+		wake_up(&the_locks.read_wait);
+		msm_adsp_disable(prtd->audpre);
+		msm_adsp_disable(prtd->audrec);
+		audmgr_disable(&prtd->audmgr);
+		prtd->out_needed = 0;
+		prtd->opened = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audrec_disable);
+
+static int audio_dsp_read_buffer(struct msm_audio *prtd, uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	/* Both WAV and AAC use AUDREC_CMD_TYPE_0 */
+	cmd.type = AUDREC_CMD_TYPE_0;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(prtd, &cmd, sizeof(cmd));
+}
+
+int audrec_encoder_config(struct msm_audio *prtd)
+{
+	audrec_cmd_arec0param_cfg cmd;
+	uint16_t *data = (void *)prtd->data;
+	unsigned n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG;
+	cmd.ptr_to_extpkt_buffer_msw = prtd->phys >> 16;
+	cmd.ptr_to_extpkt_buffer_lsw = prtd->phys;
+	cmd.buf_len = FRAME_NUM;	/* Both WAV and AAC use 8 frames */
+	cmd.samp_rate_index = prtd->samp_rate_index;
+	/* 0 for mono, 1 for stereo */
+	cmd.stereo_mode = prtd->channel_mode;
+	cmd.rec_quality = 0x1C00;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 */
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		prtd->in[n].data = data + 4;
+		data += (4 + (prtd->channel_mode ? 2048 : 1024));
+	}
+
+	return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
+}
+
+int audio_dsp_out_enable(struct msm_audio *prtd, int yes)
+{
+	audpp_cmd_pcm_intf cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
+	cmd.object_num = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW = prtd->out[0].addr;
+		cmd.write_buf1MSW = prtd->out[0].addr >> 16;
+		cmd.write_buf1_len = 0;
+		cmd.write_buf2LSW = prtd->out[1].addr;
+		cmd.write_buf2MSW = prtd->out[1].addr >> 16;
+		cmd.write_buf2_len = prtd->out[1].used;
+		cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = prtd->out_weight;
+		cmd.weight_arm_to_rx = 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate = prtd->out_sample_rate;
+		cmd.channel_mode = prtd->out_channel_mode;
+	}
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+		      size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&the_locks.read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(the_locks.read_wait,
+					      (prtd->in_count > 0)
+					      || prtd->stopped);
+		if (rc < 0)
+			break;
+
+		if (prtd->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+
+		index = prtd->in_tail;
+		data = (uint8_t *) prtd->in[index].data;
+		size = prtd->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			if (index != prtd->in_tail) {
+				/* overrun: data is invalid, we need to retry */
+				spin_unlock_irqrestore(&the_locks.read_dsp_lock,
+						       flag);
+				continue;
+			}
+			prtd->in[index].size = 0;
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+			prtd->in_count--;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			count -= size;
+			buf += size;
+		} else {
+			break;
+		}
+	}
+	mutex_unlock(&the_locks.read_lock);
+	return rc;
+}
+EXPORT_SYMBOL(alsa_buffer_read);
+
+static int audio_dsp_send_buffer(struct msm_audio *prtd,
+					unsigned idx, unsigned len)
+{
+	audpp_cmd_pcm_intf_send_buffer cmd;
+	cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
+	cmd.host_pcm_object = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id = 0;
+	cmd.arm_to_dsp_buf_id = idx + 1;
+	cmd.arm_to_dsp_buf_len = len;
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable)
+{
+	audrec_cmd_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_CFG;
+	cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS;
+	cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | prtd->type);
+	cmd.type_1 = 0;
+
+	return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(alsa_rec_dsp_enable);
+
+void alsa_get_dsp_frames(struct msm_audio *prtd)
+{
+	struct audio_frame *frame;
+	uint32_t index = 0;
+	unsigned long flag;
+
+	if (prtd->type == AUDREC_CMD_TYPE_0_INDEX_WAV) {
+		index = prtd->in_head;
+
+		frame =
+		    (void *)(((char *)prtd->in[index].data) - sizeof(*frame));
+
+		spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+		prtd->in[index].size = frame->bytes;
+
+		prtd->in_head = (prtd->in_head + 1) & (FRAME_NUM - 1);
+
+		/* If overflow, move the tail index foward. */
+		if (prtd->in_head == prtd->in_tail)
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+		else
+			prtd->in_count++;
+
+		audio_dsp_read_buffer(prtd, prtd->dsp_cnt++);
+		spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+		wake_up(&the_locks.read_wait);
+	} else {
+		/* TODO AAC not supported yet. */
+	}
+}
+EXPORT_SYMBOL(alsa_get_dsp_frames);
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
new file mode 100644
index 0000000..e7ddd30
--- /dev/null
+++ b/sound/soc/msm/msm-pcm.h
@@ -0,0 +1,200 @@
+/* sound/soc/msm/msm-pcm.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+
+#include <../arch/arm/mach-msm/qdsp5/adsp.h>
+#include <../arch/arm/mach-msm/qdsp5/audmgr.h>
+
+
+#define FRAME_NUM               (8)
+#define FRAME_SIZE              (2052 * 2)
+#define MONO_DATA_SIZE          (2048)
+#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
+#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
+
+#define BUFSZ			(960 * 5)
+#define PLAYBACK_DMASZ 		(BUFSZ * 2)
+
+#define MSM_PLAYBACK_DEFAULT_VOLUME 0 /* 0dB */
+#define MSM_PLAYBACK_DEFAULT_PAN 0
+
+#define USE_FORMATS             SNDRV_PCM_FMTBIT_S16_LE
+#define USE_CHANNELS_MIN        1
+#define USE_CHANNELS_MAX        2
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+#define USE_RATE_MIN            8000
+#define USE_RATE_MAX            48000
+#define MAX_BUFFER_PLAYBACK_SIZE \
+				(4800*4)
+/* 2048 frames (Mono), 1024 frames (Stereo) */
+#define CAPTURE_SIZE		4096
+#define MAX_BUFFER_CAPTURE_SIZE (4096*4)
+#define MAX_PERIOD_SIZE         BUFSZ
+#define USE_PERIODS_MAX         1024
+#define USE_PERIODS_MIN		1
+
+
+#define MAX_DB			(16)
+#define MIN_DB			(-50)
+#define PCMPLAYBACK_DECODERID   5
+
+/* 0xFFFFFFFF Indicates not to be used for audio data copy */
+#define	BUF_INVALID_LEN		0xFFFFFFFF
+
+extern int copy_count;
+extern int intcnt;
+
+struct msm_volume {
+	bool update;
+	int volume; /* Volume parameter, in dB Scale */
+	int pan;
+};
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	struct mutex lock;
+	struct mutex write_lock;
+	struct mutex read_lock;
+	spinlock_t read_dsp_lock;
+	spinlock_t write_dsp_lock;
+	spinlock_t mixer_lock;
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t eos_wait;
+};
+
+extern struct audio_locks the_locks;
+
+struct msm_audio_event_callbacks {
+	/* event is called from interrupt context when a message
+	 * arrives from the DSP.
+	*/
+	void (*playback)(void *);
+	void (*capture)(void *);
+};
+
+
+struct msm_audio {
+	struct buffer out[2];
+	struct buffer_rec in[8];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	atomic_t out_bytes;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+
+	struct audmgr audmgr;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	unsigned int pcm_buf_pos;       /* position in buffer */
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t type; /* 0 for PCM ,1 for AAC */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+
+	/* audpre settings */
+	audpreproc_cmd_cfg_agc_params tx_agc_cfg;
+	audpreproc_cmd_cfg_ns_params ns_cfg;
+	/* For different sample rate, the coeff might be different. *
+	* All the coeff should be passed from user space           */
+	audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+
+	struct  msm_audio_event_callbacks *ops;
+
+	int dir;
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int eos_ack;
+};
+
+
+
+/* platform data */
+extern int audio_dsp_out_enable(struct msm_audio *prtd, int yes);
+extern struct snd_soc_platform_driver msm_soc_platform;
+
+int audrec_encoder_config(struct msm_audio *prtd);
+extern void alsa_get_dsp_frames(struct msm_audio *prtd);
+extern int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable);
+extern int alsa_audrec_disable(struct msm_audio *prtd);
+extern int alsa_audio_configure(struct msm_audio *prtd);
+extern int alsa_audio_disable(struct msm_audio *prtd);
+extern int alsa_adsp_configure(struct msm_audio *prtd);
+extern int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+					size_t count, loff_t *pos);
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+					size_t count, loff_t *pos);
+int msm_audio_volume_update(unsigned id,
+				int volume, int pan);
+extern struct audio_locks the_locks;
+extern struct msm_volume msm_vol_ctl;
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm-voip.c b/sound/soc/msm/msm-voip.c
new file mode 100644
index 0000000..082c840
--- /dev/null
+++ b/sound/soc/msm/msm-voip.c
@@ -0,0 +1,610 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/qdsp6v2/q6voice.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include "msm_audio_mvs.h"
+
+
+static struct audio_voip_info_type audio_voip_info;
+static void audio_mvs_process_ul_pkt(uint8_t *voc_pkt,
+				uint32_t pkt_len,
+				void *private_data);
+static void audio_mvs_process_dl_pkt(uint8_t *voc_pkt,
+				uint32_t *pkt_len,
+				void *private_data);
+
+struct msm_audio_mvs_frame {
+	uint32_t frame_type;
+	uint32_t len;
+	uint8_t voc_pkt[MVS_MAX_VOC_PKT_SIZE];
+};
+
+struct audio_mvs_buf_node {
+	struct list_head list;
+	struct msm_audio_mvs_frame frame;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= (SNDRV_PCM_RATE_8000),
+	.rate_min		= 8000,
+	.rate_max		= 8000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN,
+	.period_bytes_min	= MVS_MAX_VOC_PKT_SIZE,
+	.period_bytes_max	= MVS_MAX_VOC_PKT_SIZE,
+	.periods_min		= VOIP_MAX_Q_LEN,
+	.periods_max		= VOIP_MAX_Q_LEN,
+	.fifo_size		= 0,
+};
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+
+	struct audio_voip_info_type *audio = &audio_voip_info;
+	pr_debug("%s\n", __func__);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
+			audio->playback_start = 1;
+		else
+			audio->capture_start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
+			audio->playback_start = 0;
+		else
+			audio->capture_start = 0;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int rc = 0;
+	struct audio_voip_info_type *audio = &audio_voip_info;
+	struct audio_mvs_release_msg release_msg;
+
+	pr_debug("%s\n", __func__);
+	memset(&release_msg, 0, sizeof(release_msg));
+	mutex_lock(&audio->lock);
+
+	audio->instance--;
+	wake_up(&audio->out_wait);
+
+	if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
+		audio->playback_state = AUDIO_MVS_CLOSED;
+	else if (substream->stream ==  SNDRV_PCM_STREAM_CAPTURE)
+		audio->capture_state = AUDIO_MVS_CLOSED;
+	if (!audio->instance) {
+		/* Release MVS. */
+		release_msg.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+		/* Derigstering the callbacks with voice driver */
+		voice_register_mvs_cb(NULL, NULL, audio);
+	} else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		voice_register_mvs_cb(audio_mvs_process_ul_pkt,
+			NULL, audio);
+	} else {
+		voice_register_mvs_cb(NULL, audio_mvs_process_dl_pkt,
+				audio);
+	}
+
+	mutex_unlock(&audio->lock);
+
+	wake_unlock(&audio->suspend_lock);
+	wake_unlock(&audio->idle_lock);
+	/* Release the IO buffers. */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		audio->in_write = 0;
+		audio->in_read = 0;
+		memset(audio->in[0].voc_pkt, 0,
+			 MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN);
+		audio->playback_substream = NULL;
+	} else {
+		audio->out_write = 0;
+		audio->out_read = 0;
+		memset(audio->out[0].voc_pkt, 0,
+			 MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN);
+		audio->capture_substream = NULL;
+	}
+	return rc;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_voip_info_type *audio = &audio_voip_info;
+
+	pr_debug("%s\n", __func__);
+	mutex_lock(&audio->lock);
+
+	if (audio->playback_substream == NULL ||
+		audio->capture_substream == NULL) {
+		if (substream->stream ==
+			SNDRV_PCM_STREAM_PLAYBACK) {
+			audio->playback_substream = substream;
+			runtime->hw = msm_pcm_hardware;
+			audio_voip_info.in_read = 0;
+			audio_voip_info.in_write = 0;
+			if (audio->playback_state < AUDIO_MVS_OPENED)
+				audio->playback_state = AUDIO_MVS_OPENED;
+		} else if (substream->stream ==
+			SNDRV_PCM_STREAM_CAPTURE) {
+			audio->capture_substream = substream;
+			runtime->hw = msm_pcm_hardware;
+			audio_voip_info.out_read = 0;
+			audio_voip_info.out_write = 0;
+			if (audio->capture_state < AUDIO_MVS_OPENED)
+				audio->capture_state = AUDIO_MVS_OPENED;
+		}
+	} else {
+		ret  = -EPERM;
+		goto err;
+	}
+	ret = snd_pcm_hw_constraint_integer(runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		pr_debug("%s:snd_pcm_hw_constraint_integer failed\n", __func__);
+		goto err;
+	}
+	audio->instance++;
+
+err:
+	mutex_unlock(&audio->lock);
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+				 snd_pcm_uframes_t hwoff, void __user *buf,
+				 snd_pcm_uframes_t frames)
+{
+	int rc = 0;
+	int count = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_voip_info_type *audio = &audio_voip_info;
+	uint32_t index;
+	pr_debug("%s\n", __func__);
+
+	rc = wait_event_timeout(audio->in_wait,
+		(audio->in_write - audio->in_read <= VOIP_MAX_Q_LEN-1),
+		1 * HZ);
+	if (rc < 0) {
+		pr_debug("%s: write was interrupted\n", __func__);
+		return  -ERESTARTSYS;
+	}
+
+	if (audio->playback_state == AUDIO_MVS_ENABLED) {
+		index = audio->in_write % VOIP_MAX_Q_LEN;
+		count = frames_to_bytes(runtime, frames);
+		if (count == MVS_MAX_VOC_PKT_SIZE) {
+			pr_debug("%s:write index = %d\n", __func__, index);
+			rc = copy_from_user(audio->in[index].voc_pkt, buf,
+						 count);
+			if (!rc) {
+				audio->in[index].len = count;
+				audio->in_write++;
+			} else {
+				pr_debug("%s:Copy from user returned %d\n",
+						__func__, rc);
+				rc = -EFAULT;
+			}
+		} else
+			rc = -ENOMEM;
+
+	} else {
+		pr_debug("%s:Write performed in invalid state %d\n",
+					__func__, audio->playback_state);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+			int channel, snd_pcm_uframes_t hwoff,
+			void __user *buf, snd_pcm_uframes_t frames)
+{
+	int rc = 0;
+	int count = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_voip_info_type *audio = &audio_voip_info;
+	uint32_t index = 0;
+
+	pr_debug("%s\n", __func__);
+
+	/* Ensure the driver has been enabled. */
+	if (audio->capture_state != AUDIO_MVS_ENABLED) {
+		pr_debug("%s:Read performed in invalid state %d\n",
+				__func__, audio->capture_state);
+		return -EPERM;
+	}
+	rc = wait_event_timeout(audio->out_wait,
+		((audio->out_read < audio->out_write) ||
+		(audio->capture_state == AUDIO_MVS_CLOSING) ||
+		(audio->capture_state == AUDIO_MVS_CLOSED)),
+		1 * HZ);
+
+	if (rc < 0) {
+		pr_debug("%s: Read was interrupted\n", __func__);
+		return  -ERESTARTSYS;
+	}
+
+	if (audio->capture_state  == AUDIO_MVS_CLOSING
+		|| audio->capture_state == AUDIO_MVS_CLOSED) {
+		pr_debug("%s:EBUSY STATE\n", __func__);
+		rc = -EBUSY;
+	} else {
+		count = frames_to_bytes(runtime, frames);
+		index = audio->out_read % VOIP_MAX_Q_LEN;
+		pr_debug("%s:index=%d\n", __func__, index);
+		if (audio->out[index].len <= count) {
+				rc = copy_to_user(buf,
+				audio->out[index].voc_pkt,
+				audio->out[index].len);
+				if (rc) {
+					pr_debug("%s:Copy to user %d\n",
+							__func__, rc);
+					rc = -EFAULT;
+				} else
+					audio->out_read++;
+		} else {
+			pr_debug("%s:returning ENOMEM\n", __func__);
+			rc = -ENOMEM;
+		}
+	}
+	return rc;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+			snd_pcm_uframes_t hwoff, void __user *buf,
+			snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	pr_debug("%s\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+/* Capture path */
+static void audio_mvs_process_ul_pkt(uint8_t *voc_pkt,
+				uint32_t pkt_len,
+				void *private_data)
+{
+	struct audio_voip_info_type *audio = private_data;
+	uint32_t index;
+	static int i;
+	pr_debug("%s\n", __func__);
+
+	if (audio->capture_substream == NULL)
+		return;
+	index = audio->out_write % VOIP_MAX_Q_LEN;
+	memcpy(audio->out[index].voc_pkt, voc_pkt, pkt_len);
+	audio->out[index].len = pkt_len;
+	audio->out_write++;
+	wake_up(&audio->out_wait);
+	i++;
+	if (audio->capture_start) {
+		audio->pcm_capture_irq_pos += audio->pcm_count;
+		if (!(i % 2))
+			snd_pcm_period_elapsed(audio->capture_substream);
+	}
+}
+
+/* Playback path */
+static void audio_mvs_process_dl_pkt(uint8_t *voc_pkt,
+				uint32_t *pkt_len,
+				void *private_data)
+{
+	struct audio_voip_info_type *audio = private_data;
+	uint32_t index;
+	static int i;
+	pr_debug("%s\n", __func__);
+
+	if (audio->playback_substream == NULL)
+		return;
+	if ((audio->in_write - audio->in_read >= 0)
+		&& (audio->playback_start)) {
+		index = audio->in_read % VOIP_MAX_Q_LEN;
+		*pkt_len = audio->pcm_count;
+		memcpy(voc_pkt, audio->in[index].voc_pkt, *pkt_len);
+		audio->in_read++;
+		wake_up(&audio->in_wait);
+		i++;
+		audio->pcm_playback_irq_pos += audio->pcm_count;
+		if (!(i%2))
+			snd_pcm_period_elapsed(audio->playback_substream);
+		pr_debug("%s:read_index=%d\n", __func__, index);
+	}
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int rc = 0;
+	struct audio_voip_info_type *prtd = &audio_voip_info;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_playback_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	pr_debug("%s:prtd->pcm_playback_size:%d\n",
+			__func__, prtd->pcm_playback_size);
+	pr_debug("%s:prtd->pcm_count:%d\n", __func__, prtd->pcm_count);
+
+	mutex_lock(&prtd->prepare_lock);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (prtd->playback_state == AUDIO_MVS_ENABLED)
+			goto enabled;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (prtd->capture_state == AUDIO_MVS_ENABLED)
+			goto enabled;
+	}
+
+	pr_debug("%s:Register cbs with voice driver check audio_mvs_driver\n",
+			__func__);
+	if (prtd->instance == 2) {
+		voice_register_mvs_cb(audio_mvs_process_ul_pkt,
+				audio_mvs_process_dl_pkt,
+				prtd);
+	} else {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			voice_register_mvs_cb(NULL,
+					audio_mvs_process_dl_pkt,
+					prtd);
+		} else {
+			voice_register_mvs_cb(audio_mvs_process_ul_pkt,
+					NULL,
+					prtd);
+		}
+	}
+
+enabled:
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->playback_state = AUDIO_MVS_ENABLED;
+		prtd->pcm_playback_irq_pos = 0;
+		prtd->pcm_playback_buf_pos = 0;
+		/* rate and channels are sent to audio driver */
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->capture_state = AUDIO_MVS_ENABLED;
+		prtd->pcm_capture_size  = snd_pcm_lib_buffer_bytes(substream);
+		prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+		prtd->pcm_capture_irq_pos = 0;
+		prtd->pcm_capture_buf_pos = 0;
+	}
+	mutex_unlock(&prtd->prepare_lock);
+	return rc;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_voip_info_type *audio = &audio_voip_info;
+
+	if (audio->pcm_playback_irq_pos >= audio->pcm_playback_size)
+		audio->pcm_playback_irq_pos = 0;
+	return bytes_to_frames(runtime, (audio->pcm_playback_irq_pos));
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_voip_info_type *audio = &audio_voip_info;
+
+	if (audio->pcm_capture_irq_pos >= audio->pcm_capture_size)
+		audio->pcm_capture_irq_pos = 0;
+	return bytes_to_frames(runtime, (audio->pcm_capture_irq_pos));
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+	pr_debug("%s\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_pointer(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_pointer(substream);
+	return ret;
+}
+
+static struct snd_pcm_ops msm_mvs_pcm_ops = {
+	.open = msm_pcm_open,
+	.copy = msm_pcm_copy,
+	.close = msm_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.prepare = msm_pcm_prepare,
+	.trigger = msm_pcm_trigger,
+	.pointer = msm_pcm_pointer,
+
+};
+
+static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int   i, ret, offset = 0;
+	struct snd_pcm_substream *substream = NULL;
+	struct snd_dma_buffer *dma_buffer = NULL;
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+	if (ret)
+		return ret;
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+	if (ret)
+		return ret;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_mvs_pcm_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_mvs_pcm_ops);
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	if (!substream)
+		return -ENOMEM;
+
+	dma_buffer = &substream->dma_buffer;
+	dma_buffer->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buffer->dev.dev = card->dev;
+	dma_buffer->private_data = NULL;
+	dma_buffer->area = dma_alloc_coherent(card->dev,
+				(MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN),
+				&dma_buffer->addr, GFP_KERNEL);
+	if (!dma_buffer->area) {
+		pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	dma_buffer->bytes = MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN;
+	memset(dma_buffer->area, 0, MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN);
+	audio_voip_info.in_read = 0;
+	audio_voip_info.in_write = 0;
+	audio_voip_info.out_read = 0;
+	audio_voip_info.out_write = 0;
+	for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
+		audio_voip_info.in[i].voc_pkt =
+		dma_buffer->area + offset;
+		offset = offset + MVS_MAX_VOC_PKT_SIZE;
+	}
+	substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	if (!substream)
+		return -ENOMEM;
+
+	dma_buffer = &substream->dma_buffer;
+	dma_buffer->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buffer->dev.dev = card->dev;
+	dma_buffer->private_data = NULL;
+	dma_buffer->area = dma_alloc_coherent(card->dev,
+					(MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN),
+					&dma_buffer->addr, GFP_KERNEL);
+	if (!dma_buffer->area) {
+		pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	memset(dma_buffer->area, 0, MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN);
+	dma_buffer->bytes = MVS_MAX_VOC_PKT_SIZE * VOIP_MAX_Q_LEN;
+	for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
+		audio_voip_info.out[i].voc_pkt =
+		dma_buffer->area + offset;
+		offset = offset + MVS_MAX_VOC_PKT_SIZE;
+	}
+	audio_voip_info.playback_substream = NULL;
+	audio_voip_info.capture_substream = NULL;
+
+	return 0;
+}
+
+static void msm_pcm_free_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+struct snd_soc_platform_driver msm_mvs_soc_platform = {
+	.ops		= &msm_mvs_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+	.pcm_free	= msm_pcm_free_buffers,
+};
+EXPORT_SYMBOL(msm_mvs_soc_platform);
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_mvs_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-mvs-audio",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_mvs_soc_platform_init(void)
+{
+	memset(&audio_voip_info, 0, sizeof(audio_voip_info));
+	mutex_init(&audio_voip_info.lock);
+	mutex_init(&audio_voip_info.prepare_lock);
+	init_waitqueue_head(&audio_voip_info.out_wait);
+	init_waitqueue_head(&audio_voip_info.in_wait);
+	wake_lock_init(&audio_voip_info.suspend_lock, WAKE_LOCK_SUSPEND,
+				"audio_mvs_suspend");
+	wake_lock_init(&audio_voip_info.idle_lock, WAKE_LOCK_IDLE,
+				"audio_mvs_idle");
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_mvs_soc_platform_init);
+
+static void __exit msm_mvs_soc_platform_exit(void)
+{
+	 platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_mvs_soc_platform_exit);
+
+MODULE_DESCRIPTION("MVS PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
new file mode 100644
index 0000000..061529a
--- /dev/null
+++ b/sound/soc/msm/msm7201.c
@@ -0,0 +1,329 @@
+/* linux/sound/soc/msm/msm7201.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+#include <asm/mach-types.h>
+#include <mach/msm_rpcrouter.h>
+
+static struct msm_rpc_endpoint *snd_ep;
+
+struct msm_snd_rpc_ids {
+	unsigned long   prog;
+	unsigned long   vers;
+	unsigned long   rpc_set_snd_device;
+	int device;
+};
+
+static struct msm_snd_rpc_ids snd_rpc_ids;
+
+static struct platform_device *msm_audio_snd_device;
+
+static int snd_msm_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Volume Param, in dB */
+	uinfo->value.integer.min = MIN_DB;
+	uinfo->value.integer.max = MAX_DB;
+	return 0;
+}
+
+static int snd_msm_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	spin_lock_irq(&the_locks.mixer_lock);
+	ucontrol->value.integer.value[0] = msm_vol_ctl.volume;
+	spin_unlock_irq(&the_locks.mixer_lock);
+	return 0;
+}
+
+static int snd_msm_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	int volume;
+
+	volume = ucontrol->value.integer.value[0];
+	spin_lock_irq(&the_locks.mixer_lock);
+	change = (msm_vol_ctl.volume != volume);
+	if (change) {
+		msm_vol_ctl.update = 1;
+		msm_vol_ctl.volume = volume;
+	}
+	spin_unlock_irq(&the_locks.mixer_lock);
+	return change;
+}
+
+static int snd_msm_device_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Device */
+
+	/*
+	 * The number of devices supported is 26 (0 to 25)
+	 */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 25;
+	return 0;
+}
+
+static int snd_msm_device_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = (uint32_t)snd_rpc_ids.device;
+	return 0;
+}
+
+int msm_snd_init_rpc_ids(void)
+{
+	snd_rpc_ids.prog	= 0x30000002;
+	snd_rpc_ids.vers	= 0x00020001;
+	/*
+	 * The magic number 2 corresponds to the rpc call
+	 * index for snd_set_device
+	 */
+	snd_rpc_ids.rpc_set_snd_device = 2;
+	return 0;
+}
+
+int msm_snd_rpc_connect(void)
+{
+	if (snd_ep) {
+		printk(KERN_INFO "%s: snd_ep already connected\n", __func__);
+		return 0;
+	}
+
+	/* Initialize rpc ids */
+	if (msm_snd_init_rpc_ids()) {
+		printk(KERN_ERR "%s: snd rpc ids initialization failed\n"
+			, __func__);
+		return -ENODATA;
+	}
+
+	snd_ep = msm_rpc_connect_compatible(snd_rpc_ids.prog,
+				snd_rpc_ids.vers, 0);
+	if (IS_ERR(snd_ep)) {
+		printk(KERN_ERR "%s: failed (compatible VERS = %ld)\n",
+				__func__, snd_rpc_ids.vers);
+		snd_ep = NULL;
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+int msm_snd_rpc_close(void)
+{
+	int rc = 0;
+
+	if (IS_ERR(snd_ep)) {
+		printk(KERN_ERR "%s: snd handle unavailable, rc = %ld\n",
+				__func__, PTR_ERR(snd_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_close(snd_ep);
+	snd_ep = NULL;
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: close rpc failed! rc = %d\n",
+				__func__, rc);
+		return -EAGAIN;
+	} else
+		printk(KERN_INFO "rpc close success\n");
+
+	return rc;
+}
+
+static int snd_msm_device_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_start_req {
+		struct rpc_request_hdr hdr;
+		uint32_t rpc_snd_device;
+		uint32_t snd_mute_ear_mute;
+		uint32_t snd_mute_mic_mute;
+		uint32_t callback_ptr;
+		uint32_t client_data;
+	} req;
+
+	snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+	req.hdr.type = 0;
+	req.hdr.rpc_vers = 2;
+
+	req.rpc_snd_device = cpu_to_be32(snd_rpc_ids.device);
+	req.snd_mute_ear_mute = cpu_to_be32(1);
+	req.snd_mute_mic_mute = cpu_to_be32(0);
+	req.callback_ptr = -1;
+	req.client_data = cpu_to_be32(0);
+
+	req.hdr.prog = snd_rpc_ids.prog;
+	req.hdr.vers = snd_rpc_ids.vers;
+
+	rc = msm_rpc_call(snd_ep, snd_rpc_ids.rpc_set_snd_device ,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: snd rpc call failed! rc = %d\n",
+			__func__, rc);
+	} else
+		printk(KERN_INFO "snd device connected \n");
+
+	return rc;
+}
+
+/* Supported range -50dB to 18dB */
+static const DECLARE_TLV_DB_LINEAR(db_scale_linear, -5000, 1800);
+
+#define MSM_EXT(xname, xindex, fp_info, fp_get, fp_put, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+  .name = xname, .index = xindex, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, \
+  .private_value = addr, \
+}
+
+#define MSM_EXT_TLV(xname, xindex, fp_info, fp_get, fp_put, addr, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = (SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE), \
+  .name = xname, .index = xindex, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, .tlv.p = tlv_array, \
+  .private_value = addr, \
+}
+
+static struct snd_kcontrol_new snd_msm_controls[] = {
+	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
+	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
+	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
+						 snd_msm_device_put, 0),
+};
+
+static int msm_new_mixer(struct snd_soc_codec *codec)
+{
+	unsigned int idx;
+	int err;
+
+	pr_err("msm_soc: ALSA MSM Mixer Setting\n");
+	strcpy(codec->card->snd_card->mixername, "MSM Mixer");
+	for (idx = 0; idx < ARRAY_SIZE(snd_msm_controls); idx++) {
+		err = snd_ctl_add(codec->card->snd_card,
+				snd_ctl_new1(&snd_msm_controls[idx], NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int msm_soc_dai_init(
+	struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+        struct snd_soc_codec *codec = rtd->codec;
+
+	mutex_init(&the_locks.lock);
+	mutex_init(&the_locks.write_lock);
+	mutex_init(&the_locks.read_lock);
+	spin_lock_init(&the_locks.read_dsp_lock);
+	spin_lock_init(&the_locks.write_dsp_lock);
+	spin_lock_init(&the_locks.mixer_lock);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+	msm_vol_ctl.volume = MSM_PLAYBACK_DEFAULT_VOLUME;
+	msm_vol_ctl.pan = MSM_PLAYBACK_DEFAULT_PAN;
+
+	ret = msm_new_mixer(codec);
+	if (ret < 0) {
+		pr_err("msm_soc: ALSA MSM Mixer Fail\n");
+	}
+
+	return ret;
+}
+
+static struct snd_soc_dai_link msm_dai[] = {
+{
+	.name = "MSM Primary I2S",
+	.stream_name = "DSP 1",
+	.cpu_dai_name = "msm-cpu-dai.0",
+	.platform_name = "msm-dsp-audio.0",
+	.codec_name = "msm-codec-dai.0",
+	.codec_dai_name = "msm-codec-dai",
+	.init   = &msm_soc_dai_init,
+},
+};
+
+static struct snd_soc_card snd_soc_card_msm = {
+	.name		= "msm-audio",
+	.dai_link	= msm_dai,
+	.num_links = ARRAY_SIZE(msm_dai),
+};
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	msm_audio_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!msm_audio_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(msm_audio_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_audio_snd_device);
+	if (ret) {
+		platform_device_put(msm_audio_snd_device);
+		return ret;
+	}
+
+	ret = msm_snd_rpc_connect();
+
+	return ret;
+}
+
+static void __exit msm_audio_exit(void)
+{
+	msm_snd_rpc_close();
+	platform_device_unregister(msm_audio_snd_device);
+}
+
+module_init(msm_audio_init);
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("PCM module");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
new file mode 100644
index 0000000..1f36e3b
--- /dev/null
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -0,0 +1,600 @@
+/* linux/sound/soc/msm/msm7k-pcm.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+
+#define SND_DRIVER        "snd_msm"
+#define MAX_PCM_DEVICES	SNDRV_CARDS
+#define MAX_PCM_SUBSTREAMS 1
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+int copy_count;
+
+struct audio_locks the_locks;
+EXPORT_SYMBOL(the_locks);
+struct msm_volume msm_vol_ctl;
+EXPORT_SYMBOL(msm_vol_ctl);
+
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:
+		return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:
+		return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:
+		return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:
+		return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:
+		return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:
+		return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:
+		return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:
+		return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:
+		return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default:
+		return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000:
+		return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100:
+		return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000:
+		return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000:
+		return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050:
+		return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000:
+		return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000:
+		return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025:
+		return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:
+		return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:
+		return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	}
+}
+
+static struct snd_pcm_hardware msm_pcm_playback_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =              USE_FORMATS,
+	.rates =                USE_RATE,
+	.rate_min =             USE_RATE_MIN,
+	.rate_max =             USE_RATE_MAX,
+	.channels_min =         USE_CHANNELS_MIN,
+	.channels_max =         USE_CHANNELS_MAX,
+	.buffer_bytes_max =     MAX_BUFFER_PLAYBACK_SIZE,
+	.period_bytes_min =     64,
+	.period_bytes_max =     MAX_PERIOD_SIZE,
+	.periods_min =          USE_PERIODS_MIN,
+	.periods_max =          USE_PERIODS_MAX,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_capture_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =		USE_FORMATS,
+	.rates =		USE_RATE,
+	.rate_min =		USE_RATE_MIN,
+	.rate_max =		USE_RATE_MAX,
+	.channels_min =		USE_CHANNELS_MIN,
+	.channels_max =		USE_CHANNELS_MAX,
+	.buffer_bytes_max =	MAX_BUFFER_CAPTURE_SIZE,
+	.period_bytes_min =	CAPTURE_SIZE,
+	.period_bytes_max =	CAPTURE_SIZE,
+	.periods_min =		USE_PERIODS_MIN,
+	.periods_max =		USE_PERIODS_MAX,
+	.fifo_size =		0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void playback_event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	snd_pcm_period_elapsed(prtd->playback_substream);
+}
+
+static void capture_event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	snd_pcm_period_elapsed(prtd->capture_substream);
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->out_sample_rate = runtime->rate;
+	prtd->out_channel_mode = runtime->channels;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct audmgr_config cfg;
+	int rc;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = convert_samp_rate(runtime->rate);
+	prtd->samp_rate_index = convert_dsp_samp_index(runtime->rate);
+	prtd->channel_mode = (runtime->channels - 1);
+	prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \
+							MONO_DATA_SIZE;
+
+	if (prtd->enabled == 1)
+		return 0;
+
+	prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+
+	cfg.tx_rate = convert_samp_rate(runtime->rate);
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&prtd->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(prtd->audpre)) {
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+	if (msm_adsp_enable(prtd->audrec)) {
+		msm_adsp_disable(prtd->audpre);
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+	prtd->enabled = 1;
+	alsa_rec_dsp_enable(prtd, 1);
+
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos == prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int rc = 0, rc1 = 0, rc2 = 0;
+	int fbytes = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+	int monofbytes = 0;
+	char *bufferp = NULL;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	monofbytes = fbytes / 2;
+	if (runtime->channels == 2) {
+		rc = alsa_buffer_read(prtd, buf, fbytes, NULL);
+	} else {
+		bufferp = buf;
+		rc1 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		bufferp = buf + monofbytes ;
+		rc2 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		rc = rc1 + rc2;
+	}
+	prtd->pcm_buf_pos += fbytes;
+	return rc;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	alsa_audrec_disable(prtd);
+	audmgr_close(&prtd->audmgr);
+	msm_adsp_put(prtd->audrec);
+	msm_adsp_put(prtd->audpre);
+	kfree(prtd);
+
+	return 0;
+}
+
+struct  msm_audio_event_callbacks snd_msm_audio_ops = {
+	.playback = playback_event_handler,
+	.capture = capture_event_handler,
+};
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msm_vol_ctl.update = 1; /* Update Volume, with Cached value */
+		runtime->hw = msm_pcm_playback_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
+		prtd->playback_substream = substream;
+		prtd->eos_ack = 0;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_capture_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
+		prtd->capture_substream = substream;
+	}
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+						SNDRV_PCM_HW_PARAM_RATE,
+						&constraints_sample_rates);
+	if (ret < 0)
+		goto out;
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	prtd->ops = &snd_msm_audio_ops;
+	prtd->out[0].used = BUF_INVALID_LEN;
+	prtd->out_head = 1; /* point to second buffer on startup */
+	runtime->private_data = prtd;
+
+	ret = alsa_adsp_configure(prtd);
+	if (ret)
+		goto out;
+	copy_count = 0;
+	return 0;
+
+ out:
+	kfree(prtd);
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int rc = 1;
+	int fbytes = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	rc = alsa_send_buffer(prtd, buf, fbytes, NULL);
+	++copy_count;
+	prtd->pcm_buf_pos += fbytes;
+	if (copy_count == 1) {
+		mutex_lock(&the_locks.lock);
+		alsa_audio_configure(prtd);
+		mutex_unlock(&the_locks.lock);
+	}
+	if ((prtd->running) && (msm_vol_ctl.update)) {
+		rc = msm_audio_volume_update(PCMPLAYBACK_DECODERID,
+				msm_vol_ctl.volume, msm_vol_ctl.pan);
+		msm_vol_ctl.update = 0;
+	}
+
+	return  rc;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	int rc = 0;
+
+	pr_debug("%s()\n", __func__);
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	if (prtd->enabled)
+		rc = wait_event_interruptible(the_locks.eos_wait,
+					prtd->eos_ack);
+
+	alsa_audio_disable(prtd);
+	audmgr_close(&prtd->audmgr);
+	kfree(prtd);
+
+	return 0;
+}
+
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_pointer(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_pointer(substream);
+	return ret;
+}
+
+int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (substream->pcm->device & 1) {
+		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
+		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
+	}
+	return 0;
+
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+};
+
+static int pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+	int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size;
+	if (!stream)
+		size = PLAYBACK_DMASZ;
+	else
+		size = CAPTURE_DMASZ;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void msm_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+	if (ret)
+		return ret;
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+	if (ret)
+		return ret;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_pcm_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_pcm_ops);
+
+	ret = pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+	if (ret)
+		return ret;
+
+	ret = pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+	if (ret)
+		msm_pcm_free_dma_buffers(pcm);
+	return ret;
+}
+
+struct snd_soc_platform_driver msm_soc_platform = {
+	.ops            = &msm_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+	.pcm_free	= msm_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL(msm_soc_platform);
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-dsp-audio",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	 platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7kv2-dai.c b/sound/soc/msm/msm7kv2-dai.c
new file mode 100644
index 0000000..e8d51ac
--- /dev/null
+++ b/sound/soc/msm/msm7kv2-dai.c
@@ -0,0 +1,149 @@
+/* sound/soc/msm/msm-dai.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * Derived from msm-pcm.c and msm7201.c.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <linux/slab.h>
+#include "msm7kv2-pcm.h"
+
+static struct snd_soc_dai_driver msm_pcm_codec_dais[] = {
+{
+	.name = "msm-codec-dai",
+	.playback = {
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+static struct snd_soc_dai_driver msm_pcm_cpu_dais[] = {
+{
+	.name = "msm-cpu-dai",
+	.playback = {
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_msm = {
+        .compress_type = SND_SOC_FLAT_COMPRESSION,
+};
+
+static __devinit int asoc_msm_codec_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm,
+                        msm_pcm_codec_dais, ARRAY_SIZE(msm_pcm_codec_dais));
+}
+
+static int __devexit asoc_msm_codec_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static __devinit int asoc_msm_cpu_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_dai(&pdev->dev, msm_pcm_cpu_dais);
+}
+
+static int __devexit asoc_msm_cpu_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_msm_codec_driver = {
+	.probe = asoc_msm_codec_probe,
+	.remove = __devexit_p(asoc_msm_codec_remove),
+	.driver = {
+			.name = "msm-codec-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_driver asoc_msm_cpu_driver = {
+	.probe = asoc_msm_cpu_probe,
+	.remove = __devexit_p(asoc_msm_cpu_remove),
+	.driver = {
+			.name = "msm-cpu-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_codec_dai_init(void)
+{
+	return platform_driver_register(&asoc_msm_codec_driver);
+}
+
+static void __exit msm_codec_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_msm_codec_driver);
+}
+
+static int __init msm_cpu_dai_init(void)
+{
+	return platform_driver_register(&asoc_msm_cpu_driver);
+}
+
+static void __exit msm_cpu_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_msm_cpu_driver);
+}
+
+module_init(msm_codec_dai_init);
+module_exit(msm_codec_dai_exit);
+module_init(msm_cpu_dai_init);
+module_exit(msm_cpu_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Codec/Cpu Dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7kv2-dsp.c b/sound/soc/msm/msm7kv2-dsp.c
new file mode 100644
index 0000000..50bf6fb
--- /dev/null
+++ b/sound/soc/msm/msm7kv2-dsp.c
@@ -0,0 +1,633 @@
+/* Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+
+#include "msm7kv2-pcm.h"
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_id & 0xFFFF0000) >> 16),\
+		cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_id & 0x0000FFFF),\
+		cmd, len)
+
+static int alsa_dsp_read_buffer(struct msm_audio *audio,
+			uint32_t read_cnt);
+static void alsa_get_dsp_frames(struct msm_audio *prtd);
+static int alsa_in_param_config(struct msm_audio *audio);
+
+static int alsa_in_mem_config(struct msm_audio *audio);
+static int alsa_in_enc_config(struct msm_audio *audio, int enable);
+
+int intcnt;
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __attribute__ ((packed));
+
+void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
+{
+	struct msm_audio *prtd = data;
+	struct buffer *frame;
+	unsigned long flag = 0;
+
+	MM_DBG("\n");
+	switch (id) {
+	case AUDPP_MSG_HOST_PCM_INTF_MSG: {
+		unsigned id = msg[3];
+		unsigned idx = msg[4] - 1;
+
+		MM_DBG("HOST_PCM id %d idx %d\n", id, idx);
+		if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+			MM_ERR("bogus id\n");
+			break;
+		}
+		if (idx > 1) {
+			MM_ERR("bogus buffer idx\n");
+			break;
+		}
+
+		/* Update with actual sent buffer size */
+		if (prtd->out[idx].used != BUF_INVALID_LEN)
+			prtd->pcm_irq_pos += prtd->out[idx].used;
+
+		if (prtd->pcm_irq_pos > prtd->pcm_size)
+			prtd->pcm_irq_pos = prtd->pcm_count;
+
+		if (prtd->ops->playback)
+			prtd->ops->playback(prtd);
+
+		if (prtd->mmap_flag)
+			break;
+
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		if (prtd->running) {
+			prtd->out[idx].used = 0;
+			frame = prtd->out + prtd->out_tail;
+			if (frame->used) {
+				alsa_dsp_send_buffer(
+					prtd, prtd->out_tail, frame->used);
+				/* Reset eos_ack flag to avoid stale
+				 * PCMDMAMISS been considered
+				 */
+				prtd->eos_ack = 0;
+				prtd->out_tail ^= 1;
+			} else {
+				prtd->out_needed++;
+			}
+			wake_up(&the_locks.write_wait);
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+		break;
+	}
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_INFO("PCMDMAMISSED %d\n", msg[0]);
+		prtd->eos_ack++;
+		MM_DBG("PCMDMAMISSED Count per Buffer %d\n", prtd->eos_ack);
+		wake_up(&the_locks.eos_wait);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			prtd->out_needed = 0;
+			prtd->running = 1;
+			audpp_dsp_set_vol_pan(prtd->session_id, &prtd->vol_pan,
+					POPP);
+			audpp_route_stream(prtd->session_id,
+				msm_snddev_route_dec(prtd->session_id));
+			audio_dsp_out_enable(prtd, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			prtd->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	default:
+		MM_DBG("UNKNOWN (%d)\n", id);
+	}
+}
+
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct msm_audio *prtd = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+			err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG\n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE)
+			alsa_in_param_config(prtd);
+		else { /* Encoder disable success */
+			prtd->running = 0;
+			alsa_in_record_config(prtd, 0);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG\n");
+		alsa_in_mem_config(prtd);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG\n");
+		wake_up(&the_locks.enable_wait);
+		break;
+	}
+	default:
+		MM_DBG("Unknown Event id %d\n", id);
+	}
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	struct msm_audio *prtd = data;
+	unsigned long flag = 0;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("AUDREC_CMD_MEM_CFG_DONE_MSG\n");
+		prtd->running = 1;
+		alsa_in_record_config(prtd, 1);
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+			fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		prtd->stopped = 1;
+		wake_up(&the_locks.read_wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+		MM_DBG("AUDREC_UP_PACKET_READY_MSG\n");
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+			write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+			pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+			pkt_ready_msg.audrec_packet_write_cnt_msw, \
+			pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+			pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		alsa_get_dsp_frames(prtd);
+		++intcnt;
+		if (prtd->channel_mode == 1) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		} else if ((prtd->channel_mode == 0) && (intcnt % 2 == 0)) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		}
+		break;
+	}
+	default:
+		MM_DBG("Unknown Event id %d\n", id);
+	}
+}
+
+struct msm_adsp_ops alsa_audrec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+int alsa_audio_configure(struct msm_audio *prtd)
+{
+	if (prtd->enabled)
+		return 0;
+
+	MM_DBG("\n");
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->out_weight = 100;
+		if (audpp_enable(-1, alsa_dsp_event, prtd)) {
+			MM_ERR("audpp_enable() failed\n");
+			return -ENODEV;
+		}
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		if (audpreproc_enable(prtd->session_id,
+				&audpreproc_dsp_event, prtd)) {
+			MM_ERR("audpreproc_enable failed\n");
+			return -ENODEV;
+		}
+
+		if (msm_adsp_enable(prtd->audrec)) {
+			MM_ERR("msm_adsp_enable(audrec) enable failed\n");
+			audpreproc_disable(prtd->session_id, prtd);
+			return -ENODEV;
+		}
+		alsa_in_enc_config(prtd, 1);
+
+	}
+	prtd->enabled = 1;
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_configure);
+
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	unsigned long flag = 0;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int ret = 0;
+
+	MM_DBG("\n");
+	mutex_lock(&the_locks.write_lock);
+	while (count > 0) {
+		frame = prtd->out + prtd->out_head;
+		ret = wait_event_interruptible(the_locks.write_wait,
+					      (frame->used == 0)
+					      || (prtd->stopped));
+		if (ret < 0)
+			break;
+		if (prtd->stopped) {
+			ret = -EBUSY;
+			break;
+		}
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			ret = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		prtd->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		frame = prtd->out + prtd->out_tail;
+		if (frame->used && prtd->out_needed) {
+			alsa_dsp_send_buffer(prtd, prtd->out_tail,
+					      frame->used);
+			/* Reset eos_ack flag to avoid stale
+			 * PCMDMAMISS been considered
+			 */
+			prtd->eos_ack = 0;
+			prtd->out_tail ^= 1;
+			prtd->out_needed--;
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+	}
+	mutex_unlock(&the_locks.write_lock);
+	if (buf > start)
+		return buf - start;
+	return ret;
+}
+EXPORT_SYMBOL(alsa_send_buffer);
+
+int alsa_audio_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		MM_DBG("\n");
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		audio_dsp_out_enable(prtd, 0);
+		wake_up(&the_locks.write_wait);
+		audpp_disable(-1, prtd);
+		prtd->out_needed = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_disable);
+
+int alsa_audrec_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		prtd->enabled = 0;
+		alsa_in_enc_config(prtd, 0);
+		wake_up(&the_locks.read_wait);
+		msm_adsp_disable(prtd->audrec);
+		prtd->out_needed = 0;
+		audpreproc_disable(prtd->session_id, prtd);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audrec_disable);
+
+static int alsa_in_enc_config(struct msm_audio *prtd, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+	int i;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+	cmd.stream_id = prtd->session_id;
+
+	if (enable)
+		cmd.audrec_enc_type = prtd->type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int alsa_in_param_config(struct msm_audio *prtd)
+{
+	struct audpreproc_audrec_cmd_parm_cfg_wav cmd;
+	int i;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+	cmd.common.stream_id = prtd->session_id;
+
+	cmd.aud_rec_samplerate_idx = prtd->samp_rate;
+	cmd.aud_rec_stereo_mode = prtd->channel_mode;
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+int alsa_in_record_config(struct msm_audio *prtd, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+	int i;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = prtd->session_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+	cmd.source_mix_mask = prtd->source;
+	if (prtd->session_id == 2) {
+		if ((cmd.source_mix_mask &
+			INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+			AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int alsa_in_mem_config(struct msm_audio *prtd)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) prtd->data;
+	int n;
+	int i;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = prtd->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = prtd->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	* Mono: 1024 samples + 4 halfword header
+	* Stereo: 2048 samples + 4 halfword header
+	*/
+	for (n = 0; n < FRAME_NUM; n++) {
+		prtd->in[n].data = data + 4;
+		data += (4 + (prtd->channel_mode ? 2048 : 1024));
+		MM_DBG("0x%8x\n", (int)(prtd->in[n].data - 8));
+	}
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+
+	return audrec_send_audrecqueue(prtd, &cmd, sizeof(cmd));
+}
+
+int audio_dsp_out_enable(struct msm_audio *prtd, int yes)
+{
+	struct audpp_cmd_pcm_intf cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id	= AUDPP_CMD_PCM_INTF;
+	cmd.stream	= AUDPP_CMD_POPP_STREAM;
+	cmd.stream_id	= prtd->session_id;
+	cmd.config	= AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type	= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW	= prtd->out[0].addr;
+		cmd.write_buf1MSW	= prtd->out[0].addr >> 16;
+		cmd.write_buf1_len	= prtd->out[0].size;
+		cmd.write_buf2LSW	= prtd->out[1].addr;
+		cmd.write_buf2MSW	= prtd->out[1].addr >> 16;
+		if (prtd->out[1].used)
+			cmd.write_buf2_len	= prtd->out[1].used;
+		else
+			cmd.write_buf2_len	= prtd->out[1].size;
+		cmd.arm_to_rx_flag	= AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = prtd->out_weight;
+		cmd.weight_arm_to_rx	= 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate		= prtd->out_sample_rate;
+		cmd.channel_mode	= prtd->out_channel_mode;
+	}
+
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+		      size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int ret = 0;
+
+	mutex_lock(&the_locks.read_lock);
+	while (count > 0) {
+		ret = wait_event_interruptible(the_locks.read_wait,
+					      (prtd->in_count > 0)
+					      || prtd->stopped ||
+						  prtd->abort);
+
+		if (ret < 0)
+			break;
+
+		if (prtd->stopped) {
+			ret = -EBUSY;
+			break;
+		}
+
+		if (prtd->abort) {
+			MM_DBG(" prtd->abort !\n");
+			ret = -EPERM; /* Not permitted due to abort */
+			break;
+		}
+
+		index = prtd->in_tail;
+		data = (uint8_t *) prtd->in[index].data;
+		size = prtd->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				ret = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			if (index != prtd->in_tail) {
+				/* overrun: data is invalid, we need to retry */
+				spin_unlock_irqrestore(&the_locks.read_dsp_lock,
+						       flag);
+				continue;
+			}
+			prtd->in[index].size = 0;
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+			prtd->in_count--;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			count -= size;
+			buf += size;
+		} else {
+			break;
+		}
+	}
+	mutex_unlock(&the_locks.read_lock);
+	return ret;
+}
+EXPORT_SYMBOL(alsa_buffer_read);
+
+int alsa_dsp_send_buffer(struct msm_audio *prtd,
+					unsigned idx, unsigned len)
+{
+	struct audpp_cmd_pcm_intf_send_buffer cmd;
+	int i;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	cmd.cmd_id	= AUDPP_CMD_PCM_INTF;
+	cmd.stream	= AUDPP_CMD_POPP_STREAM;
+	cmd.stream_id	= prtd->session_id;
+	cmd.config	= AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type	= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id	= 0;
+	cmd.arm_to_dsp_buf_id	= idx + 1;
+	cmd.arm_to_dsp_buf_len	= len;
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int alsa_dsp_read_buffer(struct msm_audio *audio, uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+	int i;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+
+static void alsa_get_dsp_frames(struct msm_audio *prtd)
+{
+	struct audio_frame *frame;
+	uint32_t index = 0;
+	unsigned long flag;
+
+	if (prtd->type == ENC_TYPE_WAV) {
+		index = prtd->in_head;
+
+		frame =
+		    (void *)(((char *)prtd->in[index].data) - sizeof(*frame));
+
+		spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+		prtd->in[index].size = frame->bytes;
+		MM_DBG("frame = %08x\n", (unsigned int) frame);
+		MM_DBG("prtd->in[index].size = %08x\n",
+				(unsigned int) prtd->in[index].size);
+
+		prtd->in_head = (prtd->in_head + 1) & (FRAME_NUM - 1);
+
+		/* If overflow, move the tail index foward. */
+		if (prtd->in_head == prtd->in_tail)
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+		else
+			prtd->in_count++;
+
+		prtd->pcm_irq_pos += frame->bytes;
+		alsa_dsp_read_buffer(prtd, prtd->dsp_cnt++);
+		spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+		wake_up(&the_locks.read_wait);
+	}
+}
diff --git a/sound/soc/msm/msm7kv2-pcm.c b/sound/soc/msm/msm7kv2-pcm.c
new file mode 100644
index 0000000..c64a3ff
--- /dev/null
+++ b/sound/soc/msm/msm7kv2-pcm.c
@@ -0,0 +1,774 @@
+/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include "msm7kv2-pcm.h"
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+
+#define HOSTPCM_STREAM_ID 5
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+int copy_count;
+
+static struct snd_pcm_hardware msm_pcm_playback_hardware = {
+	.info =                 SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =              USE_FORMATS,
+	.rates =                USE_RATE,
+	.rate_min =             USE_RATE_MIN,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     MAX_BUFFER_PLAYBACK_SIZE,
+	.period_bytes_min =     BUFSZ,
+	.period_bytes_max =     BUFSZ,
+	.periods_min =          2,
+	.periods_max =          2,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_capture_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =              USE_FORMATS,
+	.rates =                USE_RATE,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     MAX_BUFFER_CAPTURE_SIZE,
+	.period_bytes_min =	4096,
+	.period_bytes_max =     4096,
+	.periods_min =          4,
+	.periods_max =          4,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+static void alsa_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+							void *private_data)
+{
+	struct msm_audio *prtd = (struct msm_audio *) private_data;
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		prtd->source |= (0x1 << evt_payload->routing_id);
+		if (prtd->running == 1 && prtd->enabled == 1)
+			audpp_route_stream(prtd->session_id, prtd->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		prtd->source &= ~(0x1 << evt_payload->routing_id);
+		if (prtd->running == 1 && prtd->enabled == 1)
+			audpp_route_stream(prtd->session_id, prtd->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		prtd->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				prtd->vol_pan.volume);
+		if (prtd->running)
+			audpp_set_volume_and_pan(prtd->session_id,
+					prtd->vol_pan.volume,
+					0, POPP);
+		break;
+	default:
+		MM_DBG("Unknown Event\n");
+		break;
+	}
+}
+
+static void alsa_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+							void *private_data)
+{
+	struct msm_audio *prtd = (struct msm_audio *) private_data;
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		prtd->source |= (0x1 << evt_payload->routing_id);
+
+		if ((prtd->running == 1) && (prtd->enabled == 1))
+			alsa_in_record_config(prtd, 1);
+
+		break;
+	}
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		prtd->source &= ~(0x1 << evt_payload->routing_id);
+
+		if (!prtd->running || !prtd->enabled)
+			break;
+
+		/* Turn off as per source */
+		if (prtd->source)
+			alsa_in_record_config(prtd, 1);
+		else
+			/* Turn off all */
+			alsa_in_record_config(prtd, 0);
+
+		break;
+	}
+	case AUDDEV_EVT_FREQ_CHG: {
+		MM_DBG("Encoder Driver got sample rate change event\n");
+		MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
+		MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
+		MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
+		if (prtd->running == 1) {
+			/* Stop Recording sample rate does not match
+			with device sample rate */
+			if (evt_payload->freq_info.sample_rate !=
+				prtd->samp_rate) {
+				alsa_in_record_config(prtd, 0);
+				prtd->abort = 1;
+				wake_up(&the_locks.read_wait);
+			}
+		}
+		break;
+	}
+	default:
+		MM_DBG("Unknown Event\n");
+		break;
+	}
+}
+
+static void msm_pcm_enqueue_data(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	unsigned int period_size;
+
+	MM_DBG("prtd->out_tail =%d mmap_flag=%d\n",
+			prtd->out_tail, prtd->mmap_flag);
+	period_size = snd_pcm_lib_period_bytes(substream);
+	alsa_dsp_send_buffer(prtd, prtd->out_tail, period_size);
+	prtd->out_tail ^= 1;
+	++copy_count;
+	prtd->period++;
+	if (unlikely(prtd->period >= runtime->periods))
+		prtd->period = 0;
+
+}
+
+static void event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	MM_DBG("\n");
+	snd_pcm_period_elapsed(prtd->substream);
+	if (prtd->mmap_flag) {
+		if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE)
+			return;
+		if (!prtd->stopped)
+			msm_pcm_enqueue_data(prtd->substream);
+		else
+			prtd->out_needed++;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	MM_DBG("\n");
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+	if (prtd->enabled)
+		return 0;
+
+	MM_DBG("\n");
+	/* rate and channels are sent to audio driver */
+	prtd->out_sample_rate = runtime->rate;
+	prtd->out_channel_mode = runtime->channels;
+	prtd->data = prtd->substream->dma_buffer.area;
+	prtd->phys = prtd->substream->dma_buffer.addr;
+	prtd->out[0].data = prtd->data + 0;
+	prtd->out[0].addr = prtd->phys + 0;
+	prtd->out[0].size = BUFSZ;
+	prtd->out[1].data = prtd->data + BUFSZ;
+	prtd->out[1].addr = prtd->phys + BUFSZ;
+	prtd->out[1].size = BUFSZ;
+
+	if (prtd->enabled | !(prtd->mmap_flag))
+		return 0;
+
+	prtd->out[0].used = prtd->pcm_count;
+	prtd->out[1].used = prtd->pcm_count;
+
+	mutex_lock(&the_locks.lock);
+	alsa_audio_configure(prtd);
+	mutex_unlock(&the_locks.lock);
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	uint32_t freq;
+	MM_DBG("\n");
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->type = ENC_TYPE_WAV;
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = (runtime->channels - 1);
+	prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \
+							MONO_DATA_SIZE;
+
+	if (prtd->enabled)
+		return 0;
+
+	freq = prtd->samp_rate;
+
+	prtd->data = prtd->substream->dma_buffer.area;
+	prtd->phys = prtd->substream->dma_buffer.addr;
+	MM_DBG("prtd->data =%08x\n", (unsigned int)prtd->data);
+	MM_DBG("prtd->phys =%08x\n", (unsigned int)prtd->phys);
+
+	mutex_lock(&the_locks.lock);
+	ret = alsa_audio_configure(prtd);
+	mutex_unlock(&the_locks.lock);
+	if (ret)
+		return ret;
+	ret = wait_event_interruptible(the_locks.enable_wait,
+				prtd->running != 0);
+	MM_DBG("state prtd->running = %d ret = %d\n", prtd->running, ret);
+
+	if (prtd->running == 0)
+		ret = -ENODEV;
+	else
+		ret = 0;
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	unsigned long flag = 0;
+	int ret = 0;
+
+	MM_DBG("\n");
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			|| !prtd->mmap_flag)
+			break;
+		if (!prtd->out_needed) {
+			prtd->stopped = 0;
+			break;
+		}
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		if (prtd->running == 1) {
+			if (prtd->stopped == 1) {
+				prtd->stopped = 0;
+				prtd->period = 0;
+				if (prtd->pcm_irq_pos == 0) {
+					prtd->out_tail = 0;
+					msm_pcm_enqueue_data(prtd->substream);
+					prtd->out_needed--;
+				} else {
+					prtd->out_tail = 1;
+					msm_pcm_enqueue_data(prtd->substream);
+					prtd->out_needed--;
+				}
+				if (prtd->out_needed) {
+					prtd->out_tail ^= 1;
+					msm_pcm_enqueue_data(prtd->substream);
+					prtd->out_needed--;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			|| !prtd->mmap_flag)
+			break;
+		prtd->stopped = 1;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+struct  msm_audio_event_callbacks snd_msm_audio_ops = {
+	.playback = event_handler,
+	.capture = event_handler,
+};
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd;
+	int ret = 0;
+	int i = 0;
+	int session_attrb, sessionid;
+
+	MM_DBG("\n");
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (prtd->opened) {
+			kfree(prtd);
+			return -EBUSY;
+		}
+		runtime->hw = msm_pcm_playback_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
+		prtd->eos_ack = 0;
+		prtd->session_id = HOSTPCM_STREAM_ID;
+		prtd->device_events = AUDDEV_EVT_DEV_RDY |
+				AUDDEV_EVT_STREAM_VOL_CHG |
+				AUDDEV_EVT_DEV_RLS;
+		prtd->source = msm_snddev_route_dec(prtd->session_id);
+		MM_ERR("Register device event listener\n");
+		ret = auddev_register_evt_listner(prtd->device_events,
+				AUDDEV_CLNT_DEC, prtd->session_id,
+				alsa_out_listener, (void *) prtd);
+		if (ret) {
+			MM_ERR("failed to register device event listener\n");
+			goto evt_error;
+		}
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_capture_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
+		session_attrb = ENC_TYPE_WAV;
+		sessionid = audpreproc_aenc_alloc(session_attrb,
+				&prtd->module_name, &prtd->queue_id);
+		if (sessionid < 0) {
+			MM_ERR("AUDREC not available\n");
+			kfree(prtd);
+			return -ENODEV;
+		}
+		prtd->session_id = sessionid;
+		MM_DBG("%s\n", prtd->module_name);
+		ret = msm_adsp_get(prtd->module_name, &prtd->audrec,
+				&alsa_audrec_adsp_ops, prtd);
+		if (ret < 0) {
+			audpreproc_aenc_free(prtd->session_id);
+			kfree(prtd);
+			return -ENODEV;
+		}
+
+		prtd->abort = 0;
+		prtd->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_FREQ_CHG;
+		prtd->source = msm_snddev_route_enc(prtd->session_id);
+		MM_ERR("Register device event listener\n");
+		ret = auddev_register_evt_listner(prtd->device_events,
+				AUDDEV_CLNT_ENC, prtd->session_id,
+				alsa_in_listener, (void *) prtd);
+		if (ret) {
+			MM_ERR("failed to register device event listener\n");
+			audpreproc_aenc_free(prtd->session_id);
+			msm_adsp_put(prtd->audrec);
+			goto evt_error;
+		}
+	}
+	prtd->substream = substream;
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+						SNDRV_PCM_HW_PARAM_RATE,
+						&constraints_sample_rates);
+	if (ret < 0)
+		MM_ERR("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		MM_ERR("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->ops = &snd_msm_audio_ops;
+	prtd->out[0].used = BUF_INVALID_LEN;
+	prtd->out[1].used = 0;
+	prtd->out_head = 1; /* point to second buffer on startup */
+	prtd->out_tail = 0;
+	prtd->dsp_cnt = 0;
+	prtd->in_head = 0;
+	prtd->in_tail = 0;
+	prtd->in_count = 0;
+	prtd->out_needed = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		prtd->in[i].size = 0;
+		prtd->in[i].read = 0;
+	}
+	prtd->vol_pan.volume = 0x2000;
+	prtd->vol_pan.pan = 0x0;
+	prtd->opened = 1;
+	runtime->private_data = prtd;
+
+	copy_count = 0;
+	return 0;
+evt_error:
+	kfree(prtd);
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	MM_DBG("%d\n", fbytes);
+	ret = alsa_send_buffer(prtd, buf, fbytes, NULL);
+	++copy_count;
+	prtd->pcm_buf_pos += fbytes;
+	if (copy_count == 1) {
+		mutex_lock(&the_locks.lock);
+		ret = alsa_audio_configure(prtd);
+		mutex_unlock(&the_locks.lock);
+	}
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	int ret = 0;
+
+	MM_DBG("\n");
+	if ((!prtd->mmap_flag) && prtd->enabled) {
+		ret = wait_event_interruptible(the_locks.eos_wait,
+		(!(prtd->out[0].used) && !(prtd->out[1].used)));
+
+		if (ret < 0)
+			goto done;
+	}
+
+	/* PCM DMAMISS message is sent only once in
+	 * hpcm interface. So, wait for buffer complete
+	 * and teos flag.
+	 */
+	if (prtd->enabled)
+		ret = wait_event_interruptible(the_locks.eos_wait,
+					prtd->eos_ack);
+
+done:
+	alsa_audio_disable(prtd);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, prtd->session_id);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0, rc1 = 0, rc2 = 0;
+	int fbytes = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+	int monofbytes = 0;
+	char *bufferp = NULL;
+
+	if (prtd->abort)
+		return -EPERM;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	MM_DBG("%d\n", fbytes);
+	monofbytes = fbytes / 2;
+	if (runtime->channels == 2) {
+		ret = alsa_buffer_read(prtd, buf, fbytes, NULL);
+	} else {
+		bufferp = buf;
+		rc1 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		bufferp = buf + monofbytes ;
+		rc2 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		ret = rc1 + rc2;
+	}
+	prtd->pcm_buf_pos += fbytes;
+	MM_DBG("prtd->pcm_buf_pos =%d, prtd->mmap_flag =%d\n",
+				prtd->pcm_buf_pos, prtd->mmap_flag);
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+
+	MM_DBG("\n");
+	ret = msm_snddev_withdraw_freq(prtd->session_id,
+			SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+	MM_DBG("msm_snddev_withdraw_freq\n");
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, prtd->session_id);
+	prtd->abort = 0;
+	wake_up(&the_locks.enable_wait);
+	alsa_audrec_disable(prtd);
+	audpreproc_aenc_free(prtd->session_id);
+	msm_adsp_put(prtd->audrec);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	MM_DBG("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	if (prtd->pcm_irq_pos == prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	prtd->out_head = 0; /* point to First buffer on startup */
+	prtd->mmap_flag = 1;
+	runtime->dma_bytes = snd_pcm_lib_period_bytes(substream)*2;
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+	return 0;
+}
+
+int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap           = msm_pcm_mmap,
+};
+
+static int pcm_preallocate_buffer(struct snd_pcm *pcm,
+	int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size;
+	if (!stream)
+		size = PLAYBACK_DMASZ;
+	else
+		size = CAPTURE_DMASZ;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void msm_pcm_free_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+	if (ret)
+		return ret;
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+	if (ret)
+		return ret;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_pcm_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_pcm_ops);
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	ret = pcm_preallocate_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	if (ret)
+		return ret;
+	ret = pcm_preallocate_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+	if (ret)
+		msm_pcm_free_buffers(pcm);
+	return ret;
+}
+
+struct snd_soc_platform_driver msm_soc_platform = {
+	.ops            = &msm_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+	.pcm_free	= msm_pcm_free_buffers,
+};
+EXPORT_SYMBOL(msm_soc_platform);
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-dsp-audio",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	 platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7kv2-pcm.h b/sound/soc/msm/msm7kv2-pcm.h
new file mode 100644
index 0000000..fec7cf5
--- /dev/null
+++ b/sound/soc/msm/msm7kv2-pcm.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+
+
+#include <mach/qdsp5v2/qdsp5audppcmdi.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/msm_adsp.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+
+
+#define FRAME_NUM               (8)
+#define FRAME_SIZE              (2052 * 2)
+#define MONO_DATA_SIZE          (2048)
+#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
+#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
+
+#define BUFSZ			(960 * 5)
+#define PLAYBACK_DMASZ 		(BUFSZ * 2)
+
+#define MSM_PLAYBACK_DEFAULT_VOLUME 0 /* 0dB */
+#define MSM_PLAYBACK_DEFAULT_PAN 0
+
+#define USE_FORMATS             SNDRV_PCM_FMTBIT_S16_LE
+#define USE_CHANNELS_MIN        1
+#define USE_CHANNELS_MAX        2
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+#define USE_RATE_MIN            8000
+#define USE_RATE_MAX            48000
+#define MAX_BUFFER_PLAYBACK_SIZE \
+				PLAYBACK_DMASZ
+/* 2048 frames (Mono), 1024 frames (Stereo) */
+#define CAPTURE_SIZE		4096
+#define MAX_BUFFER_CAPTURE_SIZE (4096*4)
+#define MAX_PERIOD_SIZE         BUFSZ
+#define USE_PERIODS_MAX         1024
+#define USE_PERIODS_MIN		1
+
+
+#define MAX_DB			(16)
+#define MIN_DB			(-50)
+#define PCMPLAYBACK_DECODERID   5
+
+/* 0xFFFFFFFF Indicates not to be used for audio data copy */
+#define	BUF_INVALID_LEN		0xFFFFFFFF
+#define EVENT_MSG_ID 		((uint16_t)~0)
+
+#define AUDDEC_DEC_PCM 		0
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define  AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+extern int copy_count;
+extern int intcnt;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	struct mutex lock;
+	struct mutex write_lock;
+	struct mutex read_lock;
+	spinlock_t read_dsp_lock;
+	spinlock_t write_dsp_lock;
+	spinlock_t mixer_lock;
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t wait;
+	wait_queue_head_t eos_wait;
+	wait_queue_head_t enable_wait;
+};
+
+extern struct audio_locks the_locks;
+
+struct msm_audio_event_callbacks {
+	/* event is called from interrupt context when a message
+	 * arrives from the DSP.
+	*/
+	void (*playback)(void *);
+	void (*capture)(void *);
+};
+
+
+struct msm_audio {
+	struct buffer out[2];
+	struct buffer_rec in[8];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	atomic_t out_bytes;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+
+	struct snd_pcm_substream *substream;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	unsigned int pcm_buf_pos;       /* position in buffer */
+	uint16_t source; /* Encoding source bit mask */
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+	struct msm_adsp_module *audplay;
+	enum msm_aud_decoder_state dec_state; /* Represents decoder state */
+
+	uint16_t session_id;
+	uint32_t out_bits; /* bits per sample */
+	const char *module_name;
+	unsigned queue_id;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t type; /* 0 for PCM ,1 for AAC */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+	uint32_t device_events; /* device events interested in */
+	int abort; /* set when error, like sample rate mismatch */
+
+	/* audpre settings */
+	/* For different sample rate, the coeff might be different. *
+	* All the coeff should be passed from user space           */
+
+	struct  msm_audio_event_callbacks *ops;
+
+	int dir;
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int eos_ack;
+	int mmap_flag;
+	int period;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+
+
+/* platform data */
+extern int alsa_dsp_send_buffer(struct msm_audio *prtd,
+			unsigned idx, unsigned len);
+extern int audio_dsp_out_enable(struct msm_audio *prtd, int yes);
+extern struct snd_soc_platform_driver msm_soc_platform;
+
+extern int audrec_encoder_config(struct msm_audio *prtd);
+extern int alsa_audrec_disable(struct msm_audio *prtd);
+extern int alsa_audio_configure(struct msm_audio *prtd);
+extern int alsa_audio_disable(struct msm_audio *prtd);
+extern int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+		size_t count, loff_t *pos);
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+		size_t count, loff_t *pos);
+extern struct msm_adsp_ops alsa_audrec_adsp_ops;
+extern int alsa_in_record_config(struct msm_audio *prtd, int enable);
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm7x30.c b/sound/soc/msm/msm7x30.c
new file mode 100644
index 0000000..94e37ca
--- /dev/null
+++ b/sound/soc/msm/msm7x30.c
@@ -0,0 +1,1004 @@
+/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio.h>
+
+#include "msm7kv2-pcm.h"
+#include <asm/mach-types.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5v2/afe.h>
+
+static struct platform_device *msm_audio_snd_device;
+struct audio_locks the_locks;
+EXPORT_SYMBOL(the_locks);
+struct msm_volume msm_vol_ctl;
+EXPORT_SYMBOL(msm_vol_ctl);
+static struct snd_kcontrol_new snd_msm_controls[];
+
+char snddev_name[AUDIO_DEV_CTL_MAX_DEV][44];
+#define MSM_MAX_VOLUME 0x2000
+#define MSM_VOLUME_STEP ((MSM_MAX_VOLUME+17)/100) /* 17 added to avoid
+						      more deviation */
+#define LOOPBACK_ENABLE         0x1
+#define LOOPBACK_DISABLE        0x0
+
+static int device_index; /* Count of Device controls */
+static int simple_control; /* Count of simple controls*/
+static int src_dev;
+static int dst_dev;
+static int loopback_status;
+
+
+static int msm_scontrol_count_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int msm_scontrol_count_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = simple_control;
+	return 0;
+}
+
+static int msm_v_call_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int msm_v_call_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_v_call_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int start = ucontrol->value.integer.value[0];
+	if (start)
+		broadcast_event(AUDDEV_EVT_START_VOICE, DEVICE_IGNORE,
+							SESSION_IGNORE);
+	else
+		broadcast_event(AUDDEV_EVT_END_VOICE, DEVICE_IGNORE,
+							SESSION_IGNORE);
+	return 0;
+}
+
+static int msm_v_mute_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 2;
+	return 0;
+}
+
+static int msm_v_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_v_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dir = ucontrol->value.integer.value[0];
+	int mute = ucontrol->value.integer.value[1];
+	return msm_set_voice_mute(dir, mute);
+}
+
+static int msm_v_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2; /* Volume */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 100;
+	return 0;
+}
+
+static int msm_v_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_v_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dir = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+
+	return msm_set_voice_vol(dir, volume);
+}
+
+static int msm_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3; /* Volume and 10-base multiply factor*/
+	uinfo->value.integer.min = 0;
+
+	/* limit the muliply factor to 4 decimal digit */
+	uinfo->value.integer.max = 1000000;
+	return 0;
+}
+static int msm_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	int session_id = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+	int factor = ucontrol->value.integer.value[2];
+	u32 session_mask = 0;
+
+
+	if (factor > 10000)
+		return -EINVAL;
+
+	if ((volume < 0) || (volume/factor > 100))
+		return -EINVAL;
+
+	volume = (MSM_VOLUME_STEP * volume);
+
+	/* Convert back to original decimal point by removing the 10-base factor
+	* and discard the fractional portion
+	*/
+
+	volume = volume/factor;
+
+	if (volume > MSM_MAX_VOLUME)
+		volume = MSM_MAX_VOLUME;
+
+	/* Only Decoder volume control supported */
+	session_mask = (0x1 << (session_id) << (8 * ((int)AUDDEV_CLNT_DEC-1)));
+	msm_vol_ctl.volume = volume;
+	MM_DBG("session_id %d, volume %d", session_id, volume);
+	broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, DEVICE_IGNORE,
+							session_mask);
+
+	return ret;
+}
+
+static int msm_voice_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3; /* Device */
+
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_voice_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	uint32_t rx_dev_id;
+	uint32_t tx_dev_id;
+	struct msm_snddev_info *rx_dev_info;
+	struct msm_snddev_info *tx_dev_info;
+	int set = ucontrol->value.integer.value[2];
+	u32 session_mask;
+
+	if (!set)
+		return -EPERM;
+	/* Rx Device Routing */
+	rx_dev_id = ucontrol->value.integer.value[0];
+	rx_dev_info = audio_dev_ctrl_find_dev(rx_dev_id);
+
+	if (IS_ERR(rx_dev_info)) {
+		MM_ERR("pass invalid dev_id\n");
+		rc = PTR_ERR(rx_dev_info);
+		return rc;
+	}
+
+	if (!(rx_dev_info->capability & SNDDEV_CAP_RX)) {
+		MM_ERR("First Dev is supposed to be RX\n");
+		return -EFAULT;
+	}
+
+	MM_DBG("route cfg %d STREAM_VOICE_RX type\n",
+		rx_dev_id);
+
+	msm_set_voc_route(rx_dev_info, AUDIO_ROUTE_STREAM_VOICE_RX,
+				rx_dev_id);
+
+	session_mask =	0x1 << (8 * ((int)AUDDEV_CLNT_VOC-1));
+
+	broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, rx_dev_id, session_mask);
+
+
+	/* Tx Device Routing */
+	tx_dev_id = ucontrol->value.integer.value[1];
+	tx_dev_info = audio_dev_ctrl_find_dev(tx_dev_id);
+
+	if (IS_ERR(tx_dev_info)) {
+		MM_ERR("pass invalid dev_id\n");
+		rc = PTR_ERR(tx_dev_info);
+		return rc;
+	}
+
+	if (!(tx_dev_info->capability & SNDDEV_CAP_TX)) {
+		MM_ERR("Second Dev is supposed to be Tx\n");
+		return -EFAULT;
+	}
+
+	MM_DBG("route cfg %d %d type\n",
+		tx_dev_id, AUDIO_ROUTE_STREAM_VOICE_TX);
+
+	msm_set_voc_route(tx_dev_info, AUDIO_ROUTE_STREAM_VOICE_TX,
+				tx_dev_id);
+
+	broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, tx_dev_id, session_mask);
+
+	if (rx_dev_info->opened)
+		broadcast_event(AUDDEV_EVT_DEV_RDY, rx_dev_id,	session_mask);
+
+	if (tx_dev_info->opened)
+		broadcast_event(AUDDEV_EVT_DEV_RDY, tx_dev_id, session_mask);
+
+	return rc;
+}
+
+static int msm_voice_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	/* TODO: query Device list */
+	return 0;
+}
+
+static int msm_device_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Device */
+
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_device_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	int set = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+	struct msm_snddev_info *dst_dev_info;
+	struct msm_snddev_info *src_dev_info;
+	int tx_freq = 0;
+	int rx_freq = 0;
+	u32 set_freq = 0;
+
+	set = ucontrol->value.integer.value[0];
+	route_cfg.dev_id = ucontrol->id.numid - device_index;
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+	if (IS_ERR(dev_info)) {
+		MM_ERR("pass invalid dev_id\n");
+		rc = PTR_ERR(dev_info);
+		return rc;
+	}
+	MM_INFO("device %s set %d\n", dev_info->name, set);
+
+	if (set) {
+		if (!dev_info->opened) {
+			set_freq = dev_info->sample_rate;
+			if (!msm_device_is_voice(route_cfg.dev_id)) {
+				msm_get_voc_freq(&tx_freq, &rx_freq);
+				if (dev_info->capability & SNDDEV_CAP_TX)
+					set_freq = tx_freq;
+
+				if (set_freq == 0)
+					set_freq = dev_info->sample_rate;
+			} else
+				set_freq = dev_info->sample_rate;
+
+
+			MM_ERR("device freq =%d\n", set_freq);
+			rc = dev_info->dev_ops.set_freq(dev_info, set_freq);
+			if (rc < 0) {
+				MM_ERR("device freq failed!\n");
+				return rc;
+			}
+			dev_info->set_sample_rate = rc;
+			rc = 0;
+			rc = dev_info->dev_ops.open(dev_info);
+			if (rc < 0) {
+				MM_ERR("Enabling %s failed", dev_info->name);
+				return rc;
+			}
+			dev_info->opened = 1;
+			broadcast_event(AUDDEV_EVT_DEV_RDY, route_cfg.dev_id,
+							SESSION_IGNORE);
+			/* Event to notify client for device info */
+			broadcast_event(AUDDEV_EVT_DEVICE_INFO,
+					route_cfg.dev_id, SESSION_IGNORE);
+			if ((route_cfg.dev_id == src_dev) ||
+				(route_cfg.dev_id == dst_dev)) {
+				dst_dev_info = audio_dev_ctrl_find_dev(
+							dst_dev);
+				if (IS_ERR(dst_dev_info)) {
+					pr_err("dst_dev:%s:pass invalid"
+						"dev_id\n", __func__);
+					rc = PTR_ERR(dst_dev_info);
+					return rc;
+				}
+				src_dev_info = audio_dev_ctrl_find_dev(
+							src_dev);
+				if (IS_ERR(src_dev_info)) {
+					pr_err("src_dev:%s:pass invalid"
+						"dev_id\n", __func__);
+					rc = PTR_ERR(src_dev_info);
+					return rc;
+				}
+				if ((dst_dev_info->opened) &&
+					(src_dev_info->opened)) {
+					pr_debug("%d: Enable afe_loopback\n",
+							__LINE__);
+					afe_ext_loopback(LOOPBACK_ENABLE,
+					       dst_dev_info->copp_id,
+					       src_dev_info->copp_id);
+					loopback_status = 1;
+				}
+			}
+		}
+	} else {
+		if (dev_info->opened) {
+			broadcast_event(AUDDEV_EVT_REL_PENDING,
+						route_cfg.dev_id,
+						SESSION_IGNORE);
+			rc = dev_info->dev_ops.close(dev_info);
+			if (rc < 0) {
+				MM_ERR("Snd device failed close!\n");
+				return rc;
+			} else {
+				dev_info->opened = 0;
+				broadcast_event(AUDDEV_EVT_DEV_RLS,
+					route_cfg.dev_id,
+					SESSION_IGNORE);
+			}
+			if (loopback_status == 1) {
+				if ((route_cfg.dev_id == src_dev) ||
+					(route_cfg.dev_id == dst_dev)) {
+					dst_dev_info = audio_dev_ctrl_find_dev(
+								dst_dev);
+					if (IS_ERR(dst_dev_info)) {
+						pr_err("dst_dev:%s:pass invalid"
+							"dev_id\n", __func__);
+						rc = PTR_ERR(dst_dev_info);
+						return rc;
+					}
+					src_dev_info = audio_dev_ctrl_find_dev(
+								src_dev);
+					if (IS_ERR(src_dev_info)) {
+						pr_err("dst_dev:%s:pass invalid"
+							"dev_id\n", __func__);
+						rc = PTR_ERR(src_dev_info);
+						return rc;
+					}
+					pr_debug("%d: Disable afe_loopback\n",
+						__LINE__);
+					afe_ext_loopback(LOOPBACK_DISABLE,
+					       dst_dev_info->copp_id,
+					       src_dev_info->copp_id);
+					loopback_status = 0;
+				}
+			}
+		}
+
+	}
+	return rc;
+}
+
+static int msm_device_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+
+	route_cfg.dev_id = ucontrol->id.numid - device_index;
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+
+	if (IS_ERR(dev_info)) {
+		MM_ERR("pass invalid dev_id\n");
+		rc = PTR_ERR(dev_info);
+		return rc;
+	}
+
+	ucontrol->value.integer.value[0] = dev_info->copp_id;
+	ucontrol->value.integer.value[1] = dev_info->capability;
+
+	return 0;
+}
+
+static int msm_route_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3; /* Device */
+
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_route_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	/* TODO: query Device list */
+	return 0;
+}
+
+static int msm_route_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	int enc_freq = 0;
+	int requested_freq = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+	int session_id = ucontrol->value.integer.value[0];
+	int set = ucontrol->value.integer.value[2];
+	u32 session_mask = 0;
+	route_cfg.dev_id = ucontrol->value.integer.value[1];
+
+	if (ucontrol->id.numid == 2)
+		route_cfg.stream_type =	AUDIO_ROUTE_STREAM_PLAYBACK;
+	else
+		route_cfg.stream_type =	AUDIO_ROUTE_STREAM_REC;
+
+	MM_DBG("route cfg %d %d type for popp %d set value %d\n",
+		route_cfg.dev_id, route_cfg.stream_type, session_id, set);
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+
+	if (IS_ERR(dev_info)) {
+		MM_ERR("pass invalid dev_id\n");
+		rc = PTR_ERR(dev_info);
+		return rc;
+	}
+	if (route_cfg.stream_type == AUDIO_ROUTE_STREAM_PLAYBACK) {
+		rc = msm_snddev_set_dec(session_id, dev_info->copp_id, set);
+		session_mask =
+			(0x1 << (session_id) << (8 * ((int)AUDDEV_CLNT_DEC-1)));
+		if (!set) {
+			if (dev_info->opened) {
+				broadcast_event(AUDDEV_EVT_REL_PENDING,
+						route_cfg.dev_id,
+						session_mask);
+
+				broadcast_event(AUDDEV_EVT_DEV_RLS,
+							route_cfg.dev_id,
+							session_mask);
+			}
+			dev_info->sessions &= ~(session_mask);
+		} else {
+			dev_info->sessions = dev_info->sessions | session_mask;
+			if (dev_info->opened) {
+				broadcast_event(AUDDEV_EVT_DEV_RDY,
+							route_cfg.dev_id,
+							session_mask);
+				/* Event to notify client for device info */
+				broadcast_event(AUDDEV_EVT_DEVICE_INFO,
+							route_cfg.dev_id,
+							session_mask);
+			}
+		}
+	} else {
+		rc = msm_snddev_set_enc(session_id, dev_info->copp_id, set);
+		session_mask =
+			(0x1 << (session_id)) << (8 * ((int)AUDDEV_CLNT_ENC-1));
+		if (!set) {
+			if (dev_info->opened)
+				broadcast_event(AUDDEV_EVT_DEV_RLS,
+							route_cfg.dev_id,
+							session_mask);
+			dev_info->sessions &= ~(session_mask);
+		} else {
+			dev_info->sessions = dev_info->sessions | session_mask;
+			enc_freq = msm_snddev_get_enc_freq(session_id);
+			requested_freq = enc_freq;
+			if (enc_freq > 0) {
+				rc = msm_snddev_request_freq(&enc_freq,
+						session_id,
+						SNDDEV_CAP_TX,
+						AUDDEV_CLNT_ENC);
+				MM_DBG("sample rate configured %d"
+					"sample rate requested %d\n",
+					enc_freq, requested_freq);
+				if ((rc <= 0) || (enc_freq != requested_freq)) {
+					MM_DBG("msm_snddev_withdraw_freq\n");
+					rc = msm_snddev_withdraw_freq
+						(session_id,
+						SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+					broadcast_event(AUDDEV_EVT_FREQ_CHG,
+							route_cfg.dev_id,
+							SESSION_IGNORE);
+				}
+			}
+			if (dev_info->opened) {
+				broadcast_event(AUDDEV_EVT_DEV_RDY,
+							route_cfg.dev_id,
+							session_mask);
+				/* Event to notify client for device info */
+				broadcast_event(AUDDEV_EVT_DEVICE_INFO,
+							route_cfg.dev_id,
+							session_mask);
+			}
+		}
+	}
+
+	if (rc < 0) {
+		MM_ERR("device could not be assigned!\n");
+		return -EFAULT;
+	}
+
+	return rc;
+}
+
+static int msm_device_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 100;
+	return 0;
+}
+
+static int msm_device_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_snddev_info *dev_info;
+
+	int dev_id = ucontrol->value.integer.value[0];
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+	ucontrol->value.integer.value[0] = dev_info->dev_volume;
+
+	return 0;
+}
+
+static int msm_device_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = -EPERM;
+	struct msm_snddev_info *dev_info;
+
+	int dev_id = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+
+	MM_DBG("dev_id = %d, volume = %d\n", dev_id, volume);
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+	if (IS_ERR(dev_info)) {
+		rc = PTR_ERR(dev_info);
+		MM_ERR("audio_dev_ctrl_find_dev failed. %ld\n",
+				PTR_ERR(dev_info));
+		return rc;
+	}
+
+	MM_DBG("dev_name = %s dev_id = %d, volume = %d\n",
+				dev_info->name, dev_id, volume);
+
+	if (dev_info->dev_ops.set_device_volume)
+		rc = dev_info->dev_ops.set_device_volume(dev_info, volume);
+	else {
+		MM_INFO("device %s does not support device volume "
+				"control.", dev_info->name);
+		return -EPERM;
+	}
+
+	return rc;
+}
+
+static int msm_reset_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0;
+	return 0;
+}
+
+static int msm_reset_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_reset_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	MM_DBG("Resetting all devices\n");
+	return msm_reset_all_device();
+}
+
+
+static int msm_dual_mic_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	/*Max value is decided based on MAX ENC sessions*/
+	uinfo->value.integer.max = MAX_AUDREC_SESSIONS - 1;
+	return 0;
+}
+
+static int msm_dual_mic_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int enc_session_id = ucontrol->value.integer.value[0];
+	ucontrol->value.integer.value[1] =
+			msm_get_dual_mic_config(enc_session_id);
+	MM_DBG("session id = %d, config = %ld\n", enc_session_id,
+				ucontrol->value.integer.value[1]);
+	return 0;
+}
+
+static int msm_dual_mic_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int enc_session_id = ucontrol->value.integer.value[0];
+	int dual_mic_config = ucontrol->value.integer.value[1];
+	MM_DBG("session id = %d, config = %d\n", enc_session_id,
+					dual_mic_config);
+	return msm_set_dual_mic_config(enc_session_id, dual_mic_config);
+}
+
+static int msm_device_mute_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_device_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int msm_device_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dev_id = ucontrol->value.integer.value[0];
+	int mute = ucontrol->value.integer.value[1];
+	struct msm_snddev_info *dev_info;
+	int afe_dev_id = 0;
+	int volume = 0x4000;
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+	if (IS_ERR(dev_info)) {
+		MM_ERR("pass invalid dev_id %d\n", dev_id);
+		return PTR_ERR(dev_info);
+	}
+
+	if (dev_info->capability & SNDDEV_CAP_RX)
+		return -EPERM;
+
+	MM_DBG("Muting device id %d(%s)\n", dev_id, dev_info->name);
+
+	if (dev_info->copp_id == 0)
+		afe_dev_id = AFE_HW_PATH_CODEC_TX;
+	if (dev_info->copp_id == 1)
+		afe_dev_id = AFE_HW_PATH_AUXPCM_TX;
+	if (dev_info->copp_id == 2)
+		afe_dev_id = AFE_HW_PATH_MI2S_TX;
+	if (mute)
+		volume = 0;
+	afe_device_volume_ctrl(afe_dev_id, volume);
+	return 0;
+}
+
+static int msm_loopback_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max =  msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_loopback_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_loopback_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct msm_snddev_info *src_dev_info = NULL; /* TX device */
+	struct msm_snddev_info *dst_dev_info = NULL; /* RX device */
+	int dst_dev_id = ucontrol->value.integer.value[0];
+	int src_dev_id = ucontrol->value.integer.value[1];
+	int set = ucontrol->value.integer.value[2];
+
+	pr_debug("%s: set=%d\n", __func__, set);
+
+	dst_dev_info = audio_dev_ctrl_find_dev(dst_dev_id);
+	if (IS_ERR(dst_dev_info)) {
+		pr_err("dst_dev:%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(dst_dev_info);
+		return rc;
+	}
+	if (!(dst_dev_info->capability & SNDDEV_CAP_RX)) {
+		pr_err("Destination device %d is not RX device\n",
+			dst_dev_id);
+		return -EFAULT;
+	}
+
+	src_dev_info = audio_dev_ctrl_find_dev(src_dev_id);
+	if (IS_ERR(src_dev_info)) {
+		pr_err("src_dev:%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(src_dev_info);
+		return rc;
+	}
+	if (!(src_dev_info->capability & SNDDEV_CAP_TX)) {
+		pr_err("Source device %d is not TX device\n", src_dev_id);
+		return -EFAULT;
+	}
+
+	if (set) {
+		pr_debug("%s:%d:Enabling AFE_Loopback\n", __func__, __LINE__);
+		src_dev = src_dev_id;
+		dst_dev = dst_dev_id;
+		loopback_status = 1;
+		if ((dst_dev_info->opened) && (src_dev_info->opened))
+			afe_ext_loopback(LOOPBACK_ENABLE,
+					dst_dev_info->copp_id,
+					src_dev_info->copp_id);
+	} else {
+		pr_debug("%s:%d:Disabling AFE_Loopback\n", __func__, __LINE__);
+		src_dev = DEVICE_IGNORE;
+		dst_dev = DEVICE_IGNORE;
+		loopback_status = 0;
+		afe_ext_loopback(LOOPBACK_DISABLE,
+				dst_dev_info->copp_id,
+				src_dev_info->copp_id);
+	}
+	return 0;
+}
+
+static struct snd_kcontrol_new snd_dev_controls[AUDIO_DEV_CTL_MAX_DEV];
+
+static int snd_dev_ctl_index(int idx)
+{
+	struct msm_snddev_info *dev_info;
+
+	dev_info = audio_dev_ctrl_find_dev(idx);
+	if (IS_ERR(dev_info)) {
+		MM_ERR("pass invalid dev_id\n");
+		return PTR_ERR(dev_info);
+	}
+	if (sizeof(dev_info->name) <= 44)
+		sprintf(&snddev_name[idx][0] , "%s", dev_info->name);
+
+	snd_dev_controls[idx].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	snd_dev_controls[idx].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	snd_dev_controls[idx].name = &snddev_name[idx][0];
+	snd_dev_controls[idx].index = idx;
+	snd_dev_controls[idx].info = msm_device_info;
+	snd_dev_controls[idx].get = msm_device_get;
+	snd_dev_controls[idx].put = msm_device_put;
+	snd_dev_controls[idx].private_value = 0;
+	return 0;
+
+}
+
+#define MSM_EXT(xname, fp_info, fp_get, fp_put, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+  .name = xname, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, \
+  .private_value = addr, \
+}
+
+static struct snd_kcontrol_new snd_msm_controls[] = {
+	MSM_EXT("Count", msm_scontrol_count_info, msm_scontrol_count_get, \
+						NULL, 0),
+	MSM_EXT("Stream", msm_route_info, msm_route_get, \
+						 msm_route_put, 0),
+	MSM_EXT("Record", msm_route_info, msm_route_get, \
+						 msm_route_put, 0),
+	MSM_EXT("Voice", msm_voice_info, msm_voice_get, \
+						 msm_voice_put, 0),
+	MSM_EXT("Volume", msm_volume_info, msm_volume_get, \
+						 msm_volume_put, 0),
+	MSM_EXT("VoiceVolume", msm_v_volume_info, msm_v_volume_get, \
+						 msm_v_volume_put, 0),
+	MSM_EXT("VoiceMute", msm_v_mute_info, msm_v_mute_get, \
+						 msm_v_mute_put, 0),
+	MSM_EXT("Voice Call", msm_v_call_info, msm_v_call_get, \
+						msm_v_call_put, 0),
+	MSM_EXT("Device_Volume", msm_device_volume_info,
+			msm_device_volume_get, msm_device_volume_put, 0),
+	MSM_EXT("Reset", msm_reset_info,
+			msm_reset_get, msm_reset_put, 0),
+	MSM_EXT("DualMic Switch", msm_dual_mic_info,
+			msm_dual_mic_get, msm_dual_mic_put, 0),
+	MSM_EXT("Device_Mute", msm_device_mute_info,
+			msm_device_mute_get, msm_device_mute_put, 0),
+	MSM_EXT("Sound Device Loopback",  msm_loopback_info,
+			msm_loopback_get, msm_loopback_put, 0),
+};
+
+static int msm_new_mixer(struct snd_soc_codec *codec)
+{
+	unsigned int idx;
+	int err;
+	int dev_cnt;
+
+	strcpy(codec->card->snd_card->mixername, "MSM Mixer");
+	for (idx = 0; idx < ARRAY_SIZE(snd_msm_controls); idx++) {
+		err = snd_ctl_add(codec->card->snd_card,
+			snd_ctl_new1(&snd_msm_controls[idx], NULL));
+		if (err < 0)
+			MM_ERR("ERR adding ctl\n");
+	}
+	dev_cnt = msm_snddev_devcount();
+
+	for (idx = 0; idx < dev_cnt; idx++) {
+		if (!snd_dev_ctl_index(idx)) {
+			err = snd_ctl_add(codec->card->snd_card,
+				snd_ctl_new1(&snd_dev_controls[idx], NULL));
+			if (err < 0)
+				MM_ERR("ERR adding ctl\n");
+		} else
+			return 0;
+	}
+	simple_control = ARRAY_SIZE(snd_msm_controls);
+	device_index = simple_control + 1;
+	return 0;
+}
+
+static int msm_soc_dai_init(
+	struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = rtd->codec;
+	ret = msm_new_mixer(codec);
+	if (ret < 0)
+		MM_ERR("msm_soc: ALSA MSM Mixer Fail\n");
+
+	mutex_init(&the_locks.lock);
+	mutex_init(&the_locks.write_lock);
+	mutex_init(&the_locks.read_lock);
+	spin_lock_init(&the_locks.read_dsp_lock);
+	spin_lock_init(&the_locks.write_dsp_lock);
+	spin_lock_init(&the_locks.mixer_lock);
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+	src_dev = DEVICE_IGNORE;
+	dst_dev = DEVICE_IGNORE;
+
+	return ret;
+}
+
+static struct snd_soc_dai_link msm_dai[] = {
+{
+	.name = "MSM Primary I2S",
+	.stream_name = "DSP 1",
+	.cpu_dai_name = "msm-cpu-dai.0",
+	.platform_name = "msm-dsp-audio.0",
+	.codec_name = "msm-codec-dai.0",
+	.codec_dai_name = "msm-codec-dai",
+	.init   = &msm_soc_dai_init,
+},
+#ifdef CONFIG_SND_MVS_SOC
+{
+	.name = "MSM Primary Voip",
+	.stream_name = "MVS",
+	.cpu_dai_name = "mvs-cpu-dai.0",
+	.platform_name = "msm-mvs-audio.0",
+	.codec_name = "mvs-codec-dai.0",
+	.codec_dai_name = "mvs-codec-dai",
+},
+#endif
+};
+
+static struct snd_soc_card snd_soc_card_msm = {
+	.name		= "msm-audio",
+	.dai_link	= msm_dai,
+	.num_links = ARRAY_SIZE(msm_dai),
+};
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	msm_audio_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!msm_audio_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(msm_audio_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_audio_snd_device);
+	if (ret) {
+		platform_device_put(msm_audio_snd_device);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void __exit msm_audio_exit(void)
+{
+	platform_device_unregister(msm_audio_snd_device);
+}
+
+module_init(msm_audio_init);
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("PCM module");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8660-dma.c b/sound/soc/msm/msm8660-dma.c
new file mode 100644
index 0000000..8ab429a
--- /dev/null
+++ b/sound/soc/msm/msm8660-dma.c
@@ -0,0 +1,432 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <mach/msm_iomap-8x60.h>
+#include <mach/audio_dma_msm8k.h>
+#include <sound/dai.h>
+#include "msm8660-pcm.h"
+
+struct dai_baseinfo {
+	void __iomem *base;
+};
+
+static struct dai_baseinfo dai_info;
+
+struct dai_drv {
+	u8	*buffer;
+	u32	buffer_phys;
+	int channels;
+	irqreturn_t (*callback) (int intrsrc, void *private_data);
+	void *private_data;
+	int in_use;
+	u32	buffer_len;
+	u32	period_len;
+	u32	master_mode;
+};
+
+static struct dai_drv *dai[MAX_CHANNELS];
+static spinlock_t dai_lock;
+
+static int dai_find_dma_channel(uint32_t intrsrc)
+{
+	int i, dma_channel = 0;
+	pr_debug("%s\n", __func__);
+
+	for (i = 0; i <= 27; i += 3) {
+		if (intrsrc & (1 << i)) {
+			dma_channel = i / 3;
+			break;
+		}
+	}
+	return dma_channel;
+}
+
+void register_dma_irq_handler(int dma_ch,
+	irqreturn_t (*callback) (int intrsrc, void *private_data),
+	void *private_data)
+{
+	pr_debug("%s\n", __func__);
+	dai[dma_ch]->callback = callback;
+	dai[dma_ch]->private_data = private_data;
+}
+
+void unregister_dma_irq_handler(int dma_ch)
+{
+	pr_debug("%s\n", __func__);
+	dai[dma_ch]->callback = NULL;
+	dai[dma_ch]->private_data = NULL;
+}
+
+static irqreturn_t dai_irq_handler(int irq, void *data)
+{
+	unsigned long flag;
+	uint32_t intrsrc;
+	uint32_t dma_ch = 0;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	pr_debug("%s\n", __func__);
+	spin_lock_irqsave(&dai_lock, flag);
+	intrsrc = readl(dai_info.base + LPAIF_IRQ_STAT(0));
+	writel(intrsrc, dai_info.base + LPAIF_IRQ_CLEAR(0));
+	while (intrsrc) {
+		dma_ch = dai_find_dma_channel(intrsrc);
+
+		if (!dai[dma_ch]->callback)
+			goto handled;
+		if (!dai[dma_ch]->private_data)
+			goto handled;
+		ret = dai[dma_ch]->callback(intrsrc,
+				dai[dma_ch]->private_data);
+		intrsrc &= ~(0x7 << (dma_ch * 3));
+	}
+handled:
+	spin_unlock_irqrestore(&dai_lock, flag);
+	return ret;
+}
+
+void dai_print_state(uint32_t dma_ch)
+{
+	int i = 0;
+	unsigned long *ptrmem = (unsigned long *)dai_info.base;
+
+	for (i = 0; i < 4; i++, ++ptrmem)
+		pr_debug("[0x%08x]=0x%08x\n", (unsigned int)ptrmem,
+					(unsigned int)*ptrmem);
+
+	ptrmem = (unsigned long *)(dai_info.base
+			+ DMA_CH_CTL_BASE + DMA_CH_INDEX(dma_ch));
+	for (i = 0; i < 10; i++, ++ptrmem)
+		pr_debug("[0x%08x]=0x%08x\n", (unsigned int)ptrmem,
+					(unsigned int) *ptrmem);
+}
+
+static int dai_enable_irq(uint32_t dma_ch)
+{
+	int ret;
+	pr_debug("%s\n", __func__);
+	ret = request_irq(LPASS_SCSS_AUDIO_IF_OUT0_IRQ, dai_irq_handler,
+			IRQF_TRIGGER_RISING | IRQF_SHARED, "msm-i2s",
+						(void *) (dma_ch+1));
+	if (ret < 0) {
+		pr_debug("Request Irq Failed err = %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static void dai_config_dma(uint32_t dma_ch)
+{
+	pr_debug("%s dma_ch = %u\n", __func__, dma_ch);
+
+	writel(dai[dma_ch]->buffer_phys,
+			dai_info.base + LPAIF_DMA_BASE(dma_ch));
+	writel(((dai[dma_ch]->buffer_len >> 2) - 1),
+			dai_info.base + LPAIF_DMA_BUFF_LEN(dma_ch));
+	writel(((dai[dma_ch]->period_len >> 2) - 1),
+			dai_info.base + LPAIF_DMA_PER_LEN(dma_ch));
+}
+
+static void dai_enable_codec(uint32_t dma_ch, int codec)
+{
+	uint32_t intrVal;
+	uint32_t i2sctl;
+	pr_debug("%s\n", __func__);
+
+	intrVal = readl(dai_info.base + LPAIF_IRQ_EN(0));
+	intrVal = intrVal | (7 << (dma_ch * 3));
+	writel(intrVal, dai_info.base + LPAIF_IRQ_EN(0));
+	if (codec == DAI_SPKR) {
+		writel(0x0813, dai_info.base + LPAIF_DMA_CTL(dma_ch));
+		i2sctl = 0x4400;
+		i2sctl |= (dai[dma_ch]->master_mode ? WS_SRC_INT : WS_SRC_EXT);
+		writel(i2sctl, dai_info.base + LPAIF_I2S_CTL_OFFSET(DAI_SPKR));
+	} else if (codec == DAI_MIC) {
+		writel(0x81b, dai_info.base + LPAIF_DMA_CTL(dma_ch));
+		i2sctl = 0x0110;
+		i2sctl |= (dai[dma_ch]->master_mode ? WS_SRC_INT : WS_SRC_EXT);
+		writel(i2sctl, dai_info.base + LPAIF_I2S_CTL_OFFSET(DAI_MIC));
+	}
+}
+
+static void dai_disable_codec(uint32_t dma_ch, int codec)
+{
+	uint32_t intrVal = 0;
+	uint32_t intrVal1 = 0;
+	unsigned long flag = 0x0;
+
+	pr_debug("%s\n", __func__);
+	spin_lock_irqsave(&dai_lock, flag);
+
+	intrVal1 = readl(dai_info.base + LPAIF_I2S_CTL_OFFSET(codec));
+
+	if (codec == DAI_SPKR)
+		intrVal1 = intrVal1 & ~(1 << 14);
+	else if (codec == DAI_MIC)
+		intrVal1 = intrVal1 & ~(1 << 8);
+
+	writel(intrVal1, dai_info.base + LPAIF_I2S_CTL_OFFSET(codec));
+	intrVal = 0x0;
+	writel(intrVal, dai_info.base + LPAIF_DMA_CTL(dma_ch));
+
+	spin_unlock_irqrestore(&dai_lock, flag);
+}
+
+int dai_open(uint32_t dma_ch)
+{
+
+	pr_debug("%s\n", __func__);
+	if (!dai_info.base) {
+		pr_debug("%s failed as no msm-dai device\n", __func__);
+		return -ENODEV;
+	}
+	if (dma_ch >= MAX_CHANNELS) {
+		pr_debug("%s over max channesl %d\n", __func__, dma_ch);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+void dai_close(uint32_t dma_ch)
+{
+	pr_debug("%s\n", __func__);
+	if ((dma_ch >= 0) && (dma_ch < 5))
+		dai_disable_codec(dma_ch, DAI_SPKR);
+	else
+		dai_disable_codec(dma_ch, DAI_MIC);
+	free_irq(LPASS_SCSS_AUDIO_IF_OUT0_IRQ, (void *) (dma_ch + 1));
+}
+
+void dai_set_master_mode(uint32_t dma_ch, int mode)
+{
+	if (dma_ch < MAX_CHANNELS)
+		dai[dma_ch]->master_mode = mode;
+	else
+		pr_err("%s: invalid dma channel\n", __func__);
+}
+
+int dai_set_params(uint32_t dma_ch, struct dai_dma_params *params)
+{
+	pr_debug("%s\n", __func__);
+	dai[dma_ch]->buffer = params->buffer;
+	dai[dma_ch]->buffer_phys = params->src_start;
+	dai[dma_ch]->channels = params->channels;
+	dai[dma_ch]->buffer_len = params->buffer_size;
+	dai[dma_ch]->period_len = params->period_size;
+	dai_config_dma(dma_ch);
+	return dma_ch;
+}
+
+int dai_start(uint32_t dma_ch)
+{
+	unsigned long flag = 0x0;
+
+	spin_lock_irqsave(&dai_lock, flag);
+	dai_enable_irq(dma_ch);
+	if ((dma_ch >= 0) && (dma_ch < 5))
+		dai_enable_codec(dma_ch, DAI_SPKR);
+	else
+		dai_enable_codec(dma_ch, DAI_MIC);
+	spin_unlock_irqrestore(&dai_lock, flag);
+	dai_print_state(dma_ch);
+	return 0;
+}
+
+#define   HDMI_BURST_INCR4		(1 << 11)
+#define   HDMI_WPSCNT			(1 << 8)
+#define   HDMI_AUDIO_INTF		(5 << 4)
+#define   HDMI_FIFO_WATER_MARK		(7 << 1)
+#define   HDMI_ENABLE			(1)
+
+int dai_start_hdmi(uint32_t dma_ch)
+{
+	unsigned long flag = 0x0;
+	uint32_t val;
+
+	pr_debug("%s dma_ch = %u\n", __func__, dma_ch);
+
+	spin_lock_irqsave(&dai_lock, flag);
+
+	dai_enable_irq(dma_ch);
+
+	if ((dma_ch >= 0) && (dma_ch < 5)) {
+
+		val = readl(dai_info.base + LPAIF_IRQ_EN(0));
+		val = val | (7 << (dma_ch * 3));
+		writel(val, dai_info.base + LPAIF_IRQ_EN(0));
+
+
+		val = (HDMI_BURST_INCR4 | HDMI_WPSCNT | HDMI_AUDIO_INTF |
+			HDMI_FIFO_WATER_MARK | HDMI_ENABLE);
+
+		writel(val, dai_info.base + LPAIF_DMA_CTL(dma_ch));
+	}
+	spin_unlock_irqrestore(&dai_lock, flag);
+
+	dai_print_state(dma_ch);
+	return 0;
+}
+
+void dai_stop_hdmi(uint32_t dma_ch)
+{
+	unsigned long flag = 0x0;
+	uint32_t intrVal;
+	uint32_t int_mask = 0x00000007;
+
+	pr_debug("%s dma_ch %u\n", __func__, dma_ch);
+
+	spin_lock_irqsave(&dai_lock, flag);
+
+	free_irq(LPASS_SCSS_AUDIO_IF_OUT0_IRQ, (void *) (dma_ch + 1));
+
+
+	intrVal = 0x0;
+	writel(intrVal, dai_info.base + LPAIF_DMA_CTL(dma_ch));
+
+	intrVal = readl(dai_info.base + LPAIF_IRQ_EN(0));
+
+	int_mask = ((int_mask) << (dma_ch * 3));
+	int_mask = ~int_mask;
+
+	intrVal = intrVal && int_mask;
+	writel(intrVal, dai_info.base + LPAIF_IRQ_EN(0));
+
+	spin_unlock_irqrestore(&dai_lock, flag);
+}
+
+int dai_stop(uint32_t dma_ch)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+
+uint32_t dai_get_dma_pos(uint32_t dma_ch)
+{
+
+	uint32_t addr;
+
+	pr_debug("%s\n", __func__);
+	addr = readl(dai_info.base + LPAIF_DMA_CURR_ADDR(dma_ch));
+
+	return addr;
+}
+
+static int __devinit dai_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	int i = 0;
+	struct resource *src;
+	src = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msm-dai");
+	if (!src) {
+		rc = -ENODEV;
+		pr_debug("%s Error  rc=%d\n", __func__, rc);
+		goto error;
+	}
+	for (i = 0; i <= MAX_CHANNELS; i++) {
+		dai[i] = kzalloc(sizeof(struct dai_drv), GFP_KERNEL);
+		if (!dai[0]) {
+			pr_debug("Allocation failed for dma_channel = 0\n");
+			return -ENODEV;
+		}
+	}
+	dai_info.base = ioremap(src->start, (src->end - src->start) + 1);
+	pr_debug("%s: msm-dai: 0x%08x\n", __func__,
+				(unsigned int)dai_info.base);
+	spin_lock_init(&dai_lock);
+error:
+	return rc;
+}
+
+static int dai_remove(struct platform_device *pdev)
+{
+	iounmap(dai_info.base);
+	return 0;
+}
+
+static struct platform_driver dai_driver = {
+	.probe = dai_probe,
+	.remove = dai_remove,
+	.driver = {
+		.name = "msm-dai",
+		.owner = THIS_MODULE
+		},
+};
+
+static struct resource msm_lpa_resources[] = {
+	{
+		.start = MSM_LPA_PHYS,
+		.end   = MSM_LPA_END,
+		.flags = IORESOURCE_MEM,
+		.name  = "msm-dai",
+	},
+};
+
+static struct platform_device *codec_device;
+
+static int msm_dai_dev_register(const char *name)
+{
+	int ret = 0;
+
+	pr_debug("%s : called\n", __func__);
+	codec_device = platform_device_alloc(name, -1);
+	if (codec_device == NULL) {
+		pr_debug("Failed to allocate %s\n", name);
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(codec_device, (void *)&dai_info);
+	platform_device_add_resources(codec_device, &msm_lpa_resources[0],
+				ARRAY_SIZE(msm_lpa_resources));
+	ret = platform_device_add(codec_device);
+	if (ret != 0) {
+		pr_debug("Failed to register %s: %d\n", name, ret);
+		platform_device_put(codec_device);
+	}
+	return ret;
+}
+
+static int __init dai_init(void)
+{
+	if (msm_dai_dev_register("msm-dai")) {
+		pr_notice("dai_init: msm-dai Failed");
+		return -ENODEV;
+	}
+	return platform_driver_register(&dai_driver);
+}
+
+static void __exit dai_exit(void)
+{
+	platform_driver_unregister(&dai_driver);
+	platform_device_put(codec_device);
+}
+
+module_init(dai_init);
+module_exit(dai_exit);
+
+MODULE_DESCRIPTION("MSM I2S driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8660-i2s.c b/sound/soc/msm/msm8660-i2s.c
new file mode 100644
index 0000000..9583c52
--- /dev/null
+++ b/sound/soc/msm/msm8660-i2s.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dai.h>
+
+static int msm_cpu_dai_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	uint32_t dma_ch = dai->id;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	ret = dai_open(dma_ch);
+	return ret;
+
+}
+
+static void msm_cpu_dai_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	uint32_t dma_ch = dai->id;
+
+	pr_debug("%s\n", __func__);
+	dai_close(dma_ch);
+}
+
+static int msm_cpu_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int msm_cpu_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	uint32_t dma_ch = dai->id;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dai_set_master_mode(dma_ch, 1); /* CPU is master */
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dai_set_master_mode(dma_ch, 0); /* CPU is slave */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_cpu_dai_ops = {
+	.startup	= msm_cpu_dai_startup,
+	.shutdown	= msm_cpu_dai_shutdown,
+	.trigger	= msm_cpu_dai_trigger,
+	.set_fmt	= msm_cpu_dai_fmt,
+
+};
+
+
+#define MSM_DAI_SPEAKER_BUILDER(link_id)			\
+{								\
+	.name = "msm-speaker-dai-"#link_id,			\
+	.id = (link_id),					\
+	.playback = {						\
+		.rates = SNDRV_PCM_RATE_8000_96000,		\
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
+		.channels_min = 1,				\
+		.channels_max = 2,				\
+		.rate_max =	96000,				\
+		.rate_min =	8000,				\
+	},							\
+	.ops = &msm_cpu_dai_ops,				\
+}
+
+
+#define MSM_DAI_MIC_BUILDER(link_id)				\
+{								\
+	.name = "msm-mic-dai-"#link_id,				\
+	.id = (link_id),					\
+	.capture = {						\
+		.rates = SNDRV_PCM_RATE_8000_96000,		\
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
+		.rate_min =	8000,				\
+		.rate_max =	96000,				\
+		.channels_min = 1,				\
+		.channels_max = 2,				\
+	},							\
+	.ops = &msm_cpu_dai_ops,				\
+}
+
+
+struct snd_soc_dai msm_cpu_dai[] = {
+	MSM_DAI_SPEAKER_BUILDER(0),
+	MSM_DAI_SPEAKER_BUILDER(1),
+	MSM_DAI_SPEAKER_BUILDER(2),
+	MSM_DAI_SPEAKER_BUILDER(3),
+	MSM_DAI_SPEAKER_BUILDER(4),
+	MSM_DAI_MIC_BUILDER(5),
+	MSM_DAI_MIC_BUILDER(6),
+	MSM_DAI_MIC_BUILDER(7),
+};
+EXPORT_SYMBOL_GPL(msm_cpu_dai);
+
+static int __init msm_cpu_dai_init(void)
+{
+	return snd_soc_register_dais(msm_cpu_dai, ARRAY_SIZE(msm_cpu_dai));
+}
+module_init(msm_cpu_dai_init);
+
+static void __exit msm_cpu_dai_exit(void)
+{
+	snd_soc_unregister_dais(msm_cpu_dai, ARRAY_SIZE(msm_cpu_dai));
+}
+module_exit(msm_cpu_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM CPU DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8660-pcm.c b/sound/soc/msm/msm8660-pcm.c
new file mode 100644
index 0000000..6f6fe43
--- /dev/null
+++ b/sound/soc/msm/msm8660-pcm.c
@@ -0,0 +1,369 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/audio_dma_msm8k.h>
+#include <sound/dai.h>
+#include "msm8660-pcm.h"
+
+static const struct snd_pcm_hardware msm_pcm_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.rates			=	SNDRV_PCM_RATE_8000_48000,
+	.formats		=	SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min =	32,
+	.period_bytes_max =	DMASZ/4,
+	.buffer_bytes_max =	DMASZ,
+	.rate_max =	96000,
+	.rate_min =	8000,
+	.channels_min =	USE_CHANNELS_MIN,
+	.channels_max =	USE_CHANNELS_MAX,
+	.periods_min =	4,
+	.periods_max =	512,
+	.fifo_size =	0,
+};
+
+struct msm_pcm_data {
+	spinlock_t		lock;
+	int			ch;
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+
+	pr_debug("%s\n", __func__);
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static irqreturn_t msm_pcm_irq(int intrsrc, void *data)
+{
+	struct snd_pcm_substream *substream = data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = (struct msm_audio *)runtime->private_data;
+	int dma_ch = 0;
+	unsigned int has_xrun, pending;
+	int ret = IRQ_NONE;
+
+	if (prtd)
+		dma_ch = prtd->dma_ch;
+	else
+		return ret;
+
+	pr_debug("msm8660-pcm: msm_pcm_irq called\n");
+	pending = (intrsrc
+		& (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
+	has_xrun = (pending & UNDER_CH(dma_ch));
+
+	if (unlikely(has_xrun) &&
+	    substream->runtime &&
+	    snd_pcm_running(substream)) {
+		pr_err("xrun\n");
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+		ret = IRQ_HANDLED;
+		pending &= ~UNDER_CH(dma_ch);
+	}
+
+
+	if (pending & PER_CH(dma_ch)) {
+		ret = IRQ_HANDLED;
+		if (likely(substream->runtime &&
+			   snd_pcm_running(substream))) {
+			/* end of buffer missed? loop back */
+			if (++prtd->period_index >= runtime->periods)
+				prtd->period_index = 0;
+				snd_pcm_period_elapsed(substream);
+			pr_debug("period elapsed\n");
+		}
+		pending &= ~PER_CH(dma_ch);
+	}
+
+	if (unlikely(pending
+		& (UNDER_CH(dma_ch) & PER_CH(dma_ch) & ERR_CH(dma_ch)))) {
+		if (pending & UNDER_CH(dma_ch))
+			pr_err("msm8660-pcm: DMA %x Underflow\n",
+			       dma_ch);
+		if (pending & ERR_CH(dma_ch))
+			pr_err("msm8660-pcm: DMA %x Master Error\n",
+			       dma_ch);
+
+	}
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = (struct msm_audio *)runtime->private_data;
+	struct dai_dma_params dma_params;
+	int dma_ch = 0;
+
+	if (prtd)
+		dma_ch = prtd->dma_ch;
+	else
+		return 0;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	pr_debug("%s:prtd->pcm_size = %d\n", __func__, prtd->pcm_size);
+	pr_debug("%s:prtd->pcm_count = %d\n", __func__, prtd->pcm_count);
+
+	if (prtd->enabled)
+		return 0;
+
+	dma_params.src_start = runtime->dma_addr;
+	dma_params.buffer = (u8 *)runtime->dma_area;
+	dma_params.buffer_size = prtd->pcm_size;
+	dma_params.period_size = prtd->pcm_count;
+	dma_params.channels = runtime->channels;
+
+	dai_set_params(dma_ch, &dma_params);
+	register_dma_irq_handler(dma_ch, msm_pcm_irq, (void *)substream);
+
+	prtd->enabled = 1;
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = (struct msm_audio *)runtime->private_data;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dai_start(prtd->dma_ch);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		dai_stop(prtd->dma_ch);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = (struct msm_audio *)runtime->private_data;
+	snd_pcm_uframes_t offset = 0;
+
+	pr_debug("%s: period_index =%d\n", __func__, prtd->period_index);
+	offset = prtd->period_index * runtime->period_size;
+	if (offset >= runtime->buffer_size)
+		offset = 0;
+	return offset;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+	struct msm_audio *prtd = NULL;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	snd_soc_set_runtime_hwparams(substream, &msm_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+				SNDRV_PCM_HW_PARAM_PERIODS);
+
+	if (ret < 0) {
+		pr_err("Error setting hw_constraint\n");
+		goto err;
+	}
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_err("Error snd_pcm_hw_constraint_list failed\n");
+
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+
+	if (prtd == NULL) {
+		pr_err("Error allocating prtd\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	prtd->dma_ch = cpu_dai->id;
+	prtd->enabled = 0;
+	runtime->dma_bytes = msm_pcm_hardware.buffer_bytes_max;
+	runtime->private_data = prtd;
+err:
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = (struct msm_audio *)runtime->private_data;
+	int dma_ch = 0;
+
+	if (prtd)
+		dma_ch = prtd->dma_ch;
+	else
+		return 0;
+
+	pr_debug("%s\n", __func__);
+	unregister_dma_irq_handler(dma_ch);
+	kfree(runtime->private_data);
+	return 0;
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+			struct vm_area_struct *vms)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	pr_debug("%s\n", __func__);
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	pr_debug("%s: snd_msm_audio_hw_params runtime->dma_addr 0x(%x)\n",
+		__func__, (unsigned int)runtime->dma_addr);
+	pr_debug("%s: snd_msm_audio_hw_params runtime->dma_area 0x(%x)\n",
+		__func__, (unsigned int)runtime->dma_area);
+	pr_debug("%s: snd_msm_audio_hw_params runtime->dma_bytes 0x(%x)\n",
+		__func__, (unsigned int)runtime->dma_bytes);
+
+	return dma_mmap_coherent(substream->pcm->card->dev, vms,
+					runtime->dma_area,
+					runtime->dma_addr,
+					runtime->dma_bytes);
+}
+
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open		= msm_pcm_open,
+	.close		= msm_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= msm_pcm_hw_params,
+	.prepare	= msm_pcm_prepare,
+	.trigger	= msm_pcm_trigger,
+	.pointer	= msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int pcm_preallocate_buffer(struct snd_pcm *pcm,
+					int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = msm_pcm_hardware.buffer_bytes_max;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					&buf->addr, GFP_KERNEL);
+
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void msm_pcm_free_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!stream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+					buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+static u64 msm_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int msm_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+			struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &msm_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (dai->playback.channels_min) {
+		ret = pcm_preallocate_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+	if (dai->capture.channels_min) {
+		ret = pcm_preallocate_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+	return ret;
+}
+
+struct snd_soc_platform msm8660_soc_platform = {
+	.name		= "msm8660-pcm-audio",
+	.pcm_ops	= &msm_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+	.pcm_free	= msm_pcm_free_buffers,
+};
+EXPORT_SYMBOL_GPL(msm8660_soc_platform);
+
+static int __init msm_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&msm8660_soc_platform);
+}
+static void __exit msm_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&msm8660_soc_platform);
+}
+module_init(msm_soc_platform_init);
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("MSM PCM module");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8660-pcm.h b/sound/soc/msm/msm8660-pcm.h
new file mode 100644
index 0000000..3bec9a7
--- /dev/null
+++ b/sound/soc/msm/msm8660-pcm.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2010, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+
+#define USE_CHANNELS_MIN        1
+#define USE_CHANNELS_MAX        2
+#define NUM_DMAS 9
+#define DMASZ	16384
+#define MAX_CHANNELS 9
+
+#define MSM_LPA_PHYS   0x28100000
+#define MSM_LPA_END    0x2810DFFF
+
+
+struct msm_audio {
+	struct snd_pcm_substream *substream;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	int enabled;
+	int period;
+	int dma_ch;
+	int period_index;
+	int start;
+};
+
+extern struct snd_soc_dai msm_cpu_dai[NUM_DMAS];
+extern struct snd_soc_platform msm8660_soc_platform;
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm8660.c b/sound/soc/msm/msm8660.c
new file mode 100644
index 0000000..8469507
--- /dev/null
+++ b/sound/soc/msm/msm8660.c
@@ -0,0 +1,342 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pmic8901.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+#include <mach/mpp.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/dai.h>
+#include "msm8660-pcm.h"
+#include "../codecs/timpani.h"
+
+#define PM8058_GPIO_BASE			NR_MSM_GPIOS
+#define PM8901_GPIO_BASE			(PM8058_GPIO_BASE + \
+						PM8058_GPIOS + PM8058_MPPS)
+#define PM8901_GPIO_PM_TO_SYS(pm_gpio)		(pm_gpio + PM8901_GPIO_BASE)
+#define GPIO_EXPANDER_GPIO_BASE \
+	(PM8901_GPIO_BASE + PM8901_MPPS)
+
+static struct clk *rx_osr_clk;
+static struct clk *rx_bit_clk;
+static struct clk *tx_osr_clk;
+static struct clk *tx_bit_clk;
+
+static int rx_hw_param_status;
+static int tx_hw_param_status;
+/* Platform specific logic */
+
+static int timpani_rx_route_enable(void)
+{
+	int ret = 0;
+	pr_debug("%s\n", __func__);
+	ret = gpio_request(109, "I2S_Clock");
+	if (ret != 0) {
+		pr_err("%s: I2s clk gpio 109 request"
+			"failed\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static int timpani_rx_route_disable(void)
+{
+	int ret = 0;
+	pr_debug("%s\n", __func__);
+	gpio_free(109);
+	return ret;
+}
+
+
+#define GPIO_CLASS_D1_EN (GPIO_EXPANDER_GPIO_BASE + 0)
+#define PM8901_MPP_3 (2) /* PM8901 MPP starts from 0 */
+static void config_class_d1_gpio(int enable)
+{
+	int rc;
+
+	if (enable) {
+		rc = gpio_request(GPIO_CLASS_D1_EN, "CLASSD1_EN");
+		if (rc) {
+			pr_err("%s: spkr pamp gpio %d request"
+			"failed\n", __func__, GPIO_CLASS_D1_EN);
+			return;
+		}
+		gpio_direction_output(GPIO_CLASS_D1_EN, 1);
+		gpio_set_value_cansleep(GPIO_CLASS_D1_EN, 1);
+	} else {
+		gpio_set_value_cansleep(GPIO_CLASS_D1_EN, 0);
+		gpio_free(GPIO_CLASS_D1_EN);
+	}
+}
+
+static void config_class_d0_gpio(int enable)
+{
+	int rc;
+
+	if (enable) {
+		rc = pm8901_mpp_config_digital_out(PM8901_MPP_3,
+			PM8901_MPP_DIG_LEVEL_MSMIO, 1);
+
+		if (rc) {
+			pr_err("%s: CLASS_D0_EN failed\n", __func__);
+			return;
+		}
+
+		rc = gpio_request(PM8901_GPIO_PM_TO_SYS(PM8901_MPP_3),
+			"CLASSD0_EN");
+
+		if (rc) {
+			pr_err("%s: spkr pamp gpio pm8901 mpp3 request"
+			"failed\n", __func__);
+			pm8901_mpp_config_digital_out(PM8901_MPP_3,
+			PM8901_MPP_DIG_LEVEL_MSMIO, 0);
+			return;
+		}
+
+		gpio_direction_output(PM8901_GPIO_PM_TO_SYS(PM8901_MPP_3), 1);
+		gpio_set_value_cansleep(PM8901_GPIO_PM_TO_SYS(PM8901_MPP_3), 1);
+
+	} else {
+		pm8901_mpp_config_digital_out(PM8901_MPP_3,
+		PM8901_MPP_DIG_LEVEL_MSMIO, 0);
+		gpio_set_value_cansleep(PM8901_GPIO_PM_TO_SYS(PM8901_MPP_3), 0);
+		gpio_free(PM8901_GPIO_PM_TO_SYS(PM8901_MPP_3));
+	}
+}
+
+static void timpani_poweramp_on(void)
+{
+
+	pr_debug("%s: enable stereo spkr amp\n", __func__);
+	timpani_rx_route_enable();
+	config_class_d0_gpio(1);
+	config_class_d1_gpio(1);
+}
+
+static void timpani_poweramp_off(void)
+{
+
+	pr_debug("%s: disable stereo spkr amp\n", __func__);
+	timpani_rx_route_disable();
+	config_class_d0_gpio(0);
+	config_class_d1_gpio(0);
+}
+
+static int msm8660_hw_params(struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params)
+{
+	int rate = params_rate(params);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (rx_hw_param_status)
+			return 0;
+		clk_set_rate(rx_osr_clk, rate * 256);
+		rx_hw_param_status++;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (tx_hw_param_status)
+			return 0;
+		clk_set_rate(tx_osr_clk, rate * 256);
+		tx_hw_param_status++;
+	}
+	return 0;
+}
+
+static int msm8660_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		rx_osr_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+		if (IS_ERR(rx_osr_clk)) {
+			pr_debug("Failed to get i2s_spkr_osr_clk\n");
+			return PTR_ERR(rx_osr_clk);
+		}
+		/* Master clock OSR 256 */
+		/* Initially set to Lowest sample rate Needed */
+		clk_set_rate(rx_osr_clk, 8000 * 256);
+		ret = clk_enable(rx_osr_clk);
+		if (ret != 0) {
+			pr_debug("Unable to enable i2s_spkr_osr_clk\n");
+			clk_put(rx_osr_clk);
+			return ret;
+		}
+		rx_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk");
+		if (IS_ERR(rx_bit_clk)) {
+			pr_debug("Failed to get i2s_spkr_bit_clk\n");
+			clk_disable(rx_osr_clk);
+			clk_put(rx_osr_clk);
+			return PTR_ERR(rx_bit_clk);
+		}
+		clk_set_rate(rx_bit_clk, 8);
+		ret = clk_enable(rx_bit_clk);
+		if (ret != 0) {
+			pr_debug("Unable to enable i2s_spkr_bit_clk\n");
+			clk_put(rx_bit_clk);
+			clk_disable(rx_osr_clk);
+			clk_put(rx_osr_clk);
+			return ret;
+		}
+		timpani_poweramp_on();
+		msleep(30);
+		/* End of platform specific logic */
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		tx_osr_clk = clk_get(NULL, "i2s_mic_osr_clk");
+		if (IS_ERR(tx_osr_clk)) {
+			pr_debug("Failed to get i2s_mic_osr_clk\n");
+			return PTR_ERR(tx_osr_clk);
+		}
+		/* Master clock OSR 256 */
+		clk_set_rate(tx_osr_clk, 8000 * 256);
+		ret = clk_enable(tx_osr_clk);
+		if (ret != 0) {
+			pr_debug("Unable to enable i2s_mic_osr_clk\n");
+			clk_put(tx_osr_clk);
+			return ret;
+		}
+		tx_bit_clk = clk_get(NULL, "i2s_mic_bit_clk");
+		if (IS_ERR(tx_bit_clk)) {
+			pr_debug("Failed to get i2s_mic_bit_clk\n");
+			clk_disable(tx_osr_clk);
+			clk_put(tx_osr_clk);
+			return PTR_ERR(tx_bit_clk);
+		}
+		clk_set_rate(tx_bit_clk, 8);
+		ret = clk_enable(tx_bit_clk);
+		if (ret != 0) {
+			pr_debug("Unable to enable i2s_mic_bit_clk\n");
+			clk_put(tx_bit_clk);
+			clk_disable(tx_osr_clk);
+			clk_put(tx_osr_clk);
+			return ret;
+		}
+		msm_snddev_enable_dmic_power();
+		msleep(30);
+	}
+	return ret;
+}
+
+/*
+ * TODO: rx/tx_hw_param_status should be a counter in the below code
+ * when driver starts supporting mutisession else setting it to 0
+ * will stop audio in all sessions.
+ */
+static void msm8660_shutdown(struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		rx_hw_param_status = 0;
+		timpani_poweramp_off();
+		msleep(30);
+		if (rx_bit_clk) {
+			clk_disable(rx_bit_clk);
+			clk_put(rx_bit_clk);
+			rx_bit_clk = NULL;
+		}
+		if (rx_osr_clk) {
+			clk_disable(rx_osr_clk);
+			clk_put(rx_osr_clk);
+			rx_osr_clk = NULL;
+		}
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		tx_hw_param_status = 0;
+		msm_snddev_disable_dmic_power();
+		msleep(30);
+		if (tx_bit_clk) {
+			clk_disable(tx_bit_clk);
+			clk_put(tx_bit_clk);
+			tx_bit_clk = NULL;
+		}
+		if (tx_osr_clk) {
+			clk_disable(tx_osr_clk);
+			clk_put(tx_osr_clk);
+			tx_osr_clk = NULL;
+		}
+	}
+}
+
+static struct snd_soc_ops machine_ops  = {
+	.startup	= msm8660_startup,
+	.shutdown	= msm8660_shutdown,
+	.hw_params	= msm8660_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm8660_dai[] = {
+	{
+		.name		= "Audio Rx",
+		.stream_name	= "Audio Rx",
+		.cpu_dai	= &msm_cpu_dai[0],
+		.codec_dai	= &timpani_codec_dai[0],
+		.ops		= &machine_ops,
+	},
+	{
+		.name		= "Audio Tx",
+		.stream_name	= "Audio Tx",
+		.cpu_dai	= &msm_cpu_dai[5],
+		.codec_dai	= &timpani_codec_dai[1],
+		.ops		= &machine_ops,
+	}
+};
+
+struct snd_soc_card snd_soc_card_msm8660 = {
+	.name		= "msm8660-pcm-audio",
+	.dai_link	= msm8660_dai,
+	.num_links	= ARRAY_SIZE(msm8660_dai),
+	.platform = &msm8660_soc_platform,
+};
+
+/* msm_audio audio subsystem */
+static struct snd_soc_device msm_snd_devdata = {
+	.card = &snd_soc_card_msm8660,
+	.codec_dev = &soc_codec_dev_timpani,
+};
+
+static struct platform_device *msm_snd_device;
+
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	msm_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(msm_snd_device, &msm_snd_devdata);
+
+	msm_snd_devdata.dev = &msm_snd_device->dev;
+	ret = platform_device_add(msm_snd_device);
+	if (ret) {
+		platform_device_put(msm_snd_device);
+		return ret;
+	}
+
+	return ret;
+}
+module_init(msm_audio_init);
+
+static void __exit msm_audio_exit(void)
+{
+	platform_device_unregister(msm_snd_device);
+}
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MSM8660");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
new file mode 100644
index 0000000..8c0df5c
--- /dev/null
+++ b/sound/soc/msm/msm8960.c
@@ -0,0 +1,673 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include "msm-pcm-routing.h"
+#include <../codecs/wcd9310.h>
+
+/* 8960 machine driver */
+
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM_CDC_PAMPL (PM8921_GPIO_PM_TO_SYS(18))
+#define MSM_CDC_PAMPR (PM8921_GPIO_PM_TO_SYS(19))
+#define MSM8960_SPK_ON 1
+#define MSM8960_SPK_OFF 0
+
+#define msm8960_SLIM_0_RX_MAX_CHANNELS		2
+#define msm8960_SLIM_0_TX_MAX_CHANNELS		4
+
+
+static int msm8960_spk_control;
+static int msm8960_pamp_on;
+static int msm8960_slim_0_rx_ch = 1;
+static int msm8960_slim_0_tx_ch = 1;
+
+struct tabla_mbhc_calibration tabla_cal = {
+	.bias = TABLA_MICBIAS2,
+	.tldoh = 100,
+	.bg_fast_settle = 100,
+	.mic_current = TABLA_PID_MIC_5_UA,
+	.mic_pid = 100,
+	.hph_current = TABLA_PID_MIC_5_UA,
+	.setup_plug_removal_delay = 1000000,
+	.shutdown_plug_removal = 100000,
+};
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static int msm8960_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+
+static void codec_poweramp_on(void)
+{
+	int ret = 0;
+
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull      = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	if (msm8960_pamp_on)
+		return;
+
+	pr_debug("%s: enable stereo spkr amp\n", __func__);
+	ret = gpio_request(MSM_CDC_PAMPL, "CDC PAMP1");
+	if (ret) {
+		pr_err("%s: Error requesting GPIO %d\n", __func__,
+			MSM_CDC_PAMPL);
+		return;
+	}
+	ret = pm8xxx_gpio_config(MSM_CDC_PAMPL, &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			MSM_CDC_PAMPL);
+	else
+		gpio_direction_output(MSM_CDC_PAMPL, 1);
+
+	ret = gpio_request(MSM_CDC_PAMPR, "CDC PAMPL");
+	if (ret) {
+		pr_err("%s: Error requesting GPIO %d\n", __func__,
+			MSM_CDC_PAMPR);
+		gpio_free(MSM_CDC_PAMPL);
+		return;
+	}
+	ret = pm8xxx_gpio_config(MSM_CDC_PAMPR, &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			MSM_CDC_PAMPR);
+	else
+		gpio_direction_output(MSM_CDC_PAMPR, 1);
+
+	msm8960_pamp_on = 1;
+}
+static void codec_poweramp_off(void)
+{
+	if (!msm8960_pamp_on)
+		return;
+
+	pr_debug("%s: disable stereo spkr amp\n", __func__);
+	gpio_direction_output(MSM_CDC_PAMPL, 0);
+	gpio_free(MSM_CDC_PAMPL);
+	gpio_direction_output(MSM_CDC_PAMPR, 0);
+	gpio_free(MSM_CDC_PAMPR);
+	msm8960_pamp_on = 0;
+}
+static void msm8960_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
+	if (msm8960_spk_control == MSM8960_SPK_ON)
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+	else
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+
+	snd_soc_dapm_sync(dapm);
+}
+
+static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
+	ucontrol->value.integer.value[0] = msm8960_spk_control;
+	return 0;
+}
+static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (msm8960_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	msm8960_spk_control = ucontrol->value.integer.value[0];
+	msm8960_ext_control(codec);
+	return 1;
+}
+static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		codec_poweramp_on();
+	else
+		codec_poweramp_off();
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Ext Spk", msm8960_spkramp_event),
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Speaker path */
+	{"Ext Spk", NULL, "LINEOUT"},
+
+	/* Microphone path */
+	{"AMIC1", NULL, "MIC BIAS1 Internal"},
+	{"DMIC1 IN", NULL, "MIC BIAS1 External"},
+	{"AMIC2", NULL, "MIC BIAS2 External"},
+	{"MIC BIAS1 Internal", NULL, "Handset Mic"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+	{"MIC BIAS2 External", NULL, "Headset Mic"},
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const struct soc_enum msm8960_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8960_slim_0_rx_ch  = %d", __func__,
+			msm8960_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch;
+	return 0;
+}
+
+static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
+			msm8960_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm8960_slim_0_tx_ch  = %d", __func__,
+			msm8960_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch;
+	return 0;
+}
+
+static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
+			msm8960_slim_0_tx_ch);
+	return 1;
+}
+
+
+static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
+		msm8960_set_spk),
+	SOC_SINGLE_EXT("SLIM_0_RX Channels", 0, 0,
+			msm8960_SLIM_0_RX_MAX_CHANNELS, 0,
+			msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
+	SOC_SINGLE_EXT("SLIM_0_TX Channels", 0, 0,
+			msm8960_SLIM_0_TX_MAX_CHANNELS, 0,
+			msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
+};
+
+static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	pr_debug("%s()\n", __func__);
+
+	err = snd_soc_add_controls(codec, tabla_msm8960_controls,
+				ARRAY_SIZE(tabla_msm8960_controls));
+	if (err < 0)
+		return err;
+
+	snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
+				ARRAY_SIZE(msm8960_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+
+	snd_soc_dapm_sync(dapm);
+
+	err = snd_soc_jack_new(codec, "Headset Jack",
+				SND_JACK_HEADSET, &hs_jack);
+	if (err) {
+		pr_err("failed to create new jack\n");
+		return err;
+	}
+	tabla_hs_detect(codec, &hs_jack, &tabla_cal);
+
+	return 0;
+}
+
+/*
+ * LPA Needs only RX BE DAI links.
+ * Hence define seperate BE list for lpa
+ */
+
+static const char *lpa_mm_be[] = {
+	LPASS_BE_SLIMBUS_0_RX,
+};
+
+static struct snd_soc_dsp_link lpa_fe_media = {
+	.supported_be = lpa_mm_be,
+	.num_be = ARRAY_SIZE(lpa_mm_be),
+	.fe_playback_channels = 2,
+	.fe_capture_channels = 1,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static const char *mm_be[] = {
+	LPASS_BE_SLIMBUS_0_RX,
+	LPASS_BE_SLIMBUS_0_TX,
+	LPASS_BE_HDMI,
+	LPASS_BE_INT_BT_SCO_RX,
+	LPASS_BE_INT_BT_SCO_TX,
+	LPASS_BE_INT_FM_RX,
+	LPASS_BE_INT_FM_TX,
+};
+
+static struct snd_soc_dsp_link fe_media = {
+	.supported_be = mm_be,
+	.num_be = ARRAY_SIZE(mm_be),
+	.fe_playback_channels = 2,
+	.fe_capture_channels = 1,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static const char *slimbus0_hl_be[] = {
+	LPASS_BE_SLIMBUS_0_RX,
+	LPASS_BE_SLIMBUS_0_TX,
+};
+
+static struct snd_soc_dsp_link slimbus0_hl_media = {
+	.supported_be = slimbus0_hl_be,
+	.num_be = ARRAY_SIZE(slimbus0_hl_be),
+	.fe_playback_channels = 2,
+	.fe_capture_channels = 2,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static const char *int_fm_hl_be[] = {
+	LPASS_BE_INT_FM_RX,
+	LPASS_BE_INT_FM_TX,
+};
+
+static struct snd_soc_dsp_link int_fm_hl_media = {
+	.supported_be = int_fm_hl_be,
+	.num_be = ARRAY_SIZE(int_fm_hl_be),
+	.fe_playback_channels = 2,
+	.fe_capture_channels = 2,
+	.trigger = {
+		SND_SOC_DSP_TRIGGER_POST,
+		SND_SOC_DSP_TRIGGER_POST
+	},
+};
+
+static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm8960_slim_0_rx_ch;
+
+	return 0;
+}
+
+static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm8960_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static int msm8960_startup(struct snd_pcm_substream *substream)
+{
+	if (clk_users++)
+		return 0;
+
+	codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+	if (codec_clk) {
+		clk_set_rate(codec_clk, 12288000);
+		clk_enable(codec_clk);
+	} else {
+		pr_err("%s: Error setting Tabla MCLK\n", __func__);
+		clk_users--;
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm8960_shutdown(struct snd_pcm_substream *substream)
+{
+	clk_users--;
+	if (!clk_users) {
+		clk_disable(codec_clk);
+		clk_put(codec_clk);
+	}
+}
+
+static struct snd_soc_ops msm8960_be_ops = {
+	.startup = msm8960_startup,
+	.shutdown = msm8960_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm8960_dai[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8960 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8960 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name	= "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.dsp_link = &fe_media,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
+		.name = "MSM8960 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.dynamic = 1,
+		.dsp_link = &lpa_fe_media,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+	},
+	/* Hostless PMC purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &slimbus0_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* .be_id = do not care */
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.dsp_link = &int_fm_hl_media,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* .be_id = do not care */
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm8960_audrx_init,
+		.be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8960_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8960_be_ops,
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6.12288",
+		.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_INT_BT_SCO_RX,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6.12289",
+		.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_INT_BT_SCO_TX,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6.12292",
+		.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_INT_FM_RX,
+		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6.12293",
+		.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_INT_FM_TX,
+		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+	},
+	/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+	},
+};
+
+struct snd_soc_card snd_soc_card_msm8960 = {
+	.name		= "msm8960-snd-card",
+	.dai_link	= msm8960_dai,
+	.num_links	= ARRAY_SIZE(msm8960_dai),
+};
+
+static struct platform_device *msm8960_snd_device;
+
+static int msm8960_configure_headset_mic_gpios(void)
+{
+	int ret;
+	struct pm_gpio param = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull	   = PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S4,
+		.out_strength   = PM_GPIO_STRENGTH_MED,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+
+	ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(23));
+		return ret;
+	}
+
+	ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(23));
+	else
+		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
+
+	ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
+	if (ret) {
+		pr_err("%s: Failed to request gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(35));
+		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
+		return ret;
+	}
+	ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
+	if (ret)
+		pr_err("%s: Failed to configure gpio %d\n", __func__,
+			PM8921_GPIO_PM_TO_SYS(35));
+	else
+		gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 1);
+
+	return 0;
+}
+static void msm8960_free_headset_mic_gpios(void)
+{
+	if (msm8960_headset_gpios_configured) {
+		gpio_free(PM8921_GPIO_PM_TO_SYS(23));
+		gpio_free(PM8921_GPIO_PM_TO_SYS(35));
+	}
+}
+
+static int __init msm8960_audio_init(void)
+{
+	int ret;
+
+	msm8960_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!msm8960_snd_device) {
+		pr_err("Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
+	ret = platform_device_add(msm8960_snd_device);
+	if (ret) {
+		platform_device_put(msm8960_snd_device);
+		return ret;
+	}
+
+	if (msm8960_configure_headset_mic_gpios()) {
+		pr_err("%s Fail to configure headset mic gpios\n", __func__);
+		msm8960_headset_gpios_configured = 0;
+	} else
+		msm8960_headset_gpios_configured = 1;
+
+	return ret;
+
+}
+module_init(msm8960_audio_init);
+
+static void __exit msm8960_audio_exit(void)
+{
+	msm8960_free_headset_mic_gpios();
+	platform_device_unregister(msm8960_snd_device);
+}
+module_exit(msm8960_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MSM8960");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8x60-dai.c b/sound/soc/msm/msm8x60-dai.c
new file mode 100644
index 0000000..8130f07
--- /dev/null
+++ b/sound/soc/msm/msm8x60-dai.c
@@ -0,0 +1,148 @@
+/* sound/soc/msm/msm-dai.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Derived from msm-pcm.c and msm7201.c.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include "msm8x60-pcm.h"
+
+static struct snd_soc_dai_driver msm_pcm_codec_dais[] = {
+{
+	.name = "msm-codec-dai",
+	.playback = {
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.rate_min = 8000,
+		.rate_max = 48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_max = 2,
+		.rate_min = 8000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+static struct snd_soc_dai_driver msm_pcm_cpu_dais[] = {
+{
+	.name = "msm-cpu-dai",
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.rate_min = 8000,
+		.rate_max = 48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min = 8000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_msm = {
+        .compress_type = SND_SOC_FLAT_COMPRESSION,
+};
+
+static __devinit int asoc_msm_codec_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm,
+                        msm_pcm_codec_dais, ARRAY_SIZE(msm_pcm_codec_dais));
+}
+
+static int __devexit asoc_msm_codec_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static __devinit int asoc_msm_cpu_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_dai(&pdev->dev, msm_pcm_cpu_dais);
+}
+
+static int __devexit asoc_msm_cpu_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_msm_codec_driver = {
+	.probe = asoc_msm_codec_probe,
+	.remove = __devexit_p(asoc_msm_codec_remove),
+	.driver = {
+			.name = "msm-codec-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_driver asoc_msm_cpu_driver = {
+	.probe = asoc_msm_cpu_probe,
+	.remove = __devexit_p(asoc_msm_cpu_remove),
+	.driver = {
+			.name = "msm-cpu-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_codec_dai_init(void)
+{
+	return platform_driver_register(&asoc_msm_codec_driver);
+}
+
+static void __exit msm_codec_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_msm_codec_driver);
+}
+
+static int __init msm_cpu_dai_init(void)
+{
+	return platform_driver_register(&asoc_msm_cpu_driver);
+}
+
+static void __exit msm_cpu_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_msm_cpu_driver);
+}
+
+module_init(msm_codec_dai_init);
+module_exit(msm_codec_dai_exit);
+module_init(msm_cpu_dai_init);
+module_exit(msm_cpu_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Codec/Cpu Dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8x60-pcm.c b/sound/soc/msm/msm8x60-pcm.c
new file mode 100644
index 0000000..a6f7350
--- /dev/null
+++ b/sound/soc/msm/msm8x60-pcm.c
@@ -0,0 +1,806 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#include "msm8x60-pcm.h"
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         2,
+	.buffer_bytes_max =     960 * 10,
+	.period_bytes_min =     960 * 5,
+	.period_bytes_max =     960 * 5,
+	.periods_min =          2,
+	.periods_max =          2,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+uint32_t in_frame_info[8][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void alsa_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+							void *private_data)
+{
+	int ret = 0;
+	struct msm_audio *prtd = (struct msm_audio *) private_data;
+	int dev_rate = 48000;
+	pr_debug("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		pr_debug("AUDDEV_EVT_DEV_RDY\n");
+		prtd->copp_id = evt_payload->routing_id;
+		pr_debug("prtd->session_id = %d, copp_id= %d",
+			prtd->session_id, prtd->copp_id);
+		if (prtd->copp_id == PCM_RX)
+			dev_rate = 8000;
+
+		ret = msm_snddev_set_dec(prtd->session_id, prtd->copp_id, 1,
+			dev_rate, 1);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		pr_debug("AUDDEV_EVT_DEV_RLS\n");
+		prtd->copp_id = evt_payload->routing_id;
+		pr_debug("prtd->session_id = %d, copp_id= %d",
+			prtd->session_id, prtd->copp_id);
+		if (prtd->copp_id == PCM_RX)
+			dev_rate = 8000;
+
+		ret = msm_snddev_set_dec(prtd->session_id, prtd->copp_id, 0,
+			dev_rate, 1);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		pr_debug("AUDDEV_EVT_STREAM_VOL_CHG\n");
+		break;
+	default:
+		pr_debug("Unknown Event\n");
+		break;
+	}
+}
+
+static void alsa_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+							void *private_data)
+{
+	int ret = 0;
+	struct msm_audio *prtd = (struct msm_audio *) private_data;
+	int dev_rate = 48000;
+	pr_debug("evt_id = 0x%8x\n", evt_id);
+
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		prtd->copp_id = evt_payload->routing_id;
+		if (prtd->copp_id == PCM_TX)
+			dev_rate = 8000;
+
+		ret = msm_snddev_set_enc(prtd->session_id, prtd->copp_id, 1,
+			dev_rate, 1);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		prtd->copp_id = evt_payload->routing_id;
+		if (prtd->copp_id == PCM_TX)
+			dev_rate = 8000;
+
+		ret = msm_snddev_set_enc(prtd->session_id, prtd->copp_id, 0,
+			dev_rate, 1);
+		break;
+	default:
+		pr_debug("Unknown Event\n");
+		break;
+	}
+}
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	uint32_t *ptrmem = (uint32_t *)payload;
+	int i = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE: {
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		if (!prtd->mmap_flag)
+			break;
+		pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+				__func__, prtd->pcm_count);
+		q6asm_write_nolock(prtd->audio_client,
+			prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		break;
+	}
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case ASM_DATA_EVENT_READ_DONE: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("token = 0x%08x\n", token);
+		for (i = 0; i < 8; i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		in_frame_info[token][0] = payload[2];
+		in_frame_info[token][1] = payload[3];
+		prtd->pcm_irq_pos += in_frame_info[token][0];
+		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		if (atomic_read(&prtd->in_count) <= prtd->periods)
+			atomic_inc(&prtd->in_count);
+		wake_up(&the_locks.read_wait);
+		if (prtd->mmap_flag)
+			q6asm_read_nolock(prtd->audio_client);
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		if (!prtd->mmap_flag
+			&& !atomic_read(&prtd->out_needed))
+			break;
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN:
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK)
+				break;
+			if (prtd->mmap_flag) {
+				pr_debug("%s:writing %d bytes"
+					" of buffer to dsp\n",
+					__func__,
+					prtd->pcm_count);
+				q6asm_write_nolock(prtd->audio_client,
+					prtd->pcm_count,
+					0, 0, NO_TIMESTAMP);
+			} else {
+				while (atomic_read(&prtd->out_needed)) {
+					pr_debug("%s:writing %d bytes"
+						 " of buffer to dsp\n",
+						__func__,
+						prtd->pcm_count);
+					q6asm_write_nolock(prtd->audio_client,
+						prtd->pcm_count,
+						0, 0, NO_TIMESTAMP);
+					atomic_dec(&prtd->out_needed);
+					wake_up(&the_locks.write_wait);
+				};
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+	int dev_rate = 48000;
+	int i = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
+				runtime->channels);
+	if (ret < 0)
+		pr_debug("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+	atomic_set(&prtd->in_count, 0);
+	for (i = 0; i < MAX_COPP; i++) {
+		pr_debug("prtd->session_id = %d, copp_id= %d",
+			prtd->session_id, i);
+		if (session_route.playback_session[substream->number][i]
+				!= DEVICE_IGNORE) {
+			pr_err("Device active\n");
+			if (i == PCM_RX)
+				dev_rate = 8000;
+			msm_snddev_set_dec(prtd->session_id,
+				       i, 1, dev_rate, runtime->channels);
+		}
+	}
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	int i = 0;
+	int dev_rate = 48000;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return 0;
+
+	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+	pr_debug("Channel = %d\n", prtd->channel_mode);
+	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
+					prtd->channel_mode);
+	if (ret < 0)
+		pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+	for (i = 0; i < runtime->periods; i++)
+		q6asm_read_nolock(prtd->audio_client);
+	prtd->periods = runtime->periods;
+	for (i = 0; i < MAX_COPP; i++) {
+		pr_debug("prtd->session_id = %d, copp_id= %d",
+			prtd->session_id,
+			session_route.capture_session[prtd->session_id][i]);
+		if (session_route.capture_session[prtd->session_id][i]
+				!= DEVICE_IGNORE) {
+			if (i == PCM_RX)
+				dev_rate = 8000;
+			msm_snddev_set_enc(prtd->session_id, i, 1, dev_rate, 1);
+		}
+	}
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	pr_debug("%s\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("SNDRV_PCM_TRIGGER_START\n");
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		atomic_set(&prtd->start, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	runtime->hw = msm_pcm_hardware;
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_debug("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm in open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* The session id returned by q6asm_open_read above is random and
+	 * hence we cannot use the session id to route from user space.
+	 * This results in need of a hardcoded session id for both playback
+	 * and capture sessions. we can use the subdevice id to identify
+	 * the session and use that for routing. Hence using
+	 * substream->number as the session id for routing purpose. However
+	 * DSP understands the session based on the allocated session id,
+	 * hence using the variable prtd->session_id for all dsp commands.
+	 */
+
+	prtd->session_id = prtd->audio_client->session;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->cmd_ack = 1;
+		prtd->device_events = AUDDEV_EVT_DEV_RDY |
+				AUDDEV_EVT_STREAM_VOL_CHG |
+				AUDDEV_EVT_DEV_RLS;
+		prtd->source = msm_snddev_route_dec(prtd->session_id);
+		pr_debug("Register device event listener for"
+				"SNDRV_PCM_STREAM_PLAYBACK session %d\n",
+				substream->number);
+		ret = auddev_register_evt_listner(prtd->device_events,
+				AUDDEV_CLNT_DEC, substream->number,
+				alsa_out_listener, (void *) prtd);
+		if (ret)
+			pr_debug("failed to register device event listener\n");
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_FREQ_CHG;
+		prtd->source = msm_snddev_route_enc(prtd->session_id);
+		pr_debug("Register device event listener for"
+				"SNDRV_PCM_STREAM_CAPTURE session %d\n",
+				substream->number);
+		ret = auddev_register_evt_listner(prtd->device_events,
+				AUDDEV_CLNT_ENC, substream->number,
+				alsa_in_listener, (void *) prtd);
+		if (ret)
+			pr_debug("failed to register device event listener\n");
+	}
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_debug("snd_pcm_hw_constraint_integer failed\n");
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer = 0;
+	char *bufptr = NULL;
+	void *data = NULL;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	pr_debug("%s: prtd->out_count = %d\n",
+				__func__, atomic_read(&prtd->out_count));
+	ret = wait_event_timeout(the_locks.write_wait,
+			(atomic_read(&prtd->out_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+
+	if (!atomic_read(&prtd->out_count)) {
+		pr_debug("%s: pcm stopped out_count 0\n", __func__);
+		return 0;
+	}
+	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	if (bufptr) {
+		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+					__func__, fbytes, xfer, size);
+		xfer = fbytes;
+		if (copy_from_user(bufptr, buf, xfer)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		fbytes -= xfer;
+		pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+		if (atomic_read(&prtd->start)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
+					__func__, xfer);
+			ret = q6asm_write_nolock(prtd->audio_client, xfer,
+						0, 0, NO_TIMESTAMP);
+			if (ret < 0) {
+				ret = -EFAULT;
+				goto fail;
+			}
+		} else
+			atomic_inc(&prtd->out_needed);
+		atomic_dec(&prtd->out_count);
+	}
+fail:
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	pr_debug("%s\n", __func__);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC,
+		substream->number);
+	pr_debug("%s\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	msm_clear_session_id(prtd->session_id);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer;
+	char *bufptr;
+	void *data = NULL;
+	static uint32_t idx;
+	static uint32_t size;
+	uint32_t offset = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+
+	pr_debug("%s\n", __func__);
+	fbytes = frames_to_bytes(runtime, frames);
+
+	pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+	pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+	pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+	ret = wait_event_timeout(the_locks.read_wait,
+			(atomic_read(&prtd->in_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+	if (!atomic_read(&prtd->in_count)) {
+		pr_debug("%s: pcm stopped in_count 0\n", __func__);
+		return 0;
+	}
+	pr_debug("Checking if valid buffer is available...%08x\n",
+						(unsigned int) data);
+	data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	pr_debug("Size = %d\n", size);
+	pr_debug("fbytes = %d\n", fbytes);
+	pr_debug("idx = %d\n", idx);
+	if (bufptr) {
+		xfer = fbytes;
+		if (xfer > size)
+			xfer = size;
+		offset = in_frame_info[idx][1];
+		pr_debug("Offset value = %d\n", offset);
+		if (copy_to_user(buf, bufptr+offset, xfer)) {
+			pr_err("Failed to copy buf to user\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+		fbytes -= xfer;
+		size -= xfer;
+		in_frame_info[idx][1] += xfer;
+		pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+					__func__, fbytes, size, xfer);
+		pr_debug(" Sending next buffer to dsp\n");
+		memset(&in_frame_info[idx], 0,
+			sizeof(uint32_t) * 2);
+		atomic_dec(&prtd->in_count);
+		ret = q6asm_read_nolock(prtd->audio_client);
+		if (ret < 0) {
+			pr_err("q6asm read failed\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+	} else
+		pr_err("No valid buffer\n");
+
+	pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC,
+		substream->number);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	msm_clear_session_id(prtd->session_id);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+	pr_debug("%s: pcm_irq_pos = %d\n", __func__, prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+	dma_mmap_coherent(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+	return 0;
+}
+
+int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed \
+					rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret = 0;
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 2);
+	if (ret)
+		return ret;
+	ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+	if (ret)
+		return ret;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_pcm_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_pcm_ops);
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+struct snd_soc_platform_driver msm_soc_platform = {
+	.ops            = &msm_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+};
+EXPORT_SYMBOL(msm_soc_platform);
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				&msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+	.driver = {
+		.name = "msm-dsp-audio",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	 platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8x60-pcm.h b/sound/soc/msm/msm8x60-pcm.h
new file mode 100644
index 0000000..d7c9ad8
--- /dev/null
+++ b/sound/soc/msm/msm8x60-pcm.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+#define MAX_PLAYBACK_SESSIONS	2
+#define MAX_CAPTURE_SESSIONS	1
+#define MAX_COPP               12
+
+extern int copy_count;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t eos_wait;
+	wait_queue_head_t enable_wait;
+};
+
+extern struct audio_locks the_locks;
+
+struct msm_audio {
+	struct snd_pcm_substream *substream;
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	uint16_t source; /* Encoding source bit mask */
+
+	struct audio_client *audio_client;
+
+	uint16_t session_id;
+	int copp_id;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t dsp_cnt;
+
+	uint32_t device_events; /* device events interested in */
+	int abort; /* set when error, like sample rate mismatch */
+
+	int enabled;
+	int close_ack;
+	int cmd_ack;
+	atomic_t start;
+	atomic_t out_count;
+	atomic_t in_count;
+	atomic_t out_needed;
+	int periods;
+	int mmap_flag;
+};
+
+struct pcm_session {
+	unsigned short playback_session[MAX_PLAYBACK_SESSIONS][MAX_COPP];
+	unsigned short capture_session[MAX_CAPTURE_SESSIONS][MAX_COPP];
+};
+
+/* platform data */
+extern struct snd_soc_platform_driver msm_soc_platform;
+extern struct pcm_session session_route;
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm8x60.c b/sound/soc/msm/msm8x60.c
new file mode 100644
index 0000000..59597f9
--- /dev/null
+++ b/sound/soc/msm/msm8x60.c
@@ -0,0 +1,1108 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6afe.h>
+#include <asm/dma.h>
+#include <asm/mach-types.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#define LOOPBACK_ENABLE		0x1
+#define LOOPBACK_DISABLE	0x0
+
+#include "msm8x60-pcm.h"
+
+static struct platform_device *msm_audio_snd_device;
+struct audio_locks the_locks;
+EXPORT_SYMBOL(the_locks);
+struct msm_volume msm_vol_ctl;
+EXPORT_SYMBOL(msm_vol_ctl);
+struct pcm_session session_route;
+EXPORT_SYMBOL(session_route);
+static struct snd_kcontrol_new snd_msm_controls[];
+
+char snddev_name[AUDIO_DEV_CTL_MAX_DEV][44];
+#define MSM_MAX_VOLUME 0x2000
+#define MSM_VOLUME_STEP ((MSM_MAX_VOLUME+17)/100) /* 17 added to avoid
+						      more deviation */
+static int device_index; /* Count of Device controls */
+static int simple_control; /* Count of simple controls*/
+static int src_dev;
+static int dst_dev;
+static int loopback_status;
+
+static int msm_scontrol_count_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int msm_scontrol_count_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = simple_control;
+	return 0;
+}
+
+static int msm_v_call_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int msm_v_call_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_v_call_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int start = ucontrol->value.integer.value[0];
+	if (start)
+		broadcast_event(AUDDEV_EVT_START_VOICE, DEVICE_IGNORE,
+							SESSION_IGNORE);
+	else
+		broadcast_event(AUDDEV_EVT_END_VOICE, DEVICE_IGNORE,
+							SESSION_IGNORE);
+	return 0;
+}
+
+static int msm_v_mute_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 2;
+	return 0;
+}
+
+static int msm_v_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_v_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dir = ucontrol->value.integer.value[0];
+	int mute = ucontrol->value.integer.value[1];
+	return msm_set_voice_mute(dir, mute);
+}
+
+static int msm_v_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2; /* Volume */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 100;
+	return 0;
+}
+
+static int msm_v_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_v_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int dir = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+
+	return msm_set_voice_vol(dir, volume);
+}
+
+static int msm_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2; /* Volume */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 16383;
+	return 0;
+}
+static int msm_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	int session_id = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+	int factor = ucontrol->value.integer.value[2];
+	u64 session_mask = 0;
+
+	if (factor > 10000)
+		return -EINVAL;
+
+	if ((volume < 0) || (volume/factor > 100))
+		return -EINVAL;
+
+	volume = (MSM_VOLUME_STEP * volume);
+
+	/* Convert back to original decimal point by removing the 10-base factor
+	* and discard the fractional portion
+	*/
+
+	volume = volume/factor;
+
+	if (volume > MSM_MAX_VOLUME)
+		volume = MSM_MAX_VOLUME;
+
+	/* Only Decoder volume control supported */
+	session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+				((int)AUDDEV_CLNT_DEC-1));
+	msm_vol_ctl.volume = volume;
+	pr_debug("%s:session_id %d, volume %d", __func__, session_id, volume);
+	broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, DEVICE_IGNORE,
+							session_mask);
+
+	return ret;
+}
+
+static int msm_voice_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3; /* Device */
+
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_voice_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	uint32_t rx_dev_id;
+	uint32_t tx_dev_id;
+	struct msm_snddev_info *rx_dev_info;
+	struct msm_snddev_info *tx_dev_info;
+	int set = ucontrol->value.integer.value[2];
+	u64 session_mask;
+
+	if (!set)
+		return -EPERM;
+	/* Rx Device Routing */
+	rx_dev_id = ucontrol->value.integer.value[0];
+	rx_dev_info = audio_dev_ctrl_find_dev(rx_dev_id);
+
+	if (IS_ERR(rx_dev_info)) {
+		pr_err("%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(rx_dev_info);
+		return rc;
+	}
+
+	if (!(rx_dev_info->capability & SNDDEV_CAP_RX)) {
+		pr_err("%s:First Dev is supposed to be RX\n", __func__);
+		return -EFAULT;
+	}
+
+	pr_debug("%s:route cfg %d STREAM_VOICE_RX type\n",
+		__func__, rx_dev_id);
+
+	msm_set_voc_route(rx_dev_info, AUDIO_ROUTE_STREAM_VOICE_RX,
+				rx_dev_id);
+
+	session_mask =	((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+				((int)AUDDEV_CLNT_VOC-1));
+
+	broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, rx_dev_id, session_mask);
+
+
+	/* Tx Device Routing */
+	tx_dev_id = ucontrol->value.integer.value[1];
+	tx_dev_info = audio_dev_ctrl_find_dev(tx_dev_id);
+
+	if (IS_ERR(tx_dev_info)) {
+		pr_err("%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(tx_dev_info);
+		return rc;
+	}
+
+	if (!(tx_dev_info->capability & SNDDEV_CAP_TX)) {
+		pr_err("%s:Second Dev is supposed to be Tx\n", __func__);
+		return -EFAULT;
+	}
+
+	pr_debug("%s:route cfg %d %d type\n",
+		__func__, tx_dev_id, AUDIO_ROUTE_STREAM_VOICE_TX);
+
+	msm_set_voc_route(tx_dev_info, AUDIO_ROUTE_STREAM_VOICE_TX,
+				tx_dev_id);
+
+	broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, tx_dev_id, session_mask);
+
+	if (rx_dev_info->opened)
+		broadcast_event(AUDDEV_EVT_DEV_RDY, rx_dev_id,	session_mask);
+
+	if (tx_dev_info->opened)
+		broadcast_event(AUDDEV_EVT_DEV_RDY, tx_dev_id, session_mask);
+
+	return rc;
+}
+
+static int msm_voice_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	/* TODO: query Device list */
+	return 0;
+}
+
+static int msm_device_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Device */
+
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_device_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	int set = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+	struct msm_snddev_info *dst_dev_info;
+	struct msm_snddev_info *src_dev_info;
+	int tx_freq = 0;
+	int rx_freq = 0;
+	u32 set_freq = 0;
+
+	set = ucontrol->value.integer.value[0];
+	route_cfg.dev_id = ucontrol->id.numid - device_index;
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+	if (IS_ERR(dev_info)) {
+		pr_err("%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(dev_info);
+		return rc;
+	}
+	pr_info("%s:device %s set %d\n", __func__, dev_info->name, set);
+
+	if (set) {
+		if (!dev_info->opened) {
+			set_freq = dev_info->sample_rate;
+			if (!msm_device_is_voice(route_cfg.dev_id)) {
+				msm_get_voc_freq(&tx_freq, &rx_freq);
+				if (dev_info->capability & SNDDEV_CAP_TX)
+					set_freq = tx_freq;
+
+				if (set_freq == 0)
+					set_freq = dev_info->sample_rate;
+			} else
+				set_freq = dev_info->sample_rate;
+
+
+			pr_err("%s:device freq =%d\n", __func__, set_freq);
+			rc = dev_info->dev_ops.set_freq(dev_info, set_freq);
+			if (rc < 0) {
+				pr_err("%s:device freq failed!\n", __func__);
+				return rc;
+			}
+			dev_info->set_sample_rate = rc;
+			rc = 0;
+			rc = dev_info->dev_ops.open(dev_info);
+			if (rc < 0) {
+				pr_err("%s:Enabling %s failed\n",
+					__func__, dev_info->name);
+				return rc;
+			}
+			dev_info->opened = 1;
+			broadcast_event(AUDDEV_EVT_DEV_RDY, route_cfg.dev_id,
+							SESSION_IGNORE);
+			if ((route_cfg.dev_id == src_dev) ||
+				(route_cfg.dev_id == dst_dev)) {
+				dst_dev_info = audio_dev_ctrl_find_dev(
+							dst_dev);
+				if (IS_ERR(dst_dev_info)) {
+					pr_err("dst_dev:%s:pass invalid"
+						"dev_id\n", __func__);
+					rc = PTR_ERR(dst_dev_info);
+					return rc;
+				}
+				src_dev_info = audio_dev_ctrl_find_dev(
+							src_dev);
+				if (IS_ERR(src_dev_info)) {
+					pr_err("src_dev:%s:pass invalid"
+						"dev_id\n", __func__);
+					rc = PTR_ERR(src_dev_info);
+					return rc;
+				}
+				if ((dst_dev_info->opened) &&
+					(src_dev_info->opened)) {
+					pr_debug("%d: Enable afe_loopback\n",
+							__LINE__);
+					afe_loopback(LOOPBACK_ENABLE,
+					       dst_dev_info->copp_id,
+					       src_dev_info->copp_id);
+					loopback_status = 1;
+				}
+			}
+		}
+	} else {
+		if (dev_info->opened) {
+			broadcast_event(AUDDEV_EVT_REL_PENDING,
+						route_cfg.dev_id,
+						SESSION_IGNORE);
+			rc = dev_info->dev_ops.close(dev_info);
+			if (rc < 0) {
+				pr_err("%s:Snd device failed close!\n",
+					__func__);
+				return rc;
+			} else {
+				dev_info->opened = 0;
+				broadcast_event(AUDDEV_EVT_DEV_RLS,
+					route_cfg.dev_id,
+					SESSION_IGNORE);
+			}
+			if (loopback_status == 1) {
+				if ((route_cfg.dev_id == src_dev) ||
+					(route_cfg.dev_id == dst_dev)) {
+					dst_dev_info = audio_dev_ctrl_find_dev(
+								dst_dev);
+					if (IS_ERR(dst_dev_info)) {
+						pr_err("dst_dev:%s:pass invalid"
+							"dev_id\n", __func__);
+						rc = PTR_ERR(dst_dev_info);
+						return rc;
+					}
+					src_dev_info = audio_dev_ctrl_find_dev(
+								src_dev);
+					if (IS_ERR(src_dev_info)) {
+						pr_err("src_dev:%s:pass invalid"
+							"dev_id\n", __func__);
+						rc = PTR_ERR(src_dev_info);
+						return rc;
+					}
+					pr_debug("%d: Disable afe_loopback\n",
+						__LINE__);
+					afe_loopback(LOOPBACK_DISABLE,
+					       dst_dev_info->copp_id,
+					       src_dev_info->copp_id);
+					loopback_status = 0;
+				}
+			}
+		}
+
+	}
+	return rc;
+}
+
+static int msm_device_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+
+	route_cfg.dev_id = ucontrol->id.numid - device_index;
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+
+	if (IS_ERR(dev_info)) {
+		pr_err("%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(dev_info);
+		return rc;
+	}
+
+	ucontrol->value.integer.value[0] = dev_info->copp_id;
+	ucontrol->value.integer.value[1] = dev_info->capability;
+
+	return 0;
+}
+
+static int msm_route_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3; /* Device */
+
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_route_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	/* TODO: query Device list */
+	return 0;
+}
+
+static int msm_route_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	int enc_freq = 0;
+	int requested_freq = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+	int session_id = ucontrol->value.integer.value[0];
+	int set = ucontrol->value.integer.value[2];
+	u64 session_mask = 0;
+	route_cfg.dev_id = ucontrol->value.integer.value[1];
+
+	if (ucontrol->id.numid == 2)
+		route_cfg.stream_type =	AUDIO_ROUTE_STREAM_PLAYBACK;
+	else
+		route_cfg.stream_type =	AUDIO_ROUTE_STREAM_REC;
+
+	pr_debug("%s:route cfg %d %d type for popp %d\n",
+		__func__, route_cfg.dev_id, route_cfg.stream_type, session_id);
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+
+	if (IS_ERR(dev_info)) {
+		pr_err("%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(dev_info);
+		return rc;
+	}
+	if (route_cfg.stream_type == AUDIO_ROUTE_STREAM_PLAYBACK) {
+		rc = msm_snddev_set_dec(session_id, dev_info->copp_id, set,
+				dev_info->sample_rate, dev_info->channel_mode);
+		session_mask =
+			(((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+				((int)AUDDEV_CLNT_DEC-1));
+		if (!set) {
+			if (dev_info->opened)
+				broadcast_event(AUDDEV_EVT_DEV_RLS,
+							route_cfg.dev_id,
+							session_mask);
+			dev_info->sessions &= ~(session_mask);
+		} else {
+			dev_info->sessions = dev_info->sessions | session_mask;
+			if (dev_info->opened)
+				broadcast_event(AUDDEV_EVT_DEV_RDY,
+							route_cfg.dev_id,
+							session_mask);
+		}
+	} else {
+
+		rc = msm_snddev_set_enc(session_id, dev_info->copp_id, set,
+				dev_info->sample_rate, dev_info->channel_mode);
+		session_mask =
+			(((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+			((int)AUDDEV_CLNT_ENC-1));
+		if (!set) {
+			if (dev_info->opened)
+				broadcast_event(AUDDEV_EVT_DEV_RLS,
+							route_cfg.dev_id,
+							session_mask);
+			dev_info->sessions &= ~(session_mask);
+		} else {
+			dev_info->sessions = dev_info->sessions | session_mask;
+			enc_freq = msm_snddev_get_enc_freq(session_id);
+			requested_freq = enc_freq;
+			if (enc_freq > 0) {
+				rc = msm_snddev_request_freq(&enc_freq,
+						session_id,
+						SNDDEV_CAP_TX,
+						AUDDEV_CLNT_ENC);
+				pr_debug("%s:sample rate configured %d\
+					sample rate requested %d \n",
+					__func__, enc_freq, requested_freq);
+				if ((rc <= 0) || (enc_freq != requested_freq)) {
+					pr_debug("%s:msm_snddev_withdraw_freq\n",
+						__func__);
+					rc = msm_snddev_withdraw_freq
+						(session_id,
+						SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+					broadcast_event(AUDDEV_EVT_FREQ_CHG,
+							route_cfg.dev_id,
+							SESSION_IGNORE);
+				}
+			}
+			if (dev_info->opened)
+				broadcast_event(AUDDEV_EVT_DEV_RDY,
+							route_cfg.dev_id,
+							session_mask);
+		}
+	}
+
+	if (rc < 0) {
+		pr_err("%s:device could not be assigned!\n", __func__);
+		return -EFAULT;
+	}
+
+	return rc;
+}
+
+static int msm_device_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 100;
+	return 0;
+}
+
+static int msm_device_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_snddev_info *dev_info;
+
+	int dev_id = ucontrol->value.integer.value[0];
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+	ucontrol->value.integer.value[0] = dev_info->dev_volume;
+
+	return 0;
+}
+
+static int msm_device_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = -EPERM;
+	struct msm_snddev_info *dev_info;
+
+	int dev_id = ucontrol->value.integer.value[0];
+	int volume = ucontrol->value.integer.value[1];
+
+	pr_debug("%s:dev_id = %d, volume = %d\n", __func__, dev_id, volume);
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+	if (IS_ERR(dev_info)) {
+		rc = PTR_ERR(dev_info);
+		pr_err("%s: audio_dev_ctrl_find_dev failed. %ld \n",
+			__func__, PTR_ERR(dev_info));
+		return rc;
+	}
+
+	pr_debug("%s:dev_name = %s dev_id = %d, volume = %d\n",
+			__func__, dev_info->name, dev_id, volume);
+
+	if (dev_info->dev_ops.set_device_volume)
+		rc = dev_info->dev_ops.set_device_volume(dev_info, volume);
+	else {
+		pr_info("%s : device %s does not support device volume "
+				"control.", __func__, dev_info->name);
+		return -EPERM;
+	}
+
+	return rc;
+}
+
+static int msm_reset_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0;
+	return 0;
+}
+
+static int msm_reset_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_reset_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	pr_err("%s:Resetting all devices\n", __func__);
+	return msm_reset_all_device();
+}
+
+static int msm_anc_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int msm_anc_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_anc_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = -EPERM;
+	struct msm_snddev_info *dev_info;
+
+	int dev_id = ucontrol->value.integer.value[0];
+	int enable = ucontrol->value.integer.value[1];
+
+	pr_debug("%s: dev_id = %d, enable = %d\n", __func__, dev_id, enable);
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+	if (IS_ERR(dev_info)) {
+		rc = PTR_ERR(dev_info);
+		pr_err("%s: audio_dev_ctrl_find_dev failed. %ld\n",
+			__func__, PTR_ERR(dev_info));
+		return rc;
+	}
+
+	if (dev_info->dev_ops.enable_anc) {
+		rc = dev_info->dev_ops.enable_anc(dev_info, enable);
+	} else {
+		pr_info("%s : device %s does not support anc control.",
+				 __func__, dev_info->name);
+		return -EPERM;
+	}
+
+	return rc;
+}
+
+static int pcm_route_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	/*
+	 * First parameter is session id ~ subdevice number
+	 * Second parameter is device id.
+	 */
+	uinfo->count = 3;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = msm_snddev_devcount();
+	return 0;
+}
+
+static int pcm_route_get_rx(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int pcm_route_get_tx(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int pcm_route_put_rx(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int session_id = 0;
+	int set = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+	u64 session_mask = 0;
+
+	/*
+	 * session id is incremented by one and stored as session id 0
+	 * is being used by dsp currently. whereas user space would use
+	 * subdevice number as session id.
+	 */
+	session_id = ucontrol->value.integer.value[0];
+	route_cfg.dev_id = ucontrol->value.integer.value[1];
+	set = ucontrol->value.integer.value[2];
+
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+	if (IS_ERR(dev_info)) {
+		pr_err("pass invalid dev_id %d\n", route_cfg.dev_id);
+		return PTR_ERR(dev_info);
+	}
+	if (!(dev_info->capability & SNDDEV_CAP_RX))
+			return -EINVAL;
+	session_mask =
+		(((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+			((int)AUDDEV_CLNT_DEC-1));
+	if (!set) {
+		session_route.playback_session[session_id][dev_info->copp_id]
+			= DEVICE_IGNORE;
+		broadcast_event(AUDDEV_EVT_DEV_RLS,
+				route_cfg.dev_id,
+				session_mask);
+		dev_info->sessions &= ~(session_mask);
+		return 0;
+	}
+	pr_debug("%s:Routing playback session %d to %s\n",
+				 __func__, (session_id),
+				dev_info->name);
+	session_route.playback_session[session_id][dev_info->copp_id] =
+							 dev_info->copp_id;
+	if (dev_info->opened) {
+		dev_info->sessions = dev_info->sessions | session_mask;
+		broadcast_event(AUDDEV_EVT_DEV_RDY,
+				route_cfg.dev_id,
+				session_mask);
+	} else {
+		broadcast_event(AUDDEV_EVT_DEV_RLS,
+				route_cfg.dev_id,
+				session_mask);
+		dev_info->sessions &= ~(session_mask);
+	}
+	return 0;
+}
+
+static int pcm_route_put_tx(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int session_id = 0;
+	int set = 0;
+	struct msm_audio_route_config route_cfg;
+	struct msm_snddev_info *dev_info;
+	u64 session_mask = 0;
+
+	session_id = ucontrol->value.integer.value[0];
+	route_cfg.dev_id = ucontrol->value.integer.value[1];
+	set = ucontrol->value.integer.value[2];
+
+	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+	if (IS_ERR(dev_info)) {
+		pr_err("pass invalid dev_id %d\n", route_cfg.dev_id);
+		return PTR_ERR(dev_info);
+	}
+	pr_debug("%s:Routing capture session %d to %s\n", __func__,
+					session_id,
+					dev_info->name);
+	if (!(dev_info->capability & SNDDEV_CAP_TX))
+			return -EINVAL;
+	session_mask =
+		(((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+			((int)AUDDEV_CLNT_ENC-1));
+	if (!set) {
+		session_route.capture_session[session_id][dev_info->copp_id]
+			= DEVICE_IGNORE;
+		broadcast_event(AUDDEV_EVT_DEV_RLS,
+				route_cfg.dev_id,
+				session_mask);
+		dev_info->sessions &= ~(session_mask);
+		return 0;
+	}
+
+	session_route.capture_session[session_id][dev_info->copp_id] =
+							dev_info->copp_id;
+	if (dev_info->opened) {
+		dev_info->sessions = dev_info->sessions | session_mask;
+		broadcast_event(AUDDEV_EVT_DEV_RDY,
+				route_cfg.dev_id,
+				session_mask);
+	} else {
+		broadcast_event(AUDDEV_EVT_DEV_RLS,
+				route_cfg.dev_id,
+				session_mask);
+		dev_info->sessions &= ~(session_mask);
+	}
+	return 0;
+}
+
+static int msm_loopback_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 3;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max =  msm_snddev_devcount();
+	return 0;
+}
+
+static int msm_loopback_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_loopback_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct msm_snddev_info *src_dev_info = NULL; /* TX device */
+	struct msm_snddev_info *dst_dev_info = NULL; /* RX device */
+	int dst_dev_id = ucontrol->value.integer.value[0];
+	int src_dev_id = ucontrol->value.integer.value[1];
+	int set = ucontrol->value.integer.value[2];
+
+	pr_debug("%s: dst=%d :src=%d set=%d\n", __func__,
+	       dst_dev_id, src_dev_id, set);
+
+	dst_dev_info = audio_dev_ctrl_find_dev(dst_dev_id);
+	if (IS_ERR(dst_dev_info)) {
+		pr_err("dst_dev:%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(dst_dev_info);
+		return rc;
+	}
+	if (!(dst_dev_info->capability & SNDDEV_CAP_RX)) {
+		pr_err("Destination device %d is not RX device\n",
+			dst_dev_id);
+		return -EFAULT;
+	}
+
+	src_dev_info = audio_dev_ctrl_find_dev(src_dev_id);
+	if (IS_ERR(src_dev_info)) {
+		pr_err("src_dev:%s:pass invalid dev_id\n", __func__);
+		rc = PTR_ERR(src_dev_info);
+		return rc;
+	}
+	if (!(src_dev_info->capability & SNDDEV_CAP_TX)) {
+		pr_err("Source device %d is not TX device\n", src_dev_id);
+		return -EFAULT;
+	}
+
+	if (set) {
+		pr_debug("%s:%d:Enabling AFE_Loopback\n", __func__, __LINE__);
+		src_dev = src_dev_id;
+		dst_dev = dst_dev_id;
+		loopback_status = 1;
+		if ((dst_dev_info->opened) && (src_dev_info->opened))
+			rc = afe_loopback(LOOPBACK_ENABLE,
+				       dst_dev_info->copp_id,
+				       src_dev_info->copp_id);
+	} else {
+		pr_debug("%s:%d:Disabling AFE_Loopback\n", __func__, __LINE__);
+		src_dev = DEVICE_IGNORE;
+		dst_dev = DEVICE_IGNORE;
+		loopback_status = 0;
+		rc = afe_loopback(LOOPBACK_DISABLE,
+			       dst_dev_info->copp_id,
+			       src_dev_info->copp_id);
+	}
+	return rc;
+}
+
+static struct snd_kcontrol_new snd_dev_controls[AUDIO_DEV_CTL_MAX_DEV];
+
+static int snd_dev_ctl_index(int idx)
+{
+	struct msm_snddev_info *dev_info;
+
+	dev_info = audio_dev_ctrl_find_dev(idx);
+	if (IS_ERR(dev_info)) {
+		pr_err("%s:pass invalid dev_id\n", __func__);
+		return PTR_ERR(dev_info);
+	}
+	if (sizeof(dev_info->name) <= 44)
+		sprintf(&snddev_name[idx][0] , "%s", dev_info->name);
+
+	snd_dev_controls[idx].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	snd_dev_controls[idx].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	snd_dev_controls[idx].name = &snddev_name[idx][0];
+	snd_dev_controls[idx].index = idx;
+	snd_dev_controls[idx].info = msm_device_info;
+	snd_dev_controls[idx].get = msm_device_get;
+	snd_dev_controls[idx].put = msm_device_put;
+	snd_dev_controls[idx].private_value = 0;
+	return 0;
+
+}
+
+#define MSM_EXT(xname, fp_info, fp_get, fp_put, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+  .name = xname, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, \
+  .private_value = addr, \
+}
+
+/* If new controls are to be added which would be constant across the
+ * different targets, please add to the structure
+ * snd_msm_controls. Please do not add any controls to the structure
+ * snd_msm_secondary_controls defined below unless they are msm8x60
+ * specific.
+ */
+
+static struct snd_kcontrol_new snd_msm_controls[] = {
+	MSM_EXT("Count", msm_scontrol_count_info, msm_scontrol_count_get, \
+						NULL, 0),
+	MSM_EXT("Stream", msm_route_info, msm_route_get, \
+						 msm_route_put, 0),
+	MSM_EXT("Record", msm_route_info, msm_route_get, \
+						 msm_route_put, 0),
+	MSM_EXT("Voice", msm_voice_info, msm_voice_get, \
+						 msm_voice_put, 0),
+	MSM_EXT("Volume", msm_volume_info, msm_volume_get, \
+						 msm_volume_put, 0),
+	MSM_EXT("VoiceVolume", msm_v_volume_info, msm_v_volume_get, \
+						 msm_v_volume_put, 0),
+	MSM_EXT("VoiceMute", msm_v_mute_info, msm_v_mute_get, \
+						 msm_v_mute_put, 0),
+	MSM_EXT("Voice Call", msm_v_call_info, msm_v_call_get, \
+						msm_v_call_put, 0),
+	MSM_EXT("Device_Volume", msm_device_volume_info,
+			msm_device_volume_get, msm_device_volume_put, 0),
+	MSM_EXT("Reset", msm_reset_info,
+			msm_reset_get, msm_reset_put, 0),
+	MSM_EXT("ANC", msm_anc_info, msm_anc_get, msm_anc_put, 0),
+};
+
+static struct snd_kcontrol_new snd_msm_secondary_controls[] = {
+	MSM_EXT("PCM Playback Sink",
+			pcm_route_info, pcm_route_get_rx, pcm_route_put_rx, 0),
+	MSM_EXT("PCM Capture Source",
+			pcm_route_info, pcm_route_get_tx, pcm_route_put_tx, 0),
+	MSM_EXT("Sound Device Loopback", msm_loopback_info,
+			msm_loopback_get, msm_loopback_put, 0),
+};
+
+static int msm_new_mixer(struct snd_soc_codec *codec)
+{
+	unsigned int idx;
+	int err;
+	int dev_cnt;
+
+	strcpy(codec->card->snd_card->mixername, "MSM Mixer");
+	for (idx = 0; idx < ARRAY_SIZE(snd_msm_controls); idx++) {
+		err = snd_ctl_add(codec->card->snd_card,
+				snd_ctl_new1(&snd_msm_controls[idx],
+					NULL));
+		if (err < 0)
+			pr_err("%s:ERR adding ctl\n", __func__);
+	}
+
+	for (idx = 0; idx < ARRAY_SIZE(snd_msm_secondary_controls); idx++) {
+		err = snd_ctl_add(codec->card->snd_card,
+			snd_ctl_new1(&snd_msm_secondary_controls[idx],
+			NULL));
+		if (err < 0)
+			pr_err("%s:ERR adding secondary ctl\n", __func__);
+	}
+	dev_cnt = msm_snddev_devcount();
+
+	for (idx = 0; idx < dev_cnt; idx++) {
+		if (!snd_dev_ctl_index(idx)) {
+			err = snd_ctl_add(codec->card->snd_card,
+				snd_ctl_new1(&snd_dev_controls[idx],
+					NULL));
+			if (err < 0)
+				pr_err("%s:ERR adding ctl\n", __func__);
+		} else
+			return 0;
+	}
+	simple_control = ARRAY_SIZE(snd_msm_controls)
+			+ ARRAY_SIZE(snd_msm_secondary_controls);
+	device_index = simple_control + 1;
+	return 0;
+}
+
+static int msm_soc_dai_init(
+	struct snd_soc_pcm_runtime *rtd)
+{
+
+	int ret = 0;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+	memset(&session_route, DEVICE_IGNORE, sizeof(struct pcm_session));
+
+	ret = msm_new_mixer(codec);
+	if (ret < 0)
+		pr_err("%s: ALSA MSM Mixer Fail\n", __func__);
+
+	return ret;
+}
+
+static struct snd_soc_dai_link msm_dai[] = {
+{
+	.name = "MSM Primary I2S",
+	.stream_name = "DSP 1",
+	.cpu_dai_name = "msm-cpu-dai.0",
+	.platform_name = "msm-dsp-audio.0",
+	.codec_name = "msm-codec-dai.0",
+	.codec_dai_name = "msm-codec-dai",
+	.init   = &msm_soc_dai_init,
+},
+#ifdef CONFIG_MSM_8x60_VOIP
+{
+	.name = "MSM Primary Voip",
+	.stream_name = "MVS",
+	.cpu_dai_name = "mvs-cpu-dai.0",
+	.platform_name = "msm-mvs-audio.0",
+	.codec_name = "mvs-codec-dai.0",
+	.codec_dai_name = "mvs-codec-dai",
+},
+#endif
+};
+
+static struct snd_soc_card snd_soc_card_msm = {
+	.name		= "msm-audio",
+	.dai_link	= msm_dai,
+	.num_links = ARRAY_SIZE(msm_dai),
+};
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	msm_audio_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!msm_audio_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(msm_audio_snd_device, &snd_soc_card_msm);
+	ret = platform_device_add(msm_audio_snd_device);
+	if (ret) {
+		platform_device_put(msm_audio_snd_device);
+		return ret;
+	}
+
+	src_dev = DEVICE_IGNORE;
+	dst_dev = DEVICE_IGNORE;
+
+	return ret;
+}
+
+static void __exit msm_audio_exit(void)
+{
+	platform_device_unregister(msm_audio_snd_device);
+}
+
+module_init(msm_audio_init);
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("PCM module");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm_audio_mvs.h b/sound/soc/msm/msm_audio_mvs.h
new file mode 100644
index 0000000..728621a
--- /dev/null
+++ b/sound/soc/msm/msm_audio_mvs.h
@@ -0,0 +1,368 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#ifndef __MSM_AUDIO_MVS_H
+#define __MSM_AUDIO_MVS_H
+#include <linux/msm_audio.h>
+#include <linux/wakelock.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/debug_mm.h>
+#include <linux/slab.h>
+
+
+#define AUDIO_GET_MVS_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+    (AUDIO_MAX_COMMON_IOCTL_NUM + 0), unsigned)
+#define AUDIO_SET_MVS_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM + 1), unsigned)
+#define AUDIO_SET_SCR_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM + 2), unsigned)
+#define AUDIO_SET_DTX_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM + 3), unsigned)
+/* MVS modes */
+#define MVS_MODE_LINEAR_PCM 9
+
+#define MVS_PROG 0x30000014
+#define MVS_VERS 0x00030001
+
+#define MVS_CLIENT_ID_VOIP 0x00000003	/* MVS_CLIENT_VOIP */
+
+#define MVS_ACQUIRE_PROC 4
+#define MVS_ENABLE_PROC 5
+#define MVS_RELEASE_PROC 6
+#define MVS_SET_PCM_MODE_PROC 9
+
+#define MVS_EVENT_CB_TYPE_PROC 1
+#define MVS_PACKET_UL_FN_TYPE_PROC 2
+#define MVS_PACKET_DL_FN_TYPE_PROC 3
+
+#define MVS_CB_FUNC_ID 0xAAAABBBB
+#define MVS_UL_CB_FUNC_ID 0xBBBBCCCC
+#define MVS_DL_CB_FUNC_ID 0xCCCCDDDD
+
+/* MVS frame modes */
+
+#define MVS_FRAME_MODE_PCM_UL 13
+#define MVS_FRAME_MODE_PCM_DL 14
+
+/* MVS context */
+#define MVS_PKT_CONTEXT_ISR 0x00000001
+
+/* Max voc packet size */
+#define MVS_MAX_VOC_PKT_SIZE 320
+
+#define VOIP_MAX_Q_LEN 20
+#define MVS_MAX_Q_LEN  8
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_STATUS_FAILURE 0
+#define RPC_STATUS_SUCCESS 1
+#define RPC_STATUS_REJECT 1
+
+
+#define RPC_COMMON_HDR_SZ       (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ      (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ        (sizeof(uint32_t) * 3)
+
+
+enum audio_mvs_state_type { AUDIO_MVS_CLOSED, AUDIO_MVS_OPENED,
+	AUDIO_MVS_PREPARING, AUDIO_MVS_ACQUIRE, AUDIO_MVS_ENABLED,
+	AUDIO_MVS_CLOSING
+};
+
+enum audio_mvs_event_type { AUDIO_MVS_COMMAND, AUDIO_MVS_MODE,
+	AUDIO_MVS_NOTIFY
+};
+
+enum audio_mvs_cmd_status_type { AUDIO_MVS_CMD_FAILURE, AUDIO_MVS_CMD_BUSY,
+	AUDIO_MVS_CMD_SUCCESS
+};
+
+enum audio_mvs_mode_status_type { AUDIO_MVS_MODE_NOT_AVAIL,
+	AUDIO_MVS_MODE_INIT, AUDIO_MVS_MODE_READY
+};
+
+enum audio_mvs_pkt_status_type { AUDIO_MVS_PKT_NORMAL, AUDIO_MVS_PKT_FAST,
+	AUDIO_MVS_PKT_SLOW
+};
+
+struct rpc_audio_mvs_acquire_args {
+	uint32_t client_id;
+	uint32_t cb_func_id;
+};
+
+struct audio_mvs_acquire_msg {
+	struct rpc_request_hdr rpc_hdr;
+	struct rpc_audio_mvs_acquire_args acquire_args;
+};
+
+struct rpc_audio_mvs_enable_args {
+	uint32_t client_id;
+	uint32_t mode;
+	uint32_t ul_cb_func_id;
+	uint32_t dl_cb_func_id;
+	uint32_t context;
+};
+
+struct audio_mvs_enable_msg {
+	struct rpc_request_hdr rpc_hdr;
+	struct rpc_audio_mvs_enable_args enable_args;
+};
+
+struct audio_mvs_release_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t client_id;
+};
+
+struct audio_mvs_set_pcm_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t pcm_mode;
+};
+
+struct audio_mvs_set_pcmwb_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t pcmwb_mode;
+};
+
+struct audio_mvs_buffer {
+	uint8_t *voc_pkt;
+	uint32_t len;
+};
+
+union audio_mvs_event_data {
+	struct mvs_ev_command_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t cmd_status;
+	} mvs_ev_command_type;
+
+	struct mvs_ev_mode_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t mode_status;
+		uint32_t mode;
+	} mvs_ev_mode_type;
+
+	struct mvs_ev_notify_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t buf_dir;
+		uint32_t max_frames;
+	} mvs_ev_notify_type;
+};
+
+struct audio_mvs_cb_func_args {
+	uint32_t cb_func_id;
+	uint32_t valid_ptr;
+	uint32_t event;
+	union audio_mvs_event_data event_data;
+};
+
+struct audio_mvs_frame_info_hdr {
+	uint32_t frame_mode;
+	uint32_t mvs_mode;
+	uint32_t buf_free_cnt;
+};
+
+struct audio_mvs_ul_cb_func_args {
+	uint32_t cb_func_id;
+	uint32_t pkt_len;
+	uint32_t voc_pkt[MVS_MAX_VOC_PKT_SIZE / 4];
+
+	uint32_t valid_ptr;
+
+	uint32_t frame_mode;
+	uint32_t frame_mode_ignore;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+
+	uint32_t pcm_frame;
+	uint32_t pcm_mode;
+
+	uint32_t pkt_len_ignore;
+};
+
+struct audio_mvs_ul_reply {
+	struct rpc_reply_hdr reply_hdr;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+
+struct audio_mvs_dl_cb_func_args {
+	uint32_t cb_func_id;
+	uint32_t valid_ptr;
+
+	uint32_t frame_mode;
+	uint32_t frame_mode_ignore;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+
+	uint32_t pcm_frame;
+	uint32_t pcm_mode;
+
+};
+
+struct audio_mvs_dl_reply {
+	struct rpc_reply_hdr reply_hdr;
+	uint32_t voc_pkt[MVS_MAX_VOC_PKT_SIZE / 4];
+	uint32_t valid_frame_info_ptr;
+
+	uint32_t frame_mode;
+	uint32_t frame_mode_again;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+
+	uint32_t pcm_frame;
+	uint32_t pcm_mode;
+
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+
+struct audio_mvs_info_type {
+	enum audio_mvs_state_type state;
+	uint32_t frame_mode;
+	uint32_t mvs_mode;
+	uint32_t buf_free_cnt;
+	uint32_t pcm_frame;
+	uint32_t pcm_mode;
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+	int dl_play;
+	struct msm_rpc_endpoint *rpc_endpt;
+	uint32_t rpc_prog;
+	uint32_t rpc_ver;
+	uint32_t rpc_status;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_playback_irq_pos;	/* IRQ position */
+	unsigned int pcm_playback_buf_pos;	/* position in buffer */
+
+	unsigned int pcm_capture_size;
+	unsigned int pcm_capture_count;
+	unsigned int pcm_capture_irq_pos;	/* IRQ position */
+	unsigned int pcm_capture_buf_pos;	/* position in buffer */
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	uint8_t *mem_chunk;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	struct audio_mvs_buffer in[MVS_MAX_Q_LEN];
+	uint32_t in_read;
+	uint32_t in_write;
+
+	struct audio_mvs_buffer out[MVS_MAX_Q_LEN];
+	uint32_t out_read;
+	uint32_t out_write;
+
+	struct task_struct *task;
+
+	wait_queue_head_t wait;
+	wait_queue_head_t prepare_wait;
+	wait_queue_head_t out_wait;
+	wait_queue_head_t in_wait;
+
+
+	struct mutex lock;
+	struct mutex prepare_lock;
+	struct mutex in_lock;
+	struct mutex out_lock;
+
+	struct wake_lock suspend_lock;
+	struct wake_lock idle_lock;
+	struct timer_list timer;
+	unsigned long expiry;
+	int ack_dl_count;
+	int ack_ul_count;
+	int prepare_ack;
+	int playback_start;
+	int capture_start;
+	unsigned long expiry_delta;
+	int mvs_enable;
+	int playback_enable;
+	int capture_enable;
+	int instance;
+
+};
+
+struct audio_voip_info_type {
+	enum audio_mvs_state_type state;
+	enum audio_mvs_state_type playback_state;
+	enum audio_mvs_state_type capture_state;
+
+	unsigned int pcm_playback_size;
+	unsigned int pcm_count;
+	unsigned int pcm_playback_irq_pos;	/* IRQ position */
+	unsigned int pcm_playback_buf_pos;	/* position in buffer */
+
+	unsigned int pcm_capture_size;
+	unsigned int pcm_capture_count;
+	unsigned int pcm_capture_irq_pos;	/* IRQ position */
+	unsigned int pcm_capture_buf_pos;	/* position in buffer */
+
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	struct audio_mvs_buffer in[VOIP_MAX_Q_LEN];
+	uint32_t in_read;
+	uint32_t in_write;
+
+	struct audio_mvs_buffer out[VOIP_MAX_Q_LEN];
+	uint32_t out_read;
+	uint32_t out_write;
+
+	wait_queue_head_t out_wait;
+	wait_queue_head_t in_wait;
+
+	struct mutex lock;
+	struct mutex prepare_lock;
+
+	struct wake_lock suspend_lock;
+	struct wake_lock idle_lock;
+	int playback_start;
+	int capture_start;
+	int instance;
+};
+
+enum msm_audio_pcm_frame_type {
+	MVS_AMR_SPEECH_GOOD,	/* Good speech frame              */
+	MVS_AMR_SPEECH_DEGRADED,	/* Speech degraded                */
+	MVS_AMR_ONSET,		/* onset                          */
+	MVS_AMR_SPEECH_BAD,	/* Corrupt speech frame (bad CRC) */
+	MVS_AMR_SID_FIRST,	/* First silence descriptor       */
+	MVS_AMR_SID_UPDATE,	/* Comfort noise frame            */
+	MVS_AMR_SID_BAD,	/* Corrupt SID frame (bad CRC)    */
+	MVS_AMR_NO_DATA,	/* Nothing to transmit            */
+	MVS_AMR_SPEECH_LOST,	/* downlink speech lost           */
+};
+
+enum msm_audio_dtx_mode_type { MVS_DTX_OFF, MVS_DTX_ON
+};
+
+struct msm_audio_mvs_config {
+	uint32_t mvs_mode;
+	uint32_t bit_rate;
+};
+
+extern struct snd_soc_dai_driver msm_mvs_dais[2];
+extern struct snd_soc_codec_device soc_codec_dev_msm_mvs;
+extern struct snd_soc_platform_driver msm_mvs_soc_platform;
+extern struct snd_soc_platform_driver msm_voip_soc_platform;
+#endif /* __MSM_AUDIO_MVS_H */
diff --git a/sound/soc/msm/mvs-dai.c b/sound/soc/msm/mvs-dai.c
new file mode 100644
index 0000000..521c5e5
--- /dev/null
+++ b/sound/soc/msm/mvs-dai.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include "msm_audio_mvs.h"
+
+static struct snd_soc_dai_driver msm_mvs_codec_dais[] = {
+{
+	.name = "mvs-codec-dai",
+	.playback = {
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_8000),
+		.rate_min = 8000,
+		.rate_max = 8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_8000),
+		.rate_min = 8000,
+		.rate_max = 8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+static struct snd_soc_dai_driver msm_mvs_cpu_dais[] = {
+{
+	.name = "mvs-cpu-dai",
+	.playback = {
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_8000),
+		.rate_min = 8000,
+		.rate_max = 8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_8000),
+		.rate_min = 8000,
+		.rate_max = 8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_msm = {
+        .compress_type = SND_SOC_FLAT_COMPRESSION,
+};
+
+static __devinit int asoc_mvs_codec_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm,
+                        msm_mvs_codec_dais, ARRAY_SIZE(msm_mvs_codec_dais));
+}
+
+static int __devexit asoc_mvs_codec_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static __devinit int asoc_mvs_cpu_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_dai(&pdev->dev, msm_mvs_cpu_dais);
+}
+
+static int __devexit asoc_mvs_cpu_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_mvs_codec_driver = {
+	.probe = asoc_mvs_codec_probe,
+	.remove = __devexit_p(asoc_mvs_codec_remove),
+	.driver = {
+			.name = "mvs-codec-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_driver asoc_mvs_cpu_driver = {
+	.probe = asoc_mvs_cpu_probe,
+	.remove = __devexit_p(asoc_mvs_cpu_remove),
+	.driver = {
+			.name = "mvs-cpu-dai",
+			.owner = THIS_MODULE,
+	},
+};
+
+static int __init mvs_codec_dai_init(void)
+{
+	return platform_driver_register(&asoc_mvs_codec_driver);
+}
+
+static void __exit mvs_codec_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_mvs_codec_driver);
+}
+
+static int __init mvs_cpu_dai_init(void)
+{
+	return platform_driver_register(&asoc_mvs_cpu_driver);
+}
+
+static void __exit mvs_cpu_dai_exit(void)
+{
+	platform_driver_unregister(&asoc_mvs_cpu_driver);
+}
+
+module_init(mvs_codec_dai_init);
+module_exit(mvs_codec_dai_exit);
+module_init(mvs_cpu_dai_init);
+module_exit(mvs_cpu_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Codec/Cpu Dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6/Makefile b/sound/soc/msm/qdsp6/Makefile
new file mode 100644
index 0000000..5fd69cc
--- /dev/null
+++ b/sound/soc/msm/qdsp6/Makefile
@@ -0,0 +1 @@
+obj-y := q6asm.o q6adm.o q6afe.o q6voice.o
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
new file mode 100644
index 0000000..65d1fbc
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -0,0 +1,804 @@
+/* Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#define TIMEOUT_MS 1000
+#define AUDIO_RX 0x0
+#define AUDIO_TX 0x1
+#define ASM_MAX_SESSION 0x8 /* To do: define in a header */
+#define RESET_COPP_ID 99
+#define INVALID_COPP_ID 0xFF
+
+struct adm_ctl {
+	void *apr;
+	atomic_t copp_id[AFE_MAX_PORTS];
+	atomic_t copp_cnt[AFE_MAX_PORTS];
+	atomic_t copp_stat[AFE_MAX_PORTS];
+	unsigned long sessions[AFE_MAX_PORTS];
+	wait_queue_head_t wait;
+};
+
+static struct adm_ctl			this_adm;
+
+static int32_t adm_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *payload;
+	int i, index;
+	payload = data->payload;
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("adm_callback: Reset event is received: %d %d apr[%p]\n",
+				data->reset_event, data->reset_proc,
+				this_adm.apr);
+		if (this_adm.apr) {
+			apr_reset(this_adm.apr);
+			for (i = 0; i < AFE_MAX_PORTS; i++) {
+				atomic_set(&this_adm.copp_id[i],
+							RESET_COPP_ID);
+				atomic_set(&this_adm.copp_cnt[i], 0);
+				atomic_set(&this_adm.copp_stat[i], 0);
+			}
+			this_adm.apr = NULL;
+		}
+		return 0;
+	}
+
+	pr_debug("%s: code = 0x%x %x %x size = %d\n", __func__,
+			data->opcode, payload[0], payload[1],
+					data->payload_size);
+
+	if (data->payload_size) {
+		index = afe_get_port_index(data->token);
+		pr_debug("%s: Port ID %d, index %d\n", __func__,
+			data->token, index);
+
+		if (data->opcode == APR_BASIC_RSP_RESULT) {
+			pr_debug("APR_BASIC_RSP_RESULT\n");
+			switch (payload[0]) {
+			case ADM_CMD_SET_PARAMS:
+#ifdef CONFIG_MSM8X60_RTAC
+				if (rtac_make_adm_callback(payload,
+						data->payload_size))
+					break;
+#endif
+			case ADM_CMD_COPP_CLOSE:
+			case ADM_CMD_MEMORY_MAP:
+			case ADM_CMD_MEMORY_UNMAP:
+			case ADM_CMD_MEMORY_MAP_REGIONS:
+			case ADM_CMD_MEMORY_UNMAP_REGIONS:
+			case ADM_CMD_MATRIX_MAP_ROUTINGS:
+				pr_debug("ADM_CMD_MATRIX_MAP_ROUTINGS\n");
+				atomic_set(&this_adm.copp_stat[index], 1);
+				wake_up(&this_adm.wait);
+				break;
+			default:
+				pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
+								payload[0]);
+				break;
+			}
+			return 0;
+		}
+
+		switch (data->opcode) {
+		case ADM_CMDRSP_COPP_OPEN: {
+			struct adm_copp_open_respond *open = data->payload;
+			if (open->copp_id == INVALID_COPP_ID) {
+				pr_err("%s: invalid coppid rxed %d\n",
+					__func__, open->copp_id);
+				atomic_set(&this_adm.copp_stat[index], 1);
+				wake_up(&this_adm.wait);
+				break;
+			}
+			atomic_set(&this_adm.copp_id[index], open->copp_id);
+			atomic_set(&this_adm.copp_stat[index], 1);
+			pr_debug("%s: coppid rxed=%d\n", __func__,
+							open->copp_id);
+			wake_up(&this_adm.wait);
+			}
+			break;
+#ifdef CONFIG_MSM8X60_RTAC
+		case ADM_CMDRSP_GET_PARAMS:
+			pr_debug("ADM_CMDRSP_GET_PARAMS\n");
+			rtac_make_adm_callback(payload,
+				data->payload_size);
+			break;
+#endif
+		default:
+			pr_err("%s: Unknown cmd:0x%x\n", __func__,
+							data->opcode);
+			break;
+		}
+	}
+	return 0;
+}
+
+void send_cal(int port_id, struct acdb_cal_block *aud_cal)
+{
+	s32				result;
+	struct adm_set_params_command	adm_params;
+	int index = afe_get_port_index(port_id);
+
+	pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+
+	if (!aud_cal || aud_cal->cal_size == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_params.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(adm_params));
+	adm_params.hdr.src_svc = APR_SVC_ADM;
+	adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+	adm_params.hdr.src_port = port_id;
+	adm_params.hdr.dest_svc = APR_SVC_ADM;
+	adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+	adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	adm_params.hdr.token = port_id;
+	adm_params.hdr.opcode = ADM_CMD_SET_PARAMS;
+	adm_params.payload = aud_cal->cal_paddr;
+	adm_params.payload_size = aud_cal->cal_size;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+	pr_debug("%s: Sending SET_PARAMS payload = 0x%x, size = %d\n",
+		__func__, adm_params.payload, adm_params.payload_size);
+	result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+	if (result < 0) {
+		pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+			__func__, port_id, aud_cal->cal_paddr);
+		goto done;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(this_adm.wait,
+		atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!result)
+		pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+			__func__, port_id, aud_cal->cal_paddr);
+done:
+	return;
+}
+
+void send_adm_cal(int port_id, int path)
+{
+	s32			acdb_path;
+	struct acdb_cal_block	aud_cal;
+
+	pr_debug("%s\n", __func__);
+
+	/* Maps audio_dev_ctrl path definition to ACDB definition */
+	acdb_path = path - 1;
+	if ((acdb_path >= NUM_AUDPROC_BUFFERS) ||
+		(acdb_path < 0)) {
+		pr_err("%s: Path is not RX or TX, path = %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	pr_debug("%s: Sending audproc cal\n", __func__);
+	get_audproc_cal(acdb_path, &aud_cal);
+	send_cal(port_id, &aud_cal);
+
+	pr_debug("%s: Sending audvol cal\n", __func__);
+	get_audvol_cal(acdb_path, &aud_cal);
+	send_cal(port_id, &aud_cal);
+done:
+	return;
+}
+
+/* This function issues routing command of ASM stream
+ * to ADM mixer associated with a particular AFE port
+ */
+int adm_cmd_map(int port_id, int session_id)
+{
+	struct adm_routings_command route;
+	int ret = 0;
+	int index = afe_get_port_index(port_id);
+
+	pr_debug("%s: port %x session %x\n", __func__, port_id, session_id);
+
+	if (!atomic_read(&this_adm.copp_cnt[index]))
+		return 0;
+
+	route.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	route.hdr.pkt_size = sizeof(route);
+	route.hdr.src_svc = 0;
+	route.hdr.src_domain = APR_DOMAIN_APPS;
+	route.hdr.src_port = port_id;
+	route.hdr.dest_svc = APR_SVC_ADM;
+	route.hdr.dest_domain = APR_DOMAIN_ADSP;
+	route.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	route.hdr.token = port_id;
+	route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
+	route.num_sessions = 1;
+	route.session[0].id = session_id;
+	route.session[0].num_copps = 1;
+	route.session[0].copp_id[0] =
+			atomic_read(&this_adm.copp_id[index]);
+
+	/* This rule can change */
+	if ((port_id & 0x1))
+		route.path = AUDIO_TX;
+	else
+		route.path = AUDIO_RX;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&route);
+	if (ret < 0) {
+		pr_err("%s: ADM routing for port %d failed\n",
+					__func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_adm.wait,
+				atomic_read(&this_adm.copp_stat[index]),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: ADM cmd Route failed for port %d\n",
+					__func__, port_id);
+		ret = -EINVAL;
+	}
+
+fail_cmd:
+	return ret;
+}
+
+/* This function establish routing of ASM stream to a particular
+ * ADM mixer that is routed to a particular hardware port
+ * session id must be in range of 0 ~ 31.
+ */
+int adm_route_session(int port_id, uint session_id, int set)
+{
+	int rc = 0;
+	int index;
+
+	pr_debug("%s: port %x session %x set %x\n", __func__,
+		port_id, session_id, set);
+
+	index = afe_get_port_index(port_id);
+
+	if (index >= AFE_MAX_PORTS) {
+		pr_err("%s port idi[%d] out of limit[%d]\n", __func__,
+						port_id, AFE_MAX_PORTS);
+		return -ENODEV;
+	}
+
+	if (set) {
+		set_bit(session_id, &this_adm.sessions[index]);
+		rc = adm_cmd_map(port_id, session_id); /* not thread safe */
+	} else /* Not sure how to deroute yet */
+		clear_bit(session_id, &this_adm.sessions[index]);
+
+	return rc;
+}
+
+/* This function instantiates a mixer in QDSP6 audio path for
+ * given audio hardware port. Topology should be made part
+ * of audio calibration
+ */
+int adm_open_mixer(int port_id, int path, int rate,
+	int channel_mode, int topology) {
+	struct adm_copp_open_command open;
+	int ret = 0;
+	u32 i;
+	int index;
+
+	pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+				port_id, path, rate, channel_mode);
+
+	if (afe_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+
+	index = afe_get_port_index(port_id);
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		open.hdr.pkt_size = sizeof(open);
+		open.hdr.src_svc = APR_SVC_ADM;
+		open.hdr.src_domain = APR_DOMAIN_APPS;
+		open.hdr.src_port = port_id;
+		open.hdr.dest_svc = APR_SVC_ADM;
+		open.hdr.dest_domain = APR_DOMAIN_ADSP;
+		open.hdr.dest_port = port_id;
+		open.hdr.token = port_id;
+		open.hdr.opcode = ADM_CMD_COPP_OPEN;
+
+		open.mode = path;
+		open.endpoint_id1 = port_id;
+		open.endpoint_id2 = 0xFFFF;
+
+		open.topology_id = get_adm_topology();
+		if (open.topology_id  == 0)
+			open.topology_id = topology;
+
+		open.channel_config = channel_mode & 0x00FF;
+		open.rate  = rate;
+
+		pr_debug("%s: channel_config=%d port_id=%d rate=%d\
+			topology_id=0x%X\n", __func__, open.channel_config,\
+			open.endpoint_id1, open.rate,\
+			open.topology_id);
+
+		atomic_set(&this_adm.copp_stat[index], 0);
+
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+		if (ret < 0) {
+			pr_err("%s:ADM enable for port %d failed\n",
+						__func__, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+		/* Wait for the callback with copp id */
+		ret = wait_event_timeout(this_adm.wait,
+			atomic_read(&this_adm.copp_stat[index]),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s ADM open failed for port %d\n", __func__,
+								port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+	}
+	atomic_inc(&this_adm.copp_cnt[index]);
+
+	/* Set up routing for cached session */
+	for (i = find_first_bit(&this_adm.sessions[index], ASM_MAX_SESSION);
+	     i < ASM_MAX_SESSION; i = find_next_bit(&this_adm.sessions[index],
+	     ASM_MAX_SESSION, i + 1))
+		adm_cmd_map(port_id, i); /* Not thread safe */
+
+fail_cmd:
+	return ret;
+}
+
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
+{
+	struct adm_copp_open_command	open;
+	int ret = 0;
+	int index;
+
+	pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+				port_id, path, rate, channel_mode);
+
+	if (afe_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+
+	index = afe_get_port_index(port_id);
+	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+#ifdef CONFIG_MSM8X60_RTAC
+		rtac_set_adm_handle(this_adm.apr);
+#endif
+	}
+
+
+	/* Create a COPP if port id are not enabled */
+	if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		open.hdr.pkt_size = sizeof(open);
+		open.hdr.src_svc = APR_SVC_ADM;
+		open.hdr.src_domain = APR_DOMAIN_APPS;
+		open.hdr.src_port = port_id;
+		open.hdr.dest_svc = APR_SVC_ADM;
+		open.hdr.dest_domain = APR_DOMAIN_ADSP;
+		open.hdr.dest_port = port_id;
+		open.hdr.token = port_id;
+		open.hdr.opcode = ADM_CMD_COPP_OPEN;
+
+		open.mode = path;
+		open.endpoint_id1 = port_id;
+		open.endpoint_id2 = 0xFFFF;
+
+		open.topology_id = get_adm_topology();
+		if (open.topology_id  == 0)
+			open.topology_id = topology;
+
+		open.channel_config = channel_mode & 0x00FF;
+		open.rate  = rate;
+
+		pr_debug("%s: channel_config=%d port_id=%d rate=%d\
+			topology_id=0x%X\n", __func__, open.channel_config,\
+			open.endpoint_id1, open.rate,\
+			open.topology_id);
+
+		atomic_set(&this_adm.copp_stat[index], 0);
+
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+		if (ret < 0) {
+			pr_err("%s:ADM enable for port %d failed\n",
+						__func__, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+		/* Wait for the callback with copp id */
+		ret = wait_event_timeout(this_adm.wait,
+			atomic_read(&this_adm.copp_stat[index]),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s ADM open failed for port %d\n", __func__,
+								port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+	}
+	atomic_inc(&this_adm.copp_cnt[index]);
+	return 0;
+
+fail_cmd:
+
+	return ret;
+}
+
+int adm_matrix_map(int session_id, int path, int num_copps,
+			unsigned int *port_id, int copp_id)
+{
+	struct adm_routings_command	route;
+	int ret = 0, i = 0;
+	/* Assumes port_ids have already been validated during adm_open */
+	int index = afe_get_port_index(copp_id);
+
+	pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%d\n",
+		 __func__, session_id, path, num_copps, port_id[0]);
+
+	route.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	route.hdr.pkt_size = sizeof(route);
+	route.hdr.src_svc = 0;
+	route.hdr.src_domain = APR_DOMAIN_APPS;
+	route.hdr.src_port = copp_id;
+	route.hdr.dest_svc = APR_SVC_ADM;
+	route.hdr.dest_domain = APR_DOMAIN_ADSP;
+	route.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	route.hdr.token = copp_id;
+	route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
+	route.num_sessions = 1;
+	route.session[0].id = session_id;
+	route.session[0].num_copps = num_copps;
+
+	for (i = 0; i < num_copps; i++) {
+		int tmp;
+		tmp = afe_get_port_index(port_id[i]);
+
+		pr_debug("%s: port_id[%d]: %d, index: %d\n", __func__, i,
+			 port_id[i], tmp);
+
+		route.session[0].copp_id[i] =
+					atomic_read(&this_adm.copp_id[tmp]);
+	}
+	if (num_copps % 2)
+		route.session[0].copp_id[i] = 0;
+
+	switch (path) {
+	case 0x1:
+		route.path = AUDIO_RX;
+		break;
+	case 0x2:
+	case 0x3:
+		route.path = AUDIO_TX;
+		break;
+	default:
+		pr_err("%s: Wrong path set[%d]\n", __func__, path);
+		break;
+	}
+	atomic_set(&this_adm.copp_stat[index], 0);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&route);
+	if (ret < 0) {
+		pr_err("%s: ADM routing for port %d failed\n",
+					__func__, port_id[0]);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_adm.wait,
+				atomic_read(&this_adm.copp_stat[index]),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: ADM cmd Route failed for port %d\n",
+					__func__, port_id[0]);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	for (i = 0; i < num_copps; i++)
+		send_adm_cal(port_id[i], path);
+
+#ifdef CONFIG_MSM8X60_RTAC
+	for (i = 0; i < num_copps; i++)
+		rtac_add_adm_device(port_id[i], session_id);
+#endif
+	return 0;
+
+fail_cmd:
+
+	return ret;
+}
+
+int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
+				uint32_t *bufsz, uint32_t bufcnt)
+{
+	struct  adm_cmd_memory_map_regions *mmap_regions = NULL;
+	struct  adm_memory_map_regions *mregions = NULL;
+	void    *mmap_region_cmd = NULL;
+	void    *payload = NULL;
+	int     ret = 0;
+	int     i = 0;
+	int     cmd_size = 0;
+
+	pr_info("%s\n", __func__);
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+#ifdef CONFIG_MSM8X60_RTAC
+		rtac_set_adm_handle(this_adm.apr);
+#endif
+	}
+
+	cmd_size = sizeof(struct adm_cmd_memory_map_regions)
+			+ sizeof(struct adm_memory_map_regions) * bufcnt;
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!mmap_region_cmd) {
+		pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+		return -ENOMEM;
+	}
+	mmap_regions = (struct adm_cmd_memory_map_regions *)mmap_region_cmd;
+	mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+								APR_PKT_VER);
+	mmap_regions->hdr.pkt_size = cmd_size;
+	mmap_regions->hdr.src_port = 0;
+	mmap_regions->hdr.dest_port = 0;
+	mmap_regions->hdr.token = 0;
+	mmap_regions->hdr.opcode = ADM_CMD_MEMORY_MAP_REGIONS;
+	mmap_regions->mempool_id = mempool_id & 0x00ff;
+	mmap_regions->nregions = bufcnt & 0x00ff;
+	pr_debug("%s: map_regions->nregions = %d\n", __func__,
+				mmap_regions->nregions);
+	payload = ((u8 *) mmap_region_cmd +
+				sizeof(struct adm_cmd_memory_map_regions));
+	mregions = (struct adm_memory_map_regions *)payload;
+
+	for (i = 0; i < bufcnt; i++) {
+		mregions->phys = buf_add[i];
+		mregions->buf_size = bufsz[i];
+		++mregions;
+	}
+
+	atomic_set(&this_adm.copp_stat[0], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
+	if (ret < 0) {
+		pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+					mmap_regions->hdr.opcode, ret);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_adm.wait,
+			atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+	if (!ret) {
+		pr_err("%s: timeout. waited for memory_map\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+fail_cmd:
+	kfree(mmap_region_cmd);
+	return ret;
+}
+
+int adm_memory_unmap_regions(uint32_t *buf_add, uint32_t *bufsz,
+						uint32_t bufcnt)
+{
+	struct  adm_cmd_memory_unmap_regions *unmap_regions = NULL;
+	struct  adm_memory_unmap_regions *mregions = NULL;
+	void    *unmap_region_cmd = NULL;
+	void    *payload = NULL;
+	int     ret = 0;
+	int     i = 0;
+	int     cmd_size = 0;
+
+	pr_info("%s\n", __func__);
+
+	if (this_adm.apr == NULL) {
+		pr_err("%s APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	cmd_size = sizeof(struct adm_cmd_memory_unmap_regions)
+			+ sizeof(struct adm_memory_unmap_regions) * bufcnt;
+
+	unmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!unmap_region_cmd) {
+		pr_err("%s: allocate unmap_region_cmd failed\n", __func__);
+		return -ENOMEM;
+	}
+	unmap_regions = (struct adm_cmd_memory_unmap_regions *)
+						unmap_region_cmd;
+	unmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+							APR_PKT_VER);
+	unmap_regions->hdr.pkt_size = cmd_size;
+	unmap_regions->hdr.src_port = 0;
+	unmap_regions->hdr.dest_port = 0;
+	unmap_regions->hdr.token = 0;
+	unmap_regions->hdr.opcode = ADM_CMD_MEMORY_UNMAP_REGIONS;
+	unmap_regions->nregions = bufcnt & 0x00ff;
+	unmap_regions->reserved = 0;
+	pr_debug("%s: unmap_regions->nregions = %d\n", __func__,
+				unmap_regions->nregions);
+	payload = ((u8 *) unmap_region_cmd +
+			sizeof(struct adm_cmd_memory_unmap_regions));
+	mregions = (struct adm_memory_unmap_regions *)payload;
+
+	for (i = 0; i < bufcnt; i++) {
+		mregions->phys = buf_add[i];
+		++mregions;
+	}
+	atomic_set(&this_adm.copp_stat[0], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *) unmap_region_cmd);
+	if (ret < 0) {
+		pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+				unmap_regions->hdr.opcode, ret);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_adm.wait,
+			atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+	if (!ret) {
+		pr_err("%s: timeout. waited for memory_unmap\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+fail_cmd:
+	kfree(unmap_region_cmd);
+	return ret;
+}
+
+#ifdef CONFIG_MSM8X60_RTAC
+int adm_get_copp_id(int port_id)
+{
+	pr_debug("%s\n", __func__);
+
+	if (port_id < 0) {
+		pr_err("%s: invalid port_id = %d\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	return atomic_read(&this_adm.copp_id[port_id]);
+}
+#endif
+
+int adm_close(int port_id)
+{
+	struct apr_hdr close;
+
+	int ret = 0;
+	int index = afe_get_port_index(port_id);
+
+	pr_info("%s port_id=%d index %d\n", __func__, port_id, index);
+
+	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+		pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+
+		goto fail_cmd;
+	}
+	atomic_dec(&this_adm.copp_cnt[index]);
+	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+
+		close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		close.pkt_size = sizeof(close);
+		close.src_svc = APR_SVC_ADM;
+		close.src_domain = APR_DOMAIN_APPS;
+		close.src_port = port_id;
+		close.dest_svc = APR_SVC_ADM;
+		close.dest_domain = APR_DOMAIN_ADSP;
+		close.dest_port = atomic_read(&this_adm.copp_id[index]);
+		close.token = port_id;
+		close.opcode = ADM_CMD_COPP_CLOSE;
+
+		atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
+		atomic_set(&this_adm.copp_stat[index], 0);
+
+
+		pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+				__func__,
+				atomic_read(&this_adm.copp_id[index]),
+				port_id, index,
+				atomic_read(&this_adm.copp_cnt[index]));
+
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
+		if (ret < 0) {
+			pr_err("%s ADM close failed\n", __func__);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+
+		ret = wait_event_timeout(this_adm.wait,
+				atomic_read(&this_adm.copp_stat[index]),
+				msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: ADM cmd Route failed for port %d\n",
+						__func__, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+
+#ifdef CONFIG_MSM8X60_RTAC
+		rtac_remove_adm_device(port_id);
+#endif
+	}
+
+fail_cmd:
+	return ret;
+}
+
+static int __init adm_init(void)
+{
+	int i = 0;
+	init_waitqueue_head(&this_adm.wait);
+	this_adm.apr = NULL;
+
+	for (i = 0; i < AFE_MAX_PORTS; i++) {
+		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+		atomic_set(&this_adm.copp_cnt[i], 0);
+		atomic_set(&this_adm.copp_stat[i], 0);
+	}
+	return 0;
+}
+
+device_initcall(adm_init);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
new file mode 100644
index 0000000..500ceb5
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -0,0 +1,868 @@
+/*  Copyright (c) 2010-2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+
+struct afe_ctl {
+	void *apr;
+	atomic_t state;
+	atomic_t status;
+	wait_queue_head_t wait;
+	struct task_struct *task;
+};
+
+static struct afe_ctl this_afe;
+
+#define TIMEOUT_MS 1000
+#define Q6AFE_MAX_VOLUME 0x3FFF
+
+#define SIZEOF_CFG_CMD(y) \
+		(sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+
+static int32_t afe_callback(struct apr_client_data *data, void *priv)
+{
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("q6afe: reset event = %d %d apr[%p]\n",
+			data->reset_event, data->reset_proc, this_afe.apr);
+		if (this_afe.apr) {
+			apr_reset(this_afe.apr);
+			atomic_set(&this_afe.state, 0);
+			this_afe.apr = NULL;
+		}
+		/* send info to user */
+		pr_debug("task_name = %s pid = %d\n",
+			this_afe.task->comm, this_afe.task->pid);
+		send_sig(SIGUSR1, this_afe.task, 0);
+	}
+	if (data->payload_size) {
+		uint32_t *payload;
+		payload = data->payload;
+		pr_debug("%s: cmd = 0x%x status = 0x%x\n", __func__,
+					payload[0], payload[1]);
+		/* payload[1] contains the error status for response */
+		if (payload[1] != 0) {
+			atomic_set(&this_afe.status, -1);
+			pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+					__func__, payload[0], payload[1]);
+		}
+		if (data->opcode == APR_BASIC_RSP_RESULT) {
+			switch (payload[0]) {
+			case AFE_PORT_AUDIO_IF_CONFIG:
+			case AFE_PORT_CMD_STOP:
+			case AFE_PORT_CMD_START:
+			case AFE_PORT_CMD_LOOPBACK:
+			case AFE_PORT_CMD_SIDETONE_CTL:
+			case AFE_PORT_CMD_SET_PARAM:
+			case AFE_PSEUDOPORT_CMD_START:
+			case AFE_PSEUDOPORT_CMD_STOP:
+				atomic_set(&this_afe.state, 0);
+				wake_up(&this_afe.wait);
+				break;
+			default:
+				pr_err("Unknown cmd 0x%x\n",
+						payload[0]);
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+int afe_validate_port(u16 port_id)
+{
+	int ret;
+
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
+	case PCM_RX:
+	case PCM_TX:
+	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
+	case MI2S_RX:
+	case MI2S_TX:
+	case HDMI_RX:
+	case RSVD_2:
+	case RSVD_3:
+	case DIGI_MIC_TX:
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+	case VOICE_PLAYBACK_TX:
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+	case INT_BT_SCO_RX:
+	case INT_BT_SCO_TX:
+	case INT_BT_A2DP_RX:
+	case INT_FM_RX:
+	case INT_FM_TX:
+	{
+		ret = 0;
+		break;
+	}
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int afe_get_port_index(u16 port_id)
+{
+	switch (port_id) {
+	case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
+	case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
+	case PCM_RX: return IDX_PCM_RX;
+	case PCM_TX: return IDX_PCM_TX;
+	case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
+	case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
+	case MI2S_RX: return IDX_MI2S_RX;
+	case MI2S_TX: return IDX_MI2S_TX;
+	case HDMI_RX: return IDX_HDMI_RX;
+	case RSVD_2: return IDX_RSVD_2;
+	case RSVD_3: return IDX_RSVD_3;
+	case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
+	case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
+	case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
+	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 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;
+	case INT_FM_RX: return IDX_INT_FM_RX;
+	case INT_FM_TX: return IDX_INT_FM_TX;
+
+	default: return -EINVAL;
+	}
+}
+
+int afe_sizeof_cfg_cmd(u16 port_id)
+{
+	int ret_size;
+	switch (port_id) {
+	case PRIMARY_I2S_RX:
+	case PRIMARY_I2S_TX:
+	case SECONDARY_I2S_RX:
+	case SECONDARY_I2S_TX:
+	case MI2S_RX:
+	case MI2S_TX:
+		ret_size = SIZEOF_CFG_CMD(afe_port_mi2s_cfg);
+		break;
+	case HDMI_RX:
+		ret_size = SIZEOF_CFG_CMD(afe_port_hdmi_cfg);
+		break;
+	case SLIMBUS_0_RX:
+	case SLIMBUS_0_TX:
+		ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_cfg);
+		break;
+	case PCM_RX:
+	case PCM_TX:
+	default:
+		ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
+		break;
+	}
+	return ret_size;
+}
+
+int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+	u32 rate) /* This function is no blocking */
+{
+	struct afe_port_start_command start;
+	struct afe_audioif_config_command config;
+	int ret;
+
+	if (!afe_config) {
+		pr_err("%s: Error, no configuration data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	pr_info("%s: %d %d\n", __func__, port_id, rate);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_info("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = 0;
+	config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+
+	if (afe_validate_port(port_id) < 0) {
+
+		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	config.port_id = port_id;
+	config.port = *afe_config;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PORT_CMD_START;
+	start.port_id = port_id;
+	start.gain = 0x2000;
+	start.sample_rate = rate;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	if (this_afe.task != current)
+		this_afe.task = current;
+
+	pr_debug("task_name = %s pid = %d\n",
+	this_afe.task->comm, this_afe.task->pid);
+	return 0;
+
+fail_cmd:
+	return ret;
+}
+
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate)
+{
+	struct afe_port_start_command start;
+	struct afe_audioif_config_command config;
+	int ret = 0;
+
+	if (!afe_config) {
+		pr_err("%s: Error, no configuration data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	pr_info("%s: %d %d\n", __func__, port_id, rate);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_info("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = 0;
+	config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+
+	if (afe_validate_port(port_id) < 0) {
+
+		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	config.port_id = port_id;
+	config.port = *afe_config;
+
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+			(atomic_read(&this_afe.state) == 0),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PORT_CMD_START;
+	start.port_id = port_id;
+	start.gain = 0x2000;
+	start.sample_rate = rate;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_afe.wait,
+			(atomic_read(&this_afe.state) == 0),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	if (this_afe.task != current)
+		this_afe.task = current;
+
+	pr_debug("task_name = %s pid = %d\n",
+			this_afe.task->comm, this_afe.task->pid);
+	return 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+{
+	struct afe_loopback_command lb_cmd;
+	int ret = 0;
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_info("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+	lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(20), APR_PKT_VER);
+	lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(lb_cmd) - APR_HDR_SIZE);
+	lb_cmd.hdr.src_port = 0;
+	lb_cmd.hdr.dest_port = 0;
+	lb_cmd.hdr.token = 0;
+	lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
+	lb_cmd.tx_port_id = tx_port;
+	lb_cmd.rx_port_id = rx_port;
+	lb_cmd.mode = 0xFFFF;
+	lb_cmd.enable = (enable ? 1 : 0);
+	atomic_set(&this_afe.state, 1);
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
+	if (ret < 0) {
+		pr_err("%s: AFE loopback failed\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	ret = wait_event_timeout(this_afe.wait,
+		(atomic_read(&this_afe.state) == 0),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+	}
+done:
+	return ret;
+}
+
+
+int afe_loopback_gain(u16 port_id, u16 volume)
+{
+	struct afe_port_cmd_set_param set_param;
+	int ret = 0;
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE is not opened\n", __func__);
+		ret = -EPERM;
+		goto fail_cmd;
+	}
+
+	if (afe_validate_port(port_id) < 0) {
+
+		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+				port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	/* RX ports numbers are even .TX ports numbers are odd. */
+	if (port_id % 2 == 0) {
+		pr_err("%s: Failed : afe loopback gain only for TX ports."
+			" port_id %d\n", __func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	pr_debug("%s: %d %hX\n", __func__, port_id, volume);
+
+	set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	set_param.hdr.pkt_size = sizeof(set_param);
+	set_param.hdr.src_port = 0;
+	set_param.hdr.dest_port = 0;
+	set_param.hdr.token = 0;
+	set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+	set_param.port_id		= port_id;
+	set_param.payload_size		= sizeof(struct afe_param_payload);
+	set_param.payload_address	= 0;
+
+	set_param.payload.module_id	= AFE_MODULE_ID_PORT_INFO;
+	set_param.payload.param_id	= AFE_PARAM_ID_LOOPBACK_GAIN;
+	set_param.payload.param_size = sizeof(struct afe_param_loopback_gain);
+	set_param.payload.reserved	= 0;
+
+	set_param.payload.param.loopback_gain.gain		= volume;
+	set_param.payload.param.loopback_gain.reserved	= 0;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
+	if (ret < 0) {
+		pr_err("%s: AFE param set failed for port %d\n",
+					__func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+		(atomic_read(&this_afe.state) == 0),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (ret < 0) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_start_pseudo_port(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_start_command start;
+
+	pr_info("%s: port_id=%d\n", __func__, port_id);
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					0xFFFFFFFF, &this_afe);
+		pr_info("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+	start.port_id = port_id;
+	start.timing = 1;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed %d\n",
+		       __func__, port_id, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	return 0;
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_stop_command stop;
+
+	pr_info("%s: port_id=%d\n", __func__, port_id);
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE is already closed\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+	if (ret < 0) {
+		pr_err("%s: AFE close failed %d\n", __func__, ret);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_afelb;
+static struct dentry *debugfs_afelb_gain;
+
+static int afe_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	pr_info("debug intf %s\n", (char *) file->private_data);
+	return 0;
+}
+
+static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else
+			return -EINVAL;
+	}
+	return 0;
+}
+#define AFE_LOOPBACK_ON (1)
+#define AFE_LOOPBACK_OFF (0)
+static ssize_t afe_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char lbuf[32];
+	int rc;
+	unsigned long param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+
+	if (!strcmp(lb_str, "afe_loopback")) {
+		rc = afe_get_parameters(lbuf, param, 3);
+		if (!rc) {
+			pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
+				param[2]);
+
+			if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
+				AFE_LOOPBACK_OFF)) {
+				pr_err("%s: Error, parameter 0 incorrect\n",
+					__func__);
+				rc = -EINVAL;
+				goto afe_error;
+			}
+			if ((afe_validate_port(param[1]) < 0) ||
+			    (afe_validate_port(param[2])) < 0) {
+				pr_err("%s: Error, invalid afe port\n",
+					__func__);
+			}
+			if (this_afe.apr == NULL) {
+				pr_err("%s: Error, AFE not opened\n", __func__);
+				rc = -EINVAL;
+			} else {
+				rc = afe_loopback(param[0], param[1], param[2]);
+			}
+		} else {
+			pr_err("%s: Error, invalid parameters\n", __func__);
+			rc = -EINVAL;
+		}
+
+	} else if (!strcmp(lb_str, "afe_loopback_gain")) {
+		rc = afe_get_parameters(lbuf, param, 2);
+		if (!rc) {
+			pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
+
+			if (afe_validate_port(param[0]) < 0) {
+				pr_err("%s: Error, invalid afe port\n",
+					__func__);
+				rc = -EINVAL;
+				goto afe_error;
+			}
+
+			if (param[1] < 0 || param[1] > 100) {
+				pr_err("%s: Error, volume shoud be 0 to 100"
+					" percentage param = %lu\n",
+					__func__, param[1]);
+				rc = -EINVAL;
+				goto afe_error;
+			}
+
+			param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
+
+			if (this_afe.apr == NULL) {
+				pr_err("%s: Error, AFE not opened\n", __func__);
+				rc = -EINVAL;
+			} else {
+				rc = afe_loopback_gain(param[0], param[1]);
+			}
+		} else {
+			pr_err("%s: Error, invalid parameters\n", __func__);
+			rc = -EINVAL;
+		}
+	}
+
+afe_error:
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations afe_debug_fops = {
+	.open = afe_debug_open,
+	.write = afe_debug_write
+};
+#endif
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+{
+	struct afe_port_sidetone_command cmd_sidetone;
+	int ret = 0;
+
+	pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
+					tx_port_id, rx_port_id, enable, gain);
+	cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
+	cmd_sidetone.hdr.src_port = 0;
+	cmd_sidetone.hdr.dest_port = 0;
+	cmd_sidetone.hdr.token = 0;
+	cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SIDETONE_CTL;
+	cmd_sidetone.tx_port_id = tx_port_id;
+	cmd_sidetone.rx_port_id = rx_port_id;
+	cmd_sidetone.gain = gain;
+	cmd_sidetone.enable = enable;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
+	if (ret < 0) {
+		pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
+					__func__, tx_port_id, rx_port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+		(atomic_read(&this_afe.state) == 0),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (ret < 0) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_port_stop_nowait(int port_id)
+{
+	struct afe_port_stop_command stop;
+	int ret = 0;
+
+	if (this_afe.apr == NULL) {
+		pr_err("AFE is already closed\n");
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	pr_info("%s: port_id=%d\n", __func__, port_id);
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PORT_CMD_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+	if (ret == -ENETRESET) {
+		pr_info("%s: Need to reset, calling APR deregister", __func__);
+		return apr_deregister(this_afe.apr);
+	} else if (IS_ERR_VALUE(ret)) {
+		pr_err("%s: AFE close failed\n", __func__);
+		ret = -EINVAL;
+	}
+
+fail_cmd:
+	return ret;
+
+}
+
+int afe_close(int port_id)
+{
+	struct afe_port_stop_command stop;
+	int ret = 0;
+
+	if (this_afe.apr == NULL) {
+		pr_err("AFE is already closed\n");
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	pr_info("%s: port_id=%d\n", __func__, port_id);
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PORT_CMD_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+	if (ret == -ENETRESET) {
+		pr_info("%s: Need to reset, calling APR deregister", __func__);
+		return apr_deregister(this_afe.apr);
+	}
+
+	if (ret < 0) {
+		pr_err("%s: AFE close failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+			(atomic_read(&this_afe.state) == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+fail_cmd:
+	return ret;
+}
+
+static int __init afe_init(void)
+{
+	init_waitqueue_head(&this_afe.wait);
+	atomic_set(&this_afe.state, 0);
+	atomic_set(&this_afe.status, 0);
+	this_afe.apr = NULL;
+#ifdef CONFIG_DEBUG_FS
+	debugfs_afelb = debugfs_create_file("afe_loopback",
+	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+	&afe_debug_fops);
+
+	debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
+	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+	&afe_debug_fops);
+
+
+#endif
+	return 0;
+}
+
+static void __exit afe_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	if (debugfs_afelb)
+		debugfs_remove(debugfs_afelb);
+	if (debugfs_afelb_gain)
+		debugfs_remove(debugfs_afelb_gain);
+#endif
+}
+
+device_initcall(afe_init);
+__exitcall(afe_exit);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
new file mode 100644
index 0000000..f5f1c63
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -0,0 +1,2600 @@
+
+/*
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/msm_subsystem_map.h>
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#define TRUE        0x01
+#define FALSE       0x00
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFFER 1
+#define READDONE_IDX_SIZE 2
+#define READDONE_IDX_OFFSET 3
+#define READDONE_IDX_MSW_TS 4
+#define READDONE_IDX_LSW_TS 5
+#define READDONE_IDX_FLAGS 6
+#define READDONE_IDX_NUMFRAMES 7
+#define READDONE_IDX_ID 8
+
+static DEFINE_MUTEX(session_lock);
+
+/* session id: 0 reserved */
+static struct audio_client *session[SESSION_MAX+1];
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg);
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt);
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt);
+
+static void q6asm_reset_buf_state(struct audio_client *ac);
+
+struct asm_mmap {
+	atomic_t ref_cnt;
+	atomic_t cmd_state;
+	wait_queue_head_t cmd_wait;
+	void *apr;
+};
+
+static struct asm_mmap this_mmap;
+
+static int q6asm_session_alloc(struct audio_client *ac)
+{
+	int n;
+	mutex_lock(&session_lock);
+	for (n = 1; n <= SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void q6asm_session_free(struct audio_client *ac)
+{
+	pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
+	mutex_lock(&session_lock);
+	session[ac->session] = 0;
+	mutex_unlock(&session_lock);
+	ac->session = 0;
+	return;
+}
+
+int q6asm_audio_client_buf_free(unsigned int dir,
+			struct audio_client *ac)
+{
+	struct audio_port_data *port;
+	int cnt = 0;
+	int rc = 0;
+	pr_debug("%s: Session id %d\n", __func__, ac->session);
+	mutex_lock(&ac->cmd_lock);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[dir];
+		if (!port->buf) {
+			mutex_unlock(&ac->cmd_lock);
+			return 0;
+		}
+		cnt = port->max_buf_cnt - 1;
+
+		if (cnt >= 0) {
+			rc = q6asm_memory_unmap_regions(ac, dir,
+							port->buf[0].size,
+							port->max_buf_cnt);
+			if (rc < 0)
+				pr_err("%s CMD Memory_unmap_regions failed\n",
+								__func__);
+		}
+
+		while (cnt >= 0) {
+			if (port->buf[cnt].data) {
+				pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]"
+					 "mem_buffer[%p]\n",
+					__func__, (void *)port->buf[cnt].data,
+					   (void *)port->buf[cnt].phys,
+					   (void *)&port->buf[cnt].phys, cnt,
+					   (void *)port->buf[cnt].mem_buffer);
+				if (IS_ERR((void *)port->buf[cnt].mem_buffer))
+					pr_err("%s:mem buffer invalid, error ="
+						 "%ld\n", __func__,
+				PTR_ERR((void *)port->buf[cnt].mem_buffer));
+				else {
+					if (msm_subsystem_unmap_buffer(
+						port->buf[cnt].mem_buffer) < 0)
+						pr_err("%s: unmap buffer"
+							" failed\n", __func__);
+				}
+				free_contiguous_memory_by_paddr(
+					port->buf[cnt].phys);
+
+				port->buf[cnt].data = NULL;
+				port->buf[cnt].phys = 0;
+				--(port->max_buf_cnt);
+			}
+			--cnt;
+		}
+		kfree(port->buf);
+		port->buf = NULL;
+	}
+	mutex_unlock(&ac->cmd_lock);
+	return 0;
+}
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+			struct audio_client *ac)
+{
+	struct audio_port_data *port;
+	int cnt = 0;
+	int rc = 0;
+	pr_debug("%s: Session id %d\n", __func__, ac->session);
+	mutex_lock(&ac->cmd_lock);
+	port = &ac->port[dir];
+	if (!port->buf) {
+		mutex_unlock(&ac->cmd_lock);
+		return 0;
+	}
+	cnt = port->max_buf_cnt - 1;
+
+	if (cnt >= 0) {
+		rc = q6asm_memory_unmap(ac, port->buf[0].size, dir);
+		if (rc < 0)
+			pr_err("%s CMD Memory_unmap_regions failed\n",
+							__func__);
+	}
+
+	if (port->buf[0].data) {
+		pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]\n",
+			   __func__,
+			   (void *)port->buf[0].data,
+			   (void *)port->buf[0].phys,
+			   (void *)&port->buf[0].phys, cnt);
+		dma_free_coherent(NULL,
+			port->buf[0].size * port->max_buf_cnt,
+			port->buf[0].data,
+				port->buf[0].phys);
+	}
+	while (cnt >= 0) {
+		port->buf[cnt].data = NULL;
+		port->buf[cnt].phys = 0;
+		cnt--;
+	}
+	port->max_buf_cnt = 0;
+	kfree(port->buf);
+	port->buf = NULL;
+	mutex_unlock(&ac->cmd_lock);
+	return 0;
+}
+
+void q6asm_audio_client_free(struct audio_client *ac)
+{
+	int loopcnt;
+	struct audio_port_data *port;
+	if (!ac || !ac->session)
+		return;
+	pr_debug("%s: Session id %d\n", __func__, ac->session);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+			port = &ac->port[loopcnt];
+			if (!port->buf)
+				continue;
+			pr_debug("%s:loopcnt = %d\n", __func__, loopcnt);
+			q6asm_audio_client_buf_free(loopcnt, ac);
+		}
+	}
+
+	apr_deregister(ac->apr);
+	q6asm_session_free(ac);
+
+	pr_debug("%s: APR De-Register\n", __func__);
+	if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+		pr_err("%s: APR Common Port Already Closed\n", __func__);
+		goto done;
+	}
+
+	atomic_dec(&this_mmap.ref_cnt);
+	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+		apr_deregister(this_mmap.apr);
+		pr_debug("%s:APR De-Register common port\n", __func__);
+	}
+done:
+	kfree(ac);
+	return;
+}
+
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode)
+{
+	if (ac == NULL) {
+		pr_err("%s APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
+		ac->io_mode = mode;
+		pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+		return 0;
+	} else {
+		pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
+		return -EINVAL;
+	}
+}
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
+{
+	struct audio_client *ac;
+	int n;
+	int lcnt = 0;
+
+	ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
+	if (!ac)
+		return NULL;
+	n = q6asm_session_alloc(ac);
+	if (n <= 0)
+		goto fail_session;
+	ac->session = n;
+	ac->cb = cb;
+	ac->priv = priv;
+	ac->io_mode = SYNC_IO_MODE;
+	ac->apr = apr_register("ADSP", "ASM", \
+				(apr_fn)q6asm_callback,\
+				((ac->session) << 8 | 0x0001),\
+				ac);
+
+	if (ac->apr == NULL) {
+		pr_err("%s Registration with APR failed\n", __func__);
+			goto fail;
+	}
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_set_asm_handle(n, ac->apr);
+#endif
+	pr_debug("%s Registering the common port with APR\n", __func__);
+	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+		this_mmap.apr = apr_register("ADSP", "ASM", \
+					(apr_fn)q6asm_mmapcallback,\
+					0x0FFFFFFFF, &this_mmap);
+		if (this_mmap.apr == NULL) {
+			pr_debug("%s Unable to register \
+				APR ASM common port \n", __func__);
+			goto fail;
+		}
+	}
+
+	atomic_inc(&this_mmap.ref_cnt);
+	init_waitqueue_head(&ac->cmd_wait);
+	init_waitqueue_head(&ac->time_wait);
+	atomic_set(&ac->time_flag, 1);
+	mutex_init(&ac->cmd_lock);
+	for (lcnt = 0; lcnt <= OUT; lcnt++) {
+		mutex_init(&ac->port[lcnt].lock);
+		spin_lock_init(&ac->port[lcnt].dsp_lock);
+	}
+	atomic_set(&ac->cmd_state, 0);
+
+	pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+	return ac;
+fail:
+	q6asm_audio_client_free(ac);
+	return NULL;
+fail_session:
+	kfree(ac);
+	return NULL;
+}
+
+int q6asm_audio_client_buf_alloc(unsigned int dir,
+			struct audio_client *ac,
+			unsigned int bufsz,
+			unsigned int bufcnt)
+{
+	int cnt = 0;
+	int rc = 0;
+	struct audio_buffer *buf;
+
+	if (!(ac) || ((dir != IN) && (dir != OUT)))
+		return -EINVAL;
+
+	pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
+		bufsz, bufcnt);
+
+	if (ac->session <= 0 || ac->session > 8)
+		goto fail;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		if (ac->port[dir].buf) {
+			pr_debug("%s: buffer already allocated\n", __func__);
+			return 0;
+		}
+		mutex_lock(&ac->cmd_lock);
+		buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+				GFP_KERNEL);
+
+		if (!buf) {
+			mutex_unlock(&ac->cmd_lock);
+			goto fail;
+		}
+
+		ac->port[dir].buf = buf;
+
+		while (cnt < bufcnt) {
+			if (bufsz > 0) {
+				if (!buf[cnt].data) {
+					unsigned int flags = 0;
+					buf[cnt].phys =
+					allocate_contiguous_ebi_nomap(bufsz,
+						SZ_4K);
+					if (!buf[cnt].phys) {
+						pr_err("%s:Buf alloc failed "
+						" size=%d\n", __func__,
+						bufsz);
+						mutex_unlock(&ac->cmd_lock);
+						goto fail;
+					}
+					flags = MSM_SUBSYSTEM_MAP_KADDR |
+						MSM_SUBSYSTEM_MAP_CACHED;
+					buf[cnt].mem_buffer =
+					msm_subsystem_map_buffer(buf[cnt].phys,
+						bufsz, flags, NULL, 0);
+					if (IS_ERR(
+						(void *)buf[cnt].mem_buffer)) {
+						pr_err("%s:map_buffer failed,"
+							"error = %ld\n",
+				__func__, PTR_ERR((void *)buf[cnt].mem_buffer));
+						goto fail;
+					}
+					buf[cnt].data =
+						buf[cnt].mem_buffer->vaddr;
+					if (!buf[cnt].data) {
+						pr_err("%s:invalid vaddr,"
+						" iomap failed\n", __func__);
+						goto fail;
+					}
+					buf[cnt].used = 1;
+					buf[cnt].size = bufsz;
+					buf[cnt].actual_size = bufsz;
+					pr_debug("%s data[%p]phys[%p][%p]"
+						 "mem_buffer[%p]\n",
+						__func__,
+					   (void *)buf[cnt].data,
+					   (void *)buf[cnt].phys,
+					   (void *)&buf[cnt].phys,
+					   (void *)buf[cnt].mem_buffer);
+					cnt++;
+				}
+			}
+		}
+		ac->port[dir].max_buf_cnt = cnt;
+
+		mutex_unlock(&ac->cmd_lock);
+		rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+		if (rc < 0) {
+			pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+			goto fail;
+		}
+	}
+	return 0;
+fail:
+	q6asm_audio_client_buf_free(dir, ac);
+	return -EINVAL;
+}
+
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
+			struct audio_client *ac,
+			unsigned int bufsz,
+			unsigned int bufcnt)
+{
+	int cnt = 0;
+	int rc = 0;
+	struct audio_buffer *buf;
+
+	if (!(ac) || ((dir != IN) && (dir != OUT)))
+		return -EINVAL;
+
+	pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
+			__func__, ac->session,
+			bufsz, bufcnt);
+
+	if (ac->session <= 0 || ac->session > 8)
+		goto fail;
+
+	if (ac->port[dir].buf) {
+		pr_debug("%s: buffer already allocated\n", __func__);
+		return 0;
+	}
+	mutex_lock(&ac->cmd_lock);
+	buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+			GFP_KERNEL);
+
+	if (!buf) {
+		mutex_unlock(&ac->cmd_lock);
+		goto fail;
+	}
+
+	ac->port[dir].buf = buf;
+
+	buf[0].data =  dma_alloc_coherent(NULL, bufsz * bufcnt,
+				&buf[0].phys, GFP_KERNEL);
+	buf[0].used = dir ^ 1;
+	buf[0].size = bufsz;
+	buf[0].actual_size = bufsz;
+	cnt = 1;
+	while (cnt < bufcnt) {
+		if (bufsz > 0) {
+			buf[cnt].data =  buf[0].data + (cnt * bufsz);
+			buf[cnt].phys =  buf[0].phys + (cnt * bufsz);
+			if (!buf[cnt].data) {
+				pr_err("%s Buf alloc failed\n",
+							__func__);
+				mutex_unlock(&ac->cmd_lock);
+				goto fail;
+			}
+			buf[cnt].used = dir ^ 1;
+			buf[cnt].size = bufsz;
+			buf[cnt].actual_size = bufsz;
+			pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+				   (void *)buf[cnt].data,
+				   (void *)buf[cnt].phys,
+				   (void *)&buf[cnt].phys);
+		}
+		cnt++;
+	}
+	ac->port[dir].max_buf_cnt = cnt;
+	mutex_unlock(&ac->cmd_lock);
+	rc = q6asm_memory_map(ac, buf[0].phys, dir, bufsz, cnt);
+	if (rc < 0) {
+		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+		goto fail;
+	}
+	return 0;
+fail:
+	q6asm_audio_client_buf_free_contiguous(dir, ac);
+	return -EINVAL;
+}
+
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+	uint32_t token;
+	uint32_t *payload = data->payload;
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
+				__func__,
+				data->reset_event,
+				data->reset_proc,
+				this_mmap.apr);
+		apr_reset(this_mmap.apr);
+		this_mmap.apr = NULL;
+		atomic_set(&this_mmap.cmd_state, 0);
+		return 0;
+	}
+
+	pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x]"
+		"token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+		payload[0], payload[1], data->opcode, data->token,
+		data->payload_size, data->src_port, data->dest_port);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		token = data->token;
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_MEMORY_MAP:
+		case ASM_SESSION_CMD_MEMORY_UNMAP:
+		case ASM_SESSION_CMD_MEMORY_MAP_REGIONS:
+		case ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS:
+			pr_debug("%s:command[0x%x]success [0x%x]\n",
+					__func__, payload[0], payload[1]);
+			if (atomic_read(&this_mmap.cmd_state)) {
+				atomic_set(&this_mmap.cmd_state, 0);
+				wake_up(&this_mmap.cmd_wait);
+			}
+			break;
+		default:
+			pr_debug("%s:command[0x%x] not expecting rsp\n",
+						__func__, payload[0]);
+			break;
+		}
+	}
+	return 0;
+}
+
+
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
+{
+	int i = 0;
+	struct audio_client *ac = (struct audio_client *)priv;
+	uint32_t token;
+	unsigned long dsp_flags;
+	uint32_t *payload;
+
+
+	if ((ac == NULL) || (data == NULL)) {
+		pr_err("ac or priv NULL\n");
+		return -EINVAL;
+	}
+	if (ac->session <= 0 || ac->session > 8) {
+		pr_err("%s:Session ID is invalid, session = %d\n", __func__,
+			ac->session);
+		return -EINVAL;
+	}
+
+	payload = data->payload;
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
+				data->reset_event, data->reset_proc, ac->apr);
+		apr_reset(ac->apr);
+		return 0;
+	}
+
+	pr_debug("%s: session[%d]opcode[0x%x] \
+		token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+		ac->session, data->opcode,
+		data->token, data->payload_size, data->src_port,
+		data->dest_port);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		token = data->token;
+		switch (payload[0]) {
+		case ASM_STREAM_CMD_SET_PP_PARAMS:
+#ifdef CONFIG_MSM8X60_RTAC
+			if (rtac_make_asm_callback(ac->session, payload,
+					data->payload_size))
+				break;
+#endif
+		case ASM_SESSION_CMD_PAUSE:
+		case ASM_DATA_CMD_EOS:
+		case ASM_STREAM_CMD_CLOSE:
+		case ASM_STREAM_CMD_FLUSH:
+		case ASM_SESSION_CMD_RUN:
+		case ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS:
+		case ASM_STREAM_CMD_FLUSH_READBUFS:
+		pr_debug("%s:Payload = [0x%x]\n", __func__, payload[0]);
+		if (token != ac->session) {
+			pr_err("%s:Invalid session[%d] rxed expected[%d]",
+					__func__, token, ac->session);
+			return -EINVAL;
+		}
+		case ASM_STREAM_CMD_OPEN_READ:
+		case ASM_STREAM_CMD_OPEN_WRITE:
+		case ASM_STREAM_CMD_OPEN_READWRITE:
+		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+			if (atomic_read(&ac->cmd_state)) {
+				atomic_set(&ac->cmd_state, 0);
+				wake_up(&ac->cmd_wait);
+			}
+			if (ac->cb)
+				ac->cb(data->opcode, data->token,
+					(uint32_t *)data->payload, ac->priv);
+			break;
+		default:
+			pr_debug("%s:command[0x%x] not expecting rsp\n",
+							__func__, payload[0]);
+			break;
+		}
+		return 0;
+	}
+
+	switch (data->opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:{
+		struct audio_port_data *port = &ac->port[IN];
+		pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
+				__func__, payload[0], payload[1],
+				data->token);
+		if (ac->io_mode == SYNC_IO_MODE) {
+			if (port->buf == NULL) {
+				pr_err("%s: Unexpected Write Done\n",
+								__func__);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+			if (port->buf[data->token].phys !=
+				payload[0]) {
+				pr_err("Buf expected[%p]rxed[%p]\n",\
+				   (void *)port->buf[data->token].phys,\
+				   (void *)payload[0]);
+				spin_unlock_irqrestore(&port->dsp_lock,
+								dsp_flags);
+				return -EINVAL;
+			}
+			token = data->token;
+			port->buf[token].used = 1;
+			spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+			for (i = 0; i < port->max_buf_cnt; i++)
+				pr_debug("%d ", port->buf[i].used);
+
+		}
+		break;
+	}
+#ifdef CONFIG_MSM8X60_RTAC
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		rtac_make_asm_callback(ac->session, payload,
+			data->payload_size);
+		break;
+#endif
+	case ASM_DATA_EVENT_READ_DONE:{
+
+		struct audio_port_data *port = &ac->port[OUT];
+
+		pr_debug("%s:R-D: status=%d buff_add=%x act_size=%d offset=%d\n",
+				__func__, payload[READDONE_IDX_STATUS],
+				payload[READDONE_IDX_BUFFER],
+				payload[READDONE_IDX_SIZE],
+				payload[READDONE_IDX_OFFSET]);
+		pr_debug("%s:R-D:msw_ts=%d lsw_ts=%d flags=%d id=%d num=%d\n",
+				__func__, payload[READDONE_IDX_MSW_TS],
+				payload[READDONE_IDX_LSW_TS],
+				payload[READDONE_IDX_FLAGS],
+				payload[READDONE_IDX_ID],
+				payload[READDONE_IDX_NUMFRAMES]);
+
+		if (ac->io_mode == SYNC_IO_MODE) {
+			if (port->buf == NULL) {
+				pr_err("%s: Unexpected Write Done\n", __func__);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+			token = data->token;
+			port->buf[token].used = 0;
+			if (port->buf[token].phys !=
+				payload[READDONE_IDX_BUFFER]) {
+				pr_err("Buf expected[%p]rxed[%p]\n",\
+				   (void *)port->buf[token].phys,\
+				   (void *)payload[READDONE_IDX_BUFFER]);
+				spin_unlock_irqrestore(&port->dsp_lock,
+							dsp_flags);
+				break;
+			}
+			port->buf[token].actual_size =
+				payload[READDONE_IDX_SIZE];
+			spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+		}
+		break;
+	}
+	case ASM_DATA_EVENT_EOS:
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("%s:EOS ACK received: rxed opcode[0x%x]\n",
+				  __func__, data->opcode);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("ASM_SESSION_EVENT_TX_OVERFLOW\n");
+		break;
+	case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
+		pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSION_TIME, "
+				"payload[0] = %d, payload[1] = %d, "
+				"payload[2] = %d\n", __func__,
+				 payload[0], payload[1], payload[2]);
+		ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
+				payload[2]);
+		if (atomic_read(&ac->time_flag)) {
+			atomic_set(&ac->time_flag, 0);
+			wake_up(&ac->time_wait);
+		}
+		break;
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"payload[0] = %d, payload[1] = %d, "
+				"payload[2] = %d, payload[3] = %d\n", __func__,
+				payload[0], payload[1], payload[2],
+				payload[3]);
+		break;
+	}
+	if (ac->cb)
+		ac->cb(data->opcode, data->token,
+			data->payload, ac->priv);
+
+	return 0;
+}
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
+				uint32_t *index)
+{
+	void *data;
+	unsigned char idx;
+	struct audio_port_data *port;
+
+	if (!ac || ((dir != IN) && (dir != OUT)))
+		return NULL;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[dir];
+
+		mutex_lock(&port->lock);
+		idx = port->cpu_buf;
+		if (port->buf == NULL) {
+			pr_debug("%s:Buffer pointer null\n", __func__);
+			return NULL;
+		}
+		/*  dir 0: used = 0 means buf in use
+			dir 1: used = 1 means buf in use */
+		if (port->buf[idx].used == dir) {
+			/* To make it more robust, we could loop and get the
+			next avail buf, its risky though */
+			pr_debug("%s:Next buf idx[0x%x] not available,\
+				dir[%d]\n", __func__, idx, dir);
+			mutex_unlock(&port->lock);
+			return NULL;
+		}
+		*size = port->buf[idx].actual_size;
+		*index = port->cpu_buf;
+		data = port->buf[idx].data;
+		pr_debug("%s:session[%d]index[%d] data[%p]size[%d]\n",
+						__func__,
+						ac->session,
+						port->cpu_buf,
+						data, *size);
+		/* By default increase the cpu_buf cnt
+		user accesses this function,increase cpu
+		buf(to avoid another api)*/
+		port->buf[idx].used = dir;
+		port->cpu_buf = ((port->cpu_buf + 1) & (port->max_buf_cnt - 1));
+		mutex_unlock(&port->lock);
+		return data;
+	}
+	return NULL;
+}
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
+{
+	int ret = -1;
+	struct audio_port_data *port;
+	uint32_t idx;
+
+	if (!ac || (dir != OUT))
+		return ret;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[dir];
+
+		mutex_lock(&port->lock);
+		idx = port->dsp_buf;
+
+		if (port->buf[idx].used == (dir ^ 1)) {
+			/* To make it more robust, we could loop and get the
+			next avail buf, its risky though */
+			pr_err("Next buf idx[0x%x] not available, dir[%d]\n",
+								idx, dir);
+			mutex_unlock(&port->lock);
+			return ret;
+		}
+		pr_debug("%s: session[%d]dsp_buf=%d cpu_buf=%d\n", __func__,
+			ac->session, port->dsp_buf, port->cpu_buf);
+		ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
+		mutex_unlock(&port->lock);
+	}
+	return ret;
+}
+
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg)
+{
+	pr_debug("%s:session=%d pkt size=%d cmd_flg=%d\n", __func__, pkt_size,
+		cmd_flg, ac->session);
+	mutex_lock(&ac->cmd_lock);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				APR_PKT_VER);
+	hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_ASM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	if (cmd_flg) {
+		hdr->token = ac->session;
+		atomic_set(&ac->cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	mutex_unlock(&ac->cmd_lock);
+	return;
+}
+
+static void q6asm_add_mmaphdr(struct apr_hdr *hdr, uint32_t pkt_size,
+							uint32_t cmd_flg)
+{
+	pr_debug("%s:pkt size=%d cmd_flg=%d\n", __func__, pkt_size, cmd_flg);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	hdr->src_port = 0;
+	hdr->dest_port = 0;
+	if (cmd_flg) {
+		hdr->token = 0;
+		atomic_set(&this_mmap.cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	return;
+}
+
+int q6asm_open_read(struct audio_client *ac,
+		uint32_t format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_read open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ;
+	/* Stream prio : High, provide meta info with encoded frames */
+	open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+
+	open.pre_proc_top = get_asm_topology();
+	if (open.pre_proc_top == 0)
+		open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open.uMode = STREAM_PRIORITY_HIGH;
+		open.format = LINEAR_PCM;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = MPEG4_AAC;
+		break;
+	case FORMAT_V13K:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = EVRC_FS;
+		break;
+	case FORMAT_AMRNB:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = AMRNB_FS;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", format);
+		goto fail_cmd;
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_write open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
+		format);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
+	open.uMode = STREAM_PRIORITY_HIGH;
+	/* source endpoint : matrix */
+	open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+	open.stream_handle = 0x00;
+
+	open.post_proc_top = get_asm_topology();
+	if (open.post_proc_top == 0)
+		open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open.format = LINEAR_PCM;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.format = MPEG4_AAC;
+		break;
+	case FORMAT_WMA_V9:
+		open.format = WMA_V9;
+		break;
+	case FORMAT_WMA_V10PRO:
+		open.format = WMA_V10PRO;
+		break;
+	default:
+		pr_err("%s: Invalid format[%d]\n", __func__, format);
+		goto fail_cmd;
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s: open failed op[0x%x]rc[%d]\n", \
+					__func__, open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_open_read_write(struct audio_client *ac,
+			uint32_t rd_format,
+			uint32_t wr_format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_read_write open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+	pr_debug("wr_format[0x%x]rd_format[0x%x]",
+				wr_format, rd_format);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE;
+
+	open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_NORMAL |
+				 SR_CM_NOTIFY_ENABLE;
+	/* source endpoint : matrix */
+	open.post_proc_top = get_asm_topology();
+	if (open.post_proc_top == 0)
+		open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+	switch (wr_format) {
+	case FORMAT_LINEAR_PCM:
+		open.write_format = LINEAR_PCM;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.write_format = MPEG4_AAC;
+		break;
+	case FORMAT_WMA_V9:
+		open.write_format = WMA_V9;
+		break;
+	case FORMAT_WMA_V10PRO:
+		open.write_format = WMA_V10PRO;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", wr_format);
+		goto fail_cmd;
+	}
+
+	switch (rd_format) {
+	case FORMAT_LINEAR_PCM:
+		open.read_format = LINEAR_PCM;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.read_format = MPEG4_AAC;
+		break;
+	case FORMAT_V13K:
+		open.read_format = V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.read_format = EVRC_FS;
+		break;
+	case FORMAT_AMRNB:
+		open.read_format = AMRNB_FS;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", rd_format);
+		goto fail_cmd;
+	}
+	pr_debug("%s:rdformat[0x%x]wrformat[0x%x]\n", __func__,
+			open.read_format, open.write_format);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts)
+{
+	struct asm_stream_cmd_run run;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s session[%d]", __func__, ac->session);
+	q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+
+	run.hdr.opcode = ASM_SESSION_CMD_RUN;
+	run.flags    = flags;
+	run.msw_ts   = msw_ts;
+	run.lsw_ts   = lsw_ts;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+	if (rc < 0) {
+		pr_err("Commmand run failed[%d]", rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for run success rc[%d]", rc);
+		goto fail_cmd;
+	}
+
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+		uint32_t msw_ts, uint32_t lsw_ts)
+{
+	struct asm_stream_cmd_run run;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s:APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("session[%d]", ac->session);
+	q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+
+	run.hdr.opcode = ASM_SESSION_CMD_RUN;
+	run.flags    = flags;
+	run.msw_ts   = msw_ts;
+	run.lsw_ts   = lsw_ts;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+	if (rc < 0) {
+		pr_err("%s:Commmand run failed[%d]", __func__, rc);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+			 uint32_t frames_per_buf,
+			uint32_t sample_rate, uint32_t channels,
+			uint32_t bit_rate, uint32_t mode, uint32_t format)
+{
+	struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d]"
+		"format[%d]", __func__, ac->session, frames_per_buf,
+		sample_rate, channels, bit_rate, mode, format);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+	enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+	enc_cfg.enc_blk.format_id = MPEG4_AAC;
+	enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_aac_read_cfg);
+	enc_cfg.enc_blk.cfg.aac.bitrate = bit_rate;
+	enc_cfg.enc_blk.cfg.aac.enc_mode = mode;
+	enc_cfg.enc_blk.cfg.aac.format = format;
+	enc_cfg.enc_blk.cfg.aac.ch_cfg = channels;
+	enc_cfg.enc_blk.cfg.aac.sample_rate = sample_rate;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+			uint32_t rate, uint32_t channels)
+{
+	struct asm_stream_cmd_encdec_cfg_blk  enc_cfg;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+			 ac->session, rate, channels);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+	enc_cfg.enc_blk.frames_per_buf = 1;
+	enc_cfg.enc_blk.format_id = LINEAR_PCM;
+	enc_cfg.enc_blk.cfg_size = sizeof(struct asm_pcm_cfg);
+	enc_cfg.enc_blk.cfg.pcm.ch_cfg = channels;
+	enc_cfg.enc_blk.cfg.pcm.bits_per_sample = 16;
+	enc_cfg.enc_blk.cfg.pcm.sample_rate = rate;
+	enc_cfg.enc_blk.cfg.pcm.is_signed = 1;
+	enc_cfg.enc_blk.cfg.pcm.interleaved = 1;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd open failed\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+			uint32_t sbr_ps_enable)
+{
+	struct asm_stream_cmd_encdec_sbr  sbrps;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d\n", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+
+	sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	sbrps.param_id = ASM_ENABLE_SBR_PS;
+	sbrps.param_size = sizeof(struct asm_sbr_ps);
+	sbrps.sbr_ps.enable = sbr_ps_enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
+	if (rc < 0) {
+		pr_err("Command opcode[0x%x]paramid[0x%x] failed\n",
+				ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+				ASM_ENABLE_SBR_PS);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout opcode[0x%x] ", sbrps.hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t min_rate, uint16_t max_rate,
+		uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
+{
+	struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] \
+		reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]", __func__,
+		ac->session, frames_per_buf, min_rate, max_rate,
+		reduced_rate_level, rate_modulation_cmd);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+	enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+	enc_cfg.enc_blk.format_id = V13K_FS;
+	enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_qcelp13_read_cfg);
+	enc_cfg.enc_blk.cfg.qcelp13.min_rate = min_rate;
+	enc_cfg.enc_blk.cfg.qcelp13.max_rate = max_rate;
+	enc_cfg.enc_blk.cfg.qcelp13.reduced_rate_level = reduced_rate_level;
+	enc_cfg.enc_blk.cfg.qcelp13.rate_modulation_cmd = rate_modulation_cmd;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+		uint16_t min_rate, uint16_t max_rate,
+		uint16_t rate_modulation_cmd)
+{
+	struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] \
+		rate_modulation_cmd[0x%4x]", __func__, ac->session,
+		frames_per_buf,	min_rate, max_rate, rate_modulation_cmd);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+	enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+	enc_cfg.enc_blk.format_id = EVRC_FS;
+	enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_evrc_read_cfg);
+	enc_cfg.enc_blk.cfg.evrc.min_rate = min_rate;
+	enc_cfg.enc_blk.cfg.evrc.max_rate = max_rate;
+	enc_cfg.enc_blk.cfg.evrc.rate_modulation_cmd = rate_modulation_cmd;
+	enc_cfg.enc_blk.cfg.evrc.reserved = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+			uint16_t band_mode, uint16_t dtx_enable)
+{
+	struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]",
+		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+	enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+	enc_cfg.enc_blk.format_id = AMRNB_FS;
+	enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_amrnb_read_cfg);
+	enc_cfg.enc_blk.cfg.amrnb.mode = band_mode;
+	enc_cfg.enc_blk.cfg.amrnb.dtx_mode = dtx_enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+				uint32_t rate, uint32_t channels)
+{
+	struct asm_stream_media_format_update fmt;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+		channels);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+	fmt.format = LINEAR_PCM;
+	fmt.cfg_size = sizeof(struct asm_pcm_cfg);
+	fmt.write_cfg.pcm_cfg.ch_cfg = channels;
+	fmt.write_cfg.pcm_cfg.bits_per_sample = 16;
+	fmt.write_cfg.pcm_cfg.sample_rate = rate;
+	fmt.write_cfg.pcm_cfg.is_signed = 1;
+	fmt.write_cfg.pcm_cfg.interleaved = 1;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+				struct asm_aac_cfg *cfg)
+{
+	struct asm_stream_media_format_update fmt;
+	int rc = 0;
+
+	pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
+		cfg->sample_rate, cfg->ch_cfg);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+	fmt.format = MPEG4_AAC;
+	fmt.cfg_size = sizeof(struct asm_aac_cfg);
+	fmt.write_cfg.aac_cfg.format = cfg->format;
+	fmt.write_cfg.aac_cfg.aot = cfg->aot;
+	fmt.write_cfg.aac_cfg.ep_config = cfg->ep_config;
+	fmt.write_cfg.aac_cfg.section_data_resilience =
+					cfg->section_data_resilience;
+	fmt.write_cfg.aac_cfg.scalefactor_data_resilience =
+					cfg->scalefactor_data_resilience;
+	fmt.write_cfg.aac_cfg.spectral_data_resilience =
+					cfg->spectral_data_resilience;
+	fmt.write_cfg.aac_cfg.ch_cfg = cfg->ch_cfg;
+	fmt.write_cfg.aac_cfg.sample_rate = cfg->sample_rate;
+	pr_info("%s:format=%x cfg_size=%d aac-cfg=%x aot=%d ch=%d sr=%d\n",
+			__func__, fmt.format, fmt.cfg_size,
+			fmt.write_cfg.aac_cfg.format,
+			fmt.write_cfg.aac_cfg.aot,
+			fmt.write_cfg.aac_cfg.ch_cfg,
+			fmt.write_cfg.aac_cfg.sample_rate);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+				void *cfg)
+{
+	struct asm_stream_media_format_update fmt;
+	struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
+	int rc = 0;
+
+	pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],\
+		balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+		ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
+		wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
+		wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
+		wma_cfg->ch_mask, wma_cfg->encode_opt);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+	fmt.format = WMA_V9;
+	fmt.cfg_size = sizeof(struct asm_wma_cfg);
+	fmt.write_cfg.wma_cfg.format_tag = wma_cfg->format_tag;
+	fmt.write_cfg.wma_cfg.ch_cfg = wma_cfg->ch_cfg;
+	fmt.write_cfg.wma_cfg.sample_rate = wma_cfg->sample_rate;
+	fmt.write_cfg.wma_cfg.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
+	fmt.write_cfg.wma_cfg.block_align = wma_cfg->block_align;
+	fmt.write_cfg.wma_cfg.valid_bits_per_sample =
+			wma_cfg->valid_bits_per_sample;
+	fmt.write_cfg.wma_cfg.ch_mask = wma_cfg->ch_mask;
+	fmt.write_cfg.wma_cfg.encode_opt = wma_cfg->encode_opt;
+	fmt.write_cfg.wma_cfg.adv_encode_opt = 0;
+	fmt.write_cfg.wma_cfg.adv_encode_opt2 = 0;
+	fmt.write_cfg.wma_cfg.drc_peak_ref = 0;
+	fmt.write_cfg.wma_cfg.drc_peak_target = 0;
+	fmt.write_cfg.wma_cfg.drc_ave_ref = 0;
+	fmt.write_cfg.wma_cfg.drc_ave_target = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+				void *cfg)
+{
+	struct asm_stream_media_format_update fmt;
+	struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
+	int rc = 0;
+
+	pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
+		"balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x],\
+		adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+		ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
+		wmapro_cfg->ch_cfg,  wmapro_cfg->avg_bytes_per_sec,
+		wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
+		wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
+		wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
+
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+	fmt.format = WMA_V10PRO;
+	fmt.cfg_size = sizeof(struct asm_wmapro_cfg);
+	fmt.write_cfg.wmapro_cfg.format_tag = wmapro_cfg->format_tag;
+	fmt.write_cfg.wmapro_cfg.ch_cfg = wmapro_cfg->ch_cfg;
+	fmt.write_cfg.wmapro_cfg.sample_rate = wmapro_cfg->sample_rate;
+	fmt.write_cfg.wmapro_cfg.avg_bytes_per_sec =
+				wmapro_cfg->avg_bytes_per_sec;
+	fmt.write_cfg.wmapro_cfg.block_align = wmapro_cfg->block_align;
+	fmt.write_cfg.wmapro_cfg.valid_bits_per_sample =
+				wmapro_cfg->valid_bits_per_sample;
+	fmt.write_cfg.wmapro_cfg.ch_mask = wmapro_cfg->ch_mask;
+	fmt.write_cfg.wmapro_cfg.encode_opt = wmapro_cfg->encode_opt;
+	fmt.write_cfg.wmapro_cfg.adv_encode_opt = wmapro_cfg->adv_encode_opt;
+	fmt.write_cfg.wmapro_cfg.adv_encode_opt2 = wmapro_cfg->adv_encode_opt2;
+	fmt.write_cfg.wmapro_cfg.drc_peak_ref = 0;
+	fmt.write_cfg.wmapro_cfg.drc_peak_target = 0;
+	fmt.write_cfg.wmapro_cfg.drc_ave_ref = 0;
+	fmt.write_cfg.wmapro_cfg.drc_ave_target = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add, int dir,
+					uint32_t bufsz, uint32_t bufcnt)
+{
+	struct asm_stream_cmd_memory_map mem_map;
+	int rc = 0;
+
+	if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	mem_map.hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP;
+
+	mem_map.buf_add = buf_add;
+	mem_map.buf_size = bufsz * bufcnt;
+	mem_map.mempool_id = 0; /* EBI */
+	mem_map.reserved = 0;
+
+	q6asm_add_mmaphdr(&mem_map.hdr,
+			sizeof(struct asm_stream_cmd_memory_map), TRUE);
+
+	pr_debug("buf add[%x]  buf_add_parameter[%x]\n",
+					mem_map.buf_add, buf_add);
+
+	rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_map);
+	if (rc < 0) {
+		pr_err("mem_map op[0x%x]rc[%d]\n",
+				mem_map.hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(this_mmap.cmd_wait,
+		(atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_map\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add, int dir)
+{
+	struct asm_stream_cmd_memory_unmap mem_unmap;
+	int rc = 0;
+
+	if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	q6asm_add_mmaphdr(&mem_unmap.hdr,
+			sizeof(struct asm_stream_cmd_memory_unmap), TRUE);
+	mem_unmap.hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP;
+	mem_unmap.buf_add = buf_add;
+
+	rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
+	if (rc < 0) {
+		pr_err("mem_unmap op[0x%x]rc[%d]\n",
+					mem_unmap.hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(this_mmap.cmd_wait,
+			(atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_map\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
+{
+	void *vol_cmd = NULL;
+	void *payload = NULL;
+	struct asm_pp_params_command *cmd = NULL;
+	struct asm_lrchannel_gain_params *lrgain = NULL;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_pp_params_command) +
+		+ sizeof(struct asm_lrchannel_gain_params);
+	vol_cmd = kzalloc(sz, GFP_KERNEL);
+	if (vol_cmd == NULL) {
+		pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+		rc = -EINVAL;
+		return rc;
+	}
+	cmd = (struct asm_pp_params_command *)vol_cmd;
+	q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+	cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+	cmd->payload = NULL;
+	cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+				sizeof(struct asm_lrchannel_gain_params);
+	cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+	cmd->params.param_id = L_R_CHANNEL_GAIN_PARAM_ID;
+	cmd->params.param_size = sizeof(struct asm_lrchannel_gain_params);
+	cmd->params.reserved = 0;
+
+	payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+	lrgain = (struct asm_lrchannel_gain_params *)payload;
+
+	lrgain->left_gain = left_gain;
+	lrgain->right_gain = right_gain;
+	rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+	if (rc < 0) {
+		pr_err("%s: Volume Command failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in sending volume command to apr\n",
+			__func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	kfree(vol_cmd);
+	return rc;
+}
+
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt)
+{
+	struct	 asm_stream_cmd_memory_map_regions *mmap_regions = NULL;
+	struct asm_memory_map_regions *mregions = NULL;
+	struct audio_port_data *port = NULL;
+	struct audio_buffer *ab = NULL;
+	void	*mmap_region_cmd = NULL;
+	void	*payload = NULL;
+	int	rc = 0;
+	int	i = 0;
+	int	cmd_size = 0;
+
+	if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	cmd_size = sizeof(struct asm_stream_cmd_memory_map_regions)
+			+ sizeof(struct asm_memory_map_regions) * bufcnt;
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	mmap_regions = (struct asm_stream_cmd_memory_map_regions *)
+							mmap_region_cmd;
+	q6asm_add_mmaphdr(&mmap_regions->hdr, cmd_size, TRUE);
+	mmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP_REGIONS;
+	mmap_regions->mempool_id = 0;
+	mmap_regions->nregions = bufcnt & 0x00ff;
+	pr_debug("map_regions->nregions = %d\n", mmap_regions->nregions);
+	payload = ((u8 *) mmap_region_cmd +
+		sizeof(struct asm_stream_cmd_memory_map_regions));
+	mregions = (struct asm_memory_map_regions *)payload;
+
+	port = &ac->port[dir];
+	for (i = 0; i < bufcnt; i++) {
+		ab = &port->buf[i];
+		mregions->phys = ab->phys;
+		mregions->buf_size = ab->size;
+		++mregions;
+	}
+
+	rc = apr_send_pkt(this_mmap.apr, (uint32_t *) mmap_region_cmd);
+	if (rc < 0) {
+		pr_err("mmap_regions op[0x%x]rc[%d]\n",
+					mmap_regions->hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(this_mmap.cmd_wait,
+			(atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_map\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	kfree(mmap_region_cmd);
+	return rc;
+}
+
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+				uint32_t bufsz, uint32_t bufcnt)
+{
+	struct asm_stream_cmd_memory_unmap_regions *unmap_regions = NULL;
+	struct asm_memory_unmap_regions *mregions = NULL;
+	struct audio_port_data *port = NULL;
+	struct audio_buffer *ab = NULL;
+	void	*unmap_region_cmd = NULL;
+	void	*payload = NULL;
+	int	rc = 0;
+	int	i = 0;
+	int	cmd_size = 0;
+
+	if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+	cmd_size = sizeof(struct asm_stream_cmd_memory_unmap_regions) +
+			sizeof(struct asm_memory_unmap_regions) * bufcnt;
+
+	unmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	unmap_regions = (struct asm_stream_cmd_memory_unmap_regions *)
+							unmap_region_cmd;
+	q6asm_add_mmaphdr(&unmap_regions->hdr, cmd_size, TRUE);
+	unmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS;
+	unmap_regions->nregions = bufcnt & 0x00ff;
+	pr_debug("unmap_regions->nregions = %d\n", unmap_regions->nregions);
+	payload = ((u8 *) unmap_region_cmd +
+			sizeof(struct asm_stream_cmd_memory_unmap_regions));
+	mregions = (struct asm_memory_unmap_regions *)payload;
+	port = &ac->port[dir];
+	for (i = 0; i < bufcnt; i++) {
+		ab = &port->buf[i];
+		mregions->phys = ab->phys;
+		++mregions;
+	}
+
+	rc = apr_send_pkt(this_mmap.apr, (uint32_t *) unmap_region_cmd);
+	if (rc < 0) {
+		pr_err("mmap_regions op[0x%x]rc[%d]\n",
+					unmap_regions->hdr.opcode, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(this_mmap.cmd_wait,
+			(atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for memory_unmap\n");
+		goto fail_cmd;
+	}
+	rc = 0;
+
+fail_cmd:
+	kfree(unmap_region_cmd);
+	return rc;
+}
+
+int q6asm_set_mute(struct audio_client *ac, int muteflag)
+{
+	void *vol_cmd = NULL;
+	void *payload = NULL;
+	struct asm_pp_params_command *cmd = NULL;
+	struct asm_mute_params *mute = NULL;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_pp_params_command) +
+		+ sizeof(struct asm_mute_params);
+	vol_cmd = kzalloc(sz, GFP_KERNEL);
+	if (vol_cmd == NULL) {
+		pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+		rc = -EINVAL;
+		return rc;
+	}
+	cmd = (struct asm_pp_params_command *)vol_cmd;
+	q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+	cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+	cmd->payload = NULL;
+	cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+				sizeof(struct asm_mute_params);
+	cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+	cmd->params.param_id = MUTE_CONFIG_PARAM_ID;
+	cmd->params.param_size = sizeof(struct asm_mute_params);
+	cmd->params.reserved = 0;
+
+	payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+	mute = (struct asm_mute_params *)payload;
+
+	mute->muteflag = muteflag;
+	rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+	if (rc < 0) {
+		pr_err("%s: Mute Command failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in sending mute command to apr\n",
+			__func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	kfree(vol_cmd);
+	return rc;
+}
+
+int q6asm_set_volume(struct audio_client *ac, int volume)
+{
+	void *vol_cmd = NULL;
+	void *payload = NULL;
+	struct asm_pp_params_command *cmd = NULL;
+	struct asm_master_gain_params *mgain = NULL;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_pp_params_command) +
+		+ sizeof(struct asm_master_gain_params);
+	vol_cmd = kzalloc(sz, GFP_KERNEL);
+	if (vol_cmd == NULL) {
+		pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+		rc = -EINVAL;
+		return rc;
+	}
+	cmd = (struct asm_pp_params_command *)vol_cmd;
+	q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+	cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+	cmd->payload = NULL;
+	cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+				sizeof(struct asm_master_gain_params);
+	cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+	cmd->params.param_id = MASTER_GAIN_PARAM_ID;
+	cmd->params.param_size = sizeof(struct asm_master_gain_params);
+	cmd->params.reserved = 0;
+
+	payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+	mgain = (struct asm_master_gain_params *)payload;
+
+	mgain->master_gain = volume;
+	mgain->padding = 0x00;
+	rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+	if (rc < 0) {
+		pr_err("%s: Volume Command failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in sending volume command to apr\n",
+			__func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	kfree(vol_cmd);
+	return rc;
+}
+
+int q6asm_set_softpause(struct audio_client *ac,
+			struct asm_softpause_params *pause_param)
+{
+	void *vol_cmd = NULL;
+	void *payload = NULL;
+	struct asm_pp_params_command *cmd = NULL;
+	struct asm_softpause_params *params = NULL;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_pp_params_command) +
+		+ sizeof(struct asm_softpause_params);
+	vol_cmd = kzalloc(sz, GFP_KERNEL);
+	if (vol_cmd == NULL) {
+		pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+		rc = -EINVAL;
+		return rc;
+	}
+	cmd = (struct asm_pp_params_command *)vol_cmd;
+	q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+	cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+	cmd->payload = NULL;
+	cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+				sizeof(struct asm_softpause_params);
+	cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+	cmd->params.param_id = SOFT_PAUSE_PARAM_ID;
+	cmd->params.param_size = sizeof(struct asm_softpause_params);
+	cmd->params.reserved = 0;
+
+	payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+	params = (struct asm_softpause_params *)payload;
+
+	params->enable = pause_param->enable;
+	params->period = pause_param->period;
+	params->step = pause_param->step;
+	params->rampingcurve = pause_param->rampingcurve;
+	pr_debug("%s: soft Pause Command: enable = %d, period = %d,"
+			 "step = %d, curve = %d\n", __func__, params->enable,
+			 params->period, params->step, params->rampingcurve);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+	if (rc < 0) {
+		pr_err("%s: Volume Command(soft_pause) failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in sending volume command(soft_pause)"
+		       "to apr\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	kfree(vol_cmd);
+	return rc;
+}
+
+int q6asm_equalizer(struct audio_client *ac, void *eq)
+{
+	void *eq_cmd = NULL;
+	void *payload = NULL;
+	struct asm_pp_params_command *cmd = NULL;
+	struct asm_equalizer_params *equalizer = NULL;
+	struct msm_audio_eq_stream_config *eq_params = NULL;
+	int i  = 0;
+	int sz = 0;
+	int rc  = 0;
+
+	sz = sizeof(struct asm_pp_params_command) +
+		+ sizeof(struct asm_equalizer_params);
+	eq_cmd = kzalloc(sz, GFP_KERNEL);
+	if (eq_cmd == NULL) {
+		pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	eq_params = (struct msm_audio_eq_stream_config *) eq;
+	cmd = (struct asm_pp_params_command *)eq_cmd;
+	q6asm_add_hdr(ac, &cmd->hdr, sz, TRUE);
+	cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+	cmd->payload = NULL;
+	cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+				sizeof(struct asm_equalizer_params);
+	cmd->params.module_id = EQUALIZER_MODULE_ID;
+	cmd->params.param_id = EQUALIZER_PARAM_ID;
+	cmd->params.param_size = sizeof(struct asm_equalizer_params);
+	cmd->params.reserved = 0;
+	payload = (u8 *)(eq_cmd + sizeof(struct asm_pp_params_command));
+	equalizer = (struct asm_equalizer_params *)payload;
+
+	equalizer->enable = eq_params->enable;
+	equalizer->num_bands = eq_params->num_bands;
+	pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
+							eq_params->num_bands);
+	for (i = 0; i < eq_params->num_bands; i++) {
+		equalizer->eq_bands[i].band_idx =
+					eq_params->eq_bands[i].band_idx;
+		equalizer->eq_bands[i].filter_type =
+					eq_params->eq_bands[i].filter_type;
+		equalizer->eq_bands[i].center_freq_hz =
+					eq_params->eq_bands[i].center_freq_hz;
+		equalizer->eq_bands[i].filter_gain =
+					eq_params->eq_bands[i].filter_gain;
+		equalizer->eq_bands[i].q_factor =
+					eq_params->eq_bands[i].q_factor;
+		pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].filter_type, i);
+		pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].center_freq_hz, i);
+		pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].filter_gain, i);
+		pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
+				eq_params->eq_bands[i].q_factor, i);
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *) eq_cmd);
+	if (rc < 0) {
+		pr_err("%s: Equalizer Command failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in sending equalizer command to apr\n",
+			__func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	kfree(eq_cmd);
+	return rc;
+}
+
+int q6asm_read(struct audio_client *ac)
+{
+	struct asm_stream_cmd_read read;
+	struct audio_buffer        *ab;
+	int dsp_buf;
+	struct audio_port_data     *port;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[OUT];
+
+		q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
+
+		mutex_lock(&port->lock);
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+					__func__,
+					ac->session,
+					dsp_buf,
+					(void *)port->buf[dsp_buf].data,
+					port->cpu_buf,
+					(void *)port->buf[port->cpu_buf].phys);
+
+		read.hdr.opcode = ASM_DATA_CMD_READ;
+		read.buf_add = ab->phys;
+		read.buf_size = ab->size;
+		read.uid = port->dsp_buf;
+		read.hdr.token = port->dsp_buf;
+
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+		mutex_unlock(&port->lock);
+		pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+						read.buf_add,
+						read.hdr.token,
+						read.uid);
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+		if (rc < 0) {
+			pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_read_nolock(struct audio_client *ac)
+{
+	struct asm_stream_cmd_read read;
+	struct audio_buffer        *ab;
+	int dsp_buf;
+	struct audio_port_data     *port;
+	int rc;
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[OUT];
+
+		q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+					__func__,
+					ac->session,
+					dsp_buf,
+					(void *)port->buf[dsp_buf].data,
+					port->cpu_buf,
+					(void *)port->buf[port->cpu_buf].phys);
+
+		read.hdr.opcode = ASM_DATA_CMD_READ;
+		read.buf_add = ab->phys;
+		read.buf_size = ab->size;
+		read.uid = port->dsp_buf;
+		read.hdr.token = port->dsp_buf;
+
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+		pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+					read.buf_add,
+					read.hdr.token,
+					read.uid);
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+		if (rc < 0) {
+			pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+			uint32_t pkt_size, uint32_t cmd_flg)
+{
+	pr_debug("session=%d pkt size=%d cmd_flg=%d\n", pkt_size, cmd_flg,
+		ac->session);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				APR_PKT_VER);
+	hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_ASM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	if (cmd_flg) {
+		hdr->token = ac->session;
+		atomic_set(&ac->cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	return;
+}
+
+int q6asm_async_write(struct audio_client *ac,
+					  struct audio_aio_write_param *param)
+{
+	int rc = 0;
+	struct asm_stream_cmd_write write;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6asm_add_hdr_async(ac, &write.hdr, sizeof(write), FALSE);
+
+	/* Pass physical address as token for AIO scheme */
+	write.hdr.token = param->uid;
+	write.hdr.opcode = ASM_DATA_CMD_WRITE;
+	write.buf_add = param->paddr;
+	write.avail_bytes = param->len;
+	write.uid = param->uid;
+	write.msw_ts = param->msw_ts;
+	write.lsw_ts = param->lsw_ts;
+	/* Use 0xFF00 for disabling timestamps */
+	if (param->flags == 0xFF00)
+		write.uflags = (0x00000000 | (param->flags & 0x800000FF));
+	else
+		write.uflags = (0x80000000 | param->flags);
+
+	pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+		write.buf_add, write.avail_bytes);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+	if (rc < 0) {
+		pr_debug("[%s] write op[0x%x]rc[%d]\n", __func__,
+			write.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_async_read(struct audio_client *ac,
+					  struct audio_aio_read_param *param)
+{
+	int rc = 0;
+	struct asm_stream_cmd_read read;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+	/* Pass physical address as token for AIO scheme */
+	read.hdr.token = param->paddr;
+	read.hdr.opcode = ASM_DATA_CMD_READ;
+	read.buf_add = param->paddr;
+	read.buf_size = param->len;
+	read.uid = param->uid;
+
+	pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+		read.buf_add, read.buf_size);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+	if (rc < 0) {
+		pr_debug("[%s] read op[0x%x]rc[%d]\n", __func__,
+			read.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+		uint32_t lsw_ts, uint32_t flags)
+{
+	int rc = 0;
+	struct asm_stream_cmd_write write;
+	struct audio_port_data *port;
+	struct audio_buffer    *ab;
+	int dsp_buf = 0;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[IN];
+
+		q6asm_add_hdr(ac, &write.hdr, sizeof(write),
+				FALSE);
+		mutex_lock(&port->lock);
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		write.hdr.token = port->dsp_buf;
+		write.hdr.opcode = ASM_DATA_CMD_WRITE;
+		write.buf_add = ab->phys;
+		write.avail_bytes = len;
+		write.uid = port->dsp_buf;
+		write.msw_ts = msw_ts;
+		write.lsw_ts = lsw_ts;
+		/* Use 0xFF00 for disabling timestamps */
+		if (flags == 0xFF00)
+			write.uflags = (0x00000000 | (flags & 0x800000FF));
+		else
+			write.uflags = (0x80000000 | flags);
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+		pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]buf_id[0x%x]"
+							, __func__,
+							ab->phys,
+							write.buf_add,
+							write.hdr.token,
+							write.uid);
+		mutex_unlock(&port->lock);
+
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+		if (rc < 0) {
+			pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		pr_debug("%s: WRITE SUCCESS\n", __func__);
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+			uint32_t lsw_ts, uint32_t flags)
+{
+	int rc = 0;
+	struct asm_stream_cmd_write write;
+	struct audio_port_data *port;
+	struct audio_buffer    *ab;
+	int dsp_buf = 0;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+	if (ac->io_mode == SYNC_IO_MODE) {
+		port = &ac->port[IN];
+
+		q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
+					FALSE);
+
+		dsp_buf = port->dsp_buf;
+		ab = &port->buf[dsp_buf];
+
+		write.hdr.token = port->dsp_buf;
+		write.hdr.opcode = ASM_DATA_CMD_WRITE;
+		write.buf_add = ab->phys;
+		write.avail_bytes = len;
+		write.uid = port->dsp_buf;
+		write.msw_ts = msw_ts;
+		write.lsw_ts = lsw_ts;
+		/* Use 0xFF00 for disabling timestamps */
+		if (flags == 0xFF00)
+			write.uflags = (0x00000000 | (flags & 0x800000FF));
+		else
+			write.uflags = (0x80000000 | flags);
+		port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+		pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]buf_id[0x%x]"
+							, __func__,
+							ab->phys,
+							write.buf_add,
+							write.hdr.token,
+							write.uid);
+
+		rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+		if (rc < 0) {
+			pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+			goto fail_cmd;
+		}
+		pr_debug("%s: WRITE SUCCESS\n", __func__);
+		return 0;
+	}
+fail_cmd:
+	return -EINVAL;
+}
+
+uint64_t q6asm_get_session_time(struct audio_client *ac)
+{
+	struct apr_hdr hdr;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+	hdr.opcode = ASM_SESSION_CMD_GET_SESSION_TIME;
+	atomic_set(&ac->time_flag, 1);
+
+	pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
+						ac->session,
+						hdr.opcode);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("Commmand 0x%x failed\n", hdr.opcode);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->time_wait,
+			(atomic_read(&ac->time_flag) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout in getting session time from DSP\n",
+			__func__);
+		goto fail_cmd;
+	}
+	return ac->time_stamp;
+
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+	struct apr_hdr hdr;
+	int rc;
+	atomic_t *state;
+	int cnt = 0;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+	switch (cmd) {
+	case CMD_PAUSE:
+		pr_debug("%s:CMD_PAUSE\n", __func__);
+		hdr.opcode = ASM_SESSION_CMD_PAUSE;
+		state = &ac->cmd_state;
+		break;
+	case CMD_FLUSH:
+		pr_debug("%s:CMD_FLUSH\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_FLUSH;
+		state = &ac->cmd_state;
+		break;
+	case CMD_OUT_FLUSH:
+		pr_debug("%s:CMD_OUT_FLUSH\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
+		state = &ac->cmd_state;
+		break;
+	case CMD_EOS:
+		pr_debug("%s:CMD_EOS\n", __func__);
+		hdr.opcode = ASM_DATA_CMD_EOS;
+		atomic_set(&ac->cmd_state, 0);
+		state = &ac->cmd_state;
+		break;
+	case CMD_CLOSE:
+		pr_debug("%s:CMD_CLOSE\n", __func__);
+		hdr.opcode = ASM_STREAM_CMD_CLOSE;
+		state = &ac->cmd_state;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", cmd);
+		goto fail_cmd;
+	}
+	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+						ac->session,
+						hdr.opcode);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("Commmand 0x%x failed\n", hdr.opcode);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for response opcode[0x%x]\n",
+							hdr.opcode);
+		goto fail_cmd;
+	}
+	if (cmd == CMD_FLUSH)
+		q6asm_reset_buf_state(ac);
+	if (cmd == CMD_CLOSE) {
+		/* check if DSP return all buffers */
+		if (ac->port[IN].buf) {
+			for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
+								cnt++) {
+				if (ac->port[IN].buf[cnt].used == IN) {
+					pr_debug("Write Buf[%d] not returned\n",
+									cnt);
+				}
+			}
+		}
+		if (ac->port[OUT].buf) {
+			for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
+				if (ac->port[OUT].buf[cnt].used == OUT) {
+					pr_debug("Read Buf[%d] not returned\n",
+									cnt);
+				}
+			}
+		}
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+	struct apr_hdr hdr;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("%s:APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+	switch (cmd) {
+	case CMD_PAUSE:
+		pr_debug("%s:CMD_PAUSE\n", __func__);
+		hdr.opcode = ASM_SESSION_CMD_PAUSE;
+		break;
+	case CMD_EOS:
+		pr_debug("%s:CMD_EOS\n", __func__);
+		hdr.opcode = ASM_DATA_CMD_EOS;
+		break;
+	default:
+		pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+		goto fail_cmd;
+	}
+	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+						ac->session,
+						hdr.opcode);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+static void q6asm_reset_buf_state(struct audio_client *ac)
+{
+	int cnt = 0;
+	int loopcnt = 0;
+	struct audio_port_data *port = NULL;
+
+	if (ac->io_mode == SYNC_IO_MODE) {
+		mutex_lock(&ac->cmd_lock);
+		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+			port = &ac->port[loopcnt];
+			cnt = port->max_buf_cnt - 1;
+			port->dsp_buf = 0;
+			port->cpu_buf = 0;
+			while (cnt >= 0) {
+				if (!port->buf)
+					continue;
+				port->buf[cnt].used = 1;
+				cnt--;
+			}
+		}
+		mutex_unlock(&ac->cmd_lock);
+	}
+}
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
+{
+	struct asm_stream_cmd_reg_tx_overflow_event tx_overflow;
+	int rc;
+
+	if (!ac || ac->apr == NULL) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]enable[%d]\n", __func__,
+						ac->session, enable);
+	q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+
+	tx_overflow.hdr.opcode = \
+			ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS;
+	/* tx overflow event: enable */
+	tx_overflow.enable = enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
+	if (rc < 0) {
+		pr_err("tx overflow op[0x%x]rc[%d]\n", \
+						tx_overflow.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for tx overflow\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+#ifdef CONFIG_MSM8X60_RTAC
+int q6asm_get_apr_service_id(int session_id)
+{
+	pr_debug("%s\n", __func__);
+
+	if (session_id < 0) {
+		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+		return -EINVAL;
+	}
+
+	return ((struct apr_svc *)session[session_id]->apr)->id;
+}
+#endif
+
+
+static int __init q6asm_init(void)
+{
+	pr_debug("%s\n", __func__);
+	init_waitqueue_head(&this_mmap.cmd_wait);
+	memset(session, 0, sizeof(session));
+	return 0;
+}
+
+device_initcall(q6asm_init);
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
new file mode 100644
index 0000000..28d1acf
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -0,0 +1,2089 @@
+/*  Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include "sound/apr_audio.h"
+#include "sound/q6afe.h"
+#include "q6voice.h"
+
+#define TIMEOUT_MS 3000
+
+#define CMD_STATUS_SUCCESS 0
+#define CMD_STATUS_FAIL 1
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+
+static struct voice_data voice;
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v);
+static int voice_send_netid_timing_cmd(struct voice_data *v);
+static int voice_send_attach_vocproc_cmd(struct voice_data *v);
+static int voice_send_set_device_cmd(struct voice_data *v);
+static int voice_send_disable_vocproc_cmd(struct voice_data *v);
+static int voice_send_vol_index_cmd(struct voice_data *v);
+
+static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv);
+static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
+static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
+
+static u16 voice_get_mvm_handle(struct voice_data *v)
+{
+	u16 mvm_handle = 0;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		mvm_handle = v->mvm_passive_handle;
+	else
+		mvm_handle = v->mvm_full_handle;
+
+	pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+
+	return mvm_handle;
+}
+
+static void voice_set_mvm_handle(struct voice_data *v, u16 mvm_handle)
+{
+	pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return;
+	}
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		v->mvm_passive_handle = mvm_handle;
+	else
+		v->mvm_full_handle = mvm_handle;
+}
+
+static u16 voice_get_cvs_handle(struct voice_data *v)
+{
+	u16 cvs_handle = 0;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		cvs_handle = v->cvs_passive_handle;
+	else
+		cvs_handle = v->cvs_full_handle;
+
+	pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+
+	return cvs_handle;
+}
+
+static void voice_set_cvs_handle(struct voice_data *v, u16 cvs_handle)
+{
+	pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return;
+	}
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		v->cvs_passive_handle = cvs_handle;
+	else
+		v->cvs_full_handle = cvs_handle;
+}
+
+static u16 voice_get_cvp_handle(struct voice_data *v)
+{
+	u16 cvp_handle = 0;
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		cvp_handle = v->cvp_passive_handle;
+	else
+		cvp_handle = v->cvp_full_handle;
+
+	pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+
+	return cvp_handle;
+}
+
+static void voice_set_cvp_handle(struct voice_data *v, u16 cvp_handle)
+{
+	pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return;
+	}
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		v->cvp_passive_handle = cvp_handle;
+	else
+		v->cvp_full_handle = cvp_handle;
+}
+
+static int voice_apr_register(struct voice_data *v)
+{
+	void *apr_mvm, *apr_cvs, *apr_cvp;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+	apr_cvs = v->apr_q6_cvs;
+	apr_cvp = v->apr_q6_cvp;
+
+	pr_debug("into voice_apr_register_callback\n");
+	/* register callback to APR */
+	if (apr_mvm == NULL) {
+		pr_debug("start to register MVM callback\n");
+
+		apr_mvm = apr_register("ADSP", "MVM",
+					qdsp_mvm_callback,
+					0xFFFFFFFF, v);
+
+		if (apr_mvm == NULL) {
+			pr_err("Unable to register MVM\n");
+			goto err;
+		}
+		v->apr_q6_mvm = apr_mvm;
+	}
+
+	if (apr_cvs == NULL) {
+		pr_debug("start to register CVS callback\n");
+
+		apr_cvs = apr_register("ADSP", "CVS",
+					qdsp_cvs_callback,
+					0xFFFFFFFF, v);
+
+		if (apr_cvs == NULL) {
+			pr_err("Unable to register CVS\n");
+			goto err;
+		}
+		v->apr_q6_cvs = apr_cvs;
+	}
+
+	if (apr_cvp == NULL) {
+		pr_debug("start to register CVP callback\n");
+
+		apr_cvp = apr_register("ADSP", "CVP",
+					qdsp_cvp_callback,
+					0xFFFFFFFF, v);
+
+		if (apr_cvp == NULL) {
+			pr_err("Unable to register CVP\n");
+			goto err;
+		}
+		v->apr_q6_cvp = apr_cvp;
+	}
+	return 0;
+
+err:
+	if (v->apr_q6_cvs != NULL) {
+		apr_deregister(apr_cvs);
+		v->apr_q6_cvs = NULL;
+	}
+	if (v->apr_q6_mvm != NULL) {
+		apr_deregister(apr_mvm);
+		v->apr_q6_mvm = NULL;
+	}
+
+	return -ENODEV;
+}
+
+static int voice_create_mvm_cvs_session(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_create_passive_ctl_session_cmd mvm_session_cmd;
+	struct cvs_create_passive_ctl_session_cmd cvs_session_cmd;
+	struct mvm_create_full_ctl_session_cmd mvm_full_ctl_cmd;
+	struct cvs_create_full_ctl_session_cmd cvs_full_ctl_cmd;
+	struct mvm_attach_stream_cmd attach_stream_cmd;
+	void *apr_mvm, *apr_cvs, *apr_cvp;
+	u16 mvm_handle, cvs_handle, cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+	apr_cvs = v->apr_q6_cvs;
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_mvm || !apr_cvs || !apr_cvp) {
+		pr_err("%s: apr_mvm or apr_cvs or apr_cvp is NULL\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+	cvs_handle = voice_get_cvs_handle(v);
+	cvp_handle = voice_get_cvp_handle(v);
+
+	pr_debug("%s: mvm_hdl=%d, cvs_hdl=%d\n", __func__,
+		mvm_handle, cvs_handle);
+	/* send cmd to create mvm session and wait for response */
+
+	if (!mvm_handle) {
+		if (v->voc_path == VOC_PATH_PASSIVE) {
+			mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+						APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+			mvm_session_cmd.hdr.pkt_size = APR_PKT_SIZE(
+						APR_HDR_SIZE,
+						sizeof(mvm_session_cmd) -
+						APR_HDR_SIZE);
+			pr_debug("send mvm create session pkt size = %d\n",
+				mvm_session_cmd.hdr.pkt_size);
+			mvm_session_cmd.hdr.src_port = 0;
+			mvm_session_cmd.hdr.dest_port = 0;
+			mvm_session_cmd.hdr.token = 0;
+			mvm_session_cmd.hdr.opcode =
+				VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+			v->mvm_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_mvm,
+					(uint32_t *) &mvm_session_cmd);
+			if (ret < 0) {
+				pr_err("Error sending MVM_CONTROL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					(v->mvm_state == CMD_STATUS_SUCCESS),
+					msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		} else {
+			pr_debug("%s: creating MVM full ctrl\n", __func__);
+			mvm_full_ctl_cmd.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			mvm_full_ctl_cmd.hdr.pkt_size =
+					APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(mvm_full_ctl_cmd) -
+					APR_HDR_SIZE);
+			mvm_full_ctl_cmd.hdr.src_port = 0;
+			mvm_full_ctl_cmd.hdr.dest_port = 0;
+			mvm_full_ctl_cmd.hdr.token = 0;
+			mvm_full_ctl_cmd.hdr.opcode =
+				VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION;
+			strncpy(mvm_full_ctl_cmd.mvm_session.name,
+				"default voip", 12);
+
+			v->mvm_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_mvm,
+					(uint32_t *) &mvm_full_ctl_cmd);
+			if (ret < 0) {
+				pr_err("Fail in sending MVM_CONTROL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		}
+		/* Get the created MVM handle. */
+		mvm_handle = voice_get_mvm_handle(v);
+	}
+	/* send cmd to create cvs session */
+	if (!cvs_handle) {
+		if (v->voc_path == VOC_PATH_PASSIVE) {
+			pr_debug("creating CVS passive session\n");
+
+			cvs_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+						APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+			cvs_session_cmd.hdr.pkt_size =
+						APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(cvs_session_cmd) -
+						APR_HDR_SIZE);
+			cvs_session_cmd.hdr.src_port = 0;
+			cvs_session_cmd.hdr.dest_port = 0;
+			cvs_session_cmd.hdr.token = 0;
+			cvs_session_cmd.hdr.opcode =
+				VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+			strncpy(cvs_session_cmd.cvs_session.name,
+				"default modem voice", 19);
+
+			v->cvs_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_cvs,
+					(uint32_t *) &cvs_session_cmd);
+			if (ret < 0) {
+				pr_err("Fail in sending STREAM_CONTROL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+			/* Get the created CVS handle. */
+			cvs_handle = voice_get_cvs_handle(v);
+
+		} else {
+			pr_debug("creating CVS full session\n");
+
+			cvs_full_ctl_cmd.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+
+			cvs_full_ctl_cmd.hdr.pkt_size =
+					APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_full_ctl_cmd) -
+					APR_HDR_SIZE);
+
+			cvs_full_ctl_cmd.hdr.src_port = 0;
+			cvs_full_ctl_cmd.hdr.dest_port = 0;
+			cvs_full_ctl_cmd.hdr.token = 0;
+			cvs_full_ctl_cmd.hdr.opcode =
+				VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION;
+			cvs_full_ctl_cmd.cvs_session.direction = 2;
+			cvs_full_ctl_cmd.cvs_session.enc_media_type =
+							v->mvs_info.media_type;
+			cvs_full_ctl_cmd.cvs_session.dec_media_type =
+							v->mvs_info.media_type;
+			cvs_full_ctl_cmd.cvs_session.network_id =
+						       v->mvs_info.network_type;
+			strncpy(cvs_full_ctl_cmd.cvs_session.name,
+			       "default q6 voice", 16);
+
+			v->cvs_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_cvs,
+					   (uint32_t *) &cvs_full_ctl_cmd);
+
+			if (ret < 0) {
+				pr_err("%s: Err %d sending CREATE_FULL_CTRL\n",
+					__func__, ret);
+				goto fail;
+			}
+			ret = wait_event_timeout(v->cvs_wait,
+					(v->cvs_state == CMD_STATUS_SUCCESS),
+					msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+			/* Get the created CVS handle. */
+			cvs_handle = voice_get_cvs_handle(v);
+
+			/* Attach MVM to CVS. */
+			pr_debug("Attach MVM to stream\n");
+
+			attach_stream_cmd.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+			attach_stream_cmd.hdr.pkt_size =
+					APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(attach_stream_cmd) -
+					APR_HDR_SIZE);
+			attach_stream_cmd.hdr.src_port = 0;
+			attach_stream_cmd.hdr.dest_port = mvm_handle;
+			attach_stream_cmd.hdr.token = 0;
+			attach_stream_cmd.hdr.opcode =
+						VSS_IMVM_CMD_ATTACH_STREAM;
+			attach_stream_cmd.attach_stream.handle = cvs_handle;
+
+			v->mvm_state = CMD_STATUS_FAIL;
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &attach_stream_cmd);
+			if (ret < 0) {
+				pr_err("%s: Error %d sending ATTACH_STREAM\n",
+				       __func__, ret);
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		}
+	}
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_destroy_mvm_cvs_session(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_detach_stream_cmd detach_stream;
+	struct apr_hdr mvm_destroy;
+	struct apr_hdr cvs_destroy;
+	void *apr_mvm, *apr_cvs;
+	u16 mvm_handle, cvs_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+	apr_cvs = v->apr_q6_cvs;
+
+	if (!apr_mvm || !apr_cvs) {
+		pr_err("%s: apr_mvm or apr_cvs is NULL\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+	cvs_handle = voice_get_cvs_handle(v);
+
+	/* MVM, CVS sessions are destroyed only for Full control sessions. */
+	if (v->voc_path == VOC_PATH_FULL) {
+		pr_debug("MVM detach stream\n");
+
+		/* Detach voice stream. */
+		detach_stream.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+		detach_stream.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(detach_stream) - APR_HDR_SIZE);
+		detach_stream.hdr.src_port = 0;
+		detach_stream.hdr.dest_port = mvm_handle;
+		detach_stream.hdr.token = 0;
+		detach_stream.hdr.opcode = VSS_IMVM_CMD_DETACH_STREAM;
+		detach_stream.detach_stream.handle = cvs_handle;
+
+		v->mvm_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending DETACH_STREAM\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+			goto fail;
+		}
+		/* Destroy CVS. */
+		pr_debug("CVS destroy session\n");
+
+		cvs_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		cvs_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_destroy) - APR_HDR_SIZE);
+		cvs_destroy.src_port = 0;
+		cvs_destroy.dest_port = cvs_handle;
+		cvs_destroy.token = 0;
+		cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending CVS DESTROY\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+
+			goto fail;
+		}
+		cvs_handle = 0;
+		voice_set_cvs_handle(v, cvs_handle);
+
+		/* Destroy MVM. */
+		pr_debug("MVM destroy session\n");
+
+		mvm_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		mvm_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					    sizeof(mvm_destroy) - APR_HDR_SIZE);
+		mvm_destroy.src_port = 0;
+		mvm_destroy.dest_port = mvm_handle;
+		mvm_destroy.token = 0;
+		mvm_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+		v->mvm_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_destroy);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending MVM DESTROY\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+
+			goto fail;
+		}
+		mvm_handle = 0;
+		voice_set_mvm_handle(v, mvm_handle);
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_tty_mode_cmd(struct voice_data *v)
+{
+	int tty_mode = 0;
+	int ret = 0;
+	struct mvm_set_tty_mode_cmd mvm_tty_mode_cmd;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	if (tty_mode) {
+		/* send tty mode cmd to mvm */
+		mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+						APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+		mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(mvm_tty_mode_cmd) -
+						APR_HDR_SIZE);
+		pr_debug("pkt size = %d\n", mvm_tty_mode_cmd.hdr.pkt_size);
+		mvm_tty_mode_cmd.hdr.src_port = 0;
+		mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+		mvm_tty_mode_cmd.hdr.token = 0;
+		mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+		mvm_tty_mode_cmd.tty_mode.mode = tty_mode;
+		pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+
+		v->mvm_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+		if (ret < 0) {
+			pr_err("Fail: sending VSS_ISTREAM_CMD_SET_TTY_MODE\n");
+			goto fail;
+		}
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_config_cvs_vocoder(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+	/* Set media type. */
+	struct cvs_set_media_type_cmd cvs_set_media_cmd;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = v->apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	cvs_set_media_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+	cvs_set_media_cmd.hdr.src_port = 0;
+	cvs_set_media_cmd.hdr.dest_port = cvs_handle;
+	cvs_set_media_cmd.hdr.token = 0;
+	cvs_set_media_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MEDIA_TYPE;
+	cvs_set_media_cmd.media_type.tx_media_id = v->mvs_info.media_type;
+	cvs_set_media_cmd.media_type.rx_media_id = v->mvs_info.media_type;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
+		       __func__, ret);
+
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+	/* Set encoder properties. */
+	switch (v->mvs_info.media_type) {
+	case VSS_MEDIA_ID_EVRC_MODEM: {
+		struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
+
+		pr_debug("Setting EVRC min-max rate\n");
+
+		cvs_set_cdma_rate.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+		cvs_set_cdma_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(cvs_set_cdma_rate) - APR_HDR_SIZE);
+		cvs_set_cdma_rate.hdr.src_port = 0;
+		cvs_set_cdma_rate.hdr.dest_port = cvs_handle;
+		cvs_set_cdma_rate.hdr.token = 0;
+		cvs_set_cdma_rate.hdr.opcode =
+				VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
+		cvs_set_cdma_rate.cdma_rate.min_rate = v->mvs_info.rate;
+		cvs_set_cdma_rate.cdma_rate.max_rate = v->mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_cdma_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_EVRC_MINMAX_RATE\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+		break;
+	}
+	case VSS_MEDIA_ID_AMR_NB_MODEM: {
+		struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+		pr_debug("Setting AMR rate\n");
+
+		cvs_set_amr_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE),
+				APR_PKT_VER);
+		cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+		cvs_set_amr_rate.hdr.src_port = 0;
+		cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+		cvs_set_amr_rate.hdr.token = 0;
+		cvs_set_amr_rate.hdr.opcode =
+					VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+		cvs_set_amr_rate.amr_rate.mode = v->mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_AMR_RATE\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+		/* Disable DTX */
+		pr_debug("Disabling DTX\n");
+
+		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+		cvs_set_dtx.hdr.src_port = 0;
+		cvs_set_dtx.hdr.dest_port = cvs_handle;
+		cvs_set_dtx.hdr.token = 0;
+		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+		cvs_set_dtx.dtx_mode.enable = 0;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_DTX\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+		break;
+	}
+	case VSS_MEDIA_ID_AMR_WB_MODEM: {
+		struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
+		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+		pr_debug("Setting AMR WB rate\n");
+
+		cvs_set_amrwb_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE),
+				APR_PKT_VER);
+		cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(cvs_set_amrwb_rate) -
+						APR_HDR_SIZE);
+		cvs_set_amrwb_rate.hdr.src_port = 0;
+		cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
+		cvs_set_amrwb_rate.hdr.token = 0;
+		cvs_set_amrwb_rate.hdr.opcode =
+					VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+		cvs_set_amrwb_rate.amrwb_rate.mode = v->mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+		/* Disable DTX */
+		pr_debug("Disabling DTX\n");
+
+		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+		cvs_set_dtx.hdr.src_port = 0;
+		cvs_set_dtx.hdr.dest_port = cvs_handle;
+		cvs_set_dtx.hdr.token = 0;
+		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+		cvs_set_dtx.dtx_mode.enable = 0;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_DTX\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+		break;
+	}
+	case VSS_MEDIA_ID_G729:
+	case VSS_MEDIA_ID_G711_ALAW:
+	case VSS_MEDIA_ID_G711_MULAW: {
+		struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+		/* Disable DTX */
+		pr_debug("Disabling DTX\n");
+
+		cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					    sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+		cvs_set_dtx.hdr.src_port = 0;
+		cvs_set_dtx.hdr.dest_port = cvs_handle;
+		cvs_set_dtx.hdr.token = 0;
+		cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+		cvs_set_dtx.dtx_mode.enable = 0;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_DTX\n",
+			       __func__, ret);
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+		break;
+	}
+	default:
+		/* Do nothing. */
+		break;
+	}
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_start_voice_cmd(struct voice_data *v)
+{
+	struct apr_hdr mvm_start_voice_cmd;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_start_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_start_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
+	pr_debug("send mvm_start_voice_cmd pkt size = %d\n",
+				mvm_start_voice_cmd.pkt_size);
+	mvm_start_voice_cmd.src_port = 0;
+	mvm_start_voice_cmd.dest_port = mvm_handle;
+	mvm_start_voice_cmd.token = 0;
+	mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_start_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_START_VOICE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_disable_vocproc_cmd(struct voice_data *v)
+{
+	struct apr_hdr cvp_disable_cmd;
+	int ret = 0;
+	void *apr_cvp;
+	u16 cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr regist failed\n", __func__);
+		return -EINVAL;
+	}
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* disable vocproc and wait for respose */
+	cvp_disable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_disable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_disable_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_disable_cmd pkt size = %d, cvp_handle=%d\n",
+		cvp_disable_cmd.pkt_size, cvp_handle);
+	cvp_disable_cmd.src_port = 0;
+	cvp_disable_cmd.dest_port = cvp_handle;
+	cvp_disable_cmd.token = 0;
+	cvp_disable_cmd.opcode = VSS_IVOCPROC_CMD_DISABLE;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_disable_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IVOCPROC_CMD_DISABLE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_set_device_cmd(struct voice_data *v)
+{
+	struct cvp_set_device_cmd  cvp_setdev_cmd;
+	int ret = 0;
+	void *apr_cvp;
+	u16 cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* set device and wait for response */
+	cvp_setdev_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_setdev_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_setdev_cmd) - APR_HDR_SIZE);
+	pr_debug(" send create cvp setdev, pkt size = %d\n",
+			cvp_setdev_cmd.hdr.pkt_size);
+	cvp_setdev_cmd.hdr.src_port = 0;
+	cvp_setdev_cmd.hdr.dest_port = cvp_handle;
+	cvp_setdev_cmd.hdr.token = 0;
+	cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE;
+
+	/* Use default topology if invalid value in ACDB */
+	cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				get_voice_tx_topology();
+	if (cvp_setdev_cmd.cvp_set_device.tx_topology_id == 0)
+		cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+
+	cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+				get_voice_rx_topology();
+	if (cvp_setdev_cmd.cvp_set_device.rx_topology_id == 0)
+		cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+	cvp_setdev_cmd.cvp_set_device.tx_port_id = v->dev_tx.port_id;
+	cvp_setdev_cmd.cvp_set_device.rx_port_id = v->dev_rx.port_id;
+	pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
+		cvp_setdev_cmd.cvp_set_device.tx_topology_id,
+		cvp_setdev_cmd.cvp_set_device.tx_port_id,
+		cvp_setdev_cmd.cvp_set_device.rx_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+		goto fail;
+	}
+	pr_debug("wait for cvp create session event\n");
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_stop_voice_cmd(struct voice_data *v)
+{
+	struct apr_hdr mvm_stop_voice_cmd;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_stop_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_stop_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_stop_voice_cmd) - APR_HDR_SIZE);
+	pr_debug("send mvm_stop_voice_cmd pkt size = %d\n",
+				mvm_stop_voice_cmd.pkt_size);
+	mvm_stop_voice_cmd.src_port = 0;
+	mvm_stop_voice_cmd.dest_port = mvm_handle;
+	mvm_stop_voice_cmd.token = 0;
+	mvm_stop_voice_cmd.opcode = VSS_IMVM_CMD_STOP_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_stop_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_STOP_VOICE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_setup_vocproc(struct voice_data *v)
+{
+	struct cvp_create_full_ctl_session_cmd cvp_session_cmd;
+	int ret = 0;
+	void *apr_cvp;
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	/* create cvp session and wait for response */
+	cvp_session_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_session_cmd) - APR_HDR_SIZE);
+	pr_debug(" send create cvp session, pkt size = %d\n",
+		cvp_session_cmd.hdr.pkt_size);
+	cvp_session_cmd.hdr.src_port = 0;
+	cvp_session_cmd.hdr.dest_port = 0;
+	cvp_session_cmd.hdr.token = 0;
+	cvp_session_cmd.hdr.opcode =
+			VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+
+	/* Use default topology if invalid value in ACDB */
+	cvp_session_cmd.cvp_session.tx_topology_id =
+				get_voice_tx_topology();
+	if (cvp_session_cmd.cvp_session.tx_topology_id == 0)
+		cvp_session_cmd.cvp_session.tx_topology_id =
+			VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+
+	cvp_session_cmd.cvp_session.rx_topology_id =
+				get_voice_rx_topology();
+	if (cvp_session_cmd.cvp_session.rx_topology_id == 0)
+		cvp_session_cmd.cvp_session.rx_topology_id =
+			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+
+	cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
+	cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
+	cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
+	cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
+
+	pr_debug("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+		cvp_session_cmd.cvp_session.tx_topology_id,
+		cvp_session_cmd.cvp_session.network_id,
+		cvp_session_cmd.cvp_session.direction,
+		cvp_session_cmd.cvp_session.tx_port_id,
+		cvp_session_cmd.cvp_session.rx_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* enable vocproc */
+	ret = voice_send_enable_vocproc_cmd(v);
+	if (ret < 0)
+		goto fail;
+
+	/* attach vocproc */
+	ret = voice_send_attach_vocproc_cmd(v);
+	if (ret < 0)
+		goto fail;
+
+	/* send tty mode if tty device is used */
+	voice_send_tty_mode_cmd(v);
+
+	if (v->voc_path == VOC_PATH_FULL)
+		voice_send_netid_timing_cmd(v);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	struct apr_hdr cvp_enable_cmd;
+	void *apr_cvp;
+	u16 cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* enable vocproc and wait for respose */
+	cvp_enable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_enable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_enable_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_enable_cmd pkt size = %d, cvp_handle=%d\n",
+		cvp_enable_cmd.pkt_size, cvp_handle);
+	cvp_enable_cmd.src_port = 0;
+	cvp_enable_cmd.dest_port = cvp_handle;
+	cvp_enable_cmd.token = 0;
+	cvp_enable_cmd.opcode = VSS_IVOCPROC_CMD_ENABLE;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_enable_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IVOCPROC_CMD_ENABLE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				(v->cvp_state == CMD_STATUS_SUCCESS),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_netid_timing_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+	struct mvm_set_network_cmd mvm_set_network;
+	struct mvm_set_voice_timing_cmd mvm_set_voice_timing;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	ret = voice_config_cvs_vocoder(v);
+	if (ret < 0) {
+		pr_err("%s: Error %d configuring CVS voc",
+					__func__, ret);
+		goto fail;
+	}
+	/* Set network ID. */
+	pr_debug("Setting network ID\n");
+
+	mvm_set_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_set_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(mvm_set_network) - APR_HDR_SIZE);
+	mvm_set_network.hdr.src_port = 0;
+	mvm_set_network.hdr.dest_port = mvm_handle;
+	mvm_set_network.hdr.token = 0;
+	mvm_set_network.hdr.opcode = VSS_ICOMMON_CMD_SET_NETWORK;
+	mvm_set_network.network.network_id = v->mvs_info.network_type;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_network);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+				(v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* Set voice timing. */
+	 pr_debug("Setting voice timing\n");
+
+	mvm_set_voice_timing.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_set_voice_timing.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(mvm_set_voice_timing) -
+						APR_HDR_SIZE);
+	mvm_set_voice_timing.hdr.src_port = 0;
+	mvm_set_voice_timing.hdr.dest_port = mvm_handle;
+	mvm_set_voice_timing.hdr.token = 0;
+	mvm_set_voice_timing.hdr.opcode = VSS_ICOMMON_CMD_SET_VOICE_TIMING;
+	mvm_set_voice_timing.timing.mode = 0;
+	mvm_set_voice_timing.timing.enc_offset = 8000;
+	mvm_set_voice_timing.timing.dec_req_offset = 3300;
+	mvm_set_voice_timing.timing.dec_offset = 8300;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_voice_timing);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_TIMING\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+				(v->mvm_state == CMD_STATUS_SUCCESS),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_attach_vocproc_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_attach_vocproc_cmd mvm_a_vocproc_cmd;
+	void *apr_mvm;
+	u16 mvm_handle, cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* attach vocproc and wait for response */
+	mvm_a_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_a_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_a_vocproc_cmd) - APR_HDR_SIZE);
+	pr_debug("send mvm_a_vocproc_cmd pkt size = %d\n",
+		mvm_a_vocproc_cmd.hdr.pkt_size);
+	mvm_a_vocproc_cmd.hdr.src_port = 0;
+	mvm_a_vocproc_cmd.hdr.dest_port = mvm_handle;
+	mvm_a_vocproc_cmd.hdr.token = 0;
+	mvm_a_vocproc_cmd.hdr.opcode = VSS_ISTREAM_CMD_ATTACH_VOCPROC;
+	mvm_a_vocproc_cmd.mvm_attach_cvp_handle.handle = cvp_handle;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_a_vocproc_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_ISTREAM_CMD_ATTACH_VOCPROC\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_destroy_vocproc(struct voice_data *v)
+{
+	struct mvm_detach_vocproc_cmd mvm_d_vocproc_cmd;
+	struct apr_hdr cvp_destroy_session_cmd;
+	int ret = 0;
+	void *apr_mvm, *apr_cvp;
+	u16 mvm_handle, cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = v->apr_q6_mvm;
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_mvm || !apr_cvp) {
+		pr_err("%s: apr_mvm or apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* send stop voice cmd */
+	voice_send_stop_voice_cmd(v);
+
+	/* detach VOCPROC and wait for response from mvm */
+	mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	mvm_d_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_d_vocproc_cmd) - APR_HDR_SIZE);
+	pr_debug("mvm_d_vocproc_cmd  pkt size = %d\n",
+		mvm_d_vocproc_cmd.hdr.pkt_size);
+	mvm_d_vocproc_cmd.hdr.src_port = 0;
+	mvm_d_vocproc_cmd.hdr.dest_port = mvm_handle;
+	mvm_d_vocproc_cmd.hdr.token = 0;
+	mvm_d_vocproc_cmd.hdr.opcode = VSS_ISTREAM_CMD_DETACH_VOCPROC;
+	mvm_d_vocproc_cmd.mvm_detach_cvp_handle.handle = cvp_handle;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_d_vocproc_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_ISTREAM_CMD_DETACH_VOCPROC\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* destrop cvp session */
+	cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_destroy_session_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_destroy_session_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_destroy_session_cmd pkt size = %d\n",
+		cvp_destroy_session_cmd.pkt_size);
+	cvp_destroy_session_cmd.src_port = 0;
+	cvp_destroy_session_cmd.dest_port = cvp_handle;
+	cvp_destroy_session_cmd.token = 0;
+	cvp_destroy_session_cmd.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_destroy_session_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending APRV2_IBASIC_CMD_DESTROY_SESSION\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	cvp_handle = 0;
+	voice_set_cvp_handle(v, cvp_handle);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_mute_cmd(struct voice_data *v)
+{
+	struct cvs_set_mute_cmd cvs_mute_cmd;
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = v->apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvs_handle = voice_get_cvs_handle(v);
+
+	/* send mute/unmute to cvs */
+	cvs_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvs_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_mute_cmd) - APR_HDR_SIZE);
+	cvs_mute_cmd.hdr.src_port = 0;
+	cvs_mute_cmd.hdr.dest_port = cvs_handle;
+	cvs_mute_cmd.hdr.token = 0;
+	cvs_mute_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MUTE;
+	cvs_mute_cmd.cvs_set_mute.direction = 0; /*tx*/
+	cvs_mute_cmd.cvs_set_mute.mute_flag = v->dev_tx.mute;
+
+	pr_info(" mute value =%d\n", cvs_mute_cmd.cvs_set_mute.mute_flag);
+	v->cvs_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_mute_cmd);
+	if (ret < 0) {
+		pr_err("Fail: send STREAM SET MUTE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		pr_err("%s: wait_event timeout\n", __func__);
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_vol_index_cmd(struct voice_data *v)
+{
+	struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
+	int ret = 0;
+	void *apr_cvp;
+	u16 cvp_handle;
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = v->apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* send volume index to cvp */
+	cvp_vol_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_vol_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvp_vol_cmd) - APR_HDR_SIZE);
+	cvp_vol_cmd.hdr.src_port = 0;
+	cvp_vol_cmd.hdr.dest_port = cvp_handle;
+	cvp_vol_cmd.hdr.token = 0;
+	cvp_vol_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX;
+	cvp_vol_cmd.cvp_set_vol_idx.vol_index = v->dev_rx.volume;
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending RX VOL INDEX\n");
+		return -EINVAL;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int voc_disable_cvp(void)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	if (v->voc_state == VOC_RUN) {
+		afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id, 0, 0);
+		/* send cmd to dsp to disable vocproc */
+		ret = voice_send_disable_vocproc_cmd(v);
+		if (ret < 0) {
+			pr_err("%s:  disable vocproc failed\n", __func__);
+			goto fail;
+		}
+		v->voc_state = VOC_CHANGE;
+	}
+
+fail:	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+int voc_enable_cvp(void)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	if (v->voc_state == VOC_CHANGE) {
+		ret = voice_send_set_device_cmd(v);
+		if (ret < 0) {
+			pr_err("%s:  set device failed\n", __func__);
+			goto fail;
+		}
+		ret = voice_send_enable_vocproc_cmd(v);
+		if (ret < 0) {
+			pr_err("enable vocproc failed\n");
+			goto fail;
+		}
+		ret = afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
+						 1, v->sidetone_gain);
+
+		if (ret < 0)
+			pr_err("AFE command sidetone failed\n");
+
+		v->voc_state = VOC_RUN;
+	}
+
+fail:
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+int voc_set_tx_mute(uint32_t dir, uint32_t mute)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	v->dev_tx.mute = mute;
+
+	if (v->voc_state == VOC_RUN)
+		ret = voice_send_mute_cmd(v);
+
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+int voc_set_rx_vol_index(uint32_t dir, uint32_t vol_idx)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	v->dev_rx.volume = vol_idx;
+
+	if (v->voc_state == VOC_RUN)
+		ret = voice_send_vol_index_cmd(v);
+
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+void voc_set_rxtx_port(uint32_t port_id, uint32_t dev_type)
+{
+	struct voice_data *v = &voice;
+
+	pr_debug(" port_id=%d, type=%d\n", port_id, dev_type);
+
+	mutex_lock(&v->lock);
+
+	if (dev_type == DEV_RX)
+		v->dev_rx.port_id = port_id;
+	else
+		v->dev_tx.port_id = port_id;
+
+	mutex_unlock(&v->lock);
+
+	return;
+}
+
+void voc_set_route_flag(uint8_t path_dir, uint8_t set)
+{
+	struct voice_data *v = &voice;
+
+	pr_debug("path_dir=%d, set=%d\n", path_dir, set);
+
+	mutex_lock(&v->lock);
+
+	if (path_dir == RX_PATH)
+		v->voc_route_state.rx_route_flag = set;
+	else
+		v->voc_route_state.tx_route_flag = set;
+
+	mutex_unlock(&v->lock);
+
+	return;
+}
+
+uint8_t voc_get_route_flag(uint8_t path_dir)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	if (path_dir == RX_PATH)
+		ret = v->voc_route_state.rx_route_flag;
+	else
+		ret = v->voc_route_state.tx_route_flag;
+
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+int voc_end_voice_call(void)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	if (v->voc_state == VOC_RUN) {
+		ret = voice_destroy_vocproc(v);
+		if (ret < 0)
+			pr_err("%s:  destroy voice failed\n", __func__);
+		voice_destroy_mvm_cvs_session(v);
+
+		v->voc_state = VOC_RELEASE;
+	}
+	mutex_unlock(&v->lock);
+	return ret;
+}
+
+int voc_start_voice_call(void)
+{
+	struct voice_data *v = &voice;
+	int ret = 0;
+
+	mutex_lock(&v->lock);
+
+	if ((v->voc_state == VOC_INIT) ||
+		(v->voc_state == VOC_RELEASE)) {
+		ret = voice_apr_register(v);
+		if (ret < 0) {
+			pr_err("%s:  apr register failed\n", __func__);
+			goto fail;
+		}
+		ret = voice_create_mvm_cvs_session(v);
+		if (ret < 0) {
+			pr_err("create mvm and cvs failed\n");
+			goto fail;
+		}
+		ret = voice_setup_vocproc(v);
+		if (ret < 0) {
+			pr_err("setup voice failed\n");
+			goto fail;
+		}
+		ret = voice_send_start_voice_cmd(v);
+		if (ret < 0) {
+			pr_err("start voice failed\n");
+			goto fail;
+		}
+		ret = afe_sidetone(v->dev_tx.port_id,
+				v->dev_rx.port_id, 1, v->sidetone_gain);
+		if (ret < 0)
+			pr_err("AFE command sidetone failed\n");
+
+		v->voc_state = VOC_RUN;
+	}
+
+fail:	mutex_unlock(&v->lock);
+	return ret;
+}
+
+int voc_set_voc_path_full(uint32_t set)
+{
+	int rc = 0;
+
+	pr_debug("set voc path: %d\n", set);
+
+	mutex_lock(&voice.lock);
+
+	if (voice.voc_state == VOC_INIT || voice.voc_state == VOC_RELEASE) {
+		if (set)
+			voice.voc_path = VOC_PATH_FULL;
+		else
+			voice.voc_path = VOC_PATH_PASSIVE;
+	} else {
+		pr_err("%s: Invalid voc path set to %d, in state %d\n",
+		       __func__, set, voice.voc_state);
+		rc = -EPERM;
+	}
+
+	mutex_unlock(&voice.lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(voc_set_voc_path_full);
+
+void voc_register_mvs_cb(ul_cb_fn ul_cb,
+			   dl_cb_fn dl_cb,
+			   void *private_data)
+{
+	voice.mvs_info.ul_cb = ul_cb;
+	voice.mvs_info.dl_cb = dl_cb;
+	voice.mvs_info.private_data = private_data;
+}
+
+void voc_config_vocoder(uint32_t media_type,
+			  uint32_t rate,
+			  uint32_t network_type)
+{
+	voice.mvs_info.media_type = media_type;
+	voice.mvs_info.rate = rate;
+	voice.mvs_info.network_type = network_type;
+}
+
+static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct voice_data *v;
+
+	if ((data == NULL) || (priv == NULL)) {
+		pr_err("%s: data or priv is NULL\n", __func__);
+		return -EINVAL;
+	}
+	v = priv;
+
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+		data->payload_size, data->opcode);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/* ping mvm service ACK */
+			switch (ptr[0]) {
+			case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
+			case VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION:
+				/* Passive session is used for CS call
+				 * Full session is used for VoIP call. */
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				if (!ptr[1]) {
+					pr_debug("%s: MVM handle is %d\n",
+						 __func__, data->src_port);
+					voice_set_mvm_handle(v, data->src_port);
+				} else
+					pr_err("got NACK for sending \
+						MVM create session \n");
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+				break;
+			case VSS_IMVM_CMD_START_VOICE:
+			case VSS_ISTREAM_CMD_ATTACH_VOCPROC:
+			case VSS_IMVM_CMD_STOP_VOICE:
+			case VSS_ISTREAM_CMD_DETACH_VOCPROC:
+			case VSS_ISTREAM_CMD_SET_TTY_MODE:
+			case APRV2_IBASIC_CMD_DESTROY_SESSION:
+			case VSS_IMVM_CMD_ATTACH_STREAM:
+			case VSS_IMVM_CMD_DETACH_STREAM:
+			case VSS_ICOMMON_CMD_SET_NETWORK:
+			case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+				break;
+			default:
+				pr_debug("%s: not match cmd = 0x%x\n",
+					__func__, ptr[0]);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct voice_data *v;
+
+	if ((data == NULL) || (priv == NULL)) {
+		pr_err("%s: data or priv is NULL\n", __func__);
+		return -EINVAL;
+	}
+	v = priv;
+
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+		data->payload_size, data->opcode);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/*response from  CVS */
+			switch (ptr[0]) {
+			case VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
+			case VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION:
+				if (!ptr[1]) {
+					pr_debug("%s: CVS handle is %d\n",
+						 __func__, data->src_port);
+					voice_set_cvs_handle(v, data->src_port);
+				} else
+					pr_err("got NACK for sending \
+						CVS create session \n");
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+				break;
+			case VSS_ISTREAM_CMD_SET_MUTE:
+			case VSS_ISTREAM_CMD_SET_MEDIA_TYPE:
+			case VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE:
+			case VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE:
+			case VSS_ISTREAM_CMD_SET_ENC_DTX_MODE:
+			case VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE:
+			case APRV2_IBASIC_CMD_DESTROY_SESSION:
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+				break;
+			default:
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				break;
+			}
+		}
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+		uint32_t *voc_pkt = data->payload;
+		uint32_t pkt_len = data->payload_size;
+
+		if (voc_pkt != NULL && v->mvs_info.ul_cb != NULL) {
+			pr_debug("%s: Media type is 0x%x\n",
+				 __func__, voc_pkt[0]);
+
+			/* Remove media ID from payload. */
+			voc_pkt++;
+			pkt_len = pkt_len - 4;
+
+			v->mvs_info.ul_cb((uint8_t *)voc_pkt,
+					  pkt_len,
+					  v->mvs_info.private_data);
+		} else
+			pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
+			       __func__, (unsigned int)voc_pkt,
+			       (unsigned int) v->mvs_info.ul_cb);
+	} else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+		struct cvs_send_dec_buf_cmd send_dec_buf;
+		int ret = 0;
+		uint32_t pkt_len = 0;
+
+		if (v->mvs_info.dl_cb != NULL) {
+			send_dec_buf.dec_buf.media_id = v->mvs_info.media_type;
+
+			v->mvs_info.dl_cb(
+				(uint8_t *)&send_dec_buf.dec_buf.packet_data,
+				&pkt_len,
+				v->mvs_info.private_data);
+
+			send_dec_buf.hdr.hdr_field =
+					APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+			send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			       sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
+			send_dec_buf.hdr.src_port = 0;
+			send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
+			send_dec_buf.hdr.token = 0;
+			send_dec_buf.hdr.opcode =
+					VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+
+			ret = apr_send_pkt(v->apr_q6_cvs,
+					   (uint32_t *) &send_dec_buf);
+			if (ret < 0) {
+				pr_err("%s: Error %d sending DEC_BUF\n",
+				       __func__, ret);
+				goto fail;
+			}
+		} else
+			pr_debug("%s: dl_cb is NULL\n", __func__);
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER)
+		pr_debug("Send dec buf resp\n");
+
+	else
+		pr_debug("Unknown opcode 0x%x\n", data->opcode);
+
+fail:
+	return 0;
+}
+
+static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct voice_data *v;
+
+	if ((data == NULL) || (priv == NULL)) {
+		pr_err("%s: data or priv is NULL\n", __func__);
+		return -EINVAL;
+	}
+	v = priv;
+
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+		data->payload_size, data->opcode);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+
+			switch (ptr[0]) {
+			case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION:
+			/*response from  CVP */
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				if (!ptr[1]) {
+					voice_set_cvp_handle(v, data->src_port);
+					pr_debug("cvphdl=%d\n", data->src_port);
+				} else
+					pr_err("got NACK from CVP create \
+						session response\n");
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+				break;
+			case VSS_IVOCPROC_CMD_SET_DEVICE:
+			case VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX:
+			case VSS_IVOCPROC_CMD_ENABLE:
+			case VSS_IVOCPROC_CMD_DISABLE:
+			case APRV2_IBASIC_CMD_DESTROY_SESSION:
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+				break;
+			default:
+				pr_debug("%s: not match cmd = 0x%x\n",
+					__func__, ptr[0]);
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static int __init voice_init(void)
+{
+	int rc = 0;
+	struct voice_data *v = &voice;
+
+	/* set default value */
+	v->default_mute_val = 1;  /* default is mute */
+	v->default_vol_val = 0;
+	v->default_sample_val = 8000;
+	v->sidetone_gain = 0x512;
+
+	/* initialize dev_rx and dev_tx */
+	memset(&v->dev_tx, 0, sizeof(struct device_data));
+	memset(&v->dev_rx, 0, sizeof(struct device_data));
+	v->dev_rx.volume = v->default_vol_val;
+	v->dev_tx.mute = v->default_mute_val;
+
+	v->dev_tx.port_id = 1;
+	v->dev_rx.port_id = 0;
+
+	v->voc_state = VOC_INIT;
+	v->voc_path = VOC_PATH_PASSIVE;
+	init_waitqueue_head(&v->mvm_wait);
+	init_waitqueue_head(&v->cvs_wait);
+	init_waitqueue_head(&v->cvp_wait);
+
+	mutex_init(&v->lock);
+
+	v->mvm_full_handle = 0;
+	v->mvm_passive_handle = 0;
+	v->cvs_full_handle = 0;
+	v->cvs_passive_handle = 0;
+	v->cvp_full_handle = 0;
+	v->cvp_passive_handle = 0;
+
+	v->apr_q6_mvm = NULL;
+	v->apr_q6_cvs = NULL;
+	v->apr_q6_cvp = NULL;
+
+	/* Initialize MVS info. */
+	memset(&v->mvs_info, 0, sizeof(v->mvs_info));
+	v->mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
+
+	return rc;
+}
+
+device_initcall(voice_init);
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
new file mode 100644
index 0000000..f9e1bc4
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -0,0 +1,686 @@
+/* Copyright (c) 2011, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QDSP6VOICE_H__
+#define __QDSP6VOICE_H__
+
+#include <mach/qdsp6v2/apr.h>
+
+#define MAX_VOC_PKT_SIZE 322
+
+struct voice_header {
+	uint32_t id;
+	uint32_t data_len;
+};
+
+struct voice_init {
+	struct voice_header hdr;
+	void *cb_handle;
+};
+
+/* Device information payload structure */
+
+struct device_data {
+	uint32_t volume; /* in index */
+	uint32_t mute;
+	uint32_t sample;
+	uint32_t enabled;
+	uint32_t dev_id;
+	uint32_t port_id;
+};
+
+struct voice_dev_route_state {
+	u16 rx_route_flag;
+	u16 tx_route_flag;
+};
+
+enum {
+	VOC_INIT = 0,
+	VOC_RUN,
+	VOC_CHANGE,
+	VOC_RELEASE,
+};
+
+/* TO MVM commands */
+#define VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION	0x000110FF
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION	0x000110FE
+/* Create a new full control MVM session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_ATTACH_STREAM			0x0001123C
+/* Attach a stream to the MVM. */
+
+#define VSS_IMVM_CMD_DETACH_STREAM			0x0001123D
+/* Detach a stream from the MVM. */
+
+#define VSS_IMVM_CMD_START_VOICE			0x00011190
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STOP_VOICE				0x00011192
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_ATTACH_VOCPROC			0x000110F8
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_DETACH_VOCPROC			0x000110F9
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+
+#define VSS_ISTREAM_CMD_SET_TTY_MODE			0x00011196
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ICOMMON_CMD_SET_NETWORK			0x0001119C
+/* Set the network type. */
+
+#define VSS_ICOMMON_CMD_SET_VOICE_TIMING		0x000111E0
+/* Set the voice timing parameters. */
+
+struct vss_istream_cmd_set_tty_mode_t {
+	uint32_t mode;
+	/**<
+	* TTY mode.
+	*
+	* 0 : TTY disabled
+	* 1 : HCO
+	* 2 : VCO
+	* 3 : FULL
+	*/
+} __packed;
+
+struct vss_istream_cmd_attach_vocproc_t {
+	uint16_t handle;
+	/**< Handle of vocproc being attached. */
+} __packed;
+
+struct vss_istream_cmd_detach_vocproc_t {
+	uint16_t handle;
+	/**< Handle of vocproc being detached. */
+} __packed;
+
+struct vss_imvm_cmd_attach_stream_t {
+	uint16_t handle;
+	/* The stream handle to attach. */
+} __packed;
+
+struct vss_imvm_cmd_detach_stream_t {
+	uint16_t handle;
+	/* The stream handle to detach. */
+} __packed;
+
+struct vss_icommon_cmd_set_network_t {
+	uint32_t network_id;
+	/* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+} __packed;
+
+struct vss_icommon_cmd_set_voice_timing_t {
+	uint16_t mode;
+	/*
+	 * The vocoder frame synchronization mode.
+	 *
+	 * 0 : No frame sync.
+	 * 1 : Hard VFR (20ms Vocoder Frame Reference interrupt).
+	 */
+	uint16_t enc_offset;
+	/*
+	 * The offset in microseconds from the VFR to deliver a Tx vocoder
+	 * packet. The offset should be less than 20000us.
+	 */
+	uint16_t dec_req_offset;
+	/*
+	 * The offset in microseconds from the VFR to request for an Rx vocoder
+	 * packet. The offset should be less than 20000us.
+	 */
+	uint16_t dec_offset;
+	/*
+	 * The offset in microseconds from the VFR to indicate the deadline to
+	 * receive an Rx vocoder packet. The offset should be less than 20000us.
+	 * Rx vocoder packets received after this deadline are not guaranteed to
+	 * be processed.
+	 */
+} __packed;
+
+struct vss_imvm_cmd_create_full_control_session_t {
+	char name[20];
+	/*
+	* A variable-sized stream name.
+	*
+	* The stream name size is the payload size minus the size of the other
+	* fields.
+	*/
+} __packed;
+
+
+struct mvm_attach_vocproc_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
+} __packed;
+
+struct mvm_detach_vocproc_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_detach_vocproc_t mvm_detach_cvp_handle;
+} __packed;
+
+struct mvm_create_passive_ctl_session_cmd {
+	struct apr_hdr hdr;
+} __packed;
+
+struct mvm_create_full_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_imvm_cmd_create_full_control_session_t mvm_session;
+} __packed;
+
+struct mvm_set_tty_mode_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_tty_mode_t tty_mode;
+} __packed;
+
+struct mvm_attach_stream_cmd {
+	struct apr_hdr hdr;
+	struct vss_imvm_cmd_attach_stream_t attach_stream;
+} __packed;
+
+struct mvm_detach_stream_cmd {
+	struct apr_hdr hdr;
+	struct vss_imvm_cmd_detach_stream_t detach_stream;
+} __packed;
+
+struct mvm_set_network_cmd {
+	struct apr_hdr hdr;
+	struct vss_icommon_cmd_set_network_t network;
+} __packed;
+
+struct mvm_set_voice_timing_cmd {
+	struct apr_hdr hdr;
+	struct vss_icommon_cmd_set_voice_timing_t timing;
+} __packed;
+
+/* TO CVS commands */
+#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION	0x00011140
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION	0x000110F7
+/* Create a new full control stream session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
+
+#define VSS_ISTREAM_CMD_SET_MUTE			0x00011022
+
+#define VSS_ISTREAM_CMD_SET_MEDIA_TYPE			0x00011186
+/* Set media type on the stream. */
+
+#define VSS_ISTREAM_EVT_SEND_ENC_BUFFER			0x00011015
+/* Event sent by the stream to its client to provide an encoded packet. */
+
+#define VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER		0x00011017
+/* Event sent by the stream to its client requesting for a decoder packet.
+ * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
+ */
+
+#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER			0x00011016
+/* Event sent by the client to the stream in response to a
+ * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
+ */
+
+#define VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE		0x0001113E
+/* Set AMR encoder rate. */
+
+#define VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE		0x0001113F
+/* Set AMR-WB encoder rate. */
+
+#define VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE	0x00011019
+/* Set encoder minimum and maximum rate. */
+
+#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE		0x0001101D
+/* Set encoder DTX mode. */
+
+struct vss_istream_cmd_create_passive_control_session_t {
+	char name[20];
+	/**<
+	* A variable-sized stream name.
+	*
+	* The stream name size is the payload size minus the size of the other
+	* fields.
+	*/
+} __packed;
+
+struct vss_istream_cmd_set_mute_t {
+	uint16_t direction;
+	/**<
+	* 0 : TX only
+	* 1 : RX only
+	* 2 : TX and Rx
+	*/
+	uint16_t mute_flag;
+	/**<
+	* Mute, un-mute.
+	*
+	* 0 : Silence disable
+	* 1 : Silence enable
+	* 2 : CNG enable. Applicable to TX only. If set on RX behavior
+	*     will be the same as 1
+	*/
+} __packed;
+
+struct vss_istream_cmd_create_full_control_session_t {
+	uint16_t direction;
+	/*
+	 * Stream direction.
+	 *
+	 * 0 : TX only
+	 * 1 : RX only
+	 * 2 : TX and RX
+	 * 3 : TX and RX loopback
+	 */
+	uint32_t enc_media_type;
+	/* Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+	uint32_t dec_media_type;
+	/* Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+	uint32_t network_id;
+	/* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+	char name[20];
+	/*
+	 * A variable-sized stream name.
+	 *
+	 * The stream name size is the payload size minus the size of the other
+	 * fields.
+	 */
+} __packed;
+
+struct vss_istream_cmd_set_media_type_t {
+	uint32_t rx_media_id;
+	/* Set the Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+	uint32_t tx_media_id;
+	/* Set the Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+} __packed;
+
+struct vss_istream_evt_send_enc_buffer_t {
+	uint32_t media_id;
+      /* Media ID of the packet. */
+	uint8_t packet_data[MAX_VOC_PKT_SIZE];
+      /* Packet data buffer. */
+} __packed;
+
+struct vss_istream_evt_send_dec_buffer_t {
+	uint32_t media_id;
+      /* Media ID of the packet. */
+	uint8_t packet_data[MAX_VOC_PKT_SIZE];
+      /* Packet data. */
+} __packed;
+
+struct vss_istream_cmd_voc_amr_set_enc_rate_t {
+	uint32_t mode;
+	/* Set the AMR encoder rate.
+	 *
+	 * 0x00000000 : 4.75 kbps
+	 * 0x00000001 : 5.15 kbps
+	 * 0x00000002 : 5.90 kbps
+	 * 0x00000003 : 6.70 kbps
+	 * 0x00000004 : 7.40 kbps
+	 * 0x00000005 : 7.95 kbps
+	 * 0x00000006 : 10.2 kbps
+	 * 0x00000007 : 12.2 kbps
+	 */
+} __packed;
+
+struct vss_istream_cmd_voc_amrwb_set_enc_rate_t {
+	uint32_t mode;
+	/* Set the AMR-WB encoder rate.
+	 *
+	 * 0x00000000 :  6.60 kbps
+	 * 0x00000001 :  8.85 kbps
+	 * 0x00000002 : 12.65 kbps
+	 * 0x00000003 : 14.25 kbps
+	 * 0x00000004 : 15.85 kbps
+	 * 0x00000005 : 18.25 kbps
+	 * 0x00000006 : 19.85 kbps
+	 * 0x00000007 : 23.05 kbps
+	 * 0x00000008 : 23.85 kbps
+	 */
+} __packed;
+
+struct vss_istream_cmd_cdma_set_enc_minmax_rate_t {
+	uint16_t min_rate;
+	/* Set the lower bound encoder rate.
+	 *
+	 * 0x0000 : Blank frame
+	 * 0x0001 : Eighth rate
+	 * 0x0002 : Quarter rate
+	 * 0x0003 : Half rate
+	 * 0x0004 : Full rate
+	 */
+	uint16_t max_rate;
+	/* Set the upper bound encoder rate.
+	 *
+	 * 0x0000 : Blank frame
+	 * 0x0001 : Eighth rate
+	 * 0x0002 : Quarter rate
+	 * 0x0003 : Half rate
+	 * 0x0004 : Full rate
+	 */
+} __packed;
+
+struct vss_istream_cmd_set_enc_dtx_mode_t {
+	uint32_t enable;
+	/* Toggle DTX on or off.
+	 *
+	 * 0 : Disables DTX
+	 * 1 : Enables DTX
+	 */
+} __packed;
+
+struct cvs_create_passive_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_create_passive_control_session_t cvs_session;
+} __packed;
+
+struct cvs_create_full_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_create_full_control_session_t cvs_session;
+};
+
+struct cvs_destroy_session_cmd {
+	struct apr_hdr hdr;
+} __packed;
+
+struct cvs_set_mute_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_mute_t cvs_set_mute;
+} __packed;
+
+struct cvs_set_media_type_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_media_type_t media_type;
+} __packed;
+
+struct cvs_send_dec_buf_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_evt_send_dec_buffer_t dec_buf;
+} __packed;
+
+struct cvs_set_amr_enc_rate_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_voc_amr_set_enc_rate_t amr_rate;
+} __packed;
+
+struct cvs_set_amrwb_enc_rate_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_voc_amrwb_set_enc_rate_t amrwb_rate;
+} __packed;
+
+struct cvs_set_cdma_enc_minmax_rate_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_cdma_set_enc_minmax_rate_t cdma_rate;
+} __packed;
+
+struct cvs_set_enc_dtx_mode_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_enc_dtx_mode_t dtx_mode;
+} __packed;
+
+/* TO CVP commands */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION	0x000100C3
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE			0x000100C4
+
+#define VSS_IVOCPROC_CMD_SET_VP3_DATA			0x000110EB
+
+#define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX		0x000110EE
+
+#define VSS_IVOCPROC_CMD_ENABLE				0x000100C6
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_CMD_DISABLE			0x000110E1
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_NONE			0x00010F70
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS		0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE		0x00010F72
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT		0x00010F77
+
+/* Newtwork IDs */
+#define VSS_NETWORK_ID_DEFAULT				0x00010037
+#define VSS_NETWORK_ID_VOIP_NB				0x00011240
+#define VSS_NETWORK_ID_VOIP_WB				0x00011241
+#define VSS_NETWORK_ID_VOIP_WV				0x00011242
+
+/* Media types */
+#define VSS_MEDIA_ID_EVRC_MODEM		0x00010FC2
+/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_NB_MODEM	0x00010FC6
+/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_WB_MODEM	0x00010FC7
+/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+#define VSS_MEDIA_ID_PCM_NB		0x00010FCB
+#define VSS_MEDIA_ID_PCM_WB		0x00010FCC
+/* Linear PCM (16-bit, little-endian). */
+#define VSS_MEDIA_ID_G711_ALAW		0x00010FCD
+/* G.711 a-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G711_MULAW		0x00010FCE
+/* G.711 mu-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G729		0x00010FD0
+/* G.729AB (contains two 10ms vocoder frames. */
+
+#define VOICE_CMD_SET_PARAM				0x00011006
+#define VOICE_CMD_GET_PARAM				0x00011007
+#define VOICE_EVT_GET_PARAM_ACK				0x00011008
+
+struct vss_ivocproc_cmd_create_full_control_session_t {
+	uint16_t direction;
+	/*
+	 * stream direction.
+	 * 0 : TX only
+	 * 1 : RX only
+	 * 2 : TX and RX
+	 */
+	uint32_t tx_port_id;
+	/*
+	 * TX device port ID which vocproc will connect to. If not supplying a
+	 * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+	 */
+	uint32_t tx_topology_id;
+	/*
+	 * Tx leg topology ID. If not supplying a topology ID set to
+	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+	 */
+	uint32_t rx_port_id;
+	/*
+	 * RX device port ID which vocproc will connect to. If not supplying a
+	 * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+	 */
+	uint32_t rx_topology_id;
+	/*
+	 * Rx leg topology ID. If not supplying a topology ID set to
+	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+	 */
+	int32_t network_id;
+	/*
+	 * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
+	 * ID set to VSS_NETWORK_ID_DEFAULT.
+	 */
+} __packed;
+
+struct vss_ivocproc_cmd_set_volume_index_t {
+	uint16_t vol_index;
+	/**<
+	* Volume index utilized by the vocproc to index into the volume table
+	* provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+	* volume on the VDSP.
+	*/
+} __packed;
+
+struct vss_ivocproc_cmd_set_device_t {
+	uint32_t tx_port_id;
+	/**<
+	* TX device port ID which vocproc will connect to.
+	* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+	*/
+	uint32_t tx_topology_id;
+	/**<
+	* TX leg topology ID.
+	* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+	* pre/post-processing blocks and is pass-through.
+	*/
+	int32_t rx_port_id;
+	/**<
+	* RX device port ID which vocproc will connect to.
+	* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+	*/
+	uint32_t rx_topology_id;
+	/**<
+	* RX leg topology ID.
+	* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+	* pre/post-processing blocks and is pass-through.
+	*/
+} __packed;
+
+struct cvp_create_full_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+} __packed;
+
+struct cvp_command {
+	struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_device_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+} __packed;
+
+struct cvp_set_vp3_data_cmd {
+	struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_rx_volume_index_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
+} __packed;
+
+/* CB for up-link packets. */
+typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
+			 uint32_t pkt_len,
+			 void *private_data);
+
+/* CB for down-link packets. */
+typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
+			 uint32_t *pkt_len,
+			 void *private_data);
+
+
+struct mvs_driver_info {
+	uint32_t media_type;
+	uint32_t rate;
+	uint32_t network_type;
+	ul_cb_fn ul_cb;
+	dl_cb_fn dl_cb;
+	void *private_data;
+};
+
+struct incall_rec_info {
+	uint32_t pending;
+	uint32_t rec_mode;
+};
+
+struct incall_music_info {
+	uint32_t pending;
+	uint32_t playing;
+};
+
+struct voice_data {
+	int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+	uint32_t voc_path;
+
+	wait_queue_head_t mvm_wait;
+	wait_queue_head_t cvs_wait;
+	wait_queue_head_t cvp_wait;
+
+	uint32_t device_events;
+
+	/* cache the values related to Rx and Tx */
+	struct device_data dev_rx;
+	struct device_data dev_tx;
+
+	/* these default values are for all devices */
+	uint32_t default_mute_val;
+	uint32_t default_vol_val;
+	uint32_t default_sample_val;
+
+	/* APR to MVM in the Q6 */
+	void *apr_q6_mvm;
+	/* APR to CVS in the Q6 */
+	void *apr_q6_cvs;
+	/* APR to CVP in the Q6 */
+	void *apr_q6_cvp;
+
+	u32 mvm_state;
+	u32 cvs_state;
+	u32 cvp_state;
+
+	/* Handle to MVM in the Q6 */
+	u16 mvm_passive_handle;  /* for cs call */
+	u16 mvm_full_handle;     /* for voip */
+	/* Handle to CVS in the Q6 */
+	u16 cvs_passive_handle;
+	u16 cvs_full_handle;
+	/* Handle to CVP in the Q6 */
+	u16 cvp_passive_handle;
+	u16 cvp_full_handle;
+
+	struct mutex lock;
+
+	struct mvs_driver_info mvs_info;
+
+	uint16_t sidetone_gain;
+
+	struct voice_dev_route_state voc_route_state;
+};
+
+int voc_set_voc_path_full(uint32_t set);
+
+void voc_register_mvs_cb(ul_cb_fn ul_cb,
+			dl_cb_fn dl_cb,
+			void *private_data);
+
+void voc_config_vocoder(uint32_t media_type,
+			uint32_t rate,
+			uint32_t network_type);
+
+enum {
+	DEV_RX = 0,
+	DEV_TX,
+};
+
+enum {
+	RX_PATH = 0,
+	TX_PATH,
+};
+
+/* called  by alsa driver */
+int voc_start_voice_call(void);
+int voc_end_voice_call(void);
+void voc_set_rxtx_port(uint32_t dev_port_id, uint32_t dev_type);
+int voc_set_rx_vol_index(uint32_t dir, uint32_t voc_idx);
+int voc_set_tx_mute(uint32_t dir, uint32_t mute);
+int voc_disable_cvp(void);
+int voc_enable_cvp(void);
+void voc_set_route_flag(uint8_t path_dir, uint8_t set);
+uint8_t voc_get_route_flag(uint8_t path_dir);
+
+#endif
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 9465588..f16f02b 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -10,8 +10,7 @@
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
+ *  Free Software Foundation;  only version 2 of the  License.
  */
 
 #include <linux/slab.h>
@@ -497,5 +496,5 @@
 
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index f8f6816..c004645 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -6,8 +6,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1dc6de6..87569ed 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2,12 +2,12 @@
  * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
+ *
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
+ *  Free Software Foundation;  only version 2 of the  License.
  *
  *  Features:
  *    o Changes power status of internal codec blocks depending on the
@@ -1545,7 +1545,6 @@
 			dapm->dev_power = 1;
 			break;
 		case SND_SOC_DAPM_STREAM_STOP:
-#warning need re-work
 			if (dapm->codec)
 				dapm->dev_power = !!dapm->codec->active;
 			else
@@ -3073,4 +3072,4 @@
 /* Module information */
 MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index 9323b57..77eda32 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -5,10 +5,9 @@
  *
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  *
  */
 
@@ -1511,4 +1510,4 @@
 /* Module information */
 MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("ALSA SoC DSP Core");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");