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/arch/arm/mach-msm/qdsp6/Makefile b/arch/arm/mach-msm/qdsp6/Makefile
new file mode 100644
index 0000000..9a55612
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/Makefile
@@ -0,0 +1,19 @@
+obj-y += dal.o
+obj-y += q6audio.o
+obj-y += analog_audio.o
+obj-y += pcm_out.o
+obj-y += pcm_in.o
+obj-y += auxpcm_lb_out.o
+obj-y += auxpcm_lb_in.o
+obj-y += aac_in.o
+obj-y += qcelp_in.o
+obj-y += evrc_in.o
+obj-y += amrnb_in.o
+obj-y += mp3.o
+obj-y += dtmf.o
+obj-y += routing.o
+obj-y += audio_ctl.o
+obj-y += msm_q6vdec.o
+obj-y += msm_q6venc.o
+obj-y += dsp_debug.o
+obj-$(CONFIG_QSD_AUDIO) += audiov2/
diff --git a/arch/arm/mach-msm/qdsp6/aac_in.c b/arch/arm/mach-msm/qdsp6/aac_in.c
new file mode 100644
index 0000000..9e1d5b6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/aac_in.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_aac.h>
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+#define AAC_FC_BUFF_CNT 10
+#define AAC_READ_TIMEOUT 2000
+struct aac_fc_buff {
+	struct mutex lock;
+	int empty;
+	void *data;
+	int size;
+	int actual_size;
+};
+
+struct aac_fc {
+	struct task_struct *task;
+	wait_queue_head_t fc_wq;
+	struct aac_fc_buff fc_buff[AAC_FC_BUFF_CNT];
+	int buff_index;
+};
+struct aac {
+	struct mutex lock;
+	struct msm_audio_aac_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+	struct aac_fc *aac_fc;
+};
+
+static int q6_aac_flowcontrol(void *data)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	struct aac *aac = data;
+	int buff_index = 0;
+	int xfer = 0;
+	struct aac_fc *fc;
+
+
+	ac = aac->audio_client;
+	fc = aac->aac_fc;
+	if (!ac) {
+		pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__);
+		return 0;
+	}
+
+	while (!kthread_should_stop()) {
+		ab = ac->buf + ac->cpu_buf;
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__,
+			 __func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+		mutex_lock(&(fc->fc_buff[buff_index].lock));
+		if (!fc->fc_buff[buff_index].empty) {
+			pr_err("[%s:%s] flow control buffer[%d] not read!\n",
+					__MM_FILE__, __func__, buff_index);
+		}
+
+		if (fc->fc_buff[buff_index].size < xfer) {
+			pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__,
+					__func__, buff_index);
+			memcpy(fc->fc_buff[buff_index].data,
+				ab->data, fc->fc_buff[buff_index].size);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size =
+				fc->fc_buff[buff_index].size;
+		} else {
+			memcpy(fc->fc_buff[buff_index].data, ab->data, xfer);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size = xfer;
+		}
+		mutex_unlock(&(fc->fc_buff[buff_index].lock));
+		/*wake up client, if any*/
+		wake_up(&fc->fc_wq);
+
+		buff_index++;
+		if (buff_index >= AAC_FC_BUFF_CNT)
+			buff_index = 0;
+
+		ab->used = 1;
+
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return 0;
+}
+static long q6_aac_in_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	struct aac *aac = file->private_data;
+	int rc = 0;
+	int i = 0;
+	struct aac_fc *fc;
+	int size = 0;
+
+	mutex_lock(&aac->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id, (void *) arg,
+					sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (aac->audio_client) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		} else {
+			aac->audio_client = q6audio_open_aac(
+					aac->str_cfg.buffer_size,
+					aac->cfg.sample_rate,
+					aac->cfg.channels,
+					aac->cfg.bit_rate,
+					aac->cfg.stream_format,
+					aac->voicerec_mode.rec_mode, acdb_id);
+
+			if (aac->audio_client < 0) {
+				pr_err("[%s:%s] aac open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		/*allocate flow control buffers*/
+		fc = aac->aac_fc;
+		size = ((aac->str_cfg.buffer_size < 1543) ? 1543 :
+				aac->str_cfg.buffer_size);
+		for (i = 0; i < AAC_FC_BUFF_CNT; ++i) {
+			mutex_init(&(fc->fc_buff[i].lock));
+			fc->fc_buff[i].empty = 1;
+			fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL);
+			if (fc->fc_buff[i].data == NULL) {
+				pr_err("[%s:%s] No memory for FC buffers\n",
+						__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				goto fc_fail;
+			}
+			fc->fc_buff[i].size = size;
+			fc->fc_buff[i].actual_size = 0;
+		}
+
+		/*create flow control thread*/
+		fc->task = kthread_run(q6_aac_flowcontrol,
+				aac, "aac_flowcontrol");
+		if (IS_ERR(fc->task)) {
+			rc = PTR_ERR(fc->task);
+			pr_err("[%s:%s] error creating flow control thread\n",
+					__MM_FILE__, __func__);
+			goto fc_fail;
+		}
+		break;
+fc_fail:
+		/*free flow control buffers*/
+		--i;
+		for (; i >=  0; i--) {
+			kfree(fc->fc_buff[i].data);
+			fc->fc_buff[i].data = NULL;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&aac->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (aac->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+			&& aac->voicerec_mode.rec_mode !=
+			AUDIO_FLAG_INCALL_MIXED) {
+			aac->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &aac->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, aac->str_cfg.buffer_size,
+			aac->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&aac->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, aac->str_cfg.buffer_size,
+			aac->str_cfg.buffer_count);
+		if (aac->str_cfg.buffer_size < 1543) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+		if (aac->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+
+		break;
+	case AUDIO_SET_AAC_ENC_CONFIG:
+		if (copy_from_user(&aac->cfg, (void *) arg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] SET_AAC_ENC_CONFIG: channels=%d, rate=%d\n",
+			__MM_FILE__, __func__, aac->cfg.channels,
+			aac->cfg.sample_rate);
+		if (aac->cfg.channels < 1 || aac->cfg.channels > 2) {
+			pr_err("[%s:%s]invalid number of channels\n",
+				 __MM_FILE__, __func__);
+			rc = -EINVAL;
+		}
+		if (aac->cfg.sample_rate != 48000) {
+			pr_err("[%s:%s] only 48KHz is supported\n",
+					__MM_FILE__, __func__);
+			rc = -EINVAL;
+		}
+		if (aac->cfg.stream_format != AUDIO_AAC_FORMAT_RAW &&
+			aac->cfg.stream_format != AUDIO_AAC_FORMAT_ADTS) {
+			pr_err("[%s:%s] unsupported AAC format\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_AAC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &aac->cfg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_AAC_ENC_CONFIG: channels=%d, rate=%d\n",
+			__MM_FILE__, __func__, aac->cfg.channels,
+			aac->cfg.sample_rate);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&aac->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_aac_in_open(struct inode *inode, struct file *file)
+{
+
+	struct aac *aac;
+	struct aac_fc *fc;
+	int i;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	aac = kmalloc(sizeof(struct aac), GFP_KERNEL);
+	if (aac == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for aac driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&aac->lock);
+	file->private_data = aac;
+	aac->audio_client = NULL;
+	aac->str_cfg.buffer_size = 1543;
+	aac->str_cfg.buffer_count = 2;
+	aac->cfg.channels = 1;
+	aac->cfg.bit_rate = 192000;
+	aac->cfg.stream_format = AUDIO_AAC_FORMAT_ADTS;
+	aac->cfg.sample_rate = 48000;
+	aac->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	aac->aac_fc = kmalloc(sizeof(struct aac_fc), GFP_KERNEL);
+	if (aac->aac_fc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for aac_fc\n",
+				__MM_FILE__, __func__);
+		kfree(aac);
+		return -ENOMEM;
+	}
+	fc = aac->aac_fc;
+	fc->task = NULL;
+	fc->buff_index = 0;
+	for (i = 0; i < AAC_FC_BUFF_CNT; ++i) {
+		fc->fc_buff[i].data = NULL;
+		fc->fc_buff[i].size = 0;
+		fc->fc_buff[i].actual_size = 0;
+	}
+	/*initialize wait queue head*/
+	init_waitqueue_head(&fc->fc_wq);
+	return 0;
+}
+
+static ssize_t q6_aac_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	const char __user *start = buf;
+	struct aac *aac = file->private_data;
+	struct aac_fc *fc;
+	int xfer = 0;
+	int res = 0;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&aac->lock);
+	ac = aac->audio_client;
+
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	fc = aac->aac_fc;
+
+	/*wait for buffer to full*/
+	if (fc->fc_buff[fc->buff_index].empty != 0) {
+		res = wait_event_interruptible_timeout(fc->fc_wq,
+			(fc->fc_buff[fc->buff_index].empty == 0),
+				msecs_to_jiffies(AAC_READ_TIMEOUT));
+
+		pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__,
+			__func__, fc->buff_index);
+		if (res == 0) {
+			pr_err("[%s:%s] Timeout!\n", __MM_FILE__, __func__);
+			res = -ETIMEDOUT;
+			goto fail;
+		} else if (res < 0) {
+			pr_err("[%s:%s] Returning on Interrupt\n", __MM_FILE__,
+				__func__);
+			goto fail;
+		}
+	}
+	/*lock the buffer*/
+	mutex_lock(&(fc->fc_buff[fc->buff_index].lock));
+	xfer = fc->fc_buff[fc->buff_index].actual_size;
+
+	if (xfer > count) {
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		pr_err("[%s:%s] read failed! byte count too small\n",
+				__MM_FILE__, __func__);
+		res = -EINVAL;
+		goto fail;
+	}
+
+	if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data,	xfer)) {
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		pr_err("[%s:%s] copy_to_user failed at index %d\n",
+				__MM_FILE__, __func__, fc->buff_index);
+		res = -EFAULT;
+		goto fail;
+	}
+
+	buf += xfer;
+
+	fc->fc_buff[fc->buff_index].empty = 1;
+	fc->fc_buff[fc->buff_index].actual_size = 0;
+
+	mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+	++(fc->buff_index);
+	if (fc->buff_index >= AAC_FC_BUFF_CNT)
+		fc->buff_index = 0;
+
+	res = buf - start;
+fail:
+	mutex_unlock(&aac->lock);
+
+	return res;
+}
+
+static int q6_aac_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct aac *aac = file->private_data;
+	int i = 0;
+	struct aac_fc *fc;
+
+	mutex_lock(&aac->lock);
+	fc = aac->aac_fc;
+	kthread_stop(fc->task);
+	fc->task = NULL;
+
+	/*free flow control buffers*/
+	for (i = 0; i < AAC_FC_BUFF_CNT; ++i) {
+		kfree(fc->fc_buff[i].data);
+		fc->fc_buff[i].data = NULL;
+	}
+	kfree(fc);
+	if (aac->audio_client)
+		rc = q6audio_close(aac->audio_client);
+	mutex_unlock(&aac->lock);
+	kfree(aac);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_aac_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_aac_in_open,
+	.read		= q6_aac_in_read,
+	.release	= q6_aac_in_release,
+	.unlocked_ioctl	= q6_aac_in_ioctl,
+};
+
+struct miscdevice q6_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &q6_aac_in_fops,
+};
+
+static int __init q6_aac_in_init(void)
+{
+	return misc_register(&q6_aac_in_misc);
+}
+
+device_initcall(q6_aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/amrnb_in.c b/arch/arm/mach-msm/qdsp6/amrnb_in.c
new file mode 100644
index 0000000..e7756e1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/amrnb_in.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_amrnb.h>
+#include <mach/msm_qdsp6_audio.h>
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+struct amrnb {
+	struct mutex lock;
+	struct msm_audio_amrnb_enc_config_v2 cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+};
+
+
+static long q6_amrnb_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct amrnb *amrnb = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&amrnb->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id, (void *) arg,
+						sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (amrnb->audio_client) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		} else {
+			amrnb->audio_client = q6audio_open_amrnb(
+					amrnb->str_cfg.buffer_size,
+					amrnb->cfg.band_mode,
+					amrnb->cfg.dtx_enable,
+					amrnb->voicerec_mode.rec_mode,
+					acdb_id);
+			if (!amrnb->audio_client) {
+				pr_err("[%s:%s] amrnb open session failed\n",
+					__MM_FILE__, __func__);
+				kfree(amrnb);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&amrnb->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (amrnb->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+				&& amrnb->voicerec_mode.rec_mode !=
+				AUDIO_FLAG_INCALL_MIXED) {
+			amrnb->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &amrnb->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt = %d\n",
+			 __MM_FILE__, __func__, amrnb->str_cfg.buffer_size,
+			amrnb->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&amrnb->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt = %d\n",
+			 __MM_FILE__, __func__, amrnb->str_cfg.buffer_size,
+			amrnb->str_cfg.buffer_count);
+
+		if (amrnb->str_cfg.buffer_size < 768) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (amrnb->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_AMRNB_ENC_CONFIG:
+		if (copy_from_user(&amrnb->cfg, (void *) arg,
+			sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] SET_AMRNB_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+	case AUDIO_GET_AMRNB_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &amrnb->cfg,
+				 sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_AMRNB_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&amrnb->lock);
+	pr_debug("[%s:%s] rc= %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_amrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct amrnb *amrnb;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	amrnb = kmalloc(sizeof(struct amrnb), GFP_KERNEL);
+	if (amrnb == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for amrnb driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&amrnb->lock);
+	file->private_data = amrnb;
+	amrnb->audio_client = NULL;
+	amrnb->str_cfg.buffer_size = 768;
+	amrnb->str_cfg.buffer_count = 2;
+	amrnb->cfg.band_mode = 7;
+	amrnb->cfg.dtx_enable  = 3;
+	amrnb->cfg.frame_format = ADSP_AUDIO_FORMAT_AMRNB_FS;
+	amrnb->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	return 0;
+}
+
+static ssize_t q6_amrnb_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct amrnb *amrnb = file->private_data;
+	int xfer = 0;
+	int res;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&amrnb->lock);
+	ac = amrnb->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			pr_err("[%s:%s] copy_to_user failed\n",
+				__MM_FILE__, __func__);
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+fail:
+	mutex_unlock(&amrnb->lock);
+
+	return res;
+}
+
+static int q6_amrnb_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct amrnb *amrnb = file->private_data;
+
+	mutex_lock(&amrnb->lock);
+	if (amrnb->audio_client)
+		rc = q6audio_close(amrnb->audio_client);
+	mutex_unlock(&amrnb->lock);
+	kfree(amrnb);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_amrnb_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_amrnb_in_open,
+	.read		= q6_amrnb_in_read,
+	.release	= q6_amrnb_in_release,
+	.unlocked_ioctl	= q6_amrnb_in_ioctl,
+};
+
+struct miscdevice q6_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amr_in",
+	.fops	= &q6_amrnb_in_fops,
+};
+
+static int __init q6_amrnb_in_init(void)
+{
+	return misc_register(&q6_amrnb_in_misc);
+}
+
+device_initcall(q6_amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/analog_audio.c b/arch/arm/mach-msm/qdsp6/analog_audio.c
new file mode 100644
index 0000000..688f57e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/analog_audio.c
@@ -0,0 +1,94 @@
+/* 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/init.h>
+#include <linux/wait.h>
+#include <linux/gpio.h>
+#include <mach/pmic.h>
+#include <mach/msm_qdsp6_audio.h>
+#include <asm/string.h>
+#include <asm/mach-types.h>
+#include <mach/debug_mm.h>
+
+#define GPIO_HEADSET_AMP 157
+#define GPIO_SPEAKER_AMP 39
+#define GPIO_HEADSET_SHDN_N 48
+
+void analog_init(void)
+{
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+	gpio_direction_output(GPIO_HEADSET_AMP, 1);
+	gpio_set_value(GPIO_HEADSET_AMP, 0);
+}
+
+void analog_headset_enable(int en)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	/* enable audio amp */
+	gpio_set_value(GPIO_HEADSET_AMP, !!en);
+}
+
+void analog_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	if (en) {
+		scm.is_right_chan_en = 1;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 1;
+		scm.is_hpf_en = 1;
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+		pmic_set_spkr_configuration(&scm);
+		pmic_spkr_en(LEFT_SPKR, 1);
+		pmic_spkr_en(RIGHT_SPKR, 1);
+		
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+		pmic_spkr_en_mute(RIGHT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+}
+
+void analog_mic_enable(int en)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	pmic_mic_en(en);
+}
+
+static struct q6audio_analog_ops ops = {
+	.init = analog_init,
+	.speaker_enable = analog_speaker_enable,
+	.headset_enable = analog_headset_enable,
+	.int_mic_enable = analog_mic_enable,
+	.ext_mic_enable = analog_mic_enable,
+};
+
+static int __init init(void)
+{
+	q6audio_register_analog_ops(&ops);
+	return 0;
+}
+
+device_initcall(init);
diff --git a/arch/arm/mach-msm/qdsp6/audio_ctl.c b/arch/arm/mach-msm/qdsp6/audio_ctl.c
new file mode 100644
index 0000000..ab1df39
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audio_ctl.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+#define BUFSZ (0)
+
+static DEFINE_MUTEX(voice_lock);
+static int voice_started;
+
+static struct audio_client *voc_tx_clnt;
+static struct audio_client *voc_rx_clnt;
+
+static int q6_voice_start(void)
+{
+	int rc = 0;
+
+	mutex_lock(&voice_lock);
+
+	if (voice_started) {
+		pr_err("[%s:%s] busy\n", __MM_FILE__, __func__);
+		rc = -EBUSY;
+		goto done;
+	}
+
+	voc_tx_clnt = q6voice_open(AUDIO_FLAG_WRITE);
+	if (!voc_tx_clnt) {
+		pr_err("[%s:%s] open voice tx failed.\n", __MM_FILE__,
+				__func__);
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	voc_rx_clnt = q6voice_open(AUDIO_FLAG_READ);
+	if (!voc_rx_clnt) {
+		pr_err("[%s:%s] open voice rx failed.\n", __MM_FILE__,
+				__func__);
+		q6voice_close(voc_tx_clnt);
+		rc = -ENOMEM;
+	}
+
+	voice_started = 1;
+done:
+	mutex_unlock(&voice_lock);
+	return rc;
+}
+
+static int q6_voice_stop(void)
+{
+	mutex_lock(&voice_lock);
+	if (voice_started) {
+		q6voice_close(voc_tx_clnt);
+		q6voice_close(voc_rx_clnt);
+		voice_started = 0;
+	}
+	mutex_unlock(&voice_lock);
+	return 0;
+}
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static long q6_ioctl(struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	uint32_t n;
+	uint32_t id[2];
+	uint32_t mute_status;
+
+	switch (cmd) {
+	case AUDIO_SWITCH_DEVICE:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		pr_info("[%s:%s] SWITCH_DEV: id[0] = 0x%x, id[1] = 0x%x",
+			__MM_FILE__, __func__, id[0], id[1]);
+		if (!rc)
+			rc = q6audio_do_routing(id[0], id[1]);
+		break;
+	case AUDIO_SET_VOLUME:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		pr_debug("[%s:%s] SET_VOLUME: vol = %d\n", __MM_FILE__,
+				__func__, n);
+		if (!rc)
+			rc = q6audio_set_rx_volume(n);
+		break;
+	case AUDIO_SET_MUTE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc) {
+			if (voice_started) {
+				if (n == 1)
+					mute_status = STREAM_MUTE;
+				else
+					mute_status = STREAM_UNMUTE;
+			} else {
+				if (n == 1)
+					mute_status = DEVICE_MUTE;
+				else
+					mute_status = DEVICE_UNMUTE;
+			}
+
+			pr_debug("[%s:%s] SET_MUTE: mute_status = %d\n",
+				__MM_FILE__, __func__, mute_status);
+			rc = q6audio_set_tx_mute(mute_status);
+		}
+		break;
+	case AUDIO_UPDATE_ACDB:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		pr_debug("[%s:%s] UPDATE_ACDB: id[0] = 0x%x, id[1] = 0x%x\n",
+				__MM_FILE__, __func__, id[0], id[1]);
+		if (!rc)
+			rc = q6audio_update_acdb(id[0], 0);
+		break;
+	case AUDIO_START_VOICE:
+		pr_debug("[%s:%s] START_VOICE\n", __MM_FILE__, __func__);
+		rc = q6_voice_start();
+		break;
+	case AUDIO_STOP_VOICE:
+		pr_debug("[%s:%s] STOP_VOICE\n", __MM_FILE__, __func__);
+		rc = q6_voice_stop();
+		break;
+	case AUDIO_REINIT_ACDB:
+		pr_debug("[%s:%s] REINIT_ACDB\n", __MM_FILE__, __func__);
+		rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations q6_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.unlocked_ioctl	= q6_ioctl,
+	.release	= q6_release,
+};
+
+struct miscdevice q6_control_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_ctl",
+	.fops	= &q6_dev_fops,
+};
+
+
+static int __init q6_audio_ctl_init(void) {
+	return misc_register(&q6_control_device);
+}
+
+device_initcall(q6_audio_ctl_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/Makefile b/arch/arm/mach-msm/qdsp6/audiov2/Makefile
new file mode 100644
index 0000000..86ab9ae
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/Makefile
@@ -0,0 +1,12 @@
+obj-y += q6audio.o
+obj-y += aac_in.o
+obj-y += voice.o
+obj-y += pcm_out.o
+obj-y += pcm_in.o
+obj-y += mp3.o
+obj-y += audio_ctl.o
+obj-y += analog_audio.o
+obj-y += routing.o
+obj-y += evrc_in.o
+obj-y += qcelp_in.o
+obj-y += amrnb_in.o
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/aac_in.c b/arch/arm/mach-msm/qdsp6/audiov2/aac_in.c
new file mode 100644
index 0000000..fe6c049
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/aac_in.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_aac.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+struct aac {
+	struct mutex lock;
+	struct msm_audio_aac_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+static long q6_aac_in_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	struct aac *aac = file->private_data;
+	struct adsp_open_command rpc;
+
+	int sample_rate;
+	int audio_object_type;
+	int index = sizeof(u32);
+	int rc = 0;
+	u32 *aac_type = NULL;
+
+
+	mutex_lock(&aac->lock);
+	switch (cmd) {
+
+	case AUDIO_START:
+		if (aac->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			tx_clk_freq = 48000;
+			aac->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						aac->str_cfg.buffer_size);
+
+			if (aac->audio_client < 0) {
+
+				tx_clk_freq = 8000;
+				rc = -ENOMEM;
+				break;
+			}
+		}
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.binary.format = ADSP_AUDIO_FORMAT_MPEG4_AAC;
+		/* only 48k sample rate is supported */
+		sample_rate = 3;
+
+		/* AAC OBJECT LC */
+		audio_object_type = 2;
+
+		aac_type = (u32 *)rpc.format_block.binary.data;
+		switch (aac->cfg.stream_format) {
+
+		case AUDIO_AAC_FORMAT_ADTS:
+			/* AAC Encoder expect MPEG4_ADTS media type */
+			*aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS;
+			break;
+		case AUDIO_AAC_FORMAT_RAW:
+			/* for ADIF recording */
+			*aac_type = ADSP_AUDIO_AAC_RAW;
+			break;
+		}
+
+		rpc.format_block.binary.data[index++] = (u8)(
+			((audio_object_type & 0x1F) << 3) |
+			((sample_rate >> 1) & 0x7));
+		rpc.format_block.binary.data[index] = (u8)(
+			((sample_rate & 0x1) << 7) |
+			((aac->cfg.channels & 0x7) << 3));
+
+		rpc.format_block.binary.num_bytes = index + 1;
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = aac->str_cfg.buffer_size;
+		rpc.config.aac.bit_rate = aac->cfg.bit_rate;
+		rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE;
+		q6audio_start(aac->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &aac->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&aac->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (aac->str_cfg.buffer_size < 519) {
+			pr_err("Buffer size too small\n");
+			rc = -EINVAL;
+			break;
+		}
+		if (aac->str_cfg.buffer_count != 2)
+			pr_info("Buffer count set to 2\n");
+
+		break;
+	case AUDIO_SET_AAC_ENC_CONFIG:
+		if (copy_from_user(&aac->cfg, (void *) arg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		if (aac->cfg.channels != 1) {
+			pr_err("only mono is supported\n");
+			rc = -EINVAL;
+		}
+		if (aac->cfg.sample_rate != 48000) {
+			pr_err("only 48KHz is supported\n");
+			rc = -EINVAL;
+		}
+		if (aac->cfg.stream_format != AUDIO_AAC_FORMAT_RAW &&
+			aac->cfg.stream_format != AUDIO_AAC_FORMAT_ADTS) {
+			pr_err("unsupported AAC format\n");
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_AAC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &aac->cfg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&aac->lock);
+	return rc;
+}
+
+static int q6_aac_in_open(struct inode *inode, struct file *file)
+{
+
+	struct aac *aac;
+	aac = kmalloc(sizeof(struct aac), GFP_KERNEL);
+	if (aac == NULL) {
+		pr_err("Could not allocate memory for aac driver\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&aac->lock);
+	file->private_data = aac;
+	aac->audio_client = NULL;
+	aac->str_cfg.buffer_size = 519;
+	aac->str_cfg.buffer_count = 2;
+	aac->cfg.channels = 1;
+	aac->cfg.bit_rate = 192000;
+	aac->cfg.stream_format = AUDIO_AAC_FORMAT_ADTS;
+	aac->cfg.sample_rate = 48000;
+
+	return 0;
+}
+
+static ssize_t q6_aac_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct aac *aac = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&aac->lock);
+	ac = aac->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+	res = buf - start;
+fail:
+	mutex_unlock(&aac->lock);
+
+	return res;
+}
+
+static int q6_aac_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct aac *aac = file->private_data;
+
+	mutex_lock(&aac->lock);
+	if (aac->audio_client)
+		rc = q6audio_close(aac->audio_client);
+	mutex_unlock(&aac->lock);
+	kfree(aac);
+	tx_clk_freq = 8000;
+	return rc;
+}
+
+static const struct file_operations q6_aac_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_aac_in_open,
+	.read		= q6_aac_in_read,
+	.release	= q6_aac_in_release,
+	.unlocked_ioctl	= q6_aac_in_ioctl,
+};
+
+struct miscdevice q6_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &q6_aac_in_fops,
+};
+
+static int __init q6_aac_in_init(void)
+{
+	return misc_register(&q6_aac_in_misc);
+}
+
+device_initcall(q6_aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/amrnb_in.c b/arch/arm/mach-msm/qdsp6/audiov2/amrnb_in.c
new file mode 100644
index 0000000..b877977
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/amrnb_in.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_amrnb.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+
+struct amrnb {
+	struct mutex lock;
+	struct msm_audio_amrnb_enc_config_v2 cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+
+static long q6_amrnb_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct amrnb *amrnb = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&amrnb->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if (amrnb->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			amrnb->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						amrnb->str_cfg.buffer_size);
+
+			if (!amrnb->audio_client) {
+				kfree(amrnb);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		tx_clk_freq = 8000;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_AMRNB_FS;
+		rpc.format_block.standard.channels = 1;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = 8000;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = amrnb->str_cfg.buffer_size;
+		rpc.config.amr.mode = amrnb->cfg.band_mode;
+		rpc.config.amr.dtx_mode = amrnb->cfg.dtx_enable;
+		rpc.config.amr.enable = 1;
+		q6audio_start(amrnb->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &amrnb->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&amrnb->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (amrnb->str_cfg.buffer_size < 768) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (amrnb->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_AMRNB_ENC_CONFIG:
+		if (copy_from_user(&amrnb->cfg, (void *) arg,
+			sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_GET_AMRNB_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &amrnb->cfg,
+				 sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&amrnb->lock);
+	return rc;
+}
+
+static int q6_amrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct amrnb *amrnb;
+	amrnb = kmalloc(sizeof(struct amrnb), GFP_KERNEL);
+	if (amrnb == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for amrnb driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&amrnb->lock);
+	file->private_data = amrnb;
+	amrnb->audio_client = NULL;
+	amrnb->str_cfg.buffer_size = 768;
+	amrnb->str_cfg.buffer_count = 2;
+	amrnb->cfg.band_mode = ADSP_AUDIO_AMR_MR475;
+	amrnb->cfg.dtx_enable  = ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO;
+	amrnb->cfg.frame_format  = ADSP_AUDIO_FORMAT_AMRNB_FS;
+	return 0;
+}
+
+static ssize_t q6_amrnb_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct amrnb *amrnb = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&amrnb->lock);
+	ac = amrnb->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+fail:
+	mutex_unlock(&amrnb->lock);
+
+	return res;
+}
+
+static int q6_amrnb_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct amrnb *amrnb = file->private_data;
+
+	mutex_lock(&amrnb->lock);
+	if (amrnb->audio_client)
+		rc = q6audio_close(amrnb->audio_client);
+	mutex_unlock(&amrnb->lock);
+	kfree(amrnb);
+	return rc;
+}
+
+static const struct file_operations q6_amrnb_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_amrnb_in_open,
+	.read		= q6_amrnb_in_read,
+	.release	= q6_amrnb_in_release,
+	.unlocked_ioctl	= q6_amrnb_in_ioctl,
+};
+
+struct miscdevice q6_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amr_in",
+	.fops	= &q6_amrnb_in_fops,
+};
+
+static int __init q6_amrnb_in_init(void)
+{
+	return misc_register(&q6_amrnb_in_misc);
+}
+
+device_initcall(q6_amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/analog_audio.c b/arch/arm/mach-msm/qdsp6/audiov2/analog_audio.c
new file mode 100644
index 0000000..1df4f5d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/analog_audio.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <mach/pmic.h>
+#include <mach/msm_qdsp6_audiov2.h>
+
+#define GPIO_HEADSET_AMP 157
+
+void analog_init(void)
+{
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+
+	gpio_direction_output(GPIO_HEADSET_AMP, 1);
+	gpio_set_value(GPIO_HEADSET_AMP, 0);
+}
+
+void analog_headset_enable(int en)
+{
+	/* enable audio amp */
+	gpio_set_value(GPIO_HEADSET_AMP, !!en);
+}
+
+void analog_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	if (en) {
+		scm.is_right_chan_en = 1;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 1;
+		scm.is_hpf_en = 1;
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+		pmic_set_spkr_configuration(&scm);
+		pmic_spkr_en(LEFT_SPKR, 1);
+		pmic_spkr_en(RIGHT_SPKR, 1);
+
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+		pmic_spkr_en_mute(RIGHT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+}
+
+void analog_mic_enable(int en)
+{
+	pmic_mic_en(en);
+}
+
+static struct q6audio_analog_ops ops = {
+	.init = analog_init,
+	.speaker_enable = analog_speaker_enable,
+	.headset_enable = analog_headset_enable,
+	.int_mic_enable = analog_mic_enable,
+};
+
+static int __init init(void)
+{
+	q6audio_register_analog_ops(&ops);
+	return 0;
+}
+
+device_initcall(init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/audio_ctl.c b/arch/arm/mach-msm/qdsp6/audiov2/audio_ctl.c
new file mode 100644
index 0000000..286d85d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/audio_ctl.c
@@ -0,0 +1,140 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/audio_ctrl.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+
+#define BUFSZ (0)
+
+static DEFINE_MUTEX(voice_lock);
+static int voice_started;
+
+static struct audio_client *voc_clnt;
+
+static int q6_voice_start(void)
+{
+	int rc = 0;
+
+	mutex_lock(&voice_lock);
+
+	if (voice_started) {
+		pr_err("voice: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	voc_clnt = q6voice_open();
+	if (!voc_clnt) {
+		pr_err("voice: open voice failed.\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	voice_started = 1;
+done:
+	mutex_unlock(&voice_lock);
+	return rc;
+}
+
+static int q6_voice_stop(void)
+{
+	mutex_lock(&voice_lock);
+	if (voice_started) {
+		q6voice_close(voc_clnt);
+		voice_started = 0;
+	}
+	mutex_unlock(&voice_lock);
+	return 0;
+}
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int q6_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	uint32_t n;
+	uint32_t id[2];
+
+	switch (cmd) {
+	case AUDIO_SWITCH_DEVICE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc)
+			rc = q6audio_do_routing(n);
+		break;
+	case AUDIO_SET_VOLUME:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc)
+			rc = q6audio_set_rx_volume(n);
+		break;
+	case AUDIO_SET_MUTE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc)
+			rc = q6audio_set_tx_mute(n);
+		break;
+	case AUDIO_UPDATE_ACDB:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		if (!rc)
+			rc = q6audio_update_acdb(id[0], id[1]);
+		break;
+	case AUDIO_START_VOICE:
+		rc = q6_voice_start();
+		break;
+	case AUDIO_STOP_VOICE:
+		rc = q6_voice_stop();
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations q6_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.ioctl		= q6_ioctl,
+	.release	= q6_release,
+};
+
+struct miscdevice q6_control_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_ctl",
+	.fops	= &q6_dev_fops,
+};
+
+
+static int __init q6_audio_ctl_init(void)
+{
+	return misc_register(&q6_control_device);
+}
+
+device_initcall(q6_audio_ctl_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_acdb.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_acdb.h
new file mode 100644
index 0000000..d88b7ad
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_acdb.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2009, 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 ACDB_DAL_DEVICE		0x02000069
+#define ACDB_DAL_PORT		"DAL_AM_AUD"
+#define ACDB_DAL_VERSION	0x00010000
+
+#define ACDB_OP_IOCTL		DAL_OP_FIRST_DEVICE_API
+
+/* ioctls */
+#define ACDB_GET_DEVICE		0x0108bb92
+#define ACDB_SET_DEVICE		0x0108bb93
+#define ACDB_GET_STREAM		0x0108bb95
+#define ACDB_SET_STREAM		0x0108bb96
+#define ACDB_GET_DEVICE_TABLE	0x0108bb97
+#define ACDB_GET_STREAM_TABLE	0x0108bb98
+
+#define ACDB_RES_SUCCESS	0
+#define ACDB_RES_FAILURE	-1
+#define ACDB_RES_BADPARM	-2
+#define ACDB_RES_BADSTATE	-3
+
+struct acdb_cmd_device {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+	uint32_t interface_id;
+	uint32_t algorithm_block_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+} __attribute__((packed));
+
+struct acdb_cmd_device_table {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+
+	uint32_t res_size;
+} __attribute__((packed));
+
+struct acdb_result {
+	uint32_t dal_status;
+	uint32_t size;
+
+	uint32_t total_devices;
+	uint32_t unmapped_buf;
+	uint32_t used_bytes;
+	uint32_t result;
+} __attribute__((packed));
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_adie.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_adie.h
new file mode 100644
index 0000000..e828e9c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_adie.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2009, 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 _MACH_MSM_QDSP6_ADIE_
+#define _MACH_MSM_QDSP6_ADIE_
+
+#include "../dal.h"
+
+#define ADIE_DAL_DEVICE		0x02000029
+#define ADIE_DAL_PORT		"DAL_AM_AUD"
+#define ADIE_DAL_VERSION	0x00010000
+
+enum {
+	ADIE_OP_SET_PATH =  DAL_OP_FIRST_DEVICE_API,
+	ADIE_OP_PROCEED_TO_STAGE,
+	ADIE_OP_IOCTL
+};
+
+/* Path IDs for normal operation. */
+#define ADIE_PATH_HANDSET_TX			0x010740f6
+#define ADIE_PATH_HANDSET_RX			0x010740f7
+#define ADIE_PATH_HEADSET_MONO_TX		0x010740f8
+#define ADIE_PATH_HEADSET_STEREO_TX		0x010740f9
+#define ADIE_PATH_HEADSET_MONO_RX		0x010740fa
+#define ADIE_PATH_HEADSET_STEREO_RX		0x010740fb
+#define ADIE_PATH_SPEAKER_TX			0x010740fc
+#define ADIE_PATH_SPEAKER_RX			0x010740fd
+#define ADIE_PATH_SPEAKER_STEREO_RX		0x01074101
+
+/* Path IDs used for TTY */
+#define ADIE_PATH_TTY_HEADSET_TX		0x010740fe
+#define ADIE_PATH_TTY_HEADSET_RX		0x010740ff
+
+/* Path IDs used by Factory Test Mode. */
+#define ADIE_PATH_FTM_MIC1_TX			0x01074108
+#define ADIE_PATH_FTM_MIC2_TX			0x01074107
+#define ADIE_PATH_FTM_HPH_L_RX			0x01074106
+#define ADIE_PATH_FTM_HPH_R_RX			0x01074104
+#define ADIE_PATH_FTM_EAR_RX			0x01074103
+#define ADIE_PATH_FTM_SPKR_RX			0x01074102
+
+/* Path IDs for Loopback */
+/* Path IDs used for Line in -> AuxPGA -> Line Out Stereo Mode*/
+#define ADIE_PATH_AUXPGA_LINEOUT_STEREO_LB	0x01074100
+/* Line in -> AuxPGA -> LineOut Mono */
+#define ADIE_PATH_AUXPGA_LINEOUT_MONO_LB	0x01073d82
+/* Line in -> AuxPGA -> Stereo Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_STEREO_LB		0x01074109
+/* Line in -> AuxPGA -> Mono Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_MONO_LB		0x01073d85
+/* Line in -> AuxPGA -> Earpiece */
+#define ADIE_PATH_AUXPGA_EAP_LB			0x01073d81
+/* Line in -> AuxPGA -> AuxOut */
+#define ADIE_PATH_AUXPGA_AUXOUT_LB		0x01073d86
+
+/* Concurrency Profiles */
+#define ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX	0x01073d83
+#define ADIE_PATH_SPKR_MONO_HDPH_MONO_RX	0x01073d84
+#define ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX	0x01073d88
+#define ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX	0x01073d89
+
+/* stages */
+#define ADIE_STAGE_PATH_OFF			0x0050
+#define ADIE_STAGE_DIGITAL_READY		0x0100
+#define ADIE_STAGE_DIGITAL_ANALOG_READY		0x1000
+#define ADIE_STAGE_ANALOG_OFF			0x0750
+#define ADIE_STAGE_DIGITAL_OFF			0x0600
+
+/* path types */
+#define ADIE_PATH_RX		0
+#define ADIE_PATH_TX		1
+#define ADIE_PATH_LOOPBACK	2
+
+/* mute states */
+#define ADIE_MUTE_OFF		0
+#define ADIE_MUTE_ON		1
+
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_audio.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio.h
new file mode 100644
index 0000000..52de785
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio.h
@@ -0,0 +1,546 @@
+/* Copyright (c) 2009, 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 __DAL_AUDIO_H__
+#define __DAL_AUDIO_H__
+
+#include "../dal.h"
+#include "dal_audio_format.h"
+
+#define AUDIO_DAL_DEVICE 0x02000028
+#define AUDIO_DAL_PORT "DAL_AQ_AUD"
+#define AUDIO_DAL_VERSION	0x00030001
+
+enum {
+	AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API,
+	AUDIO_OP_DATA,
+	AUDIO_OP_INIT,
+};
+
+/* ---- common audio structures ---- */
+
+/* This flag, if set, indicates that the beginning of the data in the*/
+/* buffer is a synchronization point or key frame, meaning no data */
+/* before it in the stream is required in order to render the stream */
+/* from this point onward. */
+#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT        0x01
+
+/* This flag, if set, indicates that the buffer object is using valid */
+/* physical address used to store the media data */
+#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR         0x04
+
+/* This flag, if set, indicates that a media start timestamp has been */
+/* set for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_START_SET         0x08
+
+/* This flag, if set, indicates that a media stop timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET          0x10
+
+/* This flag, if set, indicates that a preroll timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET       0x20
+
+/* This flag, if set, indicates that the data in the buffer is a fragment of */
+/* a larger block of data, and will be continued by the data in the next */
+/* buffer to be delivered. */
+#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION      0x40
+
+struct adsp_audio_buffer {
+	u32 addr;		/* Physical Address of buffer */
+	u32 max_size;		/* Maximum size of buffer */
+	u32 actual_size;	/* Actual size of valid data in the buffer */
+	u32 offset;		/* Offset to the first valid byte */
+	u32 flags;		/* ADSP_AUDIO_BUFFER_FLAGs that has been set */
+	s64 start;		/* Start timestamp, if any */
+	s64 stop;		/* Stop timestamp, if any */
+	s64 preroll;		/* Preroll timestamp, if any */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio commands ---- */
+
+/* Command/event response types */
+#define ADSP_AUDIO_RESPONSE_COMMAND   0
+#define ADSP_AUDIO_RESPONSE_ASYNC     1
+
+struct adsp_command_hdr {
+	u32 size;		/* sizeof(cmd) - sizeof(u32) */
+
+	u32 dest;
+	u32 src;
+	u32 opcode;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+	u32 padding;
+} __attribute__ ((packed));
+
+
+#define DOMAIN_APP	0
+#define DOMAIN_MODEM	1
+#define DOMAIN_DSP	2
+
+
+/* adsp audio addresses are (byte order) major, minor, domain */
+#define AUDIO_ADDR(dmn, maj, min) (((maj & 0xff) << 16) \
+		| ((min & 0xff) << 24) | (dmn & 0xff))
+
+/* AAC Encoder modes */
+#define ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE		0
+#define ADSP_AUDIO_ENC_AAC_PLUS_MODE		1
+#define ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE	2
+
+struct adsp_audio_aac_enc_cfg {
+	u32 bit_rate;		/* bits per second */
+	u32 encoder_mode;	/* ADSP_AUDIO_ENC_* */
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS     0
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR           1
+
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO                1
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO              2
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL                8
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO        9
+
+struct adsp_audio_sbc_encoder_cfg {
+	u32 num_subbands;
+	u32 block_len;
+	u32 channel_mode;
+	u32 allocation_method;
+	u32 bit_rate;
+} __attribute__ ((packed));
+
+/* AMR NB encoder modes */
+#define ADSP_AUDIO_AMR_MR475	0
+#define ADSP_AUDIO_AMR_MR515	1
+#define ADSP_AUDIO_AMR_MMR59	2
+#define ADSP_AUDIO_AMR_MMR67	3
+#define ADSP_AUDIO_AMR_MMR74	4
+#define ADSP_AUDIO_AMR_MMR795	5
+#define ADSP_AUDIO_AMR_MMR102	6
+#define ADSP_AUDIO_AMR_MMR122	7
+
+/* The following are valid AMR NB DTX modes */
+#define ADSP_AUDIO_AMR_DTX_MODE_OFF		0
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1		1
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2		2
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO		3
+
+/* AMR Encoder configuration */
+struct adsp_audio_amr_enc_cfg {
+	u32	mode;		/* ADSP_AUDIO_AMR_MR* */
+	u32	dtx_mode;	/* ADSP_AUDIO_AMR_DTX_MODE* */
+	u32	enable;		/* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+struct adsp_audio_qcelp13k_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+struct adsp_audio_evrc_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+union adsp_audio_codec_config {
+	struct adsp_audio_amr_enc_cfg amr;
+	struct adsp_audio_aac_enc_cfg aac;
+	struct adsp_audio_qcelp13k_enc_cfg qcelp13k;
+	struct adsp_audio_evrc_enc_cfg evrc;
+	struct adsp_audio_sbc_encoder_cfg sbc;
+} __attribute__ ((packed));
+
+
+/* This is the default value. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_NONE		0x0000
+
+/* This bit, if set, indicates that the AVSync mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_AVSYNC		0x0001
+
+/* This bit, if set, indicates that the Sample Rate/Channel Mode */
+/* Change Notification mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY	0x0002
+
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK	0x0004
+
+#define ADSP_AUDIO_MAX_DEVICES 1
+
+struct adsp_open_command {
+	struct adsp_command_hdr hdr;
+	u32 device;
+	u32 end_point;
+	u32 stream_context;
+	u32 mode;
+	u32 buf_max_size;
+	union adsp_audio_format format_block;
+	union adsp_audio_codec_config config;
+
+} __attribute__ ((packed));
+
+
+/* --- audio control and stream session ioctls ---- */
+
+/* Opcode to open a device stream session to capture audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ			0x0108dd79
+
+/* Opcode to open a device stream session to render audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE			0x0108dd7a
+
+/* Opcode to open a device session, must open a device */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE		0x0108dd7b
+
+/* Close an existing stream or device */
+#define ADSP_AUDIO_IOCTL_CMD_CLOSE			0x0108d8bc
+
+
+
+/* A device switch requires three IOCTL */
+/* commands in the following sequence: PREPARE, STANDBY, COMMIT */
+
+/* adsp_audio_device_switch_command structure is needed for */
+/* DEVICE_SWITCH_PREPARE */
+
+/* Device switch protocol step #1. Pause old device and */
+/* generate silence for the old device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE	0x010815c4
+
+/* Device switch protocol step #2. Release old device, */
+/* create new device and generate silence for the new device. */
+
+/* When client receives ack for this IOCTL, the client can */
+/* start sending IOCTL commands to configure, calibrate and */
+/* change filter settings on the new device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY	0x010815c5
+
+/* Device switch protocol step #3. Start normal operations on new device */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT	0x01075ee7
+
+struct adsp_device_switch_command {
+	struct adsp_command_hdr hdr;
+	u32 old_device;
+	u32 new_device;
+	u8 device_class; /* 0 = i.rx, 1 = i.tx, 2 = e.rx, 3 = e.tx */
+	u8 device_type; /* 0 = rx, 1 = tx, 2 = both */
+} __attribute__ ((packed));
+
+
+
+/* --- audio control session ioctls ---- */
+
+#define ADSP_PATH_RX	0
+#define ADSP_PATH_TX	1
+#define ADSP_PATH_BOTH	2
+
+/* These commands will affect a logical device and all its associated */
+/* streams. */
+
+
+/* Set device volume. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL		0x0107605c
+
+struct adsp_set_dev_volume_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	s32 volume;
+} __attribute__ ((packed));
+
+/* Set Device stereo volume. This command has data payload, */
+/* struct adsp_audio_set_dev_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_STEREO_VOL		0x0108df3e
+
+/* Set L, R cross channel gain for a Device. This command has */
+/* data payload, struct adsp_audio_set_dev_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_XCHAN_GAIN		0x0108df40
+
+/* Set device mute state. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE		0x0107605f
+
+struct adsp_set_dev_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	u32 mute; /* 1 = mute */
+} __attribute__ ((packed));
+
+/* Configure Equalizer for a device. */
+/* This command has payload struct adsp_audio_set_dev_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_EQ_CONFIG	0x0108b10e
+
+/* Set configuration data for an algorithm aspect of a device. */
+/* This command has payload struct adsp_audio_set_dev_cfg_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG		0x0108b6cb
+
+struct adsp_set_dev_cfg_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 block_id;
+	u32 interface_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* Set configuration data for all interfaces of a device. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE	0x0108b6bf
+
+struct adsp_set_dev_cfg_table_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* ---- audio stream data commands ---- */
+
+#define ADSP_AUDIO_IOCTL_CMD_DATA_TX			0x0108dd7f
+#define ADSP_AUDIO_IOCTL_CMD_DATA_RX			0x0108dd80
+
+struct adsp_buffer_command {
+	struct adsp_command_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+
+/* ---- audio stream ioctls (only affect a single stream in a session) ---- */
+
+/* Stop stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_STOP		0x01075c54
+
+/* End of stream reached. Client will not send any more data. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_EOS			0x0108b150
+
+/* Do sample slipping/stuffing on AAC outputs. The payload of */
+/* this command is struct adsp_audio_slip_sample_command. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE		0x0108d40e
+
+/* Set stream volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL		0x0108c0de
+
+/* Set stream stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL		0x0108dd7c
+
+/* Set L, R cross channel gain for a Stream. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_XCHAN_GAIN		0x0108dd7d
+
+/* Set stream mute state. */
+/* This command has data payload, struct adsp_audio_set_stream_mute. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE		0x0108c0df
+
+/* Reconfigure bit rate information. This command has data */
+/* payload, struct adsp_audio_set_bit_rate_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_BITRATE		0x0108ccf1
+
+/* Set Channel Mapping. This command has data payload, struct */
+/* This command has data payload struct adsp_audio_set_channel_map_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_CHANNELMAP		0x0108d32a
+
+/* Enable/disable AACPlus SBR. */
+/* This command has data payload struct adsp_audio_set_sbr_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_SBR			0x0108d416
+
+/* Enable/disable WMA Pro Chex and Fex. This command has data payload */
+/* struct adsp_audio_stream_set_wma_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_WMAPRO		0x0108d417
+
+
+/* ---- audio session ioctls (affect all streams in a session) --- */
+
+/* Start stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_START		0x010815c6
+
+/* Stop all stream(s) for audio session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_STOP		0x0108dd7e
+
+/* Pause the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_PAUSE		0x01075ee8
+
+/* Resume the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_RESUME		0x01075ee9
+
+/* Drop any unprocessed data buffers for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_FLUSH		0x01075eea
+
+/* Start Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START		0x0108c0dd
+
+/* Stop Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_STOP		0x01087554
+
+/* Set Session volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_VOL		0x0108d8bd
+
+/* Set session stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL		0x0108df3d
+
+/* Set L, R cross channel gain for a session. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN		0x0108df3f
+
+/* Set Session mute state. */
+/* This command has data payload, struct adsp_audio_set_mute_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE		0x0108d8be
+
+/* Configure Equalizer for a stream. */
+/* This command has payload struct adsp_audio_set_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG		0x0108c0e0
+
+/* Set Audio Video sync information. */
+/* This command has data payload, struct adsp_audio_set_av_sync_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_AVSYNC		0x0108d1e2
+
+/* Get Audio Media Session time. */
+/* This command returns the audioTime in adsp_audio_unsigned64_event */
+#define ADSP_AUDIO_IOCTL_CMD_GET_AUDIO_TIME		0x0108c26c
+
+
+/* these command structures are used for both STREAM and SESSION ioctls */
+
+struct adsp_set_volume_command {
+	struct adsp_command_hdr hdr;
+	s32 volume;
+} __attribute__ ((packed));
+
+struct adsp_set_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 mute; /* 1 == mute */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio events ---- */
+
+/* All IOCTL commands generate an event with the IOCTL opcode as the */
+/* event id after the IOCTL command has been executed. */
+
+/* This event is generated after a media stream session is opened. */
+#define ADSP_AUDIO_EVT_STATUS_OPEN				0x0108c0d6
+
+/* This event is generated after a media stream  session is closed. */
+#define ADSP_AUDIO_EVT_STATUS_CLOSE				0x0108c0d7
+
+/* Asyncronous buffer consumption. This event is generated after a */
+/* recived  buffer is consumed during rendering or filled during */
+/* capture opeartion. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_DONE				0x0108c0d8
+
+/* This event is generated when rendering operation is starving for */
+/* data. In order to avoid audio loss at the end of a plauback, the */
+/* client should wait for this event before issuing the close command. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN			0x0108c0d9
+
+/* This event is generated during capture operation when there are no */
+/* buffers available to copy the captured audio data */
+#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW			0x0108c0da
+
+/* This asynchronous event is generated as a result of an input */
+/* sample rate change and/or channel mode change detected by the */
+/* decoder. The event payload data is an array of 2 uint32 */
+/* values containing the sample rate in Hz and channel mode. */
+#define ADSP_AUDIO_EVT_SR_CM_CHANGE				0x0108d329
+
+struct adsp_event_hdr {
+	u32 evt_handle;		/* DAL common header */
+	u32 evt_cookie;
+	u32 evt_length;
+
+	u32 dest;
+	u32 src;
+
+	u32 event_id;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 status;
+} __attribute__ ((packed));
+
+struct adsp_buffer_event {
+	struct adsp_event_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+/* ---- audio device IDs ---- */
+
+/* Device direction Rx/Tx flag */
+#define ADSP_AUDIO_RX_DEVICE		0x00
+#define ADSP_AUDIO_TX_DEVICE		0x01
+
+#define ADSP_AUDIO_DEVICE_ID_DEFAULT		0x1081679
+
+/* Default RX or TX device */
+
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_MIC	0x107ac8d
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC		0x108f9c3
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_MIC	0x1081510
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC	0x1081512
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC	0x108f9c5
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC	0x108151b
+#define ADSP_AUDIO_DEVICE_ID_I2S_MIC		0x1089bf3
+
+/* Special loopback pseudo device to be paired with an RX device */
+/* with usage ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK */
+#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX	0x1089bf2
+
+/* Sink (RX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR			0x107ac88
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO			0x1081511
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO		0x107ac8a
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO			0x1081513
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET     0x108c508
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET   0x108c894
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO			0x1081514
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET   0x108c895
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET	0x108c509
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR			0x1081519
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR			0x108151c
+#define ADSP_AUDIO_DEVICE_ID_I2S_SPKR				0x1089bf4
+#define ADSP_AUDIO_DEVICE_ID_NULL_SINK				0x108e512
+
+/* BT A2DP playback device. */
+/* This device must be paired with */
+/* ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX using  */
+/* ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK mode */
+#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR	0x108151a
+
+/* Voice Destination identifier - specifically used for */
+/* controlling Voice module from the Device Control Session */
+#define ADSP_AUDIO_DEVICE_ID_VOICE		0x0108df3c
+
+/*  Audio device usage types. */
+/*  This is a bit mask to determine which topology to use in the */
+/* device session */
+#define ADSP_AUDIO_DEVICE_CONTEXT_VOICE			0x01
+#define ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK		0x02
+#define ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD		0x10
+#define ADSP_AUDIO_DEVICE_CONTEXT_RECORD		0x20
+#define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK		0x40
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_audio_format.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio_format.h
new file mode 100644
index 0000000..348aad1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio_format.h
@@ -0,0 +1,284 @@
+/* Copyright (c) 2009, 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 __ADSP_AUDIO_MEDIA_FORMAT_H
+#define __ADSP_AUDIO_MEDIA_FORMAT_H
+
+/* Supported audio media formats */
+
+/* format block in shmem */
+#define ADSP_AUDIO_FORMAT_SHAREDMEMORY	0x01091a78
+
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_PCM		0x0103d2fd
+
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_DTMF		0x01087725
+
+/* adsp_audio_format_adpcm type */
+#define ADSP_AUDIO_FORMAT_ADPCM		0x0103d2ff
+
+/* Yamaha PCM format */
+#define ADSP_AUDIO_FORMAT_YADPCM	0x0108dc07
+
+/* ISO/IEC 11172 */
+#define ADSP_AUDIO_FORMAT_MP3		0x0103d308
+
+/* ISO/IEC 14496 */
+#define ADSP_AUDIO_FORMAT_MPEG4_AAC	0x010422f1
+
+/* AMR-NB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRNB_FS	0x0105c16c
+
+/* AMR-WB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRWB_FS	0x0105c16e
+
+/* QCELP 13k, IS733 */
+#define ADSP_AUDIO_FORMAT_V13K_FS	0x01080b8a
+
+/* EVRC   8k, IS127 */
+#define ADSP_AUDIO_FORMAT_EVRC_FS	0x01080b89
+
+/* EVRC-B   8k, 4GV */
+#define ADSP_AUDIO_FORMAT_EVRCB_FS	0x0108f2a3
+
+/* MIDI command stream */
+#define ADSP_AUDIO_FORMAT_MIDI		0x0103d300
+
+/* A2DP SBC stream */
+#define ADSP_AUDIO_FORMAT_SBC		0x0108c4d8
+
+/* Version 10 Professional */
+#define ADSP_AUDIO_FORMAT_WMA_V10PRO	0x0108aa92
+
+/* Version 9 Starndard */
+#define ADSP_AUDIO_FORMAT_WMA_V9	0x0108d430
+
+/* AMR WideBand Plus */
+#define ADSP_AUDIO_FORMAT_AMR_WB_PLUS   0x0108f3da
+
+/* AC3 Decoder */
+#define ADSP_AUDIO_FORMAT_AC3_DECODER   0x0108d5f9
+
+/* Not yet supported audio media formats */
+
+/* ISO/IEC 13818 */
+#define ADSP_AUDIO_FORMAT_MPEG2_AAC	0x0103d309
+
+/* 3GPP TS 26.101 Sec 4.0 */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF1	0x0103d305
+
+/* 3GPP TS 26.101 Annex A */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF2	0x01057b31
+
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF1	0x0103d306
+
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF2	0x0105c16d
+
+/* G.711 */
+#define ADSP_AUDIO_FORMAT_G711		0x0106201d
+
+/* QCELP  8k, IS96A */
+#define ADSP_AUDIO_FORMAT_V8K_FS	0x01081d29
+
+/* Version 1 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V1	0x01055b2b
+
+/* Version 2, 7 & 8 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V8	0x01055b2c
+
+/* Version 9 Professional codec */
+#define ADSP_AUDIO_FORMAT_WMA_V9PRO	0x01055b2d
+
+/* Version 9 Voice codec */
+#define ADSP_AUDIO_FORMAT_WMA_SP1	0x01055b2e
+
+/* Version 9 Lossless codec */
+#define ADSP_AUDIO_FORMAT_WMA_LOSSLESS	0x01055b2f
+
+/* Real Media content, low-bitrate */
+#define ADSP_AUDIO_FORMAT_RA_SIPR	0x01042a0f
+
+/* Real Media content */
+#define ADSP_AUDIO_FORMAT_RA_COOK	0x01042a0e
+
+
+/* For all of the audio formats, unless specified otherwise, */
+/* the following apply: */
+/* Format block bits are arranged in bytes and words in little-endian */
+/* order, i.e., least-significant bit first and least-significant */
+/* byte first. */
+
+
+/* AAC Format Block. */
+
+/* AAC format block consist of a format identifier followed by */
+/* AudioSpecificConfig formatted according to ISO/IEC 14496-3 */
+
+/* The following AAC format identifiers are supported */
+#define ADSP_AUDIO_AAC_ADTS		0x010619cf
+#define ADSP_AUDIO_AAC_MPEG4_ADTS	0x010619d0
+#define ADSP_AUDIO_AAC_LOAS		0x010619d1
+#define ADSP_AUDIO_AAC_ADIF		0x010619d2
+#define ADSP_AUDIO_AAC_RAW		0x010619d3
+#define ADSP_AUDIO_AAC_FRAMED_RAW	0x0108c1fb
+
+struct adsp_audio_no_payload_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+	/* no payload for this format type */
+} __attribute__ ((packed));
+
+/* Maxmum number of bytes allowed in a format block */
+#define ADSP_AUDIO_FORMAT_DATA_MAX 16
+
+/* For convenience, to be used as a standard format block */
+/* for various media types that don't need a unique format block */
+/* ie. PCM, DTMF, etc. */
+struct adsp_audio_standard_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u16 channels;
+	u16 bits_per_sample;
+	u32 sampling_rate;
+	u8 is_signed;
+	u8 is_interleaved;
+} __attribute__ ((packed));
+
+/* ADPCM format block */
+struct adsp_audio_adpcm_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u16 channels;
+	u16 bits_per_sample;
+	u32 sampling_rate;
+	u8 is_signed;
+	u8 is_interleaved;
+	u32 block_size;
+} __attribute__ ((packed));
+
+/* MIDI format block */
+struct adsp_audio_midi_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u32 sampling_rate;
+	u16 channels;
+	u16 mode;
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_COMPANDING_ALAW	0x10619cd
+#define ADSP_AUDIO_COMPANDING_MLAW	0x10619ce
+
+/* G711 format block */
+struct adsp_audio_g711_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u32 companding;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_wma_pro_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u16 format_tag;
+	u16 channels;
+	u32 samples_per_sec;
+	u32 avg_bytes_per_sec;
+	u16 block_align;
+	u16 valid_bits_per_sample;
+	u32 channel_mask;
+	u16 encode_opt;
+	u16 advanced_encode_opt;
+	u32 advanced_encode_opt2;
+	u32 drc_peak_reference;
+	u32 drc_peak_target;
+	u32 drc_average_reference;
+	u32 drc_average_target;
+} __attribute__ ((packed));
+
+struct adsp_audio_amrwb_plus_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		size;
+	u32		version;
+	u32		channels;
+	u32		amr_band_mode;
+	u32		amr_dtx_mode;
+	u32		amr_frame_format;
+	u32		amr_isf_index;
+} __attribute__ ((packed));
+
+/* Binary Byte Stream Format */
+/* Binary format type that defines a byte stream, */
+/* can be used to specify any format (ie. AAC) */
+struct adsp_audio_binary_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	/* number of bytes set in byte stream */
+	u32 num_bytes;
+	/* Byte stream binary data */
+	u8 data[ADSP_AUDIO_FORMAT_DATA_MAX];
+} __attribute__ ((packed));
+
+struct adsp_audio_shared_memory_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* Number of bytes in shared memory */
+	u32		len;
+	/* Phyisical address to data in shared memory */
+	u32		address;
+} __attribute__ ((packed));
+
+
+/* Union of all format types */
+union adsp_audio_format {
+	/* Basic format block with no payload */
+	struct adsp_audio_no_payload_format	no_payload;
+	/* Generic format block PCM, DTMF */
+	struct adsp_audio_standard_format	standard;
+	/* ADPCM format block */
+	struct adsp_audio_adpcm_format		adpcm;
+	/* MIDI format block */
+	struct adsp_audio_midi_format		midi;
+	/* G711 format block */
+	struct adsp_audio_g711_format		g711;
+	/* WmaPro format block */
+	struct adsp_audio_wma_pro_format	wma_pro;
+	/* WmaPro format block */
+	struct adsp_audio_amrwb_plus_format	amrwb_plus;
+	/* binary (byte stream) format block, used for AAC */
+	struct adsp_audio_binary_format		binary;
+	/* format block in shared memory */
+	struct adsp_audio_shared_memory_format	shared_mem;
+};
+
+#endif
+
+
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_voice.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_voice.h
new file mode 100644
index 0000000..62c1122
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_voice.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2009, 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 __DAL_VOICE_H__
+#define __DAL_VOICE_H__
+
+#define VOICE_DAL_DEVICE 0x02000075
+#define VOICE_DAL_PORT "DAL_AM_AUD"
+#define VOICE_DAL_VERSION 0x00010000
+
+#define APR_PKTV1_TYPE_EVENT_V 0
+#define APR_UNDEFINED -1
+#define APR_PKTV1_TYPE_MASK 0x00000010
+#define APR_PKTV1_TYPE_SHFT 4
+
+#define APR_SET_BITMASK(mask, shift, value) \
+	(((value) << (shift)) & (mask))
+
+#define APR_SET_FIELD(field, value) \
+	APR_SET_BITMASK((field##_MASK), (field##_SHFT), (value))
+
+
+enum {
+	VOICE_OP_INIT = DAL_OP_FIRST_DEVICE_API,
+	VOICE_OP_CONTROL,
+};
+
+struct apr_command_pkt {
+	uint32_t size;
+	uint32_t header;
+	uint16_t reserved1;
+	uint16_t src_addr;
+	uint16_t dst_addr;
+	uint16_t ret_addr;
+	uint32_t src_token;
+	uint32_t dst_token;
+	uint32_t ret_token;
+	uint32_t context;
+	uint32_t opcode;
+} __attribute__ ((packed));
+
+
+#define APR_IBASIC_RSP_RESULT 0x00010000
+
+#define APR_OP_CMD_CREATE 0x0001001B
+
+#define APR_OP_CMD_DESTROY 0x0001001C
+
+#define VOICE_OP_CMD_BRINGUP 0x0001001E
+
+#define VOICE_OP_CMD_TEARDOWN 0x0001001F
+
+#define VOICE_OP_CMD_SET_NETWORK 0x0001001D
+
+#define VOICE_OP_CMD_STREAM_SETUP 0x00010027
+
+#define VOICE_OP_CMD_STREAM_TEARDOWN 0x00010028
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/evrc_in.c b/arch/arm/mach-msm/qdsp6/audiov2/evrc_in.c
new file mode 100644
index 0000000..88f19b7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/evrc_in.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+
+struct evrc {
+	struct mutex lock;
+	struct msm_audio_evrc_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+
+static long q6_evrc_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct evrc *evrc = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&evrc->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if (evrc->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			evrc->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						evrc->str_cfg.buffer_size);
+
+			if (!evrc->audio_client) {
+				kfree(evrc);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		tx_clk_freq = 8000;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_EVRC_FS;
+		rpc.format_block.standard.channels = 1;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = 8000;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = evrc->str_cfg.buffer_size;
+		rpc.config.evrc.min_rate = evrc->cfg.min_bit_rate;
+		rpc.config.evrc.max_rate = evrc->cfg.max_bit_rate;
+
+		q6audio_start(evrc->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &evrc->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&evrc->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (evrc->str_cfg.buffer_size < 23) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (evrc->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_EVRC_ENC_CONFIG:
+		if (copy_from_user(&evrc->cfg, (void *) arg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+
+		if (evrc->cfg.min_bit_rate > 4 || evrc->cfg.min_bit_rate < 1) {
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (evrc->cfg.max_bit_rate > 4 || evrc->cfg.max_bit_rate < 1) {
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_EVRC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &evrc->cfg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&evrc->lock);
+	return rc;
+}
+
+static int q6_evrc_in_open(struct inode *inode, struct file *file)
+{
+	struct evrc *evrc;
+	evrc = kmalloc(sizeof(struct evrc), GFP_KERNEL);
+	if (evrc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for evrc driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&evrc->lock);
+	file->private_data = evrc;
+	evrc->audio_client = NULL;
+	evrc->str_cfg.buffer_size = 23;
+	evrc->str_cfg.buffer_count = 2;
+	evrc->cfg.cdma_rate = CDMA_RATE_FULL;
+	evrc->cfg.min_bit_rate = 1;
+	evrc->cfg.max_bit_rate = 4;
+
+	return 0;
+}
+
+static ssize_t q6_evrc_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct evrc *evrc = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&evrc->lock);
+	ac = evrc->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+
+fail:
+	mutex_unlock(&evrc->lock);
+
+	return res;
+}
+
+static int q6_evrc_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct evrc *evrc = file->private_data;
+
+	mutex_lock(&evrc->lock);
+	if (evrc->audio_client)
+		rc = q6audio_close(evrc->audio_client);
+	mutex_unlock(&evrc->lock);
+	kfree(evrc);
+	return rc;
+}
+
+static const struct file_operations q6_evrc_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_evrc_in_open,
+	.read		= q6_evrc_in_read,
+	.release	= q6_evrc_in_release,
+	.unlocked_ioctl	= q6_evrc_in_ioctl,
+};
+
+struct miscdevice q6_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &q6_evrc_in_fops,
+};
+
+static int __init q6_evrc_in_init(void)
+{
+	return misc_register(&q6_evrc_in_misc);
+}
+
+device_initcall(q6_evrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/mp3.c b/arch/arm/mach-msm/qdsp6/audiov2/mp3.c
new file mode 100644
index 0000000..0781eda
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/mp3.c
@@ -0,0 +1,205 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/mp3.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct mp3 {
+	struct mutex lock;
+	struct audio_client *ac;
+	struct msm_audio_config cfg;
+};
+
+static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&mp3->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_START:
+		memset(&rpc, 0, sizeof(rpc));
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_MP3;
+		rpc.format_block.standard.channels = mp3->cfg.channel_count;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = mp3->cfg.sample_rate;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+		rpc.buf_max_size = BUFSZ;
+		q6audio_start(mp3->ac, (void *) &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG:
+		if (copy_from_user(&mp3->cfg, (void *) arg,
+			sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (mp3->cfg.channel_count < 1 || mp3->cfg.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	case AUDIO_GET_CONFIG:
+		if (copy_to_user((void *) arg, &mp3->cfg,
+			sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&mp3->lock);
+	return rc;
+}
+
+static int mp3_open(struct inode *inode, struct file *file)
+{
+
+	struct mp3 *mp3;
+	mp3 = kzalloc(sizeof(struct mp3), GFP_KERNEL);
+
+	if (!mp3)
+		return -ENOMEM;
+
+	mutex_init(&mp3->lock);
+	file->private_data = mp3;
+	mp3->ac = q6audio_open(AUDIO_FLAG_WRITE, BUFSZ);
+	if (!mp3->ac) {
+		kfree(mp3);
+		return -ENOMEM;
+	}
+	mp3->cfg.channel_count = 2;
+	mp3->cfg.buffer_count = 2;
+	mp3->cfg.buffer_size = BUFSZ;
+	mp3->cfg.unused[0] = 0;
+	mp3->cfg.unused[1] = 0;
+	mp3->cfg.unused[2] = 0;
+	mp3->cfg.sample_rate = 48000;
+
+	return 0;
+}
+
+static ssize_t mp3_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	if (!mp3->ac)
+		mp3_ioctl(file, AUDIO_START, 0);
+
+	ac = mp3->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int mp3_fsync(struct file *f, int datasync)
+{
+	struct mp3 *mp3 = f->private_data;
+	if (mp3->ac)
+		return q6audio_async(mp3->ac);
+	return -ENODEV;
+}
+
+static int mp3_release(struct inode *inode, struct file *file)
+{
+	struct mp3 *mp3 = file->private_data;
+	if (mp3->ac)
+		q6audio_close(mp3->ac);
+	kfree(mp3);
+	return 0;
+}
+
+static const struct file_operations mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mp3_open,
+	.write		= mp3_write,
+	.fsync		= mp3_fsync,
+	.release	= mp3_release,
+	.unlocked_ioctl	= mp3_ioctl,
+};
+
+struct miscdevice mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &mp3_fops,
+};
+
+static int __init mp3_init(void)
+{
+	return misc_register(&mp3_misc);
+}
+
+device_initcall(mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c b/arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
new file mode 100644
index 0000000..6ef2195
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
@@ -0,0 +1,208 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+#define BUFSZ (4096)
+#define DMASZ (BUFSZ * 2)
+
+
+struct pcm {
+	struct mutex lock;
+	struct msm_audio_config cfg;
+	struct audio_client *audio_client;
+};
+
+static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+
+	case AUDIO_START:
+		tx_clk_freq = pcm->cfg.sample_rate;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_PCM;
+		rpc.format_block.standard.channels = pcm->cfg.channel_count;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = pcm->cfg.sample_rate;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 1;
+
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = BUFSZ;
+		q6audio_start(pcm->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_SET_CONFIG:
+		if (copy_from_user(&pcm->cfg, (void *) arg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	case AUDIO_GET_CONFIG:
+		if (copy_to_user((void *) arg, &pcm->cfg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int q6_in_open(struct inode *inode, struct file *file)
+{
+
+	struct pcm *pcm;
+	pcm = kmalloc(sizeof(struct pcm), GFP_KERNEL);
+	if (pcm == NULL) {
+		pr_err("Could not allocate memory for pcm driver\n");
+		return -ENOMEM;
+	}
+	mutex_init(&pcm->lock);
+	file->private_data = pcm;
+	pcm->audio_client = q6audio_open(AUDIO_FLAG_READ, BUFSZ);
+	if (!pcm->audio_client) {
+		kfree(pcm);
+		return -ENOMEM;
+	}
+	pcm->cfg.channel_count = 1;
+	pcm->cfg.buffer_count = 2;
+	pcm->cfg.buffer_size = BUFSZ;
+	pcm->cfg.unused[0] = 0;
+	pcm->cfg.unused[1] = 0;
+	pcm->cfg.unused[2] = 0;
+	pcm->cfg.sample_rate = 8000;
+
+	return 0;
+}
+
+static ssize_t q6_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct pcm *pcm = file->private_data;
+	int xfer;
+	int res;
+
+	mutex_lock(&pcm->lock);
+	ac = pcm->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+fail:
+	res = buf - start;
+	mutex_unlock(&pcm->lock);
+
+	return res;
+}
+
+static int q6_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct pcm *pcm = file->private_data;
+
+	mutex_lock(&pcm->lock);
+	if (pcm->audio_client)
+		rc = q6audio_close(pcm->audio_client);
+	mutex_unlock(&pcm->lock);
+	kfree(pcm);
+	return rc;
+}
+
+static const struct file_operations q6_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_in_open,
+	.read		= q6_in_read,
+	.release	= q6_in_release,
+	.unlocked_ioctl	= q6_in_ioctl,
+};
+
+struct miscdevice q6_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &q6_in_fops,
+};
+
+static int __init q6_in_init(void)
+{
+	return misc_register(&q6_in_misc);
+}
+
+device_initcall(q6_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c b/arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
new file mode 100644
index 0000000..6743c6c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
@@ -0,0 +1,196 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, 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/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct pcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	struct msm_audio_config cfg;
+
+};
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		memset(&rpc, 0, sizeof(rpc));
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_PCM;
+		rpc.format_block.standard.channels = pcm->cfg.channel_count;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = pcm->cfg.sample_rate;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 1;
+		rpc.buf_max_size = BUFSZ;
+		q6audio_start(pcm->ac, (void *) &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG:
+		if (copy_from_user(&pcm->cfg, (void *) arg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (pcm->cfg.channel_count < 1 || pcm->cfg.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+
+		break;
+	case AUDIO_GET_CONFIG:
+		if (copy_to_user((void *) arg, &pcm->cfg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	mutex_init(&pcm->lock);
+	file->private_data = pcm;
+	pcm->ac = q6audio_open(AUDIO_FLAG_WRITE, BUFSZ);
+	if (!pcm->ac) {
+		kfree(pcm);
+		return -ENOMEM;
+	}
+	pcm->cfg.channel_count = 2;
+	pcm->cfg.buffer_count = 2;
+	pcm->cfg.buffer_size = BUFSZ;
+	pcm->cfg.unused[0] = 0;
+	pcm->cfg.unused[1] = 0;
+	pcm->cfg.unused[2] = 0;
+	pcm->cfg.sample_rate = 48000;
+
+	return 0;
+}
+
+static ssize_t pcm_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	ac = pcm->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		ab->actual_size = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int pcm_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		q6audio_close(pcm->ac);
+	kfree(pcm);
+	return 0;
+}
+
+static const struct file_operations pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_open,
+	.write		= pcm_write,
+	.release	= pcm_release,
+	.unlocked_ioctl	= pcm_ioctl,
+};
+
+struct miscdevice pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_fops,
+};
+
+static int __init pcm_init(void)
+{
+	return misc_register(&pcm_misc);
+}
+
+device_initcall(pcm_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/q6audio.c b/arch/arm/mach-msm/qdsp6/audiov2/q6audio.c
new file mode 100644
index 0000000..f713e3d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/q6audio.c
@@ -0,0 +1,1312 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/q6audio.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, 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/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/android_pmem.h>
+#include <linux/gpio.h>
+#include <mach/msm_qdsp6_audiov2.h>
+
+#include "../dal.h"
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include "dal_acdb.h"
+#include "dal_adie.h"
+#include "q6audio_devices.h"
+
+struct q6_hw_info {
+	int min_gain;
+	int max_gain;
+};
+
+/* TODO: provide mechanism to configure from board file */
+
+static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
+	[Q6_HW_HANDSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_HEADSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_SPEAKER] = {
+		.min_gain = -1500,
+		.max_gain = 0,
+	},
+	[Q6_HW_TTY] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_SCO] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_A2DP] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+};
+
+static struct wake_lock idlelock;
+static int idlecount;
+static DEFINE_MUTEX(idlecount_lock);
+
+void audio_prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1)
+		wake_lock(&idlelock);
+	mutex_unlock(&idlecount_lock);
+}
+
+void audio_allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0)
+		wake_unlock(&idlelock);
+	mutex_unlock(&idlecount_lock);
+}
+
+static struct clk *icodec_rx_clk;
+static struct clk *icodec_tx_clk;
+static struct clk *ecodec_clk;
+static struct clk *sdac_clk;
+
+static struct q6audio_analog_ops default_analog_ops;
+static struct q6audio_analog_ops *analog_ops = &default_analog_ops;
+uint32_t tx_clk_freq = 8000;
+static int tx_mute_status;
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops)
+{
+	analog_ops = ops;
+}
+
+static struct q6_device_info *q6_lookup_device(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_audio_devices;
+	for (;;) {
+		if (di->id == device_id)
+			return di;
+		if (di->id == 0) {
+			pr_err("q6_lookup_device: bogus id 0x%08x\n",
+			       device_id);
+			return di;
+		}
+		di++;
+	}
+}
+
+static uint32_t q6_device_to_codec(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->codec;
+}
+
+static uint32_t q6_device_to_dir(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->dir;
+}
+
+static uint32_t q6_device_to_cad_id(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->cad_id;
+}
+
+static uint32_t q6_device_to_path(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->path;
+}
+
+static uint32_t q6_device_to_rate(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->rate;
+}
+
+int q6_device_volume(uint32_t device_id, int level)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	struct q6_hw_info *hw;
+
+	hw = &q6_audio_hw[di->hw];
+
+	return hw->min_gain + ((hw->max_gain - hw->min_gain) * level) / 100;
+}
+
+static inline int adie_open(struct dal_client *client)
+{
+	return dal_call_f0(client, DAL_OP_OPEN, 0);
+}
+
+static inline int adie_close(struct dal_client *client)
+{
+	return dal_call_f0(client, DAL_OP_CLOSE, 0);
+}
+
+static inline int adie_set_path(struct dal_client *client,
+				uint32_t *adie_params, uint32_t size)
+{
+	uint32_t tmp;
+	return dal_call(client, ADIE_OP_SET_PATH, 5, adie_params, size,
+		(void *)&tmp, sizeof(uint32_t));
+
+}
+
+static inline int adie_proceed_to_stage(struct dal_client *client,
+					uint32_t path_type, uint32_t stage)
+{
+	return dal_call_f1(client, ADIE_OP_PROCEED_TO_STAGE,
+			   path_type, stage);
+}
+
+static int adie_refcount;
+
+static struct dal_client *adie;
+static struct dal_client *adsp;
+static struct dal_client *acdb;
+
+static int adie_enable(void)
+{
+	adie_refcount++;
+	if (adie_refcount == 1)
+		adie_open(adie);
+	return 0;
+}
+
+static int adie_disable(void)
+{
+	adie_refcount--;
+	if (adie_refcount == 0)
+		adie_close(adie);
+	return 0;
+}
+
+/* 4k DMA scratch page used for exchanging acdb device config tables
+ * and stream format descriptions with the DSP.
+ */
+char *audio_data;
+int32_t audio_phys;
+
+#define SESSION_MIN 0
+#define SESSION_MAX 64
+
+static DEFINE_MUTEX(session_lock);
+static DEFINE_MUTEX(audio_lock);
+
+static struct audio_client *session[SESSION_MAX];
+
+static int session_alloc(struct audio_client *ac)
+{
+	int n;
+
+	mutex_lock(&session_lock);
+	for (n = SESSION_MIN; n < SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void session_free(int n, struct audio_client *ac)
+{
+	mutex_lock(&session_lock);
+	if (session[n] == ac)
+		session[n] = 0;
+	mutex_unlock(&session_lock);
+}
+
+static void audio_client_free(struct audio_client *ac)
+{
+	session_free(ac->session, ac);
+
+	if (ac->buf[0].data)
+		pmem_kfree(ac->buf[0].phys);
+	if (ac->buf[1].data)
+		pmem_kfree(ac->buf[1].phys);
+	kfree(ac);
+}
+
+static struct audio_client *audio_client_alloc(unsigned bufsz)
+{
+	struct audio_client *ac;
+	int n;
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return 0;
+
+	n = session_alloc(ac);
+	if (n < 0)
+		goto fail_session;
+	ac->session = n;
+
+	if (bufsz > 0) {
+		ac->buf[0].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[0].data = ioremap(ac->buf[0].phys, bufsz);
+		if (!ac->buf[0].data)
+			goto fail;
+
+		ac->buf[1].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[1].data = ioremap(ac->buf[1].phys, bufsz);
+		if (!ac->buf[1].data)
+			goto fail;
+
+		ac->buf[0].size = bufsz;
+		ac->buf[1].size = bufsz;
+	}
+
+	init_waitqueue_head(&ac->wait);
+	ac->client = adsp;
+
+	return ac;
+
+fail:
+	pr_err("pmem_kalloc failed\n");
+	session_free(n, ac);
+fail_session:
+	audio_client_free(ac);
+	return 0;
+}
+
+static int audio_ioctl(struct audio_client *ac, void *ptr, uint32_t len)
+{
+	struct adsp_command_hdr *hdr = ptr;
+	uint32_t tmp;
+	int r;
+
+	hdr->size = len - sizeof(u32);
+	hdr->dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	hdr->src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	hdr->context = ac->session;
+	ac->cb_status = -EBUSY;
+	r = dal_call(ac->client, AUDIO_OP_CONTROL, 5, ptr, len,
+						&tmp, sizeof(tmp));
+	if (r != 4)
+		return -EIO;
+	wait_event(ac->wait, (ac->cb_status != -EBUSY));
+	return tmp;
+}
+
+static int audio_command(struct audio_client *ac, uint32_t cmd)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = cmd;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_open_control(struct audio_client *ac)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+
+static int audio_close(struct audio_client *ac)
+{
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_STOP);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_CLOSE);
+	return 0;
+}
+
+static int audio_set_table(struct audio_client *ac,
+			   uint32_t device_id, int size)
+{
+	struct adsp_set_dev_cfg_table_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = device_id;
+	rpc.phys_addr = audio_phys;
+	rpc.phys_size = size;
+	rpc.phys_used = size;
+
+	if (q6_device_to_dir(device_id) == Q6_TX)
+		rpc.hdr.data = tx_clk_freq;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_TX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+
+	if ((r == sizeof(res)))
+		return 0;
+
+	return -EIO;
+
+}
+
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_RX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+static int audio_rx_volume(struct audio_client *ac, uint32_t dev_id,
+				 int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_rx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_volume(struct audio_client *ac, uint32_t dev_id,
+				 int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_TX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_TX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct adsp_event_hdr *e = data;
+	struct audio_client *ac;
+	struct adsp_buffer_event *abe = data;
+
+	if (e->context >= SESSION_MAX) {
+		pr_err("audio callback: bogus session %d\n",
+		       e->context);
+		return;
+	}
+	ac = session[e->context];
+	if (!ac) {
+		pr_err("audio callback: unknown session %d\n",
+		       e->context);
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_IOCTL_CMD_STREAM_EOS) {
+		pr_info("playback done\n");
+		if (e->status)
+			pr_err("playback status %d\n", e->status);
+		if (ac->cb_status == -EBUSY) {
+			ac->cb_status = e->status;
+			wake_up(&ac->wait);
+		}
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) {
+		if (e->status)
+			pr_err("buffer status %d\n", e->status);
+
+		ac->buf[ac->dsp_buf].actual_size = abe->buffer.actual_size;
+		ac->buf[ac->dsp_buf].used = 0;
+		ac->dsp_buf ^= 1;
+		wake_up(&ac->wait);
+		return;
+	}
+
+	if (e->status)
+		pr_warning("audio_cb: s=%d e=%08x status=%d\n",
+			   e->context, e->event_id, e->status);
+
+	if (ac->cb_status == -EBUSY) {
+		ac->cb_status = e->status;
+		wake_up(&ac->wait);
+	}
+}
+
+static void audio_init(struct dal_client *client)
+{
+	u32 tmp[3];
+
+	tmp[0] = 2 * sizeof(u32);
+	tmp[1] = 0;
+	tmp[2] = 0;
+	dal_call(client, AUDIO_OP_INIT, 5, tmp, sizeof(tmp),
+		 tmp, sizeof(u32));
+}
+
+static struct audio_client *ac_control;
+
+static int q6audio_init(void)
+{
+	struct audio_client *ac = 0;
+	int res = -ENODEV;
+
+	mutex_lock(&audio_lock);
+	if (ac_control) {
+		res = 0;
+		goto done;
+	}
+
+	icodec_rx_clk = clk_get(0, "icodec_rx_clk");
+	icodec_tx_clk = clk_get(0, "icodec_tx_clk");
+	ecodec_clk = clk_get(0, "ecodec_clk");
+	sdac_clk = clk_get(0, "sdac_clk");
+
+	tx_mute_status = 0;
+	audio_phys = pmem_kalloc(4096, PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+	audio_data = ioremap(audio_phys, 4096);
+	if (!audio_data) {
+		pr_err("pmem kalloc failed\n");
+		res = -ENOMEM;
+		goto done;
+	}
+
+	adsp = dal_attach(AUDIO_DAL_DEVICE, AUDIO_DAL_PORT, 1,
+			  callback, 0);
+	if (!adsp) {
+		pr_err("audio_init: cannot attach to adsp\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (check_version(adsp, AUDIO_DAL_VERSION) != 0) {
+		pr_err("Incompatible adsp version\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+	audio_init(adsp);
+
+	ac = audio_client_alloc(0);
+	if (!ac) {
+		pr_err("audio_init: cannot allocate client\n");
+		res = -ENOMEM;
+		goto done;
+	}
+
+	if (audio_open_control(ac)) {
+		pr_err("audio_init: cannot open control channel\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+	acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0, 0);
+	if (!acdb) {
+		pr_err("audio_init: cannot attach to acdb channel\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (check_version(acdb, ACDB_DAL_VERSION) != 0) {
+		pr_err("Incompatablie acdb version\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+
+	adie = dal_attach(ADIE_DAL_DEVICE, ADIE_DAL_PORT, 0, 0, 0);
+	if (!adie) {
+		pr_err("audio_init: cannot attach to adie\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (check_version(adie, ADIE_DAL_VERSION) != 0) {
+		pr_err("Incompatablie adie version\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (analog_ops->init)
+		analog_ops->init();
+
+	res = 0;
+	ac_control = ac;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+done:
+	if ((res < 0) && ac)
+		audio_client_free(ac);
+	mutex_unlock(&audio_lock);
+
+	return res;
+}
+
+static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate)
+{
+	struct acdb_cmd_device_table rpc;
+	struct acdb_result res;
+	int r;
+
+	if (q6audio_init())
+		return 0;
+
+	memset(audio_data, 0, 4096);
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.size = sizeof(rpc) - (2 * sizeof(uint32_t));
+	rpc.command_id = ACDB_GET_DEVICE_TABLE;
+	rpc.device_id = q6_device_to_cad_id(device_id);
+	rpc.network_id = 0x00010023;
+	rpc.sample_rate_id = sample_rate;
+	rpc.total_bytes = 4096;
+	rpc.unmapped_buf = audio_phys;
+	rpc.res_size = sizeof(res) - (2 * sizeof(uint32_t));
+
+	r = dal_call(acdb, ACDB_OP_IOCTL, 8, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+
+	if ((r == sizeof(res)) && (res.dal_status == 0))
+		return res.used_bytes;
+
+	return -EIO;
+}
+
+static uint32_t audio_rx_path_id = ADIE_PATH_HANDSET_RX;
+static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR;
+static uint32_t audio_rx_device_group = -1;
+static uint32_t audio_tx_path_id = ADIE_PATH_HANDSET_TX;
+static uint32_t audio_tx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC;
+static uint32_t audio_tx_device_group = -1;
+
+static int qdsp6_devchg_notify(struct audio_client *ac,
+			       uint32_t dev_type, uint32_t dev_id)
+{
+	struct adsp_device_switch_command rpc;
+
+	if (dev_type != ADSP_AUDIO_RX_DEVICE &&
+	    dev_type != ADSP_AUDIO_TX_DEVICE)
+		return -EINVAL;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+
+	if (dev_type == ADSP_AUDIO_RX_DEVICE) {
+		rpc.old_device = audio_rx_device_id;
+		rpc.new_device = dev_id;
+	} else {
+		rpc.old_device = audio_tx_device_id;
+		rpc.new_device = dev_id;
+	}
+	rpc.device_class = 0;
+	rpc.device_type = dev_type;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int qdsp6_standby(struct audio_client *ac)
+{
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY);
+}
+
+static int qdsp6_start(struct audio_client *ac)
+{
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT);
+}
+
+static void audio_rx_analog_enable(int en)
+{
+	switch (audio_rx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO:
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO:
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static void audio_tx_analog_enable(int en)
+{
+	switch (audio_tx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC:
+		if (analog_ops->int_mic_enable)
+			analog_ops->int_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC:
+		if (analog_ops->ext_mic_enable)
+			analog_ops->ext_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static void _audio_rx_path_enable(void)
+{
+	uint32_t adev, sample_rate;
+	int sz;
+	uint32_t adie_params[5];
+
+	adev = audio_rx_device_id;
+	sample_rate = q6_device_to_rate(adev);
+
+	sz = acdb_get_config_table(adev, sample_rate);
+	audio_set_table(ac_control, adev, sz);
+
+	adie_params[0] = 4*sizeof(uint32_t);
+	adie_params[1] = audio_rx_path_id;
+	adie_params[2] = ADIE_PATH_RX;
+	adie_params[3] = 48000;
+	adie_params[4] = 256;
+	/*check for errors here*/
+	if (!adie_set_path(adie, adie_params, sizeof(adie_params)))
+		pr_err("adie set rx path failed\n");
+
+	adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_READY);
+	adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+	audio_rx_analog_enable(1);
+
+	audio_rx_mute(ac_control, adev, 0);
+
+	audio_rx_volume(ac_control, adev, q6_device_volume(adev, 100));
+}
+
+static void _audio_tx_path_enable(void)
+{
+	uint32_t adev;
+	int sz;
+	uint32_t adie_params[5];
+
+	adev = audio_tx_device_id;
+
+	pr_info("audiolib: load %08x cfg table\n", adev);
+
+	if (tx_clk_freq > 16000) {
+		adie_params[3] = 48000;
+		sz = acdb_get_config_table(adev, 48000);
+
+	} else if (tx_clk_freq > 8000) {
+		adie_params[3] = 16000;
+		sz = acdb_get_config_table(adev, 16000);
+	} else {
+
+		adie_params[3] = 8000;
+		sz = acdb_get_config_table(adev, 8000);
+	}
+
+	pr_info("cfg table is %d bytes\n", sz);
+	audio_set_table(ac_control, adev, sz);
+
+	pr_info("audiolib: set adie tx path\n");
+
+	adie_params[0] = 4*sizeof(uint32_t);
+	adie_params[1] = audio_tx_path_id;
+	adie_params[2] = ADIE_PATH_TX;
+	adie_params[4] = 256;
+
+	if (!adie_set_path(adie, adie_params, sizeof(adie_params)))
+		pr_err("adie set tx path failed\n");
+
+	adie_proceed_to_stage(adie, ADIE_PATH_TX,
+					 ADIE_STAGE_DIGITAL_READY);
+	adie_proceed_to_stage(adie, ADIE_PATH_TX,
+					 ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+	audio_tx_analog_enable(1);
+	audio_tx_mute(ac_control, adev, tx_mute_status);
+
+	if (!tx_mute_status)
+		audio_tx_volume(ac_control, adev, q6_device_volume(adev, 100));
+}
+
+static void _audio_rx_path_disable(void)
+{
+	audio_rx_analog_enable(0);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_ANALOG_OFF);
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_OFF);
+}
+
+static void _audio_tx_path_disable(void)
+{
+	audio_tx_analog_enable(0);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_ANALOG_OFF);
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_OFF);
+}
+
+static int icodec_rx_clk_refcount;
+static int icodec_tx_clk_refcount;
+static int ecodec_clk_refcount;
+static int sdac_clk_refcount;
+
+static void _audio_rx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_rx_device_id);
+
+	switch (device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount++;
+		if (icodec_rx_clk_refcount == 1) {
+			clk_set_rate(icodec_rx_clk, 12288000);
+			clk_enable(icodec_rx_clk);
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_refcount++;
+		if (ecodec_clk_refcount == 1) {
+			clk_set_rate(ecodec_clk, 2048000);
+			clk_enable(ecodec_clk);
+		}
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_rx_device_group = device_group;
+}
+
+static void _audio_tx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_tx_device_id);
+
+	switch (device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount++;
+		if (icodec_tx_clk_refcount == 1) {
+			clk_set_rate(icodec_tx_clk, tx_clk_freq * 256);
+			clk_enable(icodec_tx_clk);
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_refcount++;
+		if (ecodec_clk_refcount == 1) {
+			clk_set_rate(ecodec_clk, 2048000);
+			clk_enable(ecodec_clk);
+		}
+		break;
+	case Q6_SDAC_TX:
+		/* TODO: In QCT BSP, clk rate was set to 20480000 */
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_tx_device_group = device_group;
+}
+
+static void _audio_rx_clk_disable(void)
+{
+	switch (audio_rx_device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount--;
+		if (icodec_rx_clk_refcount == 0) {
+			clk_disable(icodec_rx_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_refcount--;
+		if (ecodec_clk_refcount == 0) {
+			clk_disable(ecodec_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("audiolib: invalid rx device group %d\n",
+			audio_rx_device_group);
+		break;
+	}
+}
+
+static void _audio_tx_clk_disable(void)
+{
+	switch (audio_tx_device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount--;
+		if (icodec_tx_clk_refcount == 0) {
+			clk_disable(icodec_tx_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_refcount--;
+		if (ecodec_clk_refcount == 0) {
+			clk_disable(ecodec_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_SDAC_TX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("audiolib: invalid tx device group %d\n",
+			audio_tx_device_group);
+		break;
+	}
+}
+
+static void _audio_rx_clk_reinit(uint32_t rx_device)
+{
+	uint32_t device_group = q6_device_to_codec(rx_device);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_disable();
+
+	audio_rx_device_id = rx_device;
+	audio_rx_path_id = q6_device_to_path(rx_device);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_enable();
+
+}
+
+static void _audio_tx_clk_reinit(uint32_t tx_device)
+{
+	uint32_t device_group = q6_device_to_codec(tx_device);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_disable();
+
+	audio_tx_device_id = tx_device;
+	audio_tx_path_id = q6_device_to_path(tx_device);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_enable();
+}
+
+static DEFINE_MUTEX(audio_path_lock);
+static int audio_rx_path_refcount;
+static int audio_tx_path_refcount;
+
+static int audio_rx_path_enable(int en)
+{
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			adie_enable();
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable();
+		}
+	} else {
+		audio_rx_path_refcount--;
+		if (audio_rx_path_refcount == 0) {
+			_audio_rx_path_disable();
+			_audio_rx_clk_disable();
+			adie_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_tx_path_enable(int en)
+{
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			adie_enable();
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable();
+		}
+	} else {
+		audio_tx_path_refcount--;
+		if (audio_tx_path_refcount == 0) {
+			_audio_tx_path_disable();
+			_audio_tx_clk_disable();
+			adie_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst)
+{
+	mutex_lock(&audio_path_lock);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_tx_mute(int mute)
+{
+	uint32_t adev;
+	int rc;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (mute == tx_mute_status) {
+		mutex_unlock(&audio_path_lock);
+		return 0;
+	}
+
+	adev = audio_tx_device_id;
+	rc = audio_tx_mute(ac_control, adev, mute);
+	if (!rc)
+		tx_mute_status = mute;
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_rx_volume(int level)
+{
+	uint32_t adev;
+	int vol;
+
+	if (q6audio_init())
+		return 0;
+
+	if (level < 0 || level > 100)
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	adev = audio_rx_device_id;
+	vol = q6_device_volume(adev, level);
+	audio_rx_mute(ac_control, adev, 0);
+	audio_rx_volume(ac_control, adev, vol);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static void do_rx_routing(uint32_t device_id)
+{
+	int sz;
+	uint32_t sample_rate;
+
+	if (device_id == audio_rx_device_id)
+		return;
+
+	if (audio_rx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE,
+					 device_id);
+		_audio_rx_path_disable();
+		_audio_rx_clk_reinit(device_id);
+		_audio_rx_path_enable();
+	} else {
+		sample_rate = q6_device_to_rate(device_id);
+		sz = acdb_get_config_table(device_id, sample_rate);
+		if (sz < 0)
+			pr_err("could not get ACDB config table\n");
+
+		audio_set_table(ac_control, device_id, sz);
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE,
+					 device_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_rx_device_id = device_id;
+		audio_rx_path_id = q6_device_to_path(device_id);
+	}
+}
+
+static void do_tx_routing(uint32_t device_id)
+{
+	int sz;
+	uint32_t sample_rate;
+
+	if (device_id == audio_tx_device_id)
+		return;
+
+	if (audio_tx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+					 device_id);
+		_audio_tx_path_disable();
+		_audio_tx_clk_reinit(device_id);
+		_audio_tx_path_enable();
+	} else {
+		sample_rate = q6_device_to_rate(device_id);
+		sz = acdb_get_config_table(device_id, sample_rate);
+		audio_set_table(ac_control, device_id, sz);
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+					 device_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_tx_device_id = device_id;
+		audio_tx_path_id = q6_device_to_path(device_id);
+	}
+}
+
+int q6audio_do_routing(uint32_t device_id)
+{
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	switch (q6_device_to_dir(device_id)) {
+	case Q6_RX:
+		do_rx_routing(device_id);
+		break;
+	case Q6_TX:
+		do_tx_routing(device_id);
+		break;
+	}
+
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_route(const char *name)
+{
+	uint32_t route;
+	if (!strcmp(name, "speaker"))
+		route = ADIE_PATH_SPEAKER_STEREO_RX;
+	else if (!strcmp(name, "headphones"))
+		route = ADIE_PATH_HEADSET_STEREO_RX;
+	else if (!strcmp(name, "handset"))
+		route = ADIE_PATH_HANDSET_RX;
+	else
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	if (route == audio_rx_path_id)
+		goto done;
+
+	audio_rx_path_id = route;
+
+	if (audio_rx_path_refcount > 0) {
+		_audio_rx_path_disable();
+		_audio_rx_path_enable();
+	}
+	if (audio_tx_path_refcount > 0) {
+		_audio_tx_path_disable();
+		_audio_tx_path_enable();
+	}
+done:
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+struct audio_client *q6audio_open(uint32_t flags, uint32_t bufsz)
+{
+	struct audio_client *ac;
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1);
+	else
+		audio_tx_path_enable(1);
+
+	return ac;
+}
+
+int q6audio_start(struct audio_client *ac, void *rpc,
+						uint32_t len)
+{
+
+	audio_ioctl(ac, rpc, len);
+
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+
+	audio_prevent_sleep();
+	return 0;
+}
+
+int q6audio_close(struct audio_client *ac)
+{
+	audio_close(ac);
+
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0);
+	else
+		audio_tx_path_enable(0);
+
+	audio_client_free(ac);
+	audio_allow_sleep();
+	return 0;
+}
+
+struct audio_client *q6voice_open(void)
+{
+	struct audio_client *ac;
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	return ac;
+}
+
+int q6voice_setup(void)
+{
+	audio_rx_path_enable(1);
+	tx_clk_freq = 8000;
+	audio_tx_path_enable(1);
+
+	return 0;
+}
+
+int q6voice_teardown(void)
+{
+	audio_rx_path_enable(0);
+	audio_tx_path_enable(0);
+	return 0;
+}
+
+
+int q6voice_close(struct audio_client *ac)
+{
+	audio_client_free(ac);
+	return 0;
+}
+
+int q6audio_async(struct audio_client *ac)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = ADSP_AUDIO_IOCTL_CMD_STREAM_EOS;
+	rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h b/arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
new file mode 100644
index 0000000..aa8a699
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
@@ -0,0 +1,276 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, 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.
+ *
+ */
+
+struct q6_device_info {
+	uint32_t id;
+	uint32_t cad_id;
+	uint32_t path;
+	uint32_t rate;
+	uint8_t dir;
+	uint8_t codec;
+	uint8_t hw;
+};
+
+#define Q6_ICODEC_RX		0
+#define Q6_ICODEC_TX		1
+#define Q6_ECODEC_RX		2
+#define Q6_ECODEC_TX		3
+#define Q6_SDAC_RX		6
+#define Q6_SDAC_TX		7
+#define Q6_CODEC_NONE		255
+
+#define Q6_TX		1
+#define Q6_RX		2
+#define Q6_TX_RX	3
+
+#define Q6_HW_HANDSET	0
+#define Q6_HW_HEADSET	1
+#define Q6_HW_SPEAKER	2
+#define Q6_HW_TTY	3
+#define Q6_HW_BT_SCO	4
+#define Q6_HW_BT_A2DP	5
+
+#define Q6_HW_COUNT	6
+
+#define CAD_HW_DEVICE_ID_HANDSET_MIC		0x01
+#define CAD_HW_DEVICE_ID_HANDSET_SPKR		0x02
+#define CAD_HW_DEVICE_ID_HEADSET_MIC		0x03
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO	0x04
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO	0x05
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MIC		0x06
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MONO	0x07
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO	0x08
+#define CAD_HW_DEVICE_ID_BT_SCO_MIC		0x09
+#define CAD_HW_DEVICE_ID_BT_SCO_SPKR		0x0A
+#define CAD_HW_DEVICE_ID_BT_A2DP_SPKR		0x0B
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_MIC	0x0C
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR	0x0D
+
+#define CAD_HW_DEVICE_ID_DEFAULT_TX		0x0E
+#define CAD_HW_DEVICE_ID_DEFAULT_RX		0x0F
+
+/* Logical Device to indicate A2DP routing */
+#define CAD_HW_DEVICE_ID_BT_A2DP_TX             0x10
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX	0x12
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX	0x13
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+
+#define CAD_HW_DEVICE_ID_VOICE			0x15
+
+#define CAD_HW_DEVICE_ID_I2S_RX                 0x20
+#define CAD_HW_DEVICE_ID_I2S_TX                 0x21
+
+/* AUXPGA */
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO_LB 0x22
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO_LB   0x23
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_STEREO_LB 0x24
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_MONO_LB   0x25
+
+#define CAD_HW_DEVICE_ID_NULL_RX		0x2A
+
+#define CAD_HW_DEVICE_ID_MAX_NUM                0x2F
+
+#define CAD_HW_DEVICE_ID_INVALID                0xFF
+
+#define CAD_RX_DEVICE  0x00
+#define CAD_TX_DEVICE  0x01
+
+static struct q6_device_info q6_audio_devices[] = {
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_SPKR,
+		.path	= ADIE_PATH_HANDSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO,
+		.path	= ADIE_PATH_HEADSET_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.path	= ADIE_PATH_HEADSET_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MONO,
+		.path	= ADIE_PATH_SPEAKER_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO,
+		.path	= ADIE_PATH_SPEAKER_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR,
+		.path	= ADIE_PATH_TTY_HEADSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_TTY,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_MIC,
+		.path	= ADIE_PATH_HANDSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MIC,
+		.path	= ADIE_PATH_HEADSET_MONO_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MIC,
+		.path	= ADIE_PATH_SPEAKER_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_MIC,
+		.path	= ADIE_PATH_TTY_HEADSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_A2DP_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_A2DP,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_RX,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_SDAC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_TX,
+		.path	= 0, /* XXX */
+		.rate   = 16000,
+		.dir	= Q6_TX,
+		.codec	= Q6_SDAC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= 0,
+		.cad_id	= 0,
+		.path	= 0,
+		.rate   = 8000,
+		.dir	= 0,
+		.codec	= Q6_CODEC_NONE,
+		.hw	= 0,
+	},
+};
+
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/qcelp_in.c b/arch/arm/mach-msm/qdsp6/audiov2/qcelp_in.c
new file mode 100644
index 0000000..a13084f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/qcelp_in.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, 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/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+
+struct qcelp {
+	struct mutex lock;
+	struct msm_audio_qcelp_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+
+static long q6_qcelp_in_ioctl(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct qcelp *qcelp = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&qcelp->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if (qcelp->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			qcelp->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						qcelp->str_cfg.buffer_size);
+
+			if (!qcelp->audio_client) {
+				kfree(qcelp);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		tx_clk_freq = 8000;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_V13K_FS;
+		rpc.format_block.standard.channels = 1;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = 8000;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = qcelp->str_cfg.buffer_size;
+		rpc.config.qcelp13k.min_rate = qcelp->cfg.min_bit_rate;
+		rpc.config.qcelp13k.max_rate = qcelp->cfg.max_bit_rate;
+
+		q6audio_start(qcelp->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &qcelp->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&qcelp->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (qcelp->str_cfg.buffer_size < 35) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (qcelp->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_QCELP_ENC_CONFIG:
+		if (copy_from_user(&qcelp->cfg, (void *) arg,
+				sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+
+		if (qcelp->cfg.min_bit_rate > 4 ||
+			 qcelp->cfg.min_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (qcelp->cfg.max_bit_rate > 4 ||
+			 qcelp->cfg.max_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+
+		break;
+	case AUDIO_GET_QCELP_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &qcelp->cfg,
+			 sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&qcelp->lock);
+	return rc;
+}
+
+static int q6_qcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct qcelp *qcelp;
+	qcelp = kmalloc(sizeof(struct qcelp), GFP_KERNEL);
+	if (qcelp == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for qcelp driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&qcelp->lock);
+	file->private_data = qcelp;
+	qcelp->audio_client = NULL;
+	qcelp->str_cfg.buffer_size = 35;
+	qcelp->str_cfg.buffer_count = 2;
+	qcelp->cfg.cdma_rate = CDMA_RATE_FULL;
+	qcelp->cfg.min_bit_rate = 1;
+	qcelp->cfg.max_bit_rate = 4;
+	return 0;
+}
+
+static ssize_t q6_qcelp_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct qcelp *qcelp = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&qcelp->lock);
+	ac = qcelp->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+
+fail:
+	mutex_unlock(&qcelp->lock);
+
+	return res;
+}
+
+static int q6_qcelp_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct qcelp *qcelp = file->private_data;
+
+	mutex_lock(&qcelp->lock);
+	if (qcelp->audio_client)
+		rc = q6audio_close(qcelp->audio_client);
+	mutex_unlock(&qcelp->lock);
+	kfree(qcelp);
+	return rc;
+}
+
+static const struct file_operations q6_qcelp_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_qcelp_in_open,
+	.read		= q6_qcelp_in_read,
+	.release	= q6_qcelp_in_release,
+	.unlocked_ioctl	= q6_qcelp_in_ioctl,
+};
+
+struct miscdevice q6_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &q6_qcelp_in_fops,
+};
+
+static int __init q6_qcelp_in_init(void)
+{
+	return misc_register(&q6_qcelp_in_misc);
+}
+
+device_initcall(q6_qcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/routing.c b/arch/arm/mach-msm/qdsp6/audiov2/routing.c
new file mode 100644
index 0000000..1a2476b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/routing.c
@@ -0,0 +1,73 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/routing.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, 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/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <mach/msm_qdsp6_audiov2.h>
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t q6_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	q6audio_set_route(cmd);
+
+	return count;
+}
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations q6_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.write		= q6_write,
+	.release	= q6_release,
+};
+
+static struct miscdevice q6_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_route",
+	.fops	= &q6_fops,
+};
+
+
+static int __init q6_init(void)
+{
+	return misc_register(&q6_misc);
+}
+
+device_initcall(q6_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/voice.c b/arch/arm/mach-msm/qdsp6/audiov2/voice.c
new file mode 100644
index 0000000..906c534
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/voice.c
@@ -0,0 +1,188 @@
+/* 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/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "../dal.h"
+#include "dal_voice.h"
+#include <mach/debug_mm.h>
+
+struct voice_struct {
+	struct dal_client *cvd;
+	struct apr_command_pkt apr_pkt;
+	struct completion compl;
+};
+
+static struct voice_struct voice;
+
+static int cvd_send_response(void)
+{
+	struct apr_command_pkt *pkt;
+	uint16_t src_addr;
+	uint16_t src_token;
+	uint16_t dst_token;
+	uint16_t dst_addr;
+
+	pkt = &voice.apr_pkt;
+	src_addr = pkt->dst_addr;
+	dst_addr = pkt->src_addr;
+	src_token = pkt->dst_token;
+	dst_token = pkt->src_token;
+
+	pkt->header &= ~APR_PKTV1_TYPE_MASK;
+	pkt->header |= APR_SET_FIELD(APR_PKTV1_TYPE, APR_PKTV1_TYPE_EVENT_V);
+	pkt->src_addr = src_addr;
+	pkt->dst_addr = dst_addr;
+	pkt->src_token = src_token;
+	pkt->dst_token = dst_token;
+	pkt->opcode = APR_IBASIC_RSP_RESULT;
+
+	dal_call(voice.cvd, VOICE_OP_CONTROL, 5, pkt,
+			sizeof(struct apr_command_pkt),
+			pkt, sizeof(u32));
+	return 0;
+}
+
+static int cvd_process_voice_setup(void)
+{
+	q6voice_setup();
+	cvd_send_response();
+	return 0;
+}
+
+static int cvd_process_voice_teardown(void)
+{
+	q6voice_teardown();
+	cvd_send_response();
+	return 0;
+}
+
+static int cvd_process_set_network(void)
+{
+	cvd_send_response();
+	return 0;
+}
+
+static int voice_thread(void *data)
+{
+	while (!kthread_should_stop()) {
+		wait_for_completion(&voice.compl);
+		init_completion(&voice.compl);
+
+		switch (voice.apr_pkt.opcode) {
+
+		case APR_OP_CMD_CREATE:
+			cvd_send_response();
+			break;
+		case VOICE_OP_CMD_BRINGUP:
+			cvd_process_voice_setup();
+			break;
+		case APR_OP_CMD_DESTROY:
+			cvd_send_response();
+			break;
+		case VOICE_OP_CMD_TEARDOWN:
+			cvd_process_voice_teardown();
+			break;
+		case VOICE_OP_CMD_SET_NETWORK:
+			cvd_process_set_network();
+			break;
+		default:
+			pr_err("[%s:%s] Undefined event\n", __MM_FILE__,
+					__func__);
+
+		}
+	}
+	return 0;
+}
+
+static void remote_cb_function(void *data, int len, void *cookie)
+{
+	struct apr_command_pkt *apr = data + 2*sizeof(uint32_t);
+
+	memcpy(&voice.apr_pkt, apr, sizeof(struct apr_command_pkt));
+
+	if (len <= 0) {
+		pr_err("[%s:%s] unexpected event with length %d\n",
+				__MM_FILE__, __func__, len);
+		return;
+	}
+
+	pr_debug("[%s:%s] APR = %x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", __MM_FILE__,
+			__func__,
+	apr->header,
+	apr->reserved1,
+	apr->src_addr,
+	apr->dst_addr,
+	apr->ret_addr,
+	apr->src_token,
+	apr->dst_token,
+	apr->ret_token,
+	apr->context,
+	apr->opcode);
+
+	complete(&voice.compl);
+}
+
+static int __init voice_init(void)
+{
+	int res = 0;
+	struct task_struct *task;
+	u32 tmp[2];
+
+	tmp[0] = sizeof(u32);
+	tmp[1] = 0;
+
+	voice.cvd = dal_attach(VOICE_DAL_DEVICE, VOICE_DAL_PORT, 0,
+			remote_cb_function, 0);
+
+	if (!voice.cvd) {
+		pr_err("[%s:%s] audio_init: cannot attach to cvd\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+
+	if (check_version(voice.cvd, VOICE_DAL_VERSION) != 0) {
+		pr_err("[%s:%s] Incompatible cvd version\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+	dal_call(voice.cvd, VOICE_OP_INIT, 5, tmp, sizeof(tmp),
+		tmp, sizeof(u32));
+
+	init_completion(&voice.compl);
+	task = kthread_run(voice_thread, &voice, "voice_thread");
+
+	if (IS_ERR(task)) {
+		pr_err("[%s:%s] Cannot start the voice thread\n", __MM_FILE__,
+				__func__);
+		res = PTR_ERR(task);
+		task = NULL;
+	} else
+		goto done;
+
+done:
+	return res;
+}
+
+late_initcall(voice_init);
diff --git a/arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c b/arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
new file mode 100644
index 0000000..4195454
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
@@ -0,0 +1,190 @@
+/* arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct auxpcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	int opened;;
+};
+
+static long auxpcmin_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct auxpcm *auxpcmin = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&auxpcmin->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void *) arg,
+					sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (auxpcmin->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			auxpcmin->ac =
+				q6audio_open_auxpcm(auxpcmin->sample_rate,
+						auxpcmin->channel_count,
+						AUDIO_FLAG_READ, acdb_id);
+			if (!auxpcmin->ac) {
+				pr_err("[%s:%s] auxpcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (auxpcmin->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count != 1) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+				__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate != 8000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		auxpcmin->sample_rate = config.sample_rate;
+		auxpcmin->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = 0;
+		config.buffer_count = 0;
+		config.sample_rate = auxpcmin->sample_rate;
+		config.channel_count = auxpcmin->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&auxpcmin->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static struct auxpcm the_auxpcmin;
+
+static int auxpcmin_open(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmin = &the_auxpcmin;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	mutex_lock(&auxpcmin->lock);
+	if (auxpcmin->opened) {
+		pr_err("aux pcm loopback tx already open!\n");
+		mutex_unlock(&auxpcmin->lock);
+		return -EBUSY;
+	}
+	auxpcmin->channel_count = 1;
+	auxpcmin->sample_rate = 8000;
+	auxpcmin->opened = 1;
+	file->private_data = auxpcmin;
+	mutex_unlock(&auxpcmin->lock);
+	return 0;
+}
+
+static int auxpcmin_release(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmin = file->private_data;
+	mutex_lock(&auxpcmin->lock);
+	if (auxpcmin->ac)
+		q6audio_auxpcm_close(auxpcmin->ac);
+	auxpcmin->ac = NULL;
+	auxpcmin->opened = 0;
+	mutex_unlock(&auxpcmin->lock);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static const struct file_operations auxpcmin_fops = {
+	.owner		= THIS_MODULE,
+	.open		= auxpcmin_open,
+	.release	= auxpcmin_release,
+	.unlocked_ioctl	= auxpcmin_ioctl,
+};
+
+struct miscdevice auxpcmin_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aux_pcm_lb_in",
+	.fops	= &auxpcmin_fops,
+};
+
+static int __init auxpcmin_init(void)
+{
+	mutex_init(&the_auxpcmin.lock);
+	return misc_register(&auxpcmin_misc);
+}
+
+device_initcall(auxpcmin_init);
diff --git a/arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c b/arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c
new file mode 100644
index 0000000..b680597
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c
@@ -0,0 +1,191 @@
+/* arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct auxpcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	int opened;;
+};
+
+static long auxpcmout_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct auxpcm *auxpcmout = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&auxpcmout->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void *) arg,
+					sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (auxpcmout->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+		} else {
+			auxpcmout->ac =
+				q6audio_open_auxpcm(auxpcmout->sample_rate,
+						auxpcmout->channel_count,
+						AUDIO_FLAG_WRITE, acdb_id);
+			if (!auxpcmout->ac) {
+				pr_err("[%s:%s] auxpcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (auxpcmout->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count != 1) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+			__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate != 8000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		auxpcmout->sample_rate = config.sample_rate;
+		auxpcmout->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = 0;
+		config.buffer_count = 0;
+		config.sample_rate = auxpcmout->sample_rate;
+		config.channel_count = auxpcmout->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels= %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&auxpcmout->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static struct auxpcm the_auxpcmout;
+
+static int auxpcmout_open(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmout = &the_auxpcmout;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+
+	mutex_lock(&auxpcmout->lock);
+
+	if (auxpcmout->opened) {
+		pr_err("aux pcm loopback rx already open!\n");
+		mutex_unlock(&auxpcmout->lock);
+		return -EBUSY;
+	}
+	auxpcmout->channel_count = 1;
+	auxpcmout->sample_rate = 8000;
+	auxpcmout->opened = 1;
+	file->private_data = auxpcmout;
+	mutex_unlock(&auxpcmout->lock);
+	return 0;
+}
+
+static int auxpcmout_release(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmout = file->private_data;
+	mutex_lock(&auxpcmout->lock);
+	if (auxpcmout->ac)
+		q6audio_auxpcm_close(auxpcmout->ac);
+	auxpcmout->ac = NULL;
+	auxpcmout->opened = 0;
+	mutex_unlock(&auxpcmout->lock);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static const struct file_operations auxpcmout_fops = {
+	.owner		= THIS_MODULE,
+	.open		= auxpcmout_open,
+	.release	= auxpcmout_release,
+	.unlocked_ioctl	= auxpcmout_ioctl,
+};
+
+struct miscdevice auxpcmout_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aux_pcm_lb_out",
+	.fops	= &auxpcmout_fops,
+};
+
+static int __init auxpcmout_init(void)
+{
+	mutex_init(&the_auxpcmout.lock);
+	return misc_register(&auxpcmout_misc);
+}
+
+device_initcall(auxpcmout_init);
diff --git a/arch/arm/mach-msm/qdsp6/dal.c b/arch/arm/mach-msm/qdsp6/dal.c
new file mode 100644
index 0000000..378432b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal.c
@@ -0,0 +1,727 @@
+/* arch/arm/mach-msm/qdsp6/dal.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+
+#include <linux/delay.h>
+
+#include <mach/msm_smd.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_qdsp6_audio.h>
+
+#include "dal.h"
+
+#define DAL_TRACE 0
+
+struct dal_hdr {
+	uint32_t length:16;	/* message length (header inclusive) */
+	uint32_t version:8;	/* DAL protocol version */
+	uint32_t priority:7;
+	uint32_t async:1;
+	uint32_t ddi:16;	/* DDI method number */
+	uint32_t prototype:8;	/* DDI serialization format */
+	uint32_t msgid:8;	/* message id (DDI, ATTACH, DETACH, ...) */
+	void *from;
+	void *to;
+} __attribute__((packed));
+
+#define TRACE_DATA_MAX	128
+#define TRACE_LOG_MAX	32
+#define TRACE_LOG_MASK	(TRACE_LOG_MAX - 1)
+
+struct dal_trace {
+	unsigned timestamp;
+	struct dal_hdr hdr;
+	uint32_t data[TRACE_DATA_MAX];
+};
+
+#define DAL_HDR_SIZE		(sizeof(struct dal_hdr))
+#define DAL_DATA_MAX		512
+#define DAL_MSG_MAX		(DAL_HDR_SIZE + DAL_DATA_MAX)
+
+#define DAL_VERSION		0x11
+
+#define DAL_MSGID_DDI		0x00
+#define DAL_MSGID_ATTACH	0x01
+#define DAL_MSGID_DETACH	0x02
+#define DAL_MSGID_ASYNCH	0xC0
+#define DAL_MSGID_REPLY		0x80
+
+struct dal_channel {
+	struct list_head list;
+	struct list_head clients;
+
+	/* synchronization for changing channel state,
+	 * adding/removing clients, smd callbacks, etc
+	 */
+	spinlock_t lock;
+
+	struct smd_channel *sch;
+	char *name;
+
+	/* events are delivered at IRQ context immediately, so
+	 * we only need one assembly buffer for the entire channel
+	 */
+	struct dal_hdr hdr;
+	unsigned char data[DAL_DATA_MAX];
+
+	unsigned count;
+	void *ptr;
+
+	/* client which the current inbound message is for */
+	struct dal_client *active;
+};
+
+struct dal_client {
+	struct list_head list;
+	struct dal_channel *dch;
+	void *cookie;
+	dal_event_func_t event;
+
+	/* opaque handle for the far side */
+	void *remote;
+
+	/* dal rpc calls are fully synchronous -- only one call may be
+	 * active per client at a time
+	 */
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+
+	unsigned char data[DAL_DATA_MAX];
+
+	void *reply;
+	int reply_max;
+	int status;
+	unsigned msgid; /* msgid of expected reply */
+
+	spinlock_t tr_lock;
+	unsigned tr_head;
+	unsigned tr_tail;
+	struct dal_trace *tr_log;
+};
+
+static unsigned now(void)
+{
+	struct timespec ts;
+	ktime_get_ts(&ts);
+	return (ts.tv_nsec / 1000000) + (ts.tv_sec * 1000);
+}
+
+void dal_trace(struct dal_client *c)
+{
+	if (c->tr_log)
+		return;
+	c->tr_log = kzalloc(sizeof(struct dal_trace) * TRACE_LOG_MAX,
+			    GFP_KERNEL);
+}
+
+void dal_trace_print(struct dal_hdr *hdr, unsigned *data, int len, unsigned when)
+{
+	int i;
+	printk("DAL %08x -> %08x L=%03x A=%d D=%04x P=%02x M=%02x T=%d",
+	       (unsigned) hdr->from, (unsigned) hdr->to,
+	       hdr->length, hdr->async,
+	       hdr->ddi, hdr->prototype, hdr->msgid,
+	       when);
+	len /= 4;
+	for (i = 0; i < len; i++) {
+		if (!(i & 7))
+			printk("\n%03x", i * 4);
+		printk(" %08x", data[i]);
+	}
+	printk("\n");
+}
+
+void dal_trace_dump(struct dal_client *c)
+{
+	struct dal_trace *dt;
+	unsigned n, len;
+
+	if (!c->tr_log)
+		return;
+
+	for (n = c->tr_tail; n != c->tr_head; n = (n + 1) & TRACE_LOG_MASK) {
+		dt = c->tr_log + n;
+		len = dt->hdr.length - sizeof(dt->hdr);
+		if (len > TRACE_DATA_MAX)
+			len = TRACE_DATA_MAX;
+		dal_trace_print(&dt->hdr, dt->data, len, dt->timestamp);
+	}
+}
+
+static void dal_trace_log(struct dal_client *c,
+			  struct dal_hdr *hdr, void *data, unsigned len)
+{
+	unsigned long flags;
+	unsigned t, n;
+	struct dal_trace *dt;
+
+	t = now();
+	if (len > TRACE_DATA_MAX)
+		len = TRACE_DATA_MAX;
+
+	spin_lock_irqsave(&c->tr_lock, flags);
+	n = (c->tr_head + 1) & TRACE_LOG_MASK;
+	if (c->tr_tail == n)
+		c->tr_tail = (c->tr_tail + 1) & TRACE_LOG_MASK;
+	dt = c->tr_log + n;
+	dt->timestamp = t;
+	memcpy(&dt->hdr, hdr, sizeof(struct dal_hdr));
+	memcpy(dt->data, data, len);
+	c->tr_head = n;
+
+	spin_unlock_irqrestore(&c->tr_lock, flags);
+}
+
+
+static void dal_channel_notify(void *priv, unsigned event)
+{
+	struct dal_channel *dch = priv;
+	struct dal_hdr *hdr = &dch->hdr;
+	struct dal_client *client;
+	unsigned long flags;
+	int len;
+	int r;
+
+	spin_lock_irqsave(&dch->lock, flags);
+
+again:
+	if (dch->count == 0) {
+		if (smd_read_avail(dch->sch) < DAL_HDR_SIZE)
+			goto done;
+
+		smd_read(dch->sch, hdr, DAL_HDR_SIZE);
+
+		if (hdr->length < DAL_HDR_SIZE)
+			goto done;
+
+		if (hdr->length > DAL_MSG_MAX)
+			panic("oversize message");
+
+		dch->count = hdr->length - DAL_HDR_SIZE;
+
+		/* locate the client this message is targeted to */
+		list_for_each_entry(client, &dch->clients, list) {
+			if (dch->hdr.to == client) {
+				dch->active = client;
+				dch->ptr = client->data;
+				goto check_data;
+			}
+		}
+		pr_err("[%s:%s] $$$ receiving unknown message len = %d $$$\n",
+				__MM_FILE__, __func__, dch->count);
+		dch->active = 0;
+		dch->ptr = dch->data;
+	}
+
+check_data:
+	len = dch->count;
+	if (len > 0) {
+		if (smd_read_avail(dch->sch) < len)
+			goto done;
+
+		r = smd_read(dch->sch, dch->ptr, len);
+		if (r != len)
+			panic("invalid read");
+
+#if DAL_TRACE
+		pr_info("[%s:%s] dal recv %p <- %p %02x:%04x:%02x %d\n",
+			__MM_FILE__, __func__, hdr->to, hdr->from, hdr->msgid,
+			hdr->ddi, hdr->prototype, hdr->length - sizeof(*hdr));
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, dch->ptr, len);
+#endif
+		dch->count = 0;
+
+		client = dch->active;
+		if (!client) {
+			pr_err("[%s:%s] message to %p discarded\n",
+				__MM_FILE__, __func__, dch->hdr.to);
+			goto again;
+		}
+
+		if (client->tr_log)
+			dal_trace_log(client, hdr, dch->ptr, len);
+
+		if (hdr->msgid == DAL_MSGID_ASYNCH) {
+			if (client->event)
+				client->event(dch->ptr, len, client->cookie);
+			else
+				pr_err("[%s:%s] client %p has no event \
+					handler\n", __MM_FILE__, __func__,
+					client);
+			goto again;
+		}
+
+		if (hdr->msgid == client->msgid) {
+			if (!client->remote)
+				client->remote = hdr->from;
+			if (len > client->reply_max)
+				len = client->reply_max;
+			memcpy(client->reply, client->data, len);
+			client->status = len;
+			wake_up(&client->wait);
+			goto again;
+		}
+
+		pr_err("[%s:%s] cannot find client %p\n", __MM_FILE__,
+				__func__, dch->hdr.to);
+		goto again;
+	}
+
+done:
+	spin_unlock_irqrestore(&dch->lock, flags);
+}
+
+static LIST_HEAD(dal_channel_list);
+static DEFINE_MUTEX(dal_channel_list_lock);
+
+static struct dal_channel *dal_open_channel(const char *name, uint32_t cpu)
+{
+	struct dal_channel *dch;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	mutex_lock(&dal_channel_list_lock);
+
+	list_for_each_entry(dch, &dal_channel_list, list) {
+		if (!strcmp(dch->name, name))
+			goto found_it;
+	}
+
+	dch = kzalloc(sizeof(*dch) + strlen(name) + 1, GFP_KERNEL);
+	if (!dch)
+		goto fail;
+
+	dch->name = (char *) (dch + 1);
+	strcpy(dch->name, name);
+	spin_lock_init(&dch->lock);
+	INIT_LIST_HEAD(&dch->clients);
+
+	list_add(&dch->list, &dal_channel_list);
+
+found_it:
+	if (!dch->sch) {
+		if (smd_named_open_on_edge(name, cpu, &dch->sch,
+					dch, dal_channel_notify)) {
+			pr_err("[%s:%s] smd open failed\n", __MM_FILE__,
+					__func__);
+			dch = NULL;
+		}
+		/* FIXME: wait for channel to open before returning */
+		msleep(100);
+	}
+
+fail:
+	mutex_unlock(&dal_channel_list_lock);
+
+	return dch;
+}
+
+int dal_call_raw(struct dal_client *client,
+		 struct dal_hdr *hdr,
+		 void *data, int data_len,
+		 void *reply, int reply_max)
+{
+	struct dal_channel *dch = client->dch;
+	unsigned long flags;
+
+	client->reply = reply;
+	client->reply_max = reply_max;
+	client->msgid = hdr->msgid | DAL_MSGID_REPLY;
+	client->status = -EBUSY;
+
+#if DAL_TRACE
+	pr_info("[%s:%s:%x] dal send %p -> %p %02x:%04x:%02x %d\n",
+		__MM_FILE__, __func__, (unsigned int)client, hdr->from, hdr->to,
+		hdr->msgid, hdr->ddi, hdr->prototype,
+		hdr->length - sizeof(*hdr));
+	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, data_len);
+#endif
+
+	if (client->tr_log)
+		dal_trace_log(client, hdr, data, data_len);
+
+	spin_lock_irqsave(&dch->lock, flags);
+	/* FIXME: ensure entire message is written or none. */
+	smd_write(dch->sch, hdr, sizeof(*hdr));
+	smd_write(dch->sch, data, data_len);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	if (!wait_event_timeout(client->wait, (client->status != -EBUSY), 5*HZ)) {
+		dal_trace_dump(client);
+		pr_err("[%s:%s] call timed out. dsp is probably dead.\n",
+				__MM_FILE__, __func__);
+		dal_trace_print(hdr, data, data_len, 0);
+		q6audio_dsp_not_responding();
+	}
+
+	return client->status;
+}
+
+int dal_call(struct dal_client *client,
+	     unsigned ddi, unsigned prototype,
+	     void *data, int data_len,
+	     void *reply, int reply_max)
+{
+	struct dal_hdr hdr;
+	int r;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.length = data_len + sizeof(hdr);
+	hdr.version = DAL_VERSION;
+	hdr.msgid = DAL_MSGID_DDI;
+	hdr.ddi = ddi;
+	hdr.prototype = prototype;
+	hdr.from = client;
+	hdr.to = client->remote;
+
+	if (hdr.length > DAL_MSG_MAX)
+		return -EINVAL;
+
+	mutex_lock(&client->write_lock);
+	r = dal_call_raw(client, &hdr, data, data_len, reply, reply_max);
+	mutex_unlock(&client->write_lock);
+
+	return r;
+}
+
+struct dal_msg_attach {
+	uint32_t device_id;
+	char attach[64];
+	char service_name[32];
+} __attribute__((packed));
+
+struct dal_reply_attach {
+	uint32_t status;
+	char name[64];
+};
+
+struct dal_client *dal_attach(uint32_t device_id, const char *name,
+			      uint32_t cpu, dal_event_func_t func, void *cookie)
+{
+	struct dal_hdr hdr;
+	struct dal_msg_attach msg;
+	struct dal_reply_attach reply;
+	struct dal_channel *dch;
+	struct dal_client *client;
+	unsigned long flags;
+	int r;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	dch = dal_open_channel(name, cpu);
+	if (!dch)
+		return 0;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return 0;
+
+	client->dch = dch;
+	client->event = func;
+	client->cookie = cookie;
+	mutex_init(&client->write_lock);
+	spin_lock_init(&client->tr_lock);
+	init_waitqueue_head(&client->wait);
+
+	spin_lock_irqsave(&dch->lock, flags);
+	list_add(&client->list, &dch->clients);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	memset(&hdr, 0, sizeof(hdr));
+	memset(&msg, 0, sizeof(msg));
+
+	hdr.length = sizeof(hdr) + sizeof(msg);
+	hdr.version = DAL_VERSION;
+	hdr.msgid = DAL_MSGID_ATTACH;
+	hdr.from = client;
+	msg.device_id = device_id;
+
+	r = dal_call_raw(client, &hdr, &msg, sizeof(msg),
+			 &reply, sizeof(reply));
+
+	if ((r == sizeof(reply)) && (reply.status == 0)) {
+		reply.name[63] = 0;
+		pr_info("[%s:%s] status = %d, name = '%s' dal_client %x\n",
+			__MM_FILE__, __func__, reply.status,
+			reply.name, (unsigned int)client);
+		return client;
+	}
+
+	pr_err("[%s:%s] failure\n", __MM_FILE__, __func__);
+
+	dal_detach(client);
+	return 0;
+}
+
+int dal_detach(struct dal_client *client)
+{
+	struct dal_channel *dch;
+	unsigned long flags;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	mutex_lock(&client->write_lock);
+	if (client->remote) {
+		struct dal_hdr hdr;
+		uint32_t data;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.length = sizeof(hdr) + sizeof(data);
+		hdr.version = DAL_VERSION;
+		hdr.msgid = DAL_MSGID_DETACH;
+		hdr.from = client;
+		hdr.to = client->remote;
+		data = (uint32_t) client;
+
+		dal_call_raw(client, &hdr, &data, sizeof(data),
+			     &data, sizeof(data));
+	}
+
+	dch = client->dch;
+	spin_lock_irqsave(&dch->lock, flags);
+	if (dch->active == client) {
+		/* We have received a message header for this client
+		 * but not the body of the message.  Ensure that when
+		 * the body arrives we don't write it into the now-closed
+		 * client.  In *theory* this should never happen.
+		 */
+		dch->active = 0;
+		dch->ptr = dch->data;
+	}
+	list_del(&client->list);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	mutex_unlock(&client->write_lock);
+
+	kfree(client);
+	return 0;
+}
+
+void *dal_get_remote_handle(struct dal_client *client)
+{
+	return client->remote;
+}
+
+/* convenience wrappers */
+
+int dal_call_f0(struct dal_client *client, uint32_t ddi, uint32_t arg1)
+{
+	uint32_t tmp = arg1;
+	int res;
+	res = dal_call(client, ddi, 0, &tmp, sizeof(tmp), &tmp, sizeof(tmp));
+	if (res >= 4)
+		return (int) tmp;
+	return res;
+}
+
+int dal_call_f1(struct dal_client *client, uint32_t ddi, uint32_t arg1,
+		uint32_t arg2)
+{
+	uint32_t tmp[2];
+	int res;
+	tmp[0] = arg1;
+	tmp[1] = arg2;
+	res = dal_call(client, ddi, 1, tmp, sizeof(tmp), tmp, sizeof(uint32_t));
+	if (res >= 4)
+		return (int) tmp[0];
+	return res;
+}
+
+int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (ilen + 4 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = ilen;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	res = dal_call(client, ddi, 5, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		return (int) tmp[0];
+	return res;
+}
+
+int dal_call_f6(struct dal_client *client, uint32_t ddi, uint32_t s1,
+		void *ibuf, uint32_t ilen)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (ilen + 8 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = s1;
+	param_idx++;
+	tmp[param_idx] = ilen;
+	param_idx++;
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	res = dal_call(client, ddi, 6, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		return (int) tmp[0];
+
+	return res;
+}
+
+int dal_call_f9(struct dal_client *client, uint32_t ddi, void *obuf,
+		uint32_t olen)
+{
+	uint32_t tmp[128];
+	int res;
+
+	if (olen > sizeof(tmp) - 8)
+		return -EINVAL;
+	tmp[0] = olen;
+
+	res = dal_call(client, ddi, 9, tmp, sizeof(uint32_t), tmp,
+		sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
+
+int dal_call_f11(struct dal_client *client, uint32_t ddi, uint32_t s1,
+		void *obuf, uint32_t olen)
+{
+	uint32_t tmp[DAL_DATA_MAX/4] = {0};
+	int res;
+	int param_idx = 0;
+	int num_bytes = 4;
+
+	num_bytes += (DIV_ROUND_UP(olen, 4)) * 4;
+
+	if ((num_bytes > DAL_DATA_MAX - 12) || (olen > DAL_DATA_MAX - 8))
+		return -EINVAL;
+
+	tmp[param_idx] = s1;
+	param_idx++;
+	tmp[param_idx] = olen;
+	param_idx += DIV_ROUND_UP(olen, 4);
+
+	res = dal_call(client, ddi, 11, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		res = (int) tmp[0];
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
+
+int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
+		 uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
+		 uint32_t olen)
+{
+	uint32_t tmp[DAL_DATA_MAX/4];
+	int res;
+	int param_idx = 0;
+	int num_bytes = 0;
+
+	num_bytes = (DIV_ROUND_UP(ilen1, 4)) * 4;
+	num_bytes += (DIV_ROUND_UP(ilen2, 4)) * 4;
+
+	if ((num_bytes > DAL_DATA_MAX - 12) || (olen > DAL_DATA_MAX - 8) ||
+			(ilen1 > DAL_DATA_MAX) || (ilen2 > DAL_DATA_MAX))
+		return -EINVAL;
+
+	tmp[param_idx] = ilen1;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf1, ilen1);
+	param_idx += DIV_ROUND_UP(ilen1, 4);
+
+	tmp[param_idx++] = ilen2;
+	memcpy(&tmp[param_idx], ibuf2, ilen2);
+	param_idx += DIV_ROUND_UP(ilen2, 4);
+
+	tmp[param_idx++] = olen;
+	res = dal_call(client, ddi, 13, tmp, param_idx * 4, tmp,
+			sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
+int dal_call_f14(struct dal_client *client, uint32_t ddi, void *ibuf,
+		 uint32_t ilen, void *obuf1, uint32_t olen1, void *obuf2,
+		 uint32_t olen2, uint32_t *oalen2)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (olen1 + olen2 + 8 > DAL_DATA_MAX ||
+		ilen + 12 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = ilen;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	tmp[param_idx++] = olen1;
+	tmp[param_idx++] = olen2;
+	res = dal_call(client, ddi, 14, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen1)
+			return -EIO;
+		param_idx = DIV_ROUND_UP(tmp[1], 4) + 2;
+		if (tmp[param_idx] > olen2)
+			return -EIO;
+
+		memcpy(obuf1, &tmp[2], tmp[1]);
+		memcpy(obuf2, &tmp[param_idx+1], tmp[param_idx]);
+		*oalen2 = tmp[param_idx];
+	}
+	return res;
+}
diff --git a/arch/arm/mach-msm/qdsp6/dal.h b/arch/arm/mach-msm/qdsp6/dal.h
new file mode 100644
index 0000000..1176eb9
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal.h
@@ -0,0 +1,96 @@
+/* arch/arm/mach-msm/qdsp6/dal.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * 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.
+ *
+ */
+
+#ifndef _MACH_MSM_DAL_
+#define _MACH_MSM_DAL_
+
+struct dal_client;
+
+struct dal_info {
+	uint32_t size;
+	uint32_t version;
+	char name[32];
+};
+
+typedef void (*dal_event_func_t)(void *data, int len, void *cookie);
+
+struct dal_client *dal_attach(uint32_t device_id, const char *name,
+			uint32_t cpu, dal_event_func_t func, void *cookie);
+
+int dal_detach(struct dal_client *client);
+
+int dal_call(struct dal_client *client,
+	     unsigned ddi, unsigned prototype,
+	     void *data, int data_len,
+	     void *reply, int reply_max);
+
+void dal_trace(struct dal_client *client);
+void dal_trace_dump(struct dal_client *client);
+
+/* function to call before panic on stalled dal calls */
+void dal_set_oops(struct dal_client *client, void (*oops)(void));
+
+/* convenience wrappers */
+int dal_call_f0(struct dal_client *client, uint32_t ddi,
+		uint32_t arg1);
+int dal_call_f1(struct dal_client *client, uint32_t ddi,
+		uint32_t arg1, uint32_t arg2);
+int dal_call_f5(struct dal_client *client, uint32_t ddi,
+		void *ibuf, uint32_t ilen);
+int dal_call_f6(struct dal_client *client, uint32_t ddi,
+		uint32_t s1, void *ibuf, uint32_t ilen);
+int dal_call_f9(struct dal_client *client, uint32_t ddi,
+		void *obuf, uint32_t olen);
+int dal_call_f11(struct dal_client *client, uint32_t ddi,
+		uint32_t s1, void *obuf, uint32_t olen);
+int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
+		 uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
+		 uint32_t olen);
+int dal_call_f14(struct dal_client *client, uint32_t ddi, void *ibuf,
+		 uint32_t ilen, void *obuf1, uint32_t olen1, void *obuf2,
+		 uint32_t olen2, uint32_t *oalen2);
+
+/* common DAL operations */
+enum {
+	DAL_OP_ATTACH = 0,
+	DAL_OP_DETACH,
+	DAL_OP_INIT,
+	DAL_OP_DEINIT,
+	DAL_OP_OPEN,
+	DAL_OP_CLOSE,
+	DAL_OP_INFO,
+	DAL_OP_POWEREVENT,
+	DAL_OP_SYSREQUEST,
+	DAL_OP_FIRST_DEVICE_API,
+};
+
+static inline int check_version(struct dal_client *client, uint32_t version)
+{
+	struct dal_info info;
+	int res;
+
+	res = dal_call_f9(client, DAL_OP_INFO, &info, sizeof(struct dal_info));
+	if (!res) {
+		if (((info.version & 0xFFFF0000) != (version & 0xFFFF0000)) ||
+		((info.version & 0x0000FFFF) <
+		(version & 0x0000FFFF))) {
+			res = -EINVAL;
+		}
+	}
+	return res;
+}
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_acdb.h b/arch/arm/mach-msm/qdsp6/dal_acdb.h
new file mode 100644
index 0000000..dfb1fef
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_acdb.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2009, 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 ACDB_DAL_DEVICE		0x02000069
+#define ACDB_DAL_PORT		"DAL_AM_AUD"
+
+#define ACDB_OP_IOCTL		DAL_OP_FIRST_DEVICE_API
+
+/* ioctls */
+#define ACDB_GET_DEVICE		0x0108bb92
+#define ACDB_SET_DEVICE		0x0108bb93
+#define ACDB_GET_STREAM		0x0108bb95
+#define ACDB_SET_STREAM		0x0108bb96
+#define ACDB_GET_DEVICE_TABLE	0x0108bb97
+#define ACDB_GET_STREAM_TABLE	0x0108bb98
+
+#define ACDB_RES_SUCCESS	0
+#define ACDB_RES_FAILURE	-1
+#define ACDB_RES_BADPARM	-2
+#define ACDB_RES_BADSTATE	-3
+
+struct acdb_cmd_device {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+	uint32_t interface_id;
+	uint32_t algorithm_block_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+} __attribute__((packed));
+
+struct acdb_cmd_device_table {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+
+	uint32_t res_size;
+} __attribute__((packed));
+
+struct acdb_result {
+	uint32_t dal_status;
+	uint32_t size;
+
+	uint32_t unmapped_buf;
+	uint32_t used_bytes;
+	uint32_t result;
+} __attribute__((packed));
diff --git a/arch/arm/mach-msm/qdsp6/dal_adie.h b/arch/arm/mach-msm/qdsp6/dal_adie.h
new file mode 100644
index 0000000..6abc60c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_adie.h
@@ -0,0 +1,104 @@
+/* Copyright (c) 2009, 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 _MACH_MSM_QDSP6_ADIE_
+#define _MACH_MSM_QDSP6_ADIE_
+
+#include "dal.h"
+
+#define ADIE_DAL_DEVICE		0x02000029
+#define ADIE_DAL_PORT		"DAL_AM_AUD"
+
+enum {
+	ADIE_OP_GET_NUM_PATHS = DAL_OP_FIRST_DEVICE_API,
+	ADIE_OP_GET_ALL_PATH_IDS,
+	ADIE_OP_SET_PATH,
+	ADIE_OP_GET_NUM_PATH_FREQUENCY_PLANS,
+	ADIE_OP_GET_PATH_FREQUENCY_PLANS,
+	ADIE_OP_SET_PATH_FREQUENCY_PLAN,
+	ADIE_OP_PROCEED_TO_STAGE,
+	ADIE_OP_MUTE_PATH
+};
+
+/* Path IDs for normal operation. */
+#define ADIE_PATH_HANDSET_TX			0x010740f6
+#define ADIE_PATH_HANDSET_RX			0x010740f7
+#define ADIE_PATH_HEADSET_MONO_TX		0x010740f8
+#define ADIE_PATH_HEADSET_STEREO_TX		0x010740f9
+#define ADIE_PATH_HEADSET_MONO_RX		0x010740fa
+#define ADIE_PATH_HEADSET_STEREO_RX		0x010740fb
+#define ADIE_PATH_SPEAKER_TX			0x010740fc
+#define ADIE_PATH_SPEAKER_RX			0x010740fd
+#define ADIE_PATH_SPEAKER_STEREO_RX		0x01074101
+
+/* Path IDs used for TTY */
+#define ADIE_PATH_TTY_HEADSET_TX		0x010740fe
+#define ADIE_PATH_TTY_HEADSET_RX		0x010740ff
+
+/* Path IDs used by Factory Test Mode. */
+#define ADIE_PATH_FTM_MIC1_TX			0x01074108
+#define ADIE_PATH_FTM_MIC2_TX			0x01074107
+#define ADIE_PATH_FTM_HPH_L_RX			0x01074106
+#define ADIE_PATH_FTM_HPH_R_RX			0x01074104
+#define ADIE_PATH_FTM_EAR_RX			0x01074103
+#define ADIE_PATH_FTM_SPKR_RX			0x01074102
+
+/* Path IDs for Loopback */
+/* Path IDs used for Line in -> AuxPGA -> Line Out Stereo Mode*/
+#define ADIE_PATH_AUXPGA_LINEOUT_STEREO_LB	0x01074100
+/* Line in -> AuxPGA -> LineOut Mono */
+#define ADIE_PATH_AUXPGA_LINEOUT_MONO_LB	0x01073d82
+/* Line in -> AuxPGA -> Stereo Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_STEREO_LB		0x01074109
+/* Line in -> AuxPGA -> Mono Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_MONO_LB		0x01073d85
+/* Line in -> AuxPGA -> Earpiece */
+#define ADIE_PATH_AUXPGA_EAP_LB			0x01073d81
+/* Line in -> AuxPGA -> AuxOut */
+#define ADIE_PATH_AUXPGA_AUXOUT_LB		0x01073d86
+
+/* Concurrency Profiles */
+#define ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX	0x01073d83
+#define ADIE_PATH_SPKR_MONO_HDPH_MONO_RX	0x01073d84
+#define ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX	0x01073d88
+#define ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX	0x01073d89
+
+
+/** Fluence Profiles **/
+
+/* Broadside/Bowsetalk profile,
+ * For Handset and Speaker phone Tx*/
+#define ADIE_CODEC_HANDSET_SPKR_BS_TX          0x0108fafa
+/* EndFire profile,
+ * For Handset and Speaker phone Tx*/
+#define ADIE_CODEC_HANDSET_SPKR_EF_TX          0x0108fafb
+
+
+/* stages */
+#define ADIE_STAGE_PATH_OFF			0x0050
+#define ADIE_STAGE_DIGITAL_READY		0x0100
+#define ADIE_STAGE_DIGITAL_ANALOG_READY		0x1000
+#define ADIE_STAGE_ANALOG_OFF			0x0750
+#define ADIE_STAGE_DIGITAL_OFF			0x0600
+
+/* path types */
+#define ADIE_PATH_RX		0
+#define ADIE_PATH_TX		1
+#define ADIE_PATH_LOOPBACK	2
+
+/* mute states */
+#define ADIE_MUTE_OFF		0
+#define ADIE_MUTE_ON		1
+
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_audio.h b/arch/arm/mach-msm/qdsp6/dal_audio.h
new file mode 100644
index 0000000..25d1e4f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_audio.h
@@ -0,0 +1,604 @@
+/* Copyright (c) 2009-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 __DAL_AUDIO_H__
+#define __DAL_AUDIO_H__
+
+#include "dal_audio_format.h"
+
+#define AUDIO_DAL_DEVICE 0x02000028
+#define AUDIO_DAL_PORT "DAL_AQ_AUD"
+
+enum {
+	AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API,
+	AUDIO_OP_DATA,
+	AUDIO_OP_INIT,
+};	
+
+/* ---- common audio structures ---- */
+
+/* This flag, if set, indicates that the beginning of the data in the*/
+/* buffer is a synchronization point or key frame, meaning no data */
+/* before it in the stream is required in order to render the stream */
+/* from this point onward. */
+#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT        0x01
+
+/* This flag, if set, indicates that the buffer object is using valid */
+/* physical address used to store the media data */
+#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR         0x04
+
+/* This flag, if set, indicates that a media start timestamp has been */
+/* set for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_START_SET         0x08
+
+/* This flag, if set, indicates that a media stop timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET          0x10
+
+/* This flag, if set, indicates that a preroll timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET       0x20
+
+/* This flag, if set, indicates that the data in the buffer is a fragment of */
+/* a larger block of data, and will be continued by the data in the next */
+/* buffer to be delivered. */
+#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION      0x40
+
+struct adsp_audio_buffer {
+	u32 addr;		/* Physical Address of buffer */
+	u32 max_size;		/* Maximum size of buffer */
+	u32 actual_size;	/* Actual size of valid data in the buffer */
+	u32 offset;		/* Offset to the first valid byte */
+	u32 flags;		/* ADSP_AUDIO_BUFFER_FLAGs that has been set */
+	s64 start;		/* Start timestamp, if any */
+	s64 stop;		/* Stop timestamp, if any */
+	s64 preroll;		/* Preroll timestamp, if any */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio commands ---- */
+
+/* Command/event response types */
+#define ADSP_AUDIO_RESPONSE_COMMAND   0
+#define ADSP_AUDIO_RESPONSE_ASYNC     1
+
+struct adsp_command_hdr {
+	u32 size;		/* sizeof(cmd) - sizeof(u32) */
+
+	u32 dst;
+	u32 src;
+
+	u32 opcode;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 padding;
+} __attribute__ ((packed));
+
+
+#define AUDIO_DOMAIN_APP	0
+#define AUDIO_DOMAIN_MODEM	1
+#define AUDIO_DOMAIN_DSP	2
+
+#define AUDIO_SERVICE_AUDIO	0
+#define AUDIO_SERVICE_VIDEO	1 /* really? */
+
+/* adsp audio addresses are (byte order) domain, service, major, minor */
+//#define AUDIO_ADDR(maj,min) ( (((maj) & 0xff) << 16) | (((min) & 0xff) << 24) | (1) )
+
+#define AUDIO_ADDR(maj,min,dom) ( (((min) & 0xff) << 24) | (((maj) & 0xff) << 16) | ((AUDIO_SERVICE_AUDIO) << 8) | (dom) )
+
+
+/* AAC Encoder modes */
+#define ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE		0
+#define ADSP_AUDIO_ENC_AAC_PLUS_MODE		1
+#define ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE	2
+
+struct adsp_audio_aac_enc_cfg {
+	u32 bit_rate;		/* bits per second */
+	u32 encoder_mode;	/* ADSP_AUDIO_ENC_* */
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS     0
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR           1
+
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO                1
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO              2
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL                8
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO        9
+
+struct adsp_audio_sbc_encoder_cfg {
+	u32 num_subbands;
+	u32 block_len;
+	u32 channel_mode;
+	u32 allocation_method;
+	u32 bit_rate;
+} __attribute__ ((packed));
+
+/* AMR NB encoder modes */
+#define ADSP_AUDIO_AMR_MR475	0
+#define ADSP_AUDIO_AMR_MR515	1
+#define ADSP_AUDIO_AMR_MMR59	2
+#define ADSP_AUDIO_AMR_MMR67	3
+#define ADSP_AUDIO_AMR_MMR74	4
+#define ADSP_AUDIO_AMR_MMR795	5
+#define ADSP_AUDIO_AMR_MMR102	6
+#define ADSP_AUDIO_AMR_MMR122	7
+
+/* The following are valid AMR NB DTX modes */
+#define ADSP_AUDIO_AMR_DTX_MODE_OFF		0
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1		1
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2		2
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO		3
+
+/* AMR Encoder configuration */
+struct adsp_audio_amr_enc_cfg {
+	u32	mode;		/* ADSP_AUDIO_AMR_MR* */
+	u32	dtx_mode;	/* ADSP_AUDIO_AMR_DTX_MODE* */
+	u32	enable;		/* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+struct adsp_audio_qcelp13k_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+struct adsp_audio_evrc_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+union adsp_audio_codec_config {
+	struct adsp_audio_amr_enc_cfg amr;
+	struct adsp_audio_aac_enc_cfg aac;
+	struct adsp_audio_qcelp13k_enc_cfg qcelp13k;
+	struct adsp_audio_evrc_enc_cfg evrc;
+	struct adsp_audio_sbc_encoder_cfg sbc;
+} __attribute__ ((packed));
+
+
+/* This is the default value. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_NONE		0x0000
+
+/* This bit, if set, indicates that the AVSync mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_AVSYNC		0x0001
+
+/* This bit, if set, indicates that the Sample Rate/Channel Mode */
+/* Change Notification mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY	0x0002
+
+/* This bit, if set, indicates that the sync clock is enabled */
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK	0x0004
+
+/* This bit, if set, indicates that the AUX PCM loopback is enabled */
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_AUX_PCM		0x0040
+
+struct adsp_open_command {
+	struct adsp_command_hdr hdr;
+
+	u32 device;
+	u32 endpoint; /* address */
+
+	u32 stream_context;
+	u32 mode;
+
+	u32 buf_max_size;
+
+	union adsp_audio_format format;
+	union adsp_audio_codec_config config;
+} __attribute__ ((packed));
+
+
+/* --- audio control and stream session ioctls ---- */
+
+/* Opcode to open a device stream session to capture audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ			0x0108dd79
+
+/* Opcode to open a device stream session to render audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE			0x0108dd7a
+
+/* Opcode to open a device session, must open a device */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE		0x0108dd7b
+
+/* Close an existing stream or device */
+#define ADSP_AUDIO_IOCTL_CMD_CLOSE			0x0108d8bc
+
+
+
+/* A device switch requires three IOCTL */
+/* commands in the following sequence: PREPARE, STANDBY, COMMIT */
+
+/* adsp_audio_device_switch_command structure is needed for */
+/* DEVICE_SWITCH_PREPARE */
+
+/* Device switch protocol step #1. Pause old device and */
+/* generate silence for the old device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE	0x010815c4
+
+/* Device switch protocol step #2. Release old device, */
+/* create new device and generate silence for the new device. */
+
+/* When client receives ack for this IOCTL, the client can */
+/* start sending IOCTL commands to configure, calibrate and */
+/* change filter settings on the new device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY	0x010815c5
+
+/* Device switch protocol step #3. Start normal operations on new device */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT	0x01075ee7
+
+struct adsp_device_switch_command {
+	struct adsp_command_hdr hdr;
+	u32 old_device;
+	u32 new_device;
+	u8 device_class; /* 0 = i.rx, 1 = i.tx, 2 = e.rx, 3 = e.tx */
+	u8 device_type; /* 0 = rx, 1 = tx, 2 = both */
+} __attribute__ ((packed));
+
+
+
+/* --- audio control session ioctls ---- */
+
+#define ADSP_PATH_RX	0
+#define ADSP_PATH_TX	1
+#define ADSP_PATH_BOTH	2
+#define ADSP_PATH_TX_CNG_DIS 3
+
+struct adsp_audio_dtmf_start_command {
+	struct adsp_command_hdr hdr;
+	u32 tone1_hz;
+	u32 tone2_hz;
+	u32 duration_usec;
+	s32 gain_mb;
+} __attribute__ ((packed));
+
+/* These commands will affect a logical device and all its associated */
+/* streams. */
+
+#define ADSP_AUDIO_MAX_EQ_BANDS 12
+
+struct adsp_audio_eq_band {
+	u16     band_idx; /* The band index, 0 .. 11 */
+	u32     filter_type; /* Filter band type */
+	u32     center_freq_hz; /* Filter band center frequency */
+	s32     filter_gain; /* Filter band initial gain (dB) */
+			/* Range is +12 dB to -12 dB with 1dB increments. */
+	s32     q_factor;
+		/* Filter band quality factor expressed as q-8 number, */
+		/* e.g. 3000/(2^8) */
+} __attribute__ ((packed));
+
+struct adsp_audio_eq_stream_config {
+	uint32_t  enable; /* Number of consequtive bands specified */
+	uint32_t  num_bands;
+	struct adsp_audio_eq_band  eq_bands[ADSP_AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+/* set device equalizer */
+struct adsp_set_dev_equalizer_command {
+	struct adsp_command_hdr hdr;
+	u32    device_id;
+	u32    enable;
+	u32    num_bands;
+	struct adsp_audio_eq_band eq_bands[ADSP_AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+/* Set device volume. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL		0x0107605c
+
+struct adsp_set_dev_volume_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	s32 volume;
+} __attribute__ ((packed));
+
+/* Set Device stereo volume. This command has data payload, */
+/* struct adsp_audio_set_dev_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_STEREO_VOL		0x0108df3e
+
+/* Set L, R cross channel gain for a Device. This command has */
+/* data payload, struct adsp_audio_set_dev_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_XCHAN_GAIN		0x0108df40
+
+/* Set device mute state. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE		0x0107605f
+
+struct adsp_set_dev_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	u32 mute; /* 1 = mute */
+} __attribute__ ((packed));
+
+/* Configure Equalizer for a device. */
+/* This command has payload struct adsp_audio_set_dev_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_EQ_CONFIG	0x0108b10e
+
+/* Set configuration data for an algorithm aspect of a device. */
+/* This command has payload struct adsp_audio_set_dev_cfg_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG		0x0108b6cb
+
+struct adsp_set_dev_cfg_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 block_id;
+	u32 interface_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* Set configuration data for all interfaces of a device. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE	0x0108b6bf
+
+struct adsp_set_dev_cfg_table_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* ---- audio stream data commands ---- */
+
+#define ADSP_AUDIO_IOCTL_CMD_DATA_TX			0x0108dd7f
+#define ADSP_AUDIO_IOCTL_CMD_DATA_RX			0x0108dd80
+
+struct adsp_buffer_command {
+	struct adsp_command_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+
+/* ---- audio stream ioctls (only affect a single stream in a session) ---- */
+
+/* Stop stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_STOP		0x01075c54
+
+/* End of stream reached. Client will not send any more data. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_EOS			0x0108b150
+
+/* Do sample slipping/stuffing on AAC outputs. The payload of */
+/* this command is struct adsp_audio_slip_sample_command. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE		0x0108d40e
+
+/* Set stream volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL		0x0108c0de
+
+/* Set stream stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL		0x0108dd7c
+
+/* Set L, R cross channel gain for a Stream. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_XCHAN_GAIN		0x0108dd7d
+
+/* Set stream mute state. */
+/* This command has data payload, struct adsp_audio_set_stream_mute. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE		0x0108c0df
+
+/* Reconfigure bit rate information. This command has data */
+/* payload, struct adsp_audio_set_bit_rate_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_BITRATE		0x0108ccf1
+
+/* Set Channel Mapping. This command has data payload, struct */
+/* This command has data payload struct adsp_audio_set_channel_map_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_CHANNELMAP		0x0108d32a
+
+/* Enable/disable AACPlus SBR. */
+/* This command has data payload struct adsp_audio_set_sbr_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_SBR			0x0108d416
+
+/* Enable/disable WMA Pro Chex and Fex. This command has data payload */
+/* struct adsp_audio_stream_set_wma_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_WMAPRO		0x0108d417
+
+
+/* ---- audio session ioctls (affect all streams in a session) --- */
+
+/* Start stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_START		0x010815c6
+
+/* Stop all stream(s) for audio session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_STOP		0x0108dd7e
+
+/* Pause the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_PAUSE		0x01075ee8
+
+/* Resume the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_RESUME		0x01075ee9
+
+/* Drop any unprocessed data buffers for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_FLUSH		0x01075eea
+
+/* Start Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START		0x0108c0dd
+
+/* Stop Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_STOP		0x01087554
+
+/* Set Session volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_VOL		0x0108d8bd
+
+/* Set session stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL		0x0108df3d
+
+/* Set L, R cross channel gain for a session. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN		0x0108df3f
+
+/* Set Session mute state. */
+/* This command has data payload, struct adsp_audio_set_mute_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE		0x0108d8be
+
+/* Configure Equalizer for a stream. */
+/* This command has payload struct adsp_audio_set_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG		0x0108c0e0
+
+/* Set Audio Video sync information. */
+/* This command has data payload, struct adsp_audio_set_av_sync_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_AVSYNC		0x0108d1e2
+
+/* Get Audio Media Session time. */
+/* This command returns the audioTime in adsp_audio_unsigned64_event */
+#define ADSP_AUDIO_IOCTL_CMD_GET_AUDIO_TIME		0x0108c26c
+
+
+/* these command structures are used for both STREAM and SESSION ioctls */
+
+struct adsp_set_volume_command {
+	struct adsp_command_hdr hdr;
+	s32 volume;
+} __attribute__ ((packed));
+	
+struct adsp_set_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 mute; /* 1 == mute */
+} __attribute__ ((packed));
+
+
+struct adsp_set_equalizer_command {
+	struct adsp_command_hdr hdr;
+	u32    enable;
+	u32    num_bands;
+	struct adsp_audio_eq_band eq_bands[ADSP_AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+/* ---- audio events ---- */
+
+/* All IOCTL commands generate an event with the IOCTL opcode as the */
+/* event id after the IOCTL command has been executed. */
+
+/* This event is generated after a media stream session is opened. */
+#define ADSP_AUDIO_EVT_STATUS_OPEN				0x0108c0d6
+
+/* This event is generated after a media stream  session is closed. */
+#define ADSP_AUDIO_EVT_STATUS_CLOSE				0x0108c0d7
+
+/* Asyncronous buffer consumption. This event is generated after a */
+/* recived  buffer is consumed during rendering or filled during */
+/* capture opeartion. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_DONE				0x0108c0d8
+
+/* This event is generated when rendering operation is starving for */
+/* data. In order to avoid audio loss at the end of a plauback, the */
+/* client should wait for this event before issuing the close command. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN			0x0108c0d9
+
+/* This event is generated during capture operation when there are no */
+/* buffers available to copy the captured audio data */
+#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW			0x0108c0da
+
+/* This asynchronous event is generated as a result of an input */
+/* sample rate change and/or channel mode change detected by the */
+/* decoder. The event payload data is an array of 2 uint32 */
+/* values containing the sample rate in Hz and channel mode. */
+#define ADSP_AUDIO_EVT_SR_CM_CHANGE				0x0108d329
+
+struct adsp_event_hdr {
+	u32 evt_handle;		/* DAL common header */
+	u32 evt_cookie;
+	u32 evt_length;
+
+	u32 src;		/* "source" audio address */
+	u32 dst;		/* "destination" audio address */
+
+	u32 event_id;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 status;
+} __attribute__ ((packed));
+
+struct adsp_buffer_event {
+	struct adsp_event_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+/* ---- audio device IDs ---- */
+
+/* Device direction Rx/Tx flag */
+#define ADSP_AUDIO_RX_DEVICE		0x00
+#define ADSP_AUDIO_TX_DEVICE		0x01
+
+/* Default RX or TX device */
+#define ADSP_AUDIO_DEVICE_ID_DEFAULT		0x1081679
+
+/* Source (TX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_MIC	0x107ac8d
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_MIC	0x1081510
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC	0x1081512
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_AUXPCM_TX		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC	0x108151b
+#define ADSP_AUDIO_DEVICE_ID_I2S_MIC		0x1089bf3
+
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC	0x108f9c5
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC		0x108f9c3
+
+/* Special loopback pseudo device to be paired with an RX device */
+/* with usage ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK */
+#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX	0x1089bf2
+
+/* Sink (RX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR			0x107ac88
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO			0x1081511
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO		0x107ac8a
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO			0x1081513
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET     0x108c508
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET   0x108c894
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO			0x1081514
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET   0x108c895
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET	0x108c509
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR			0x1081519
+#define ADSP_AUDIO_DEVICE_ID_AUXPCM_RX				0x1081519
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR			0x108151c
+#define ADSP_AUDIO_DEVICE_ID_I2S_SPKR				0x1089bf4
+#define ADSP_AUDIO_DEVICE_ID_NULL_SINK				0x108e512
+
+/* BT A2DP playback device. */
+/* This device must be paired with */
+/* ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX using  */
+/* ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK mode */
+#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR	0x108151a
+
+/* Voice Destination identifier - specifically used for */
+/* controlling Voice module from the Device Control Session */
+#define ADSP_AUDIO_DEVICE_ID_VOICE		0x0108df3c
+
+/*  Audio device usage types. */
+/*  This is a bit mask to determine which topology to use in the */
+/* device session */
+#define ADSP_AUDIO_DEVICE_CONTEXT_VOICE			0x01
+#define ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK		0x02
+#define ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD		0x10
+#define ADSP_AUDIO_DEVICE_CONTEXT_RECORD		0x20
+#define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK		0x40
+
+/* ADSP audio driver return codes */
+#define ADSP_AUDIO_STATUS_SUCCESS               0
+#define ADSP_AUDIO_STATUS_EUNSUPPORTED          20
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_audio_format.h b/arch/arm/mach-msm/qdsp6/dal_audio_format.h
new file mode 100644
index 0000000..6382693
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_audio_format.h
@@ -0,0 +1,270 @@
+/* Copyright (c) 2009, 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 __ADSP_AUDIO_MEDIA_FORMAT_H
+#define __ADSP_AUDIO_MEDIA_FORMAT_H
+
+
+
+/* Supported audio media formats */
+
+/* format block in shmem */
+#define ADSP_AUDIO_FORMAT_SHAREDMEMORY	0x01091a78
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_PCM		0x0103d2fd
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_DTMF		0x01087725
+/* adsp_audio_format_adpcm type */
+#define ADSP_AUDIO_FORMAT_ADPCM		0x0103d2ff
+/* Yamaha PCM format */
+#define ADSP_AUDIO_FORMAT_YADPCM	0x0108dc07
+/* ISO/IEC 11172 */
+#define ADSP_AUDIO_FORMAT_MP3		0x0103d308
+/* ISO/IEC 14496 */
+#define ADSP_AUDIO_FORMAT_MPEG4_AAC	0x010422f1
+/* AMR-NB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRNB_FS	0x0105c16c
+/* AMR-WB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRWB_FS	0x0105c16e
+/* QCELP 13k, IS733 */
+#define ADSP_AUDIO_FORMAT_V13K_FS	0x01080b8a
+/* EVRC   8k, IS127 */
+#define ADSP_AUDIO_FORMAT_EVRC_FS	0x01080b89
+/* EVRC-B   8k, 4GV */
+#define ADSP_AUDIO_FORMAT_EVRCB_FS	0x0108f2a3
+/* MIDI command stream */
+#define ADSP_AUDIO_FORMAT_MIDI		0x0103d300
+/* A2DP SBC stream */
+#define ADSP_AUDIO_FORMAT_SBC		0x0108c4d8
+/* Version 10 Professional */
+#define ADSP_AUDIO_FORMAT_WMA_V10PRO	0x0108aa92
+/* Version 9 Starndard */
+#define ADSP_AUDIO_FORMAT_WMA_V9	0x0108d430
+/* AMR WideBand Plus */
+#define ADSP_AUDIO_FORMAT_AMR_WB_PLUS	0x0108f3da
+/* AC3 Decoder */
+#define ADSP_AUDIO_FORMAT_AC3_DECODER	0x0108d5f9
+
+
+/* Not yet supported audio media formats */
+
+
+
+/* ISO/IEC 13818 */
+#define ADSP_AUDIO_FORMAT_MPEG2_AAC	0x0103d309
+/* 3GPP TS 26.101 Sec 4.0 */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF1	0x0103d305
+/* 3GPP TS 26.101 Annex A */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF2	0x01057b31
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF1	0x0103d306
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF2	0x0105c16d
+/* G.711 */
+#define ADSP_AUDIO_FORMAT_G711		0x0106201d
+/* QCELP  8k, IS96A */
+#define ADSP_AUDIO_FORMAT_V8K_FS	0x01081d29
+/* Version 1 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V1	0x01055b2b
+/* Version 2, 7 & 8 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V8	0x01055b2c
+/* Version 9 Professional codec */
+#define ADSP_AUDIO_FORMAT_WMA_V9PRO	0x01055b2d
+/* Version 9 Voice codec */
+#define ADSP_AUDIO_FORMAT_WMA_SP1	0x01055b2e
+/* Version 9 Lossless codec */
+#define ADSP_AUDIO_FORMAT_WMA_LOSSLESS	0x01055b2f
+/* Real Media content, low-bitrate */
+#define ADSP_AUDIO_FORMAT_RA_SIPR	0x01042a0f
+/* Real Media content */
+#define ADSP_AUDIO_FORMAT_RA_COOK	0x01042a0e
+
+
+/* For all of the audio formats, unless specified otherwise, */
+/* the following apply: */
+/* Format block bits are arranged in bytes and words in little-endian */
+/* order, i.e., least-significant bit first and least-significant */
+/* byte first. */
+
+
+
+/* AAC Format Block. */
+
+/* AAC format block consist of a format identifier followed by */
+/* AudioSpecificConfig formatted according to ISO/IEC 14496-3 */
+
+/* The following AAC format identifiers are supported */
+#define ADSP_AUDIO_AAC_ADTS		0x010619cf
+#define ADSP_AUDIO_AAC_MPEG4_ADTS	0x010619d0
+#define ADSP_AUDIO_AAC_LOAS		0x010619d1
+#define ADSP_AUDIO_AAC_ADIF		0x010619d2
+#define ADSP_AUDIO_AAC_RAW		0x010619d3
+#define ADSP_AUDIO_AAC_FRAMED_RAW	0x0108c1fb
+
+
+#define ADSP_AUDIO_COMPANDING_ALAW	0x10619cd
+#define ADSP_AUDIO_COMPANDING_MLAW	0x10619ce
+
+/* Maxmum number of bytes allowed in a format block */
+#define ADSP_AUDIO_FORMAT_DATA_MAX 16
+
+
+struct adsp_audio_no_payload_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* no payload for this format type */
+} __attribute__ ((packed));
+
+
+/* For convenience, to be used as a standard format block */
+/* for various media types that don't need a unique format block */
+/* ie. PCM, DTMF, etc. */
+struct adsp_audio_standard_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		channels;
+	u16		bits_per_sample;
+	u32		sampling_rate;
+	u8		is_signed;
+	u8		is_interleaved;
+} __attribute__ ((packed));
+
+
+
+/* ADPCM format block */
+struct adsp_audio_adpcm_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		channels;
+	u16		bits_per_sample;
+	u32		sampling_rate;
+	u8		is_signed;
+	u8		is_interleaved;
+	u32		block_size;
+} __attribute__ ((packed));
+
+
+/* MIDI format block */
+struct adsp_audio_midi_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		sampling_rate;
+	u16		channels;
+	u16		mode;
+} __attribute__ ((packed));
+
+
+/* G711 format block */
+struct adsp_audio_g711_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		companding;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_wma_pro_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		format_tag;
+	u16		channels;
+	u32		samples_per_sec;
+	u32		avg_bytes_per_sec;
+	u16		block_align;
+	u16		valid_bits_per_sample;
+	u32		channel_mask;
+	u16		encode_opt;
+	u16		advanced_encode_opt;
+	u32		advanced_encode_opt2;
+	u32		drc_peak_reference;
+	u32		drc_peak_target;
+	u32		drc_average_reference;
+	u32		drc_average_target;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_amrwb_plus_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		size;
+	u32		version;
+	u32		channels;
+	u32		amr_band_mode;
+	u32		amr_dtx_mode;
+	u32		amr_frame_format;
+	u32		amr_isf_index;
+} __attribute__ ((packed));
+
+
+/* Binary Byte Stream Format */
+/* Binary format type that defines a byte stream, */
+/* can be used to specify any format (ie. AAC) */
+struct adsp_audio_binary_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	/* number of bytes set in byte stream */
+	u32		num_bytes;
+	/* Byte stream binary data */
+	u8		data[ADSP_AUDIO_FORMAT_DATA_MAX];
+} __attribute__ ((packed));
+
+
+struct adsp_audio_shared_memory_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* Number of bytes in shared memory */
+	u32		len;
+	/* Phyisical address to data in shared memory */
+	u32		address;
+} __attribute__ ((packed));
+
+
+/* Union of all format types */
+union adsp_audio_format {
+	/* Basic format block with no payload */
+	struct adsp_audio_no_payload_format	no_payload;
+	/* Generic format block PCM, DTMF */
+	struct adsp_audio_standard_format	standard;
+	/* ADPCM format block */
+	struct adsp_audio_adpcm_format		adpcm;
+	/* MIDI format block */
+	struct adsp_audio_midi_format		midi;
+	/* G711 format block */
+	struct adsp_audio_g711_format		g711;
+	/* WmaPro format block */
+	struct adsp_audio_wma_pro_format	wma_pro;
+	/* WmaPro format block */
+	struct adsp_audio_amrwb_plus_format	amrwb_plus;
+	/* binary (byte stream) format block, used for AAC */
+	struct adsp_audio_binary_format		binary;
+	/* format block in shared memory */
+	struct adsp_audio_shared_memory_format	shared_mem;
+};
+
+#endif
+
diff --git a/arch/arm/mach-msm/qdsp6/dsp_debug.c b/arch/arm/mach-msm/qdsp6/dsp_debug.c
new file mode 100644
index 0000000..fdf049c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dsp_debug.c
@@ -0,0 +1,179 @@
+/* arch/arm/mach-msm/qdsp6/dsp_dump.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * 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/io.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+
+#include "../proc_comm.h"
+#include <mach/debug_mm.h>
+
+static wait_queue_head_t dsp_wait;
+static int dsp_has_crashed;
+static int dsp_wait_count;
+
+static atomic_t dsp_crash_count = ATOMIC_INIT(0);
+
+void q6audio_dsp_not_responding(void)
+{
+
+	if (atomic_add_return(1, &dsp_crash_count) != 1) {
+		pr_err("q6audio_dsp_not_responding() - parking additional crasher...\n");
+		for (;;)
+			msleep(1000);
+	}
+	if (dsp_wait_count) {
+		dsp_has_crashed = 1;
+		wake_up(&dsp_wait);
+
+		while (dsp_has_crashed != 2)
+			wait_event(dsp_wait, dsp_has_crashed == 2);
+	} else {
+		pr_err("q6audio_dsp_not_responding() - no waiter?\n");
+	}
+	BUG();
+}
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t dsp_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	if (!strcmp(cmd, "wait-for-crash")) {
+		while (!dsp_has_crashed) {
+			int res;
+			dsp_wait_count++;
+			res = wait_event_interruptible(dsp_wait, dsp_has_crashed);
+			if (res < 0) {
+				dsp_wait_count--;
+				return res;
+			}
+		}
+#if defined(CONFIG_MACH_MAHIMAHI)
+		/* assert DSP NMI */
+		msm_proc_comm(PCOM_CUSTOMER_CMD1, 0, 0);
+		msleep(250);
+#endif
+	} else if (!strcmp(cmd, "boom")) {
+		q6audio_dsp_not_responding();
+	} else if (!strcmp(cmd, "continue-crash")) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else {
+		pr_err("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
+				__func__, cmd);
+	}
+
+	return count;
+}
+
+#define DSP_RAM_BASE 0x2E800000
+#define DSP_RAM_SIZE 0x01800000
+
+static unsigned copy_ok_count;
+
+static ssize_t dsp_read(struct file *file, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	size_t actual = 0;
+	size_t mapsize = PAGE_SIZE;
+	unsigned addr;
+	void __iomem *ptr;
+
+	if (*pos >= DSP_RAM_SIZE)
+		return 0;
+
+	if (*pos & (PAGE_SIZE - 1))
+		return -EINVAL;
+
+	addr = (*pos + DSP_RAM_BASE);
+
+	/* don't blow up if we're unaligned */
+	if (addr & (PAGE_SIZE - 1))
+		mapsize *= 2;
+
+	while (count >= PAGE_SIZE) {
+		ptr = ioremap(addr, mapsize);
+		if (!ptr) {
+			pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
+					__func__, addr);
+			return -EFAULT;
+		}
+		if (copy_to_user(buf, ptr, PAGE_SIZE)) {
+			iounmap(ptr);
+			pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
+					__func__, buf);
+			return -EFAULT;
+		}
+		copy_ok_count += PAGE_SIZE;
+		iounmap(ptr);
+		addr += PAGE_SIZE;
+		buf += PAGE_SIZE;
+		actual += PAGE_SIZE;
+		count -= PAGE_SIZE;
+	}
+
+	*pos += actual;
+	return actual;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations dsp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dsp_open,
+	.read		= dsp_read,
+	.write		= dsp_write,
+	.release	= dsp_release,
+};
+
+static struct miscdevice dsp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "dsp_debug",
+	.fops	= &dsp_fops,
+};
+
+
+static int __init dsp_init(void)
+{
+	init_waitqueue_head(&dsp_wait);
+	return misc_register(&dsp_misc);
+}
+
+device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp6/dtmf.c b/arch/arm/mach-msm/qdsp6/dtmf.c
new file mode 100644
index 0000000..cf27488
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dtmf.c
@@ -0,0 +1,126 @@
+/* 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/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct dtmf {
+	struct mutex lock;
+	struct audio_client *ac;
+	struct msm_dtmf_config cfg;
+};
+
+static long dtmf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct dtmf *dtmf = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&dtmf->lock);
+	switch (cmd) {
+
+	case AUDIO_START: {
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (dtmf->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			dtmf->ac = q6audio_open_dtmf(48000, 2, 0);
+			if (!dtmf->ac)
+				rc = -ENOMEM;
+		}
+		break;
+	}
+	case AUDIO_PLAY_DTMF: {
+		rc = copy_from_user((void *)&dtmf->cfg, (void *)arg,
+					sizeof(struct msm_dtmf_config));
+
+		pr_debug("[%s:%s] PLAY_DTMF: high = %d, low = %d\n",
+			__MM_FILE__, __func__, dtmf->cfg.dtmf_hi,
+			dtmf->cfg.dtmf_low);
+		rc = q6audio_play_dtmf(dtmf->ac, dtmf->cfg.dtmf_hi,
+					dtmf->cfg.dtmf_low, dtmf->cfg.duration,
+					dtmf->cfg.rx_gain);
+		if (rc) {
+			pr_err("[%s:%s] DTMF_START failed\n", __MM_FILE__,
+					__func__);
+			break;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&dtmf->lock);
+
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc) ;
+	return rc;
+}
+
+static int dtmf_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	struct dtmf *dtmf;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	dtmf = kzalloc(sizeof(struct dtmf), GFP_KERNEL);
+
+	if (!dtmf)
+		return -ENOMEM;
+
+	mutex_init(&dtmf->lock);
+
+	file->private_data = dtmf;
+	return rc;
+}
+
+static int dtmf_release(struct inode *inode, struct file *file)
+{
+	struct dtmf *dtmf = file->private_data;
+	if (dtmf->ac)
+		q6audio_close(dtmf->ac);
+	kfree(dtmf);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static const struct file_operations dtmf_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dtmf_open,
+	.release	= dtmf_release,
+	.unlocked_ioctl	= dtmf_ioctl,
+};
+
+struct miscdevice dtmf_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_dtmf",
+	.fops	= &dtmf_fops,
+};
+
+static int __init dtmf_init(void)
+{
+	return misc_register(&dtmf_misc);
+}
+
+device_initcall(dtmf_init);
diff --git a/arch/arm/mach-msm/qdsp6/evrc_in.c b/arch/arm/mach-msm/qdsp6/evrc_in.c
new file mode 100644
index 0000000..9fc412b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/evrc_in.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audio.h>
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+#define EVRC_FC_BUFF_CNT 10
+#define EVRC_READ_TIMEOUT 2000
+struct evrc_fc_buff {
+	struct mutex lock;
+	int empty;
+	void *data;
+	int size;
+	int actual_size;
+};
+
+struct evrc_fc {
+	struct task_struct *task;
+	wait_queue_head_t fc_wq;
+	struct evrc_fc_buff fc_buff[EVRC_FC_BUFF_CNT];
+	int buff_index;
+};
+
+struct evrc {
+	struct mutex lock;
+	struct msm_audio_evrc_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+	struct evrc_fc *evrc_fc;
+};
+
+
+static int q6_evrc_flowcontrol(void *data)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	struct evrc *evrc = data;
+	int buff_index = 0;
+	int xfer = 0;
+	struct evrc_fc *fc;
+
+
+	ac = evrc->audio_client;
+	fc = evrc->evrc_fc;
+	if (!ac) {
+		pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__);
+		return 0;
+	}
+
+	while (!kthread_should_stop()) {
+		ab = ac->buf + ac->cpu_buf;
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+
+		mutex_lock(&(fc->fc_buff[buff_index].lock));
+		if (!fc->fc_buff[buff_index].empty) {
+			pr_err("[%s:%s] flow control buffer[%d] not read!\n",
+					__MM_FILE__, __func__, buff_index);
+		}
+
+		if (fc->fc_buff[buff_index].size < xfer) {
+			pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__,
+					__func__, buff_index);
+			memcpy(fc->fc_buff[buff_index].data, ab->data,
+					fc->fc_buff[buff_index].size);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size =
+					fc->fc_buff[buff_index].size;
+		} else {
+			memcpy(fc->fc_buff[buff_index].data, ab->data, xfer);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size = xfer;
+		}
+		mutex_unlock(&(fc->fc_buff[buff_index].lock));
+		/*wake up client, if any*/
+		wake_up(&fc->fc_wq);
+
+		buff_index++;
+		if (buff_index >= EVRC_FC_BUFF_CNT)
+			buff_index = 0;
+
+		ab->used = 1;
+
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return 0;
+}
+static long q6_evrc_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct evrc *evrc = file->private_data;
+	int rc = 0;
+	int i = 0;
+	struct evrc_fc *fc;
+	int size = 0;
+
+	mutex_lock(&evrc->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id, (void *) arg,
+				sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (evrc->audio_client) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		} else {
+			evrc->audio_client = q6audio_open_qcp(
+					evrc->str_cfg.buffer_size,
+					evrc->cfg.min_bit_rate,
+					evrc->cfg.max_bit_rate,
+					evrc->voicerec_mode.rec_mode,
+					ADSP_AUDIO_FORMAT_EVRC_FS,
+					acdb_id);
+
+			if (!evrc->audio_client) {
+				pr_err("[%s:%s] evrc open session failed\n",
+					__MM_FILE__, __func__);
+				kfree(evrc);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		/*allocate flow control buffers*/
+		fc = evrc->evrc_fc;
+		size = evrc->str_cfg.buffer_size;
+		for (i = 0; i < EVRC_FC_BUFF_CNT; ++i) {
+			mutex_init(&(fc->fc_buff[i].lock));
+			fc->fc_buff[i].empty = 1;
+			fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL);
+			if (fc->fc_buff[i].data == NULL) {
+				pr_err("[%s:%s] No memory for FC buffers\n",
+						__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				goto fc_fail;
+			}
+			fc->fc_buff[i].size = size;
+			fc->fc_buff[i].actual_size = 0;
+		}
+
+		/*create flow control thread*/
+		fc->task = kthread_run(q6_evrc_flowcontrol,
+				evrc, "evrc_flowcontrol");
+		if (IS_ERR(fc->task)) {
+			rc = PTR_ERR(fc->task);
+			pr_err("[%s:%s] error creating flow control thread\n",
+					__MM_FILE__, __func__);
+			goto fc_fail;
+		}
+		break;
+fc_fail:
+		/*free flow control buffers*/
+		--i;
+		for (; i >=  0; i--) {
+			kfree(fc->fc_buff[i].data);
+			fc->fc_buff[i].data = NULL;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&evrc->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (evrc->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+				&& evrc->voicerec_mode.rec_mode !=
+				AUDIO_FLAG_INCALL_MIXED) {
+			evrc->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &evrc->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, evrc->str_cfg.buffer_size,
+			evrc->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&evrc->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, evrc->str_cfg.buffer_size,
+			evrc->str_cfg.buffer_count);
+
+		if (evrc->str_cfg.buffer_size < 23) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (evrc->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_EVRC_ENC_CONFIG:
+		if (copy_from_user(&evrc->cfg, (void *) arg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] SET_EVRC_ENC_CONFIG\n", __MM_FILE__,
+				__func__);
+
+		if (evrc->cfg.min_bit_rate > 4 || evrc->cfg.min_bit_rate < 1) {
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (evrc->cfg.max_bit_rate > 4 || evrc->cfg.max_bit_rate < 1) {
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_EVRC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &evrc->cfg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_EVRC_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&evrc->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_evrc_in_open(struct inode *inode, struct file *file)
+{
+	struct evrc *evrc;
+	struct evrc_fc *fc;
+	int i;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	evrc = kmalloc(sizeof(struct evrc), GFP_KERNEL);
+	if (evrc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for evrc driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&evrc->lock);
+	file->private_data = evrc;
+	evrc->audio_client = NULL;
+	evrc->str_cfg.buffer_size = 23;
+	evrc->str_cfg.buffer_count = 2;
+	evrc->cfg.cdma_rate = CDMA_RATE_FULL;
+	evrc->cfg.min_bit_rate = 1;
+	evrc->cfg.max_bit_rate = 4;
+	evrc->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	evrc->evrc_fc = kmalloc(sizeof(struct evrc_fc), GFP_KERNEL);
+	if (evrc->evrc_fc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for evrc_fc\n",
+				__MM_FILE__, __func__);
+		kfree(evrc);
+		return -ENOMEM;
+	}
+	fc = evrc->evrc_fc;
+	fc->task = NULL;
+	fc->buff_index = 0;
+	for (i = 0; i < EVRC_FC_BUFF_CNT; ++i) {
+		fc->fc_buff[i].data = NULL;
+		fc->fc_buff[i].size = 0;
+		fc->fc_buff[i].actual_size = 0;
+	}
+	/*initialize wait queue head*/
+	init_waitqueue_head(&fc->fc_wq);
+	return 0;
+}
+
+static ssize_t q6_evrc_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	const char __user *start = buf;
+	struct evrc *evrc = file->private_data;
+	struct evrc_fc *fc;
+	int xfer = 0;
+	int res = 0;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&evrc->lock);
+	ac = evrc->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	fc = evrc->evrc_fc;
+	while (count > xfer) {
+		/*wait for buffer to full*/
+		if (fc->fc_buff[fc->buff_index].empty != 0) {
+			res = wait_event_interruptible_timeout(fc->fc_wq,
+				(fc->fc_buff[fc->buff_index].empty == 0),
+				msecs_to_jiffies(EVRC_READ_TIMEOUT));
+
+			pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__,
+				__func__, fc->buff_index);
+			if (res == 0) {
+				pr_err("[%s:%s] Timeout!\n", __MM_FILE__,
+						__func__);
+				res = -ETIMEDOUT;
+				goto fail;
+			} else if (res < 0) {
+				pr_err("[%s:%s] Returning on Interrupt\n",
+					__MM_FILE__, __func__);
+				goto fail;
+			}
+		}
+		/*lock the buffer*/
+		mutex_lock(&(fc->fc_buff[fc->buff_index].lock));
+		xfer = fc->fc_buff[fc->buff_index].actual_size;
+
+		if (xfer > count) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] read failed! byte count too small\n",
+					__MM_FILE__, __func__);
+			res = -EINVAL;
+			goto fail;
+		}
+
+		if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data,	xfer)) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] copy_to_user failed at index %d\n",
+					__MM_FILE__, __func__, fc->buff_index);
+			res = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		count -= xfer;
+
+		fc->fc_buff[fc->buff_index].empty = 1;
+		fc->fc_buff[fc->buff_index].actual_size = 0;
+
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		++(fc->buff_index);
+		if (fc->buff_index >= EVRC_FC_BUFF_CNT)
+			fc->buff_index = 0;
+	}
+	res = buf - start;
+
+fail:
+	mutex_unlock(&evrc->lock);
+
+	return res;
+}
+
+static int q6_evrc_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct evrc *evrc = file->private_data;
+	int i = 0;
+	struct evrc_fc *fc;
+
+	mutex_lock(&evrc->lock);
+	fc = evrc->evrc_fc;
+	kthread_stop(fc->task);
+	fc->task = NULL;
+	/*free flow control buffers*/
+	for (i = 0; i < EVRC_FC_BUFF_CNT; ++i) {
+		kfree(fc->fc_buff[i].data);
+		fc->fc_buff[i].data = NULL;
+	}
+	kfree(fc);
+	if (evrc->audio_client)
+		rc = q6audio_close(evrc->audio_client);
+	mutex_unlock(&evrc->lock);
+	kfree(evrc);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_evrc_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_evrc_in_open,
+	.read		= q6_evrc_in_read,
+	.release	= q6_evrc_in_release,
+	.unlocked_ioctl	= q6_evrc_in_ioctl,
+};
+
+struct miscdevice q6_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &q6_evrc_in_fops,
+};
+
+static int __init q6_evrc_in_init(void)
+{
+	return misc_register(&q6_evrc_in_misc);
+}
+
+device_initcall(q6_evrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/mp3.c b/arch/arm/mach-msm/qdsp6/mp3.c
new file mode 100644
index 0000000..16f6204
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/mp3.c
@@ -0,0 +1,249 @@
+/* arch/arm/mach-msm/qdsp6/mp3.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct mp3 {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+};
+
+static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct mp3 *mp3 = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&mp3->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		pr_debug("[%s:%s] SET_VOLUME = %d\n", __MM_FILE__,
+			__func__, vol);
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6audio_set_stream_volume(mp3->ac, vol);
+		break;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (mp3->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			mp3->ac = q6audio_open_mp3(BUFSZ,
+				mp3->sample_rate, mp3->channel_count, acdb_id);
+			if (!mp3->ac) {
+				pr_err("[%s:%s] mp3 open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (mp3->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: buffsize = %d, samplerate = %d, \
+			channelcount = %d\n", __MM_FILE__, __func__,
+			config.buffer_size, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount\n", __MM_FILE__,
+				__func__);
+			break;
+		}
+		mp3->sample_rate = config.sample_rate;
+		mp3->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = BUFSZ;
+		config.buffer_count = 2;
+		config.sample_rate = mp3->sample_rate;
+		config.channel_count = mp3->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_CONFIG: buffsize = %d, samplerate = %d, \
+			channelcount = %d\n", __MM_FILE__, __func__,
+			config.buffer_size, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&mp3->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int mp3_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	struct mp3 *mp3;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	mp3 = kzalloc(sizeof(struct mp3), GFP_KERNEL);
+
+	if (!mp3)
+		return -ENOMEM;
+
+	mutex_init(&mp3->lock);
+	mp3->channel_count = 2;
+	mp3->sample_rate = 44100;
+
+	file->private_data = mp3;
+	return rc;
+}
+
+static ssize_t mp3_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	if (!mp3->ac)
+		mp3_ioctl(file, AUDIO_START, 0);
+
+	ac = mp3->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		pr_debug("[%s:%s] ab->data = %p, ac->cpu_buf = %d\n",
+			__MM_FILE__, __func__, ab->data, ac->cpu_buf);
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int mp3_fsync(struct file *f, int datasync)
+{
+	struct mp3 *mp3 = f->private_data;
+	if (mp3->ac)
+		return q6audio_async(mp3->ac);
+	return -ENODEV;
+}
+
+static int mp3_release(struct inode *inode, struct file *file)
+{
+	struct mp3 *mp3 = file->private_data;
+	if (mp3->ac)
+		q6audio_mp3_close(mp3->ac);
+	kfree(mp3);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mp3_open,
+	.write		= mp3_write,
+	.fsync		= mp3_fsync,
+	.release	= mp3_release,
+	.unlocked_ioctl	= mp3_ioctl,
+};
+
+struct miscdevice mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &mp3_fops,
+};
+
+static int __init mp3_init(void) {
+	return misc_register(&mp3_misc);
+}
+
+device_initcall(mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6/msm_q6vdec.c b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c
new file mode 100644
index 0000000..c79f0c4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c
@@ -0,0 +1,1505 @@
+/* Copyright (c) 2008-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 DEBUG_TRACE_VDEC
+#define DEBUG
+*/
+
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+
+#include <linux/android_pmem.h>
+#include <linux/msm_q6vdec.h>
+
+#include "dal.h"
+
+#define DALDEVICEID_VDEC_DEVICE		0x02000026
+#define DALDEVICEID_VDEC_PORTNAME	"DAL_AQ_VID"
+
+#define VDEC_INTERFACE_VERSION		0x00020000
+
+#define MAJOR_MASK			0xFFFF0000
+#define MINOR_MASK			0x0000FFFF
+
+#define VDEC_GET_MAJOR_VERSION(version)	(((version)&MAJOR_MASK)>>16)
+
+#define VDEC_GET_MINOR_VERSION(version)	((version)&MINOR_MASK)
+
+#ifdef DEBUG_TRACE_VDEC
+#define TRACE(fmt,x...)			\
+	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
+#else
+#define TRACE(fmt,x...)		do { } while (0)
+#endif
+
+#define YAMATO_COLOR_FORMAT  0x02
+#define MAX_Q6_LOAD        ((720*1280)/256)  /* 720p */
+#define MAX_Q6_LOAD_YAMATO ((736*1280)/256)
+#define MAX_Q6_LOAD_VP6    ((800*480)/256)
+
+#define VDEC_MAX_PORTS 4
+
+/*
+ *why magic number 300?
+
+ *the Maximum size of the DAL payload is 512 bytes according to DAL protocol
+ *Initialize call to QDSP6 from scorpion need to send sequence header as part of
+ *the DAL payload. DAL payload to initialize contains the following
+
+ *1) configuration data- 52 bytes 2) length field of config data - 4 bytes
+ *3) sequence header data ( that is from the bit stream)
+ *4) length field for sequence header - 4 bytes
+ *5) length field for output structure - 4 bytes
+
+ *that left with 512 - 68 = 448 bytes. It is unusual that we get a sequence
+ *header with such a big length unless the bit stream has multiple sequence
+ *headers.We estimated 300 is good enough which gives enough room for rest
+ *of the payload and even reserves some space for future payload.
+ */
+
+#define VDEC_MAX_SEQ_HEADER_SIZE 300
+
+char *Q6Portnames[] = {
+"DAL_AQ_VID_0",
+"DAL_AQ_VID_1",
+"DAL_AQ_VID_2",
+"DAL_AQ_VID_3"
+};
+
+
+
+#define DALDEVICEID_VDEC_DEVICE_0        0x020000D2
+#define DALDEVICEID_VDEC_DEVICE_1        0x020000D3
+#define DALDEVICEID_VDEC_DEVICE_2        0x020000D4
+#define DALDEVICEID_VDEC_DEVICE_3        0x020000D5
+#define DALDEVICEID_VDEC_DEVICE_4        0x020000D6
+#define DALDEVICEID_VDEC_DEVICE_5        0x020000D7
+#define DALDEVICEID_VDEC_DEVICE_6        0x020000D8
+#define DALDEVICEID_VDEC_DEVICE_7        0x020000D9
+#define DALDEVICEID_VDEC_DEVICE_8        0x020000DA
+#define DALDEVICEID_VDEC_DEVICE_9        0x020000DB
+#define DALDEVICEID_VDEC_DEVICE_10        0x020000DC
+#define DALDEVICEID_VDEC_DEVICE_11        0x020000DD
+#define DALDEVICEID_VDEC_DEVICE_12        0x020000DE
+#define DALDEVICEID_VDEC_DEVICE_13        0x020000DF
+#define DALDEVICEID_VDEC_DEVICE_14        0x020000E0
+#define DALDEVICEID_VDEC_DEVICE_15        0x020000E1
+#define DALDEVICEID_VDEC_DEVICE_16        0x020000E2
+#define DALDEVICEID_VDEC_DEVICE_17        0x020000E3
+#define DALDEVICEID_VDEC_DEVICE_18        0x020000E4
+#define DALDEVICEID_VDEC_DEVICE_19        0x020000E5
+#define DALDEVICEID_VDEC_DEVICE_20        0x020000E6
+#define DALDEVICEID_VDEC_DEVICE_21        0x020000E7
+#define DALDEVICEID_VDEC_DEVICE_22        0x020000E8
+#define DALDEVICEID_VDEC_DEVICE_23        0x020000E9
+#define DALDEVICEID_VDEC_DEVICE_24        0x020000EA
+#define DALDEVICEID_VDEC_DEVICE_25        0x020000EB
+#define DALDEVICEID_VDEC_DEVICE_26        0x020000EC
+#define DALDEVICEID_VDEC_DEVICE_27        0x020000ED
+#define DALDEVICEID_VDEC_DEVICE_28        0x020000EE
+#define DALDEVICEID_VDEC_DEVICE_29        0x020000EF
+#define DALDEVICEID_VDEC_DEVICE_30        0x020000F0
+#define DALDEVICEID_VDEC_DEVICE_31        0x020000F1
+
+#define DALVDEC_MAX_DEVICE_IDS        32
+
+
+static int numOfPorts;
+
+
+static char loadOnPorts[VDEC_MAX_PORTS];
+
+static char deviceIdRegistry[DALVDEC_MAX_DEVICE_IDS];
+
+
+#define VDEC_DEVID_FREE 0
+#define VDEC_DEVID_OCCUPIED 1
+
+#define MAX_SUPPORTED_INSTANCES 6
+
+#define  MAKEFOURCC(ch0, ch1, ch2, ch3) ((unsigned int)(unsigned char)(ch0) | \
+	((unsigned int)(unsigned char)(ch1) << 8) | \
+	((unsigned int)(unsigned char)(ch2) << 16) | \
+	((unsigned int)(unsigned char)(ch3) << 24))
+
+#define FOURCC_MPEG4 MAKEFOURCC('m', 'p', '4', 'v')
+#define FOURCC_H263 MAKEFOURCC('h', '2', '6', '3')
+#define FOURCC_H264 MAKEFOURCC('h', '2', '6', '4')
+#define FOURCC_VC1 MAKEFOURCC('w', 'm', 'v', '3')
+#define FOURCC_DIVX MAKEFOURCC('D', 'I', 'V', 'X')
+#define FOURCC_SPARK MAKEFOURCC('F', 'L', 'V', '1')
+#define FOURCC_VP6 MAKEFOURCC('V', 'P', '6', '0')
+
+/* static struct vdec_data *multiInstances[MAX_SUPPORTED_INSTANCES];*/
+
+static int totalPlaybackQ6load;
+static int totalTnailQ6load;
+
+#define FLAG_THUMBNAIL_MODE  0x8
+#define MAX_TNAILS  3
+
+#define TRUE 1
+#define FALSE 0
+
+enum {
+	VDEC_DALRPC_INITIALIZE = DAL_OP_FIRST_DEVICE_API,
+	VDEC_DALRPC_SETBUFFERS,
+	VDEC_DALRPC_FREEBUFFERS,
+	VDEC_DALRPC_QUEUE,
+	VDEC_DALRPC_SIGEOFSTREAM,
+	VDEC_DALRPC_FLUSH,
+	VDEC_DALRPC_REUSEFRAMEBUFFER,
+	VDEC_DALRPC_GETDECATTRIBUTES,
+	VDEC_DALRPC_SUSPEND,
+	VDEC_DALRPC_RESUME,
+	VDEC_DALRPC_INITIALIZE_00,
+	VDEC_DALRPC_GETINTERNALBUFFERREQ,
+	VDEC_DALRPC_SETBUFFERS_00,
+	VDEC_DALRPC_FREEBUFFERS_00,
+	VDEC_DALRPC_GETPROPERTY,
+	VDEC_DALRPC_SETPROPERTY,
+	VDEC_DALRPC_GETDECATTRIBUTES_00,
+	VDEC_DALRPC_PERFORMANCE_CHANGE_REQUEST
+};
+
+enum {
+	VDEC_ASYNCMSG_DECODE_DONE = 0xdec0de00,
+	VDEC_ASYNCMSG_REUSE_FRAME,
+};
+
+struct vdec_init_cfg {
+	u32			decode_done_evt;
+	u32			reuse_frame_evt;
+	struct vdec_config	cfg;
+};
+
+struct vdec_buffer_status {
+	u32			data;
+	u32			status;
+};
+
+#define VDEC_MSG_MAX		128
+
+struct vdec_msg_list {
+	struct list_head	list;
+	struct vdec_msg		vdec_msg;
+};
+
+struct vdec_mem_info {
+	u32			buf_type;
+	u32			id;
+	unsigned long		phys_addr;
+	unsigned long		len;
+	struct file		*file;
+};
+
+struct vdec_mem_list {
+	struct list_head	list;
+	struct vdec_mem_info	mem;
+};
+
+struct videoStreamDetails{
+	int height;
+	int width;
+	unsigned int fourcc;
+	int Q6usage;
+	bool isThisTnail;
+	bool isTnailGranted;
+};
+
+struct vdec_data {
+	struct dal_client	*vdec_handle;
+	unsigned int Q6deviceId;
+	struct videoStreamDetails streamDetails;
+	struct list_head	vdec_msg_list_head;
+	struct list_head	vdec_msg_list_free;
+	wait_queue_head_t	vdec_msg_evt;
+	spinlock_t		vdec_list_lock;
+	struct list_head	vdec_mem_list_head;
+	spinlock_t		vdec_mem_list_lock;
+	int			mem_initialized;
+	int			running;
+	int			close_decode;
+};
+
+static struct class *driver_class;
+static dev_t vdec_device_no;
+static struct cdev vdec_cdev;
+static int ref_cnt;
+static DEFINE_MUTEX(vdec_ref_lock);
+
+static DEFINE_MUTEX(idlecount_lock);
+
+static DEFINE_MUTEX(vdec_rm_lock);
+
+static int idlecount;
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+
+static void prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&idlelock);
+		wake_lock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static void allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static inline int vdec_check_version(u32 client, u32 server)
+{
+	int ret = -EINVAL;
+	if ((VDEC_GET_MAJOR_VERSION(client) == VDEC_GET_MAJOR_VERSION(server))
+	    && (VDEC_GET_MINOR_VERSION(client) <=
+		VDEC_GET_MINOR_VERSION(server)))
+		ret = 0;
+	return ret;
+}
+
+static int vdec_get_msg(struct vdec_data *vd, void *msg)
+{
+	struct vdec_msg_list *l;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!vd->running)
+		return -EPERM;
+
+	spin_lock_irqsave(&vd->vdec_list_lock, flags);
+	list_for_each_entry_reverse(l, &vd->vdec_msg_list_head, list) {
+		if (copy_to_user(msg, &l->vdec_msg, sizeof(struct vdec_msg)))
+			pr_err("vdec_get_msg failed to copy_to_user!\n");
+		if (l->vdec_msg.id == VDEC_MSG_REUSEINPUTBUFFER)
+			TRACE("reuse_input_buffer %d\n", l->vdec_msg.buf_id);
+		else if (l->vdec_msg.id == VDEC_MSG_FRAMEDONE)
+			TRACE("frame_done (stat=%d)\n",
+			      l->vdec_msg.vfr_info.status);
+		else
+			TRACE("unknown msg (msgid=%d)\n", l->vdec_msg.id);
+		list_del(&l->list);
+		list_add(&l->list, &vd->vdec_msg_list_free);
+		ret = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
+
+	if (vd->close_decode)
+		ret = 1;
+
+	return ret;
+}
+
+static void vdec_put_msg(struct vdec_data *vd, struct vdec_msg *msg)
+{
+	struct vdec_msg_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&vd->vdec_list_lock, flags);
+	list_for_each_entry(l, &vd->vdec_msg_list_free, list) {
+		memcpy(&l->vdec_msg, msg, sizeof(struct vdec_msg));
+		list_del(&l->list);
+		list_add(&l->list, &vd->vdec_msg_list_head);
+		found = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
+
+	if (found)
+		wake_up(&vd->vdec_msg_evt);
+	else
+		pr_err("vdec_put_msg can't find free list!\n");
+}
+
+static struct vdec_mem_list *vdec_get_mem_from_list(struct vdec_data *vd,
+						    u32 pmem_id, u32 buf_type)
+{
+	struct vdec_mem_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+	list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
+		if (l->mem.buf_type == buf_type && l->mem.id == pmem_id) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+
+	if (found)
+		return l;
+	else
+		return NULL;
+
+}
+static int vdec_setproperty(struct vdec_data *vd, void *argp)
+{
+	struct vdec_property_info property;
+	int res;
+
+   if (copy_from_user(&property, argp, sizeof(struct vdec_property_info)))
+		return -1;
+
+	res = dal_call_f6(vd->vdec_handle, VDEC_DALRPC_SETPROPERTY,
+      property.id, &(property.property), sizeof(union vdec_property));
+	if (res)
+		TRACE("Set Property failed");
+	else
+		TRACE("Set Property succeeded");
+	return res;
+}
+static int vdec_getproperty(struct vdec_data *vd, void *argp)
+{
+	int res;
+	union vdec_property property = {0};
+
+	res = dal_call_f11(vd->vdec_handle, VDEC_DALRPC_GETPROPERTY,
+		((struct vdec_property_info *)argp)->id, &property,
+		sizeof(union vdec_property));
+
+	if (res)
+		TRACE("get Property failed");
+	else
+		TRACE("get Property succeeded");
+
+	res = copy_to_user(
+		(&((struct vdec_property_info *)argp)->property),
+		&property, sizeof(property));
+
+	return res;
+}
+static int vdec_performance_change_request(struct vdec_data *vd, void* argp)
+{
+	u32 request_type;
+	int ret;
+
+	ret = copy_from_user(&request_type, argp, sizeof(request_type));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = dal_call_f0(vd->vdec_handle,
+			VDEC_DALRPC_PERFORMANCE_CHANGE_REQUEST,
+			request_type);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	return ret;
+}
+
+#ifdef TRACE_PORTS
+static void printportsanddeviceids(void)
+{
+	int i;
+
+	pr_err("\n\n%s:loadOnPorts", __func__);
+	for (i = 0; i < numOfPorts; i++)
+		pr_err("\t%d", loadOnPorts[i]);
+
+	pr_err("\n\n");
+
+	pr_err("\n\n%s:Devids", __func__);
+	for (i = 0; i < DALVDEC_MAX_DEVICE_IDS; i++)
+		pr_err("Devid[%d]:%d\n", i, deviceIdRegistry[i]);
+
+
+	pr_err("\n\n");
+}
+#endif /*TRACE_PORTS*/
+
+
+/*
+ *
+ * This method is used to get the number of ports supported on the Q6
+ *
+ */
+static int vdec_get_numberofq6ports(void)
+{
+	struct dal_client *vdec_handle = NULL;
+	int retval = 0;
+	union vdec_property property = {0};
+
+	vdec_handle = dal_attach(DALDEVICEID_VDEC_DEVICE,
+			     DALDEVICEID_VDEC_PORTNAME, 1, NULL, NULL);
+	if (!vdec_handle) {
+		pr_err("%s: failed to attach\n", __func__);
+		return 1;/* default setting */
+	}
+
+	retval = dal_call_f6(vdec_handle, VDEC_DALRPC_GETPROPERTY,
+      VDEC_NUM_DAL_PORTS, (void *)&property, sizeof(union vdec_property));
+	if (retval) {
+		pr_err("%s: Q6get prperty failed\n", __func__);
+		return 1;/* default setting */
+	}
+
+	dal_detach(vdec_handle);
+	return property.num_dal_ports ;
+}
+
+
+/**
+  * This method is used to get the find the least loaded port and a corresponding
+  * free device id in that port.
+  *
+  * Prerequisite: vdec_open should have been called.
+  *
+  *  @param[in] deviceid
+  *     device id will be populated here.
+  *
+  *  @param[in] portname
+  *     portname will be populated here.
+  */
+static void vdec_get_next_portanddevid(int *deviceid, char **portname)
+{
+
+	int i = 0;
+	int leastLoad = 0;
+	int leastLoadedIndex = 0;
+
+	if (0 == numOfPorts) {
+		numOfPorts = vdec_get_numberofq6ports();
+		pr_err("%s: Q6get numOfPorts %d\n", __func__, numOfPorts);
+		numOfPorts = 4;
+		/*fix: me currently hard coded to 4 as
+		 *the Q6 getproperty is failing
+		 */
+	}
+
+	if ((NULL == deviceid) || (NULL == portname))
+		return;
+	else
+		*deviceid = 0; /* init value */
+
+	if (numOfPorts > 1) {
+		/* multi ports mode*/
+
+		/* find the least loaded port*/
+		for (i = 1, leastLoad = loadOnPorts[0], leastLoadedIndex = 0;
+					i < numOfPorts; i++) {
+			if (leastLoad > loadOnPorts[i]) {
+				leastLoadedIndex = i;
+				leastLoad = loadOnPorts[i];
+			}
+		}
+
+		/* register the load */
+		loadOnPorts[leastLoadedIndex]++;
+		*portname = Q6Portnames[leastLoadedIndex];
+
+		/* find a free device id corresponding to the port*/
+		for (i = leastLoadedIndex; i < DALVDEC_MAX_DEVICE_IDS;
+					i += numOfPorts) {
+			if (VDEC_DEVID_FREE == deviceIdRegistry[i]) {
+				deviceIdRegistry[i] = VDEC_DEVID_OCCUPIED;
+				*deviceid = DALDEVICEID_VDEC_DEVICE_0 + i;
+				break;
+			}
+		}
+
+#ifdef TRACE_PORTS
+		printportsanddeviceids();
+#endif /*TRACE_PORTS*/
+	} else if (1 == numOfPorts) {
+		/* single port mode */
+		*deviceid = DALDEVICEID_VDEC_DEVICE;
+		*portname = DALDEVICEID_VDEC_PORTNAME;
+	} else if (numOfPorts <= 0) {
+		pr_err("%s: FATAL error numOfPorts cannot be \
+			less than or equal to zero\n", __func__);
+	}
+
+
+}
+
+
+/**
+  * This method frees up the used dev id and decrements the port load.
+  *
+  */
+
+static void vdec_freeup_portanddevid(int deviceid)
+{
+
+	if (numOfPorts > 1) {
+		/* multi ports mode*/
+		if (VDEC_DEVID_FREE ==
+			deviceIdRegistry[deviceid - DALDEVICEID_VDEC_DEVICE_0])
+			pr_err("device id cannot be already free\n");
+		deviceIdRegistry[deviceid - DALDEVICEID_VDEC_DEVICE_0] =
+			VDEC_DEVID_FREE;
+
+		loadOnPorts[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
+			% numOfPorts]--;
+
+		if (loadOnPorts[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
+			% numOfPorts] < 0)
+			pr_err("Warning:load cannot be negative\n");
+
+		pr_err("dettaching on deviceid %x portname %s\n", deviceid,
+			Q6Portnames[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
+			% numOfPorts]);
+
+#ifdef TRACE_PORTS
+		printportsanddeviceids();
+#endif /*TRACE_PORTS*/
+	} else {
+		/*single port mode, nothing to be done here*/
+	}
+
+}
+
+
+/**
+  * This method validates whether a new instance can be houred or not.
+  *
+  */
+static int vdec_rm_checkWithRm(struct vdec_data *vdecInstance,
+				unsigned int color_format)
+{
+
+	unsigned int maxQ6load = 0;/* in the units of macro blocks per second */
+	unsigned int currentq6load = 0;
+	struct videoStreamDetails *streamDetails = &vdecInstance->streamDetails;
+
+
+
+	if (streamDetails->isThisTnail) {
+		if (totalTnailQ6load < MAX_TNAILS) {
+
+			totalTnailQ6load++;
+			streamDetails->isTnailGranted = TRUE;
+			pr_info("%s: thumbnail granted %d\n", __func__,
+				totalTnailQ6load);
+			return 0;
+
+		} else {
+
+			pr_err("%s: thumbnails load max this instance cannot \
+					be supported\n", __func__);
+			streamDetails->isTnailGranted = FALSE;
+			return -ENOSPC;
+
+		}
+	}
+
+	/* calculate the Q6 percentage instance would need */
+	if ((streamDetails->fourcc == FOURCC_MPEG4) ||
+		 (streamDetails->fourcc  == FOURCC_H264) ||
+		 (streamDetails->fourcc  == FOURCC_DIVX) ||
+		 (streamDetails->fourcc  == FOURCC_VC1) ||
+		 (streamDetails->fourcc  == FOURCC_SPARK) ||
+		 (streamDetails->fourcc  == FOURCC_H263)
+		){
+
+		/* is yamato color format,
+		  Rounds the H & W --> mutiple of 32 */
+		if (color_format == YAMATO_COLOR_FORMAT)
+			maxQ6load = MAX_Q6_LOAD_YAMATO;
+		else
+			maxQ6load = MAX_Q6_LOAD; /* 720p */
+
+	} else if (streamDetails->fourcc  == FOURCC_VP6) {
+
+		maxQ6load = MAX_Q6_LOAD_VP6;    /* FWVGA */
+
+	} else {
+
+		pr_err("%s: unknown fourcc %d  maxQ6load %u\n", __func__,
+			streamDetails->fourcc, maxQ6load);
+		return -EINVAL;
+
+	}
+
+	currentq6load = ((streamDetails->height)*(streamDetails->width) / 256);
+	currentq6load = ((currentq6load * 100)/maxQ6load);
+	if ((currentq6load+totalPlaybackQ6load) > 100) {
+		/* reject this instance */
+		pr_err("%s: too much Q6load [cur+tot] = [%d + %d] = %d",
+		__func__, currentq6load, totalPlaybackQ6load,
+		(currentq6load+totalPlaybackQ6load));
+		pr_err("rejecting the instance,[WxH] = [%d x %d],color_fmt=0x%x\n",
+		streamDetails->width, streamDetails->height, color_format);
+		pr_err("VDEC_fmt=%s\n", (char *)(&streamDetails->fourcc));
+		streamDetails->Q6usage = 0;
+		return -ENOSPC;
+	}
+
+	totalPlaybackQ6load += currentq6load;
+	streamDetails->Q6usage = currentq6load;
+
+	pr_info("%s: adding a load [%d%%] bringing total Q6load to [%d%%]\n",
+		__func__, currentq6load, totalPlaybackQ6load);
+
+	return 0;
+}
+
+
+static int vdec_initialize(struct vdec_data *vd, void *argp)
+{
+	struct vdec_config_sps vdec_cfg_sps;
+	struct vdec_init_cfg vi_cfg;
+	struct vdec_buf_req vdec_buf_req;
+	struct u8 *header;
+	int ret = 0;
+
+	ret = copy_from_user(&vdec_cfg_sps,
+			     &((struct vdec_init *)argp)->sps_cfg,
+			     sizeof(vdec_cfg_sps));
+
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	vi_cfg.decode_done_evt = VDEC_ASYNCMSG_DECODE_DONE;
+	vi_cfg.reuse_frame_evt = VDEC_ASYNCMSG_REUSE_FRAME;
+	memcpy(&vi_cfg.cfg, &vdec_cfg_sps.cfg, sizeof(struct vdec_config));
+
+	/*
+	 * restricting the max value of the seq header
+	 */
+	if (vdec_cfg_sps.seq.len > VDEC_MAX_SEQ_HEADER_SIZE)
+		vdec_cfg_sps.seq.len = VDEC_MAX_SEQ_HEADER_SIZE;
+
+	header = kmalloc(vdec_cfg_sps.seq.len, GFP_KERNEL);
+	if (!header) {
+		pr_err("%s: kmalloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = copy_from_user(header,
+			     ((struct vdec_init *)argp)->sps_cfg.seq.header,
+			     vdec_cfg_sps.seq.len);
+
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		kfree(header);
+		return ret;
+	}
+
+	TRACE("vi_cfg: handle=%p fourcc=0x%x w=%d h=%d order=%d notify_en=%d "
+	      "vc1_rb=%d h264_sd=%d h264_nls=%d pp_flag=%d fruc_en=%d\n",
+	      vd->vdec_handle, vi_cfg.cfg.fourcc, vi_cfg.cfg.width,
+	      vi_cfg.cfg.height, vi_cfg.cfg.order, vi_cfg.cfg.notify_enable,
+	      vi_cfg.cfg.vc1_rowbase, vi_cfg.cfg.h264_startcode_detect,
+	      vi_cfg.cfg.h264_nal_len_size, vi_cfg.cfg.postproc_flag,
+	      vi_cfg.cfg.fruc_enable);
+
+	vd->streamDetails.height = vi_cfg.cfg.height;
+	vd->streamDetails.width = vi_cfg.cfg.width;
+	vd->streamDetails.fourcc = vi_cfg.cfg.fourcc;
+	if (FLAG_THUMBNAIL_MODE == vi_cfg.cfg.postproc_flag)
+		vd->streamDetails.isThisTnail = TRUE;
+	else
+		vd->streamDetails.isThisTnail = FALSE;
+
+	mutex_lock(&vdec_rm_lock);
+	ret = vdec_rm_checkWithRm(vd, vi_cfg.cfg.color_format);
+	mutex_unlock(&vdec_rm_lock);
+	if (ret)
+		return ret;
+
+	ret = dal_call_f13(vd->vdec_handle, VDEC_DALRPC_INITIALIZE,
+			   &vi_cfg, sizeof(vi_cfg),
+			   header, vdec_cfg_sps.seq.len,
+			   &vdec_buf_req, sizeof(vdec_buf_req));
+
+	kfree(header);
+
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	else
+		ret = copy_to_user(((struct vdec_init *)argp)->buf_req,
+				   &vdec_buf_req, sizeof(vdec_buf_req));
+
+	vd->close_decode = 0;
+	return ret;
+}
+
+static void vdec_rm_freeupResources(struct vdec_data *vdecInstance)
+{
+	struct videoStreamDetails *streamDetails = &vdecInstance->streamDetails;
+
+
+
+	if ((streamDetails->isThisTnail) &&
+		 (streamDetails->isTnailGranted)) {
+
+			totalTnailQ6load--;
+			pr_info("%s: Thumbnail released %d\n", __func__,
+				totalTnailQ6load);
+
+	} else if (streamDetails->Q6usage > 0) {
+
+		totalPlaybackQ6load -= streamDetails->Q6usage;
+		if (totalPlaybackQ6load < 0)
+			pr_err("Warning:Q6load cannot be negative\n");
+
+		pr_info("%s:Releasing [%d%%] of Q6load from a total of [%d%%]\n"
+			, __func__, streamDetails->Q6usage,
+			(streamDetails->Q6usage+totalPlaybackQ6load));
+	}
+
+}
+
+static int vdec_setbuffers(struct vdec_data *vd, void *argp)
+{
+	struct vdec_buffer vmem;
+	struct vdec_mem_list *l;
+	unsigned long vstart;
+	unsigned long flags;
+	struct {
+		uint32_t size;
+		struct vdec_buf_info buf;
+	} rpc;
+	uint32_t res;
+
+	int ret = 0;
+
+	vd->mem_initialized = 0;
+
+	ret = copy_from_user(&vmem, argp, sizeof(vmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = kzalloc(sizeof(struct vdec_mem_list), GFP_KERNEL);
+	if (!l) {
+		pr_err("%s: kzalloc failed!\n", __func__);
+		return -ENOMEM;
+	}
+
+	l->mem.id = vmem.pmem_id;
+	l->mem.buf_type = vmem.buf.buf_type;
+
+	ret = get_pmem_file(l->mem.id, &l->mem.phys_addr, &vstart,
+			    &l->mem.len, &l->mem.file);
+	if (ret) {
+		pr_err("%s: get_pmem_fd failed\n", __func__);
+		goto err_get_pmem_file;
+	}
+
+	TRACE("pmem_id=%d (phys=0x%08lx len=0x%lx) buftype=%d num_buf=%d "
+	      "islast=%d src_id=%d offset=0x%08x size=0x%x\n",
+	      vmem.pmem_id, l->mem.phys_addr, l->mem.len,
+	      vmem.buf.buf_type, vmem.buf.num_buf, vmem.buf.islast,
+	      vmem.buf.region.src_id, vmem.buf.region.offset,
+	      vmem.buf.region.size);
+
+	/* input buffers */
+	if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
+		pr_err("%s: invalid input buffer offset!\n", __func__);
+		ret = -EINVAL;
+		goto err_bad_offset;
+
+	}
+	vmem.buf.region.offset += l->mem.phys_addr;
+
+	rpc.size = sizeof(vmem.buf);
+	memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
+
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_SETBUFFERS, 5,
+		       &rpc, sizeof(rpc), &res, sizeof(res));
+
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+		goto err_dal_call;
+	}
+
+	spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+	list_add(&l->list, &vd->vdec_mem_list_head);
+	spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+
+	vd->mem_initialized = 1;
+	return ret;
+
+err_dal_call:
+err_bad_offset:
+	put_pmem_file(l->mem.file);
+err_get_pmem_file:
+	kfree(l);
+	return ret;
+}
+
+static int vdec_queue(struct vdec_data *vd, void *argp)
+{
+	struct {
+		uint32_t size;
+		struct vdec_input_buf_info buf_info;
+		uint32_t osize;
+	} rpc;
+	struct vdec_mem_list *l;
+	struct {
+		uint32_t result;
+		uint32_t size;
+		struct vdec_queue_status status;
+	} rpc_res;
+
+	u32 pmem_id;
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&rpc.buf_info,
+			     &((struct vdec_input_buf *)argp)->buffer,
+			     sizeof(rpc.buf_info));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	ret = copy_from_user(&pmem_id,
+			     &((struct vdec_input_buf *)argp)->pmem_id,
+			     sizeof(u32));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = vdec_get_mem_from_list(vd, pmem_id, VDEC_BUFFER_TYPE_INPUT);
+
+	if (NULL == l) {
+		pr_err("%s: not able to find the buffer from list\n", __func__);
+		return -EPERM;
+	}
+
+	if ((rpc.buf_info.size + rpc.buf_info.offset) >= l->mem.len) {
+		pr_err("%s: invalid queue buffer offset!\n", __func__);
+		return -EINVAL;
+	}
+
+	rpc.buf_info.offset += l->mem.phys_addr;
+	rpc.size = sizeof(struct vdec_input_buf_info);
+	rpc.osize = sizeof(struct vdec_queue_status);
+
+	/* complete the writes to the buffer */
+	wmb();
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_QUEUE, 8,
+		       &rpc, sizeof(rpc), &rpc_res, sizeof(rpc_res));
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+	}
+	return ret;
+}
+
+static int vdec_reuse_framebuffer(struct vdec_data *vd, void *argp)
+{
+	u32 buf_id;
+	int ret = 0;
+
+	ret = copy_from_user(&buf_id, argp, sizeof(buf_id));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_REUSEFRAMEBUFFER,
+			  buf_id);
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static int vdec_flush(struct vdec_data *vd, void *argp)
+{
+	u32 flush_type;
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&flush_type, argp, sizeof(flush_type));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	TRACE("flush_type=%d\n", flush_type);
+	ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_FLUSH, flush_type);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int vdec_close(struct vdec_data *vd, void *argp)
+{
+	struct vdec_mem_list *l;
+	int ret = 0;
+
+	pr_info("q6vdec_close()\n");
+	vd->close_decode = 1;
+	wake_up(&vd->vdec_msg_evt);
+
+	ret = dal_call_f0(vd->vdec_handle, DAL_OP_CLOSE, 0);
+	if (ret)
+		pr_err("%s: failed to close daldevice (%d)\n", __func__, ret);
+
+	if (vd->mem_initialized) {
+		list_for_each_entry(l, &vd->vdec_mem_list_head, list)
+			put_pmem_file(l->mem.file);
+	}
+
+	return ret;
+}
+static int vdec_getdecattributes(struct vdec_data *vd, void *argp)
+{
+	struct {
+		uint32_t status;
+		uint32_t size;
+		struct vdec_dec_attributes dec_attr;
+	} rpc;
+	uint32_t inp;
+	int ret = 0;
+	inp = sizeof(struct vdec_dec_attributes);
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_GETDECATTRIBUTES, 9,
+		       &inp, sizeof(inp), &rpc, sizeof(rpc));
+	if (ret < 4 || rpc.size != sizeof(struct vdec_dec_attributes)) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+	} else
+		ret =
+		    copy_to_user(((struct vdec_dec_attributes *)argp),
+				 &rpc.dec_attr, sizeof(rpc.dec_attr));
+	return ret;
+}
+
+static int vdec_freebuffers(struct vdec_data *vd, void *argp)
+{
+	struct vdec_buffer vmem;
+	struct vdec_mem_list *l;
+	struct {
+		uint32_t size;
+		struct vdec_buf_info buf;
+	} rpc;
+	uint32_t res;
+
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&vmem, argp, sizeof(vmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = vdec_get_mem_from_list(vd, vmem.pmem_id, vmem.buf.buf_type);
+
+	if (NULL == l) {
+		pr_err("%s: not able to find the buffer from list\n", __func__);
+		return -EPERM;
+	}
+
+	/* input buffers */
+	if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
+		pr_err("%s: invalid input buffer offset!\n", __func__);
+		return -EINVAL;
+
+	}
+	vmem.buf.region.offset += l->mem.phys_addr;
+
+	rpc.size = sizeof(vmem.buf);
+	memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_FREEBUFFERS, 5,
+		       &rpc, sizeof(rpc), &res, sizeof(res));
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	}
+
+	return ret;
+}
+
+static int vdec_getversion(struct vdec_data *vd, void *argp)
+{
+	struct vdec_version ver_info;
+	int ret = 0;
+
+	ver_info.major = VDEC_GET_MAJOR_VERSION(VDEC_INTERFACE_VERSION);
+	ver_info.minor = VDEC_GET_MINOR_VERSION(VDEC_INTERFACE_VERSION);
+
+	ret = copy_to_user(((struct vdec_version *)argp),
+				&ver_info, sizeof(ver_info));
+
+	return ret;
+
+}
+
+static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct vdec_data *vd = file->private_data;
+	void __user *argp = (void __user *)arg;
+	int ret = 0;
+
+	if (!vd->running)
+		return -EPERM;
+
+	switch (cmd) {
+	case VDEC_IOCTL_INITIALIZE:
+		ret = vdec_initialize(vd, argp);
+		break;
+
+	case VDEC_IOCTL_SETBUFFERS:
+		ret = vdec_setbuffers(vd, argp);
+		break;
+
+	case VDEC_IOCTL_QUEUE:
+		TRACE("VDEC_IOCTL_QUEUE (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_queue(vd, argp);
+		break;
+
+	case VDEC_IOCTL_REUSEFRAMEBUFFER:
+		TRACE("VDEC_IOCTL_REUSEFRAMEBUFFER (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_reuse_framebuffer(vd, argp);
+		break;
+
+	case VDEC_IOCTL_FLUSH:
+		TRACE("IOCTL flush\n");
+		ret = vdec_flush(vd, argp);
+		break;
+
+	case VDEC_IOCTL_EOS:
+		TRACE("VDEC_IOCTL_EOS (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_SIGEOFSTREAM, 0);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	case VDEC_IOCTL_GETMSG:
+		TRACE("VDEC_IOCTL_GETMSG (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		wait_event_interruptible(vd->vdec_msg_evt,
+					 vdec_get_msg(vd, argp));
+
+		if (vd->close_decode)
+			ret = -EINTR;
+		else
+			/* order the reads from the buffer */
+			rmb();
+		break;
+
+	case VDEC_IOCTL_CLOSE:
+		ret = vdec_close(vd, argp);
+		break;
+
+	case VDEC_IOCTL_GETDECATTRIBUTES:
+		TRACE("VDEC_IOCTL_GETDECATTRIBUTES (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_getdecattributes(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	case VDEC_IOCTL_FREEBUFFERS:
+		TRACE("VDEC_IOCTL_FREEBUFFERS (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_freebuffers(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+	case VDEC_IOCTL_GETVERSION:
+		TRACE("VDEC_IOCTL_GETVERSION (pid=%d tid=%d)\n",
+			current->group_leader->pid, current->pid);
+		ret = vdec_getversion(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+				__func__, ret);
+		break;
+	case VDEC_IOCTL_GETPROPERTY:
+		TRACE("VDEC_IOCTL_GETPROPERTY (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_getproperty(vd, argp);
+		break;
+	case VDEC_IOCTL_SETPROPERTY:
+		TRACE("VDEC_IOCTL_SETPROPERTY (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_setproperty(vd, argp);
+		break;
+	case VDEC_IOCTL_PERFORMANCE_CHANGE_REQ:
+		ret = vdec_performance_change_request(vd, argp);
+		break;
+	default:
+		pr_err("%s: invalid ioctl!\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+
+	TRACE("ioctl done (pid=%d tid=%d)\n",
+	      current->group_leader->pid, current->pid);
+
+	return ret;
+}
+
+static void vdec_dcdone_handler(struct vdec_data *vd, void *frame,
+				uint32_t frame_size)
+{
+	struct vdec_msg msg;
+	struct vdec_mem_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	if (frame_size < sizeof(struct vdec_frame_info)) {
+		pr_warning("%s: msg size mismatch %d != %d\n", __func__,
+			   frame_size, sizeof(struct vdec_frame_info));
+		return;
+	}
+
+	memcpy(&msg.vfr_info, (struct vdec_frame_info *)frame,
+	       sizeof(struct vdec_frame_info));
+
+	if (msg.vfr_info.status == VDEC_FRAME_DECODE_OK) {
+		spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+		list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
+			if ((l->mem.buf_type == VDEC_BUFFER_TYPE_OUTPUT) &&
+			    (msg.vfr_info.offset >= l->mem.phys_addr) &&
+			    (msg.vfr_info.offset <
+			     (l->mem.phys_addr + l->mem.len))) {
+				found = 1;
+				msg.vfr_info.offset -= l->mem.phys_addr;
+				msg.vfr_info.data2 = l->mem.id;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+	}
+
+	if (found || (msg.vfr_info.status != VDEC_FRAME_DECODE_OK)) {
+		msg.id = VDEC_MSG_FRAMEDONE;
+		vdec_put_msg(vd, &msg);
+	} else {
+		pr_err("%s: invalid phys addr = 0x%x\n",
+		       __func__, msg.vfr_info.offset);
+	}
+
+}
+
+static void vdec_reuseibuf_handler(struct vdec_data *vd, void *bufstat,
+				   uint32_t bufstat_size)
+{
+	struct vdec_buffer_status *vdec_bufstat;
+	struct vdec_msg msg;
+
+	/* TODO: how do we signal the client? If they are waiting on a
+	 * message in an ioctl, they may block forever */
+	if (bufstat_size != sizeof(struct vdec_buffer_status)) {
+		pr_warning("%s: msg size mismatch %d != %d\n", __func__,
+			   bufstat_size, sizeof(struct vdec_buffer_status));
+		return;
+	}
+	vdec_bufstat = (struct vdec_buffer_status *)bufstat;
+	msg.id = VDEC_MSG_REUSEINPUTBUFFER;
+	msg.buf_id = vdec_bufstat->data;
+	vdec_put_msg(vd, &msg);
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct vdec_data *vd = (struct vdec_data *)cookie;
+	uint32_t *tmp = (uint32_t *) data;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s:memory not initialize but callback called!\n",
+		       __func__);
+		return;
+	}
+
+	TRACE("vdec_async: tmp=0x%08x 0x%08x 0x%08x\n", tmp[0], tmp[1], tmp[2]);
+	switch (tmp[0]) {
+	case VDEC_ASYNCMSG_DECODE_DONE:
+		vdec_dcdone_handler(vd, &tmp[3], tmp[2]);
+		break;
+	case VDEC_ASYNCMSG_REUSE_FRAME:
+		vdec_reuseibuf_handler(vd, &tmp[3], tmp[2]);
+		break;
+	default:
+		pr_err("%s: Unknown async message from DSP id=0x%08x sz=%u\n",
+		       __func__, tmp[0], tmp[2]);
+	}
+}
+
+static int vdec_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	int i;
+	struct vdec_msg_list *l;
+	struct vdec_data *vd;
+	struct dal_info version_info;
+	char *portname = NULL;
+
+	pr_info("q6vdec_open()\n");
+	mutex_lock(&vdec_ref_lock);
+	if (ref_cnt >= MAX_SUPPORTED_INSTANCES) {
+		pr_err("%s: Max allowed instances exceeded \n", __func__);
+		mutex_unlock(&vdec_ref_lock);
+		return -EBUSY;
+	}
+	ref_cnt++;
+	mutex_unlock(&vdec_ref_lock);
+
+	vd = kmalloc(sizeof(struct vdec_data), GFP_KERNEL);
+	if (!vd) {
+		pr_err("%s: kmalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto vdec_open_err_handle_vd;
+	}
+	file->private_data = vd;
+
+	vd->mem_initialized = 0;
+	INIT_LIST_HEAD(&vd->vdec_msg_list_head);
+	INIT_LIST_HEAD(&vd->vdec_msg_list_free);
+	INIT_LIST_HEAD(&vd->vdec_mem_list_head);
+	init_waitqueue_head(&vd->vdec_msg_evt);
+
+	spin_lock_init(&vd->vdec_list_lock);
+	spin_lock_init(&vd->vdec_mem_list_lock);
+	for (i = 0; i < VDEC_MSG_MAX; i++) {
+		l = kzalloc(sizeof(struct vdec_msg_list), GFP_KERNEL);
+		if (!l) {
+			pr_err("%s: kzalloc failed!\n", __func__);
+			ret = -ENOMEM;
+			goto vdec_open_err_handle_list;
+		}
+		list_add(&l->list, &vd->vdec_msg_list_free);
+	}
+
+	memset(&vd->streamDetails, 0, sizeof(struct videoStreamDetails));
+
+	mutex_lock(&vdec_ref_lock);
+	vdec_get_next_portanddevid(&vd->Q6deviceId, &portname);
+	mutex_unlock(&vdec_ref_lock);
+
+	if ((0 == vd->Q6deviceId) || (NULL == portname)) {
+		pr_err("%s: FATAL error portname %s or deviceId %d not picked properly\n",
+			__func__, portname, vd->Q6deviceId);
+		ret = -EIO;
+		goto vdec_open_err_handle_list;
+	} else {
+		pr_err("attaching on deviceid %x portname %s\n",
+			vd->Q6deviceId, portname);
+		vd->vdec_handle = dal_attach(vd->Q6deviceId,
+					     portname, 1, callback, vd);
+	}
+
+	if (!vd->vdec_handle) {
+		pr_err("%s: failed to attach\n", __func__);
+		ret = -EIO;
+		goto vdec_open_err_handle_list;
+	}
+	ret = dal_call_f9(vd->vdec_handle, DAL_OP_INFO,
+				&version_info, sizeof(struct dal_info));
+
+	if (ret) {
+		pr_err("%s: failed to get version \n", __func__);
+		goto vdec_open_err_handle_version;
+	}
+
+	TRACE("q6vdec_open() interface version 0x%x\n", version_info.version);
+	if (vdec_check_version(VDEC_INTERFACE_VERSION,
+			version_info.version)) {
+		pr_err("%s: driver version mismatch !\n", __func__);
+		goto vdec_open_err_handle_version;
+	}
+
+	vd->running = 1;
+	prevent_sleep();
+
+	return 0;
+vdec_open_err_handle_version:
+	dal_detach(vd->vdec_handle);
+vdec_open_err_handle_list:
+	{
+		struct vdec_msg_list *l, *n;
+		list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
+			list_del(&l->list);
+			kfree(l);
+		}
+	}
+vdec_open_err_handle_vd:
+	mutex_lock(&vdec_ref_lock);
+	vdec_freeup_portanddevid(vd->Q6deviceId);
+	ref_cnt--;
+	mutex_unlock(&vdec_ref_lock);
+	kfree(vd);
+	return ret;
+}
+
+static int vdec_release(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct vdec_msg_list *l, *n;
+	struct vdec_mem_list *m, *k;
+	struct vdec_data *vd = file->private_data;
+
+	vd->running = 0;
+	wake_up_all(&vd->vdec_msg_evt);
+
+	if (!vd->close_decode)
+		vdec_close(vd, NULL);
+
+	ret = dal_detach(vd->vdec_handle);
+	if (ret)
+		printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret);
+
+	list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+
+	list_for_each_entry_safe(l, n, &vd->vdec_msg_list_head, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+
+	list_for_each_entry_safe(m, k, &vd->vdec_mem_list_head, list) {
+		list_del(&m->list);
+		kfree(m);
+	}
+	mutex_lock(&vdec_ref_lock);
+	BUG_ON(ref_cnt <= 0);
+	ref_cnt--;
+	vdec_freeup_portanddevid(vd->Q6deviceId);
+	mutex_unlock(&vdec_ref_lock);
+
+	mutex_lock(&vdec_rm_lock);
+	vdec_rm_freeupResources(vd);
+	mutex_unlock(&vdec_rm_lock);
+
+
+	kfree(vd);
+	allow_sleep();
+	return 0;
+}
+
+static const struct file_operations vdec_fops = {
+	.owner = THIS_MODULE,
+	.open = vdec_open,
+	.release = vdec_release,
+	.unlocked_ioctl = vdec_ioctl,
+};
+
+static int __init vdec_init(void)
+{
+	struct device *class_dev;
+	int rc = 0;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "vdec_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "vdec_suspend");
+
+	rc = alloc_chrdev_region(&vdec_device_no, 0, 1, "vdec");
+	if (rc < 0) {
+		pr_err("%s: alloc_chrdev_region failed %d\n", __func__, rc);
+		return rc;
+	}
+
+	driver_class = class_create(THIS_MODULE, "vdec");
+	if (IS_ERR(driver_class)) {
+		rc = -ENOMEM;
+		pr_err("%s: class_create failed %d\n", __func__, rc);
+		goto vdec_init_err_unregister_chrdev_region;
+	}
+	class_dev = device_create(driver_class, NULL,
+				  vdec_device_no, NULL, "vdec");
+	if (!class_dev) {
+		pr_err("%s: class_device_create failed %d\n", __func__, rc);
+		rc = -ENOMEM;
+		goto vdec_init_err_class_destroy;
+	}
+
+	cdev_init(&vdec_cdev, &vdec_fops);
+	vdec_cdev.owner = THIS_MODULE;
+	rc = cdev_add(&vdec_cdev, MKDEV(MAJOR(vdec_device_no), 0), 1);
+
+	if (rc < 0) {
+		pr_err("%s: cdev_add failed %d\n", __func__, rc);
+		goto vdec_init_err_class_device_destroy;
+	}
+
+	memset(&deviceIdRegistry, 0, sizeof(deviceIdRegistry));
+	memset(&loadOnPorts, 0, sizeof(loadOnPorts));
+	numOfPorts = 0;
+
+	return 0;
+
+vdec_init_err_class_device_destroy:
+	device_destroy(driver_class, vdec_device_no);
+vdec_init_err_class_destroy:
+	class_destroy(driver_class);
+vdec_init_err_unregister_chrdev_region:
+	unregister_chrdev_region(vdec_device_no, 1);
+	return rc;
+}
+
+static void __exit vdec_exit(void)
+{
+	device_destroy(driver_class, vdec_device_no);
+	class_destroy(driver_class);
+	unregister_chrdev_region(vdec_device_no, 1);
+}
+
+MODULE_DESCRIPTION("video decoder driver for QSD platform");
+MODULE_VERSION("2.00");
+
+module_init(vdec_init);
+module_exit(vdec_exit);
diff --git a/arch/arm/mach-msm/qdsp6/msm_q6venc.c b/arch/arm/mach-msm/qdsp6/msm_q6venc.c
new file mode 100644
index 0000000..bd5d3f6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/msm_q6venc.c
@@ -0,0 +1,1195 @@
+/* Copyright (c) 2008-2009, 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/cdev.h>
+#include <linux/file.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_q6venc.h>
+#include "dal.h"
+
+#define DALDEVICEID_VENC_DEVICE         0x0200002D
+#define DALDEVICEID_VENC_PORTNAME       "DAL_AQ_VID"
+
+#define VENC_NAME		        "q6venc"
+#define VENC_MSG_MAX                    128
+
+#define VENC_INTERFACE_VERSION		0x00020000
+#define MAJOR_MASK			0xFFFF0000
+#define MINOR_MASK			0x0000FFFF
+#define VENC_GET_MAJOR_VERSION(version) ((version & MAJOR_MASK)>>16)
+#define VENC_GET_MINOR_VERSION(version) (version & MINOR_MASK)
+
+enum {
+	VENC_BUFFER_TYPE_INPUT,
+	VENC_BUFFER_TYPE_OUTPUT,
+	VENC_BUFFER_TYPE_QDSP6,
+	VENC_BUFFER_TYPE_HDR
+};
+enum {
+	VENC_DALRPC_GET_SYNTAX_HEADER = DAL_OP_FIRST_DEVICE_API,
+	VENC_DALRPC_UPDATE_INTRA_REFRESH,
+	VENC_DALRPC_UPDATE_FRAME_RATE,
+	VENC_DALRPC_UPDATE_BITRATE,
+	VENC_DALRPC_UPDATE_QP_RANGE,
+	VENC_DALRPC_UPDATE_INTRA_PERIOD,
+	VENC_DALRPC_REQUEST_IFRAME,
+	VENC_DALRPC_START,
+	VENC_DALRPC_STOP,
+	VENC_DALRPC_SUSPEND,
+	VENC_DALRPC_RESUME,
+	VENC_DALRPC_FLUSH,
+	VENC_DALRPC_QUEUE_INPUT,
+	VENC_DALRPC_QUEUE_OUTPUT
+};
+struct venc_input_payload {
+	u32 data;
+};
+struct venc_output_payload {
+	u32 size;
+	long long time_stamp;
+	u32 flags;
+	u32 data;
+	u32 client_data_from_input;
+};
+union venc_payload {
+	struct venc_input_payload input_payload;
+	struct venc_output_payload output_payload;
+};
+struct venc_msg_type {
+	u32 event;
+	u32 status;
+	union venc_payload payload;
+};
+struct venc_input_buf {
+	struct venc_buf_type yuv_buf;
+	u32 data_size;
+	long long time_stamp;
+	u32 flags;
+	u32 dvs_offsetx;
+	u32 dvs_offsety;
+	u32 client_data;
+	u32 op_client_data;
+};
+struct venc_output_buf {
+	struct venc_buf_type bit_stream_buf;
+	u32 client_data;
+};
+
+struct venc_msg_list {
+	struct list_head list;
+	struct venc_msg msg_data;
+};
+struct venc_buf {
+	int fd;
+	u32 src;
+	u32 offset;
+	u32 size;
+	u32 btype;
+	unsigned long paddr;
+	struct file *file;
+};
+struct venc_pmem_list {
+	struct list_head list;
+	struct venc_buf buf;
+};
+struct venc_dev {
+	bool is_active;
+	bool pmem_freed;
+	enum venc_state_type state;
+	struct list_head venc_msg_list_head;
+	struct list_head venc_msg_list_free;
+	spinlock_t venc_msg_list_lock;
+	struct list_head venc_pmem_list_head;
+	spinlock_t venc_pmem_list_lock;
+	struct dal_client *q6_handle;
+	wait_queue_head_t venc_msg_evt;
+	struct device *class_devp;
+};
+
+#define DEBUG_VENC 0
+#if DEBUG_VENC
+#define TRACE(fmt, x...)     \
+	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
+#else
+#define TRACE(fmt, x...)         do { } while (0)
+#endif
+
+static struct cdev cdev;
+static dev_t venc_dev_num;
+static struct class *venc_class;
+static struct venc_dev *venc_device_p;
+static int venc_ref;
+
+static DEFINE_MUTEX(idlecount_lock);
+static int idlecount;
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+
+static void prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&idlelock);
+		wake_lock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static void allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static inline int venc_check_version(u32 client, u32 server)
+{
+	int ret = -EINVAL;
+
+	if ((VENC_GET_MAJOR_VERSION(client) == VENC_GET_MAJOR_VERSION(server))
+	     && (VENC_GET_MINOR_VERSION(client) <=
+		 VENC_GET_MINOR_VERSION(server)))
+		ret = 0;
+
+	return ret;
+}
+
+static int venc_get_msg(struct venc_dev *dvenc, void *msg)
+{
+	struct venc_msg_list *l;
+	unsigned long flags;
+	int ret = 0;
+	struct venc_msg qdsp_msg;
+
+	if (!dvenc->is_active)
+		return -EPERM;
+	spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
+	list_for_each_entry_reverse(l, &dvenc->venc_msg_list_head, list) {
+		memcpy(&qdsp_msg, &l->msg_data, sizeof(struct venc_msg));
+		list_del(&l->list);
+		list_add(&l->list, &dvenc->venc_msg_list_free);
+		ret = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
+	if (copy_to_user(msg, &qdsp_msg, sizeof(struct venc_msg)))
+		pr_err("%s failed to copy_to_user\n", __func__);
+	return ret;
+}
+
+static void venc_put_msg(struct venc_dev *dvenc, struct venc_msg *msg)
+{
+	struct venc_msg_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
+	list_for_each_entry(l, &dvenc->venc_msg_list_free, list) {
+		memcpy(&l->msg_data, msg, sizeof(struct venc_msg));
+		list_del(&l->list);
+		list_add(&l->list, &dvenc->venc_msg_list_head);
+		found = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
+	if (found)
+		wake_up(&dvenc->venc_msg_evt);
+	else
+		pr_err("%s: failed to find a free node\n", __func__);
+
+}
+
+static struct venc_pmem_list *venc_add_pmem_to_list(struct venc_dev *dvenc,
+						      struct venc_pmem *mptr,
+						      u32 btype)
+{
+	int ret = 0;
+	unsigned long flags;
+	unsigned long len;
+	unsigned long vaddr;
+	struct venc_pmem_list *plist = NULL;
+
+	plist = kzalloc(sizeof(struct venc_pmem_list), GFP_KERNEL);
+	if (!plist) {
+		pr_err("%s: kzalloc failed\n", __func__);
+		return NULL;
+	}
+
+	ret = get_pmem_file(mptr->fd, &(plist->buf.paddr),
+		&vaddr, &len, &(plist->buf.file));
+	if (ret) {
+		pr_err("%s: get_pmem_file failed for fd=%d offset=%d\n",
+			__func__, mptr->fd, mptr->offset);
+		goto err_venc_add_pmem;
+	} else if (mptr->offset >= len) {
+		pr_err("%s: invalid offset (%d > %ld) for fd=%d\n",
+		       __func__, mptr->offset, len, mptr->fd);
+		ret = -EINVAL;
+		goto err_venc_get_pmem;
+	}
+
+	plist->buf.fd = mptr->fd;
+	plist->buf.paddr += mptr->offset;
+	plist->buf.size = mptr->size;
+	plist->buf.btype = btype;
+	plist->buf.offset = mptr->offset;
+	plist->buf.src = mptr->src;
+
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	list_add(&plist->list, &dvenc->venc_pmem_list_head);
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+	return plist;
+
+err_venc_get_pmem:
+	put_pmem_file(plist->buf.file);
+err_venc_add_pmem:
+	kfree(plist);
+	return NULL;
+}
+
+static struct venc_pmem_list *venc_get_pmem_from_list(
+		struct venc_dev *dvenc, u32 pmem_fd,
+		u32 offset, u32 btype)
+{
+	struct venc_pmem_list *plist;
+	unsigned long flags;
+	struct file *file;
+	int found = 0;
+
+	file = fget(pmem_fd);
+	if (!file) {
+		pr_err("%s: invalid encoder buffer fd(%d)\n", __func__,
+			pmem_fd);
+		return NULL;
+	}
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) {
+		if (plist->buf.btype == btype && plist->buf.file == file &&
+			plist->buf.offset == offset) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+	fput(file);
+	if (found)
+		return plist;
+
+	else
+		return NULL;
+}
+
+static int venc_set_buffer(struct venc_dev *dvenc, void *argp,
+			     u32 btype)
+{
+	struct venc_pmem pmem;
+	struct venc_pmem_list *plist;
+	int ret = 0;
+
+	ret = copy_from_user(&pmem, argp, sizeof(pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	plist = venc_add_pmem_to_list(dvenc, &pmem, btype);
+	if (plist == NULL) {
+		pr_err("%s: buffer add_to_pmem_list failed\n",
+			__func__);
+		return -EPERM;
+	}
+	return ret;
+}
+
+static int venc_assign_q6_buffers(struct venc_dev *dvenc,
+				    struct venc_buffers *pbufs,
+				    struct venc_nonio_buf_config *pcfg)
+{
+	int ret = 0;
+	struct venc_pmem_list *plist;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[0]),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: recon_buf0 failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->recon_buf1.region = pbufs->recon_buf[0].src;
+	pcfg->recon_buf1.phys = plist->buf.paddr;
+	pcfg->recon_buf1.size = plist->buf.size;
+	pcfg->recon_buf1.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[1]),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: recons_buf1 failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->recon_buf2.region = pbufs->recon_buf[1].src;
+	pcfg->recon_buf2.phys = plist->buf.paddr;
+	pcfg->recon_buf2.size = plist->buf.size;
+	pcfg->recon_buf2.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->wb_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: wb_buf failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->wb_buf.region = pbufs->wb_buf.src;
+	pcfg->wb_buf.phys = plist->buf.paddr;
+	pcfg->wb_buf.size = plist->buf.size;
+	pcfg->wb_buf.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->cmd_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: cmd_buf failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->cmd_buf.region = pbufs->cmd_buf.src;
+	pcfg->cmd_buf.phys = plist->buf.paddr;
+	pcfg->cmd_buf.size = plist->buf.size;
+	pcfg->cmd_buf.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->vlc_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: vlc_buf failed to add_to_pmem_list"
+		" failed\n", __func__);
+		return -EPERM;
+	}
+	pcfg->vlc_buf.region = pbufs->vlc_buf.src;
+	pcfg->vlc_buf.phys = plist->buf.paddr;
+	pcfg->vlc_buf.size = plist->buf.size;
+	pcfg->vlc_buf.offset = 0;
+
+	return ret;
+}
+
+static int venc_start(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_q6_config q6_config;
+	struct venc_init_config vconfig;
+
+	dvenc->state = VENC_STATE_START;
+	ret = copy_from_user(&vconfig, argp, sizeof(struct venc_init_config));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	memcpy(&q6_config, &(vconfig.q6_config), sizeof(q6_config));
+	ret = venc_assign_q6_buffers(dvenc, &(vconfig.q6_bufs),
+		&(q6_config.buf_params));
+	if (ret != 0) {
+		pr_err("%s: assign_q6_buffers failed\n", __func__);
+		return -EPERM;
+	}
+
+	q6_config.callback_event = dvenc->q6_handle;
+	TRACE("%s: parameters: handle:%p, config:%p, callback:%p \n", __func__,
+		dvenc->q6_handle, &q6_config, q6_config.callback_event);
+	TRACE("%s: parameters:recon1:0x%x, recon2:0x%x,"
+		" wb_buf:0x%x, cmd:0x%x, vlc:0x%x\n", __func__,
+		q6_config.buf_params.recon_buf1.phys,
+		q6_config.buf_params.recon_buf2.phys,
+		q6_config.buf_params.wb_buf.phys,
+		q6_config.buf_params.cmd_buf.phys,
+		q6_config.buf_params.vlc_buf.phys);
+	TRACE("%s: size of param:%d \n", __func__, sizeof(q6_config));
+	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_START, &q6_config,
+		sizeof(q6_config));
+	if (ret != 0) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int venc_encode_frame(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_pmem buf;
+	struct venc_input_buf q6_input;
+	struct venc_pmem_list *plist;
+	struct venc_buffer input;
+
+	ret = copy_from_user(&input, argp, sizeof(struct venc_buffer));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = copy_from_user(&buf,
+			       ((struct venc_buffer *)argp)->ptr_buffer,
+			       sizeof(struct venc_pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
+			VENC_BUFFER_TYPE_INPUT);
+	if (NULL == plist) {
+		plist = venc_add_pmem_to_list(dvenc, &buf,
+			VENC_BUFFER_TYPE_INPUT);
+		if (plist == NULL) {
+			pr_err("%s: buffer add_to_pmem_list failed\n",
+				__func__);
+			return -EPERM;
+		}
+	}
+
+	q6_input.flags = 0;
+	if (input.flags & VENC_FLAG_EOS)
+		q6_input.flags |= 0x00000001;
+	q6_input.yuv_buf.region = plist->buf.src;
+	q6_input.yuv_buf.phys = plist->buf.paddr;
+	q6_input.yuv_buf.size = plist->buf.size;
+	q6_input.yuv_buf.offset = 0;
+	q6_input.data_size = plist->buf.size;
+	q6_input.client_data = (u32)input.client_data;
+	q6_input.time_stamp = input.time_stamp;
+	q6_input.dvs_offsetx = 0;
+	q6_input.dvs_offsety = 0;
+
+	TRACE("Pushing down input phys=0x%x fd= %d, client_data: 0x%x,"
+		" time_stamp:%lld \n", q6_input.yuv_buf.phys, plist->buf.fd,
+		input.client_data, input.time_stamp);
+	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_INPUT,
+		&q6_input, sizeof(q6_input));
+
+	if (ret != 0)
+		pr_err("%s: Q6 queue_input failed (%d)\n", __func__,
+		(int)ret);
+	return ret;
+}
+
+static int venc_fill_output(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_pmem buf;
+	struct venc_output_buf q6_output;
+	struct venc_pmem_list *plist;
+	struct venc_buffer output;
+
+	ret = copy_from_user(&output, argp, sizeof(struct venc_buffer));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = copy_from_user(&buf,
+			       ((struct venc_buffer *)argp)->ptr_buffer,
+			       sizeof(struct venc_pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	plist =	venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
+			VENC_BUFFER_TYPE_OUTPUT);
+	if (NULL == plist) {
+		plist = venc_add_pmem_to_list(dvenc, &buf,
+				VENC_BUFFER_TYPE_OUTPUT);
+		if (NULL == plist) {
+			pr_err("%s: output buffer failed to add_to_pmem_list"
+				"\n", __func__);
+			return -EPERM;
+		}
+	}
+	q6_output.bit_stream_buf.region = plist->buf.src;
+	q6_output.bit_stream_buf.phys = (u32)plist->buf.paddr;
+	q6_output.bit_stream_buf.size = plist->buf.size;
+	q6_output.bit_stream_buf.offset = 0;
+	q6_output.client_data = (u32)output.client_data;
+	ret =
+	    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_OUTPUT, &q6_output,
+			sizeof(q6_output));
+	if (ret != 0)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int venc_stop(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_msg msg;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
+	if (ret) {
+		pr_err("%s: remote runction failed (%d)\n", __func__, ret);
+		msg.msg_code = VENC_MSG_STOP;
+		msg.msg_data_size = 0;
+		msg.status_code = VENC_S_EFAIL;
+		venc_put_msg(dvenc, &msg);
+	}
+	return ret;
+}
+
+static int venc_pause(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_msg msg;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_SUSPEND, 1);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		msg.msg_code = VENC_MSG_PAUSE;
+		msg.status_code = VENC_S_EFAIL;
+		msg.msg_data_size = 0;
+		venc_put_msg(dvenc, &msg);
+	}
+	return ret;
+}
+
+static int venc_resume(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_msg msg;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_RESUME, 1);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		msg.msg_code = VENC_MSG_RESUME;
+		msg.msg_data_size = 0;
+		msg.status_code = VENC_S_EFAIL;
+		venc_put_msg(dvenc, &msg);
+	}
+	return ret;
+}
+
+static int venc_flush(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_msg msg;
+	union venc_msg_data smsg;
+	int status = VENC_S_SUCCESS;
+	struct venc_buffer_flush flush;
+
+	if (copy_from_user(&flush, argp, sizeof(struct venc_buffer_flush)))
+		return -EFAULT;
+	if (flush.flush_mode == VENC_FLUSH_ALL) {
+		ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_FLUSH, 1);
+		if (ret)
+			status = VENC_S_EFAIL;
+	} else
+		status = VENC_S_ENOTSUPP;
+
+	if (status != VENC_S_SUCCESS) {
+		if ((flush.flush_mode == VENC_FLUSH_INPUT) ||
+		     (flush.flush_mode == VENC_FLUSH_ALL)) {
+			smsg.flush_ret.flush_mode = VENC_FLUSH_INPUT;
+			msg.msg_data = smsg;
+			msg.status_code = status;
+			msg.msg_code = VENC_MSG_FLUSH;
+			msg.msg_data_size = sizeof(union venc_msg_data);
+			venc_put_msg(dvenc, &msg);
+		}
+		if (flush.flush_mode == VENC_FLUSH_OUTPUT ||
+		     (flush.flush_mode == VENC_FLUSH_ALL)) {
+			smsg.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
+			msg.msg_data = smsg;
+			msg.status_code = status;
+			msg.msg_code = VENC_MSG_FLUSH;
+			msg.msg_data_size = sizeof(union venc_msg_data);
+			venc_put_msg(dvenc, &msg);
+		}
+		return -EIO;
+	}
+	return ret;
+}
+
+static int venc_get_sequence_hdr(struct venc_dev *dvenc, void *argp)
+{
+	pr_err("%s not supported\n", __func__);
+	return -EIO;
+}
+
+static int venc_set_qp_range(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_qp_range qp;
+
+	ret = copy_from_user(&qp, argp, sizeof(struct venc_qp_range));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret =
+		    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_UPDATE_QP_RANGE,
+				&qp, sizeof(struct venc_qp_range));
+		if (ret) {
+			pr_err("%s: remote function failed (%d) \n", __func__,
+				ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int venc_set_intra_period(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 pnum = 0;
+
+	ret = copy_from_user(&pnum, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_INTRA_PERIOD, pnum);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_intra_refresh(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 mb_num = 0;
+
+	ret = copy_from_user(&mb_num, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_INTRA_REFRESH, mb_num);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_frame_rate(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_frame_rate pdata;
+	ret = copy_from_user(&pdata, argp, sizeof(struct venc_frame_rate));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f5(dvenc->q6_handle,
+				VENC_DALRPC_UPDATE_FRAME_RATE,
+				(void *)&(pdata),
+				sizeof(struct venc_frame_rate));
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_target_bitrate(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 pdata = 0;
+
+	ret = copy_from_user(&pdata, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_BITRATE, pdata);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_request_iframe(struct venc_dev *dvenc)
+{
+	int ret = 0;
+
+	if (dvenc->state != VENC_STATE_START)
+		return -EINVAL;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_REQUEST_IFRAME, 1);
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int venc_stop_read_msg(struct venc_dev *dvenc)
+{
+	struct venc_msg msg;
+	int ret = 0;
+
+	msg.status_code = 0;
+	msg.msg_code = VENC_MSG_STOP_READING_MSG;
+	msg.msg_data_size = 0;
+	venc_put_msg(dvenc, &msg);
+	return ret;
+}
+
+static int venc_q6_stop(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_pmem_list *plist;
+	unsigned long flags;
+
+	wake_up(&dvenc->venc_msg_evt);
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	if (!dvenc->pmem_freed) {
+		list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
+			put_pmem_file(plist->buf.file);
+		dvenc->pmem_freed = 1;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+
+	dvenc->state = VENC_STATE_STOP;
+	return ret;
+}
+
+static int venc_translate_error(enum venc_status_code q6_status)
+{
+	int ret = 0;
+
+	switch (q6_status) {
+	case VENC_STATUS_SUCCESS:
+		ret = VENC_S_SUCCESS;
+		break;
+	case VENC_STATUS_ERROR:
+		ret = VENC_S_EFAIL;
+		break;
+	case VENC_STATUS_INVALID_STATE:
+		ret = VENC_S_EINVALSTATE;
+		break;
+	case VENC_STATUS_FLUSHING:
+		ret = VENC_S_EFLUSHED;
+		break;
+	case VENC_STATUS_INVALID_PARAM:
+		ret = VENC_S_EBADPARAM;
+		break;
+	case VENC_STATUS_CMD_QUEUE_FULL:
+		ret = VENC_S_ECMDQFULL;
+		break;
+	case VENC_STATUS_CRITICAL:
+		ret = VENC_S_EFATAL;
+		break;
+	case VENC_STATUS_INSUFFICIENT_RESOURCES:
+		ret = VENC_S_ENOHWRES;
+		break;
+	case VENC_STATUS_TIMEOUT:
+		ret = VENC_S_ETIMEOUT;
+		break;
+	}
+	if (q6_status != VENC_STATUS_SUCCESS)
+		pr_err("%s: Q6 failed (%d)", __func__, (int)q6_status);
+	return ret;
+}
+
+static void venc_q6_callback(void *data, int len, void *cookie)
+{
+	int status = 0;
+	struct venc_dev *dvenc = (struct venc_dev *)cookie;
+	struct venc_msg_type *q6_msg = NULL;
+	struct venc_msg msg, msg1;
+	union venc_msg_data smsg1, smsg2;
+	unsigned long msg_code = 0;
+	struct venc_input_payload *pload1;
+	struct venc_output_payload *pload2;
+	uint32_t * tmp = (uint32_t *) data;
+
+	if (dvenc == NULL) {
+		pr_err("%s: empty driver parameter\n", __func__);
+		return;
+	}
+	if (tmp[2] == sizeof(struct venc_msg_type)) {
+		q6_msg = (struct venc_msg_type *)&tmp[3];
+	} else {
+		pr_err("%s: callback with empty message (%d, %d)\n",
+			__func__, tmp[2], sizeof(struct venc_msg_type));
+		return;
+	}
+	msg.msg_data_size = 0;
+	status = venc_translate_error(q6_msg->status);
+	switch ((enum venc_event_type_enum)q6_msg->event) {
+	case VENC_EVENT_START_STATUS:
+		dvenc->state = VENC_STATE_START;
+		msg_code = VENC_MSG_START;
+		break;
+	case VENC_EVENT_STOP_STATUS:
+		venc_q6_stop(dvenc);
+		msg_code = VENC_MSG_STOP;
+		break;
+	case VENC_EVENT_SUSPEND_STATUS:
+		dvenc->state = VENC_STATE_PAUSE;
+		msg_code = VENC_MSG_PAUSE;
+		break;
+	case VENC_EVENT_RESUME_STATUS:
+		dvenc->state = VENC_STATE_START;
+		msg_code = VENC_MSG_RESUME;
+		break;
+	case VENC_EVENT_FLUSH_STATUS:
+		smsg1.flush_ret.flush_mode = VENC_FLUSH_INPUT;
+		msg1.status_code = status;
+		msg1.msg_code = VENC_MSG_FLUSH;
+		msg1.msg_data = smsg1;
+		msg1.msg_data_size = sizeof(union venc_msg_data);
+		venc_put_msg(dvenc, &msg1);
+		smsg2.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
+		msg_code = VENC_MSG_FLUSH;
+		msg.msg_data = smsg2;
+		msg.msg_data_size = sizeof(union venc_msg_data);
+		break;
+	case VENC_EVENT_RELEASE_INPUT:
+		pload1 = &((q6_msg->payload).input_payload);
+		TRACE("Release_input: data: 0x%x \n", pload1->data);
+		if (pload1 != NULL) {
+			msg.msg_data.buf.client_data = pload1->data;
+			msg_code = VENC_MSG_INPUT_BUFFER_DONE;
+			msg.msg_data_size = sizeof(union venc_msg_data);
+		}
+		break;
+	case VENC_EVENT_DELIVER_OUTPUT:
+		pload2 = &((q6_msg->payload).output_payload);
+		smsg1.buf.flags = 0;
+		if (pload2->flags & VENC_FLAG_SYNC_FRAME)
+			smsg1.buf.flags |= VENC_FLAG_SYNC_FRAME;
+		if (pload2->flags & VENC_FLAG_CODEC_CONFIG)
+			smsg1.buf.flags |= VENC_FLAG_CODEC_CONFIG;
+		if (pload2->flags & VENC_FLAG_END_OF_FRAME)
+			smsg1.buf.flags |= VENC_FLAG_END_OF_FRAME;
+		if (pload2->flags & VENC_FLAG_EOS)
+			smsg1.buf.flags |= VENC_FLAG_EOS;
+		smsg1.buf.len = pload2->size;
+		smsg1.buf.offset = 0;
+		smsg1.buf.time_stamp = pload2->time_stamp;
+		smsg1.buf.client_data = pload2->data;
+		msg_code = VENC_MSG_OUTPUT_BUFFER_DONE;
+		msg.msg_data = smsg1;
+		msg.msg_data_size = sizeof(union venc_msg_data);
+		break;
+	default:
+		pr_err("%s: invalid response from Q6 (%d)\n", __func__,
+			(int)q6_msg->event);
+		return;
+	}
+	msg.status_code = status;
+	msg.msg_code = msg_code;
+	venc_put_msg(dvenc, &msg);
+	return;
+}
+
+static int venc_get_version(struct venc_dev *dvenc, void *argp)
+{
+	struct venc_version ver_info;
+	int ret = 0;
+
+	ver_info.major = VENC_GET_MAJOR_VERSION(VENC_INTERFACE_VERSION);
+	ver_info.minor = VENC_GET_MINOR_VERSION(VENC_INTERFACE_VERSION);
+
+	ret = copy_to_user(((struct venc_version *)argp),
+				&ver_info, sizeof(ver_info));
+	if (ret)
+		pr_err("%s failed to copy_to_user\n", __func__);
+
+	return ret;
+
+}
+
+static long q6venc_ioctl(struct file *file, u32 cmd,
+			   unsigned long arg)
+{
+	long ret = 0;
+	void __user *argp = (void __user *)arg;
+	struct venc_dev *dvenc = file->private_data;
+
+	if (!dvenc || !dvenc->is_active)
+		return -EPERM;
+
+	switch (cmd) {
+	case VENC_IOCTL_SET_INPUT_BUFFER:
+		ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_INPUT);
+		break;
+	case VENC_IOCTL_SET_OUTPUT_BUFFER:
+		ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_OUTPUT);
+		break;
+	case VENC_IOCTL_GET_SEQUENCE_HDR:
+		ret = venc_get_sequence_hdr(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_QP_RANGE:
+		ret = venc_set_qp_range(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_INTRA_PERIOD:
+		ret = venc_set_intra_period(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_INTRA_REFRESH:
+		ret = venc_set_intra_refresh(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_FRAME_RATE:
+		ret = venc_set_frame_rate(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_TARGET_BITRATE:
+		ret = venc_set_target_bitrate(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_REQUEST_IFRAME:
+		if (dvenc->state == VENC_STATE_START)
+			ret = venc_request_iframe(dvenc);
+		break;
+	case VENC_IOCTL_CMD_START:
+		ret = venc_start(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_STOP:
+		ret = venc_stop(dvenc);
+		break;
+	case VENC_IOCTL_CMD_PAUSE:
+		ret = venc_pause(dvenc);
+		break;
+	case VENC_IOCTL_CMD_RESUME:
+		ret = venc_resume(dvenc);
+		break;
+	case VENC_IOCTL_CMD_ENCODE_FRAME:
+		ret = venc_encode_frame(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER:
+		ret = venc_fill_output(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_FLUSH:
+		ret = venc_flush(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_READ_NEXT_MSG:
+		wait_event_interruptible(dvenc->venc_msg_evt,
+					  venc_get_msg(dvenc, argp));
+		break;
+	case VENC_IOCTL_CMD_STOP_READ_MSG:
+		ret = venc_stop_read_msg(dvenc);
+		break;
+	case VENC_IOCTL_GET_VERSION:
+		ret = venc_get_version(dvenc, argp);
+		break;
+	default:
+		pr_err("%s: invalid ioctl code (%d)\n", __func__, cmd);
+		ret = -ENOTTY;
+		break;
+	}
+	return ret;
+}
+
+static int q6venc_open(struct inode *inode, struct file *file)
+{
+	int i;
+	int ret = 0;
+	struct venc_dev *dvenc;
+	struct venc_msg_list *plist, *tmp;
+	struct dal_info version_info;
+
+	dvenc = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
+	if (!dvenc) {
+		pr_err("%s: unable to allocate memory for struct venc_dev\n",
+			__func__);
+		return -ENOMEM;
+	}
+	file->private_data = dvenc;
+	INIT_LIST_HEAD(&dvenc->venc_msg_list_head);
+	INIT_LIST_HEAD(&dvenc->venc_msg_list_free);
+	INIT_LIST_HEAD(&dvenc->venc_pmem_list_head);
+	init_waitqueue_head(&dvenc->venc_msg_evt);
+	spin_lock_init(&dvenc->venc_msg_list_lock);
+	spin_lock_init(&dvenc->venc_pmem_list_lock);
+	venc_ref++;
+	for (i = 0; i < VENC_MSG_MAX; i++) {
+		plist = kzalloc(sizeof(struct venc_msg_list), GFP_KERNEL);
+		if (!plist) {
+			pr_err("%s: kzalloc failed\n", __func__);
+			ret = -ENOMEM;
+			goto err_venc_create_msg_list;
+		}
+		list_add(&plist->list, &dvenc->venc_msg_list_free);
+	}
+	dvenc->q6_handle =
+	    dal_attach(DALDEVICEID_VENC_DEVICE, DALDEVICEID_VENC_PORTNAME, 1,
+		       venc_q6_callback, (void *)dvenc);
+	if (!(dvenc->q6_handle)) {
+		pr_err("%s: daldevice_attach failed (%d)\n", __func__, ret);
+		goto err_venc_dal_attach;
+	}
+	ret = dal_call_f9(dvenc->q6_handle, DAL_OP_INFO, &version_info,
+		sizeof(struct dal_info));
+	if (ret) {
+		pr_err("%s: failed to get version\n", __func__);
+		goto err_venc_dal_open;
+	}
+	if (venc_check_version(VENC_INTERFACE_VERSION, version_info.version)) {
+		pr_err("%s: driver version mismatch\n", __func__);
+		goto err_venc_dal_open;
+	}
+	ret = dal_call_f0(dvenc->q6_handle, DAL_OP_OPEN, 1);
+	if (ret) {
+		pr_err("%s: dal_call_open failed (%d)\n", __func__, ret);
+		goto err_venc_dal_open;
+	}
+	dvenc->state = VENC_STATE_STOP;
+	dvenc->is_active = 1;
+	prevent_sleep();
+	return ret;
+err_venc_dal_open:
+	dal_detach(dvenc->q6_handle);
+err_venc_dal_attach:
+	list_for_each_entry_safe(plist, tmp, &dvenc->venc_msg_list_free, list) {
+		list_del(&plist->list);
+		kfree(plist);
+	}
+err_venc_create_msg_list:
+	kfree(dvenc);
+	venc_ref--;
+	return ret;
+}
+
+static int q6venc_release(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+	struct venc_msg_list *l, *n;
+	struct venc_pmem_list *plist, *m;
+	struct venc_dev *dvenc;
+	unsigned long flags;
+
+	venc_ref--;
+	dvenc = file->private_data;
+	dvenc->is_active = 0;
+	wake_up_all(&dvenc->venc_msg_evt);
+	dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
+	dal_call_f0(dvenc->q6_handle, DAL_OP_CLOSE, 1);
+	dal_detach(dvenc->q6_handle);
+	list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_free, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+	list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_head, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	if (!dvenc->pmem_freed) {
+		list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
+			put_pmem_file(plist->buf.file);
+		dvenc->pmem_freed = 1;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+
+	list_for_each_entry_safe(plist, m, &dvenc->venc_pmem_list_head, list) {
+		list_del(&plist->list);
+		kfree(plist);
+	}
+	kfree(dvenc);
+	allow_sleep();
+	return ret;
+}
+
+const struct file_operations q6venc_fops = {
+	.owner = THIS_MODULE,
+	.open = q6venc_open,
+	.release = q6venc_release,
+	.unlocked_ioctl = q6venc_ioctl,
+};
+
+static int __init q6venc_init(void)
+{
+	int ret = 0;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "venc_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "venc_suspend");
+
+	venc_device_p = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
+	if (!venc_device_p) {
+		pr_err("%s: unable to allocate memory for venc_device_p\n",
+			__func__);
+		return -ENOMEM;
+	}
+	ret = alloc_chrdev_region(&venc_dev_num, 0, 1, VENC_NAME);
+	if (ret < 0) {
+		pr_err("%s: alloc_chrdev_region failed (%d)\n", __func__,
+			ret);
+		return ret;
+	}
+	venc_class = class_create(THIS_MODULE, VENC_NAME);
+	if (IS_ERR(venc_class)) {
+		ret = PTR_ERR(venc_class);
+		pr_err("%s: failed to create venc_class (%d)\n",
+			__func__, ret);
+		goto err_venc_class_create;
+	}
+	venc_device_p->class_devp =
+	    device_create(venc_class, NULL, venc_dev_num, NULL,
+			  VENC_NAME);
+	if (IS_ERR(venc_device_p->class_devp)) {
+		ret = PTR_ERR(venc_device_p->class_devp);
+		pr_err("%s: failed to create class_device (%d)\n", __func__,
+			ret);
+		goto err_venc_class_device_create;
+	}
+	cdev_init(&cdev, &q6venc_fops);
+	cdev.owner = THIS_MODULE;
+	ret = cdev_add(&cdev, venc_dev_num, 1);
+	if (ret < 0) {
+		pr_err("%s: cdev_add failed (%d)\n", __func__, ret);
+		goto err_venc_cdev_add;
+	}
+	init_waitqueue_head(&venc_device_p->venc_msg_evt);
+	return ret;
+
+err_venc_cdev_add:
+	device_destroy(venc_class, venc_dev_num);
+err_venc_class_device_create:
+	class_destroy(venc_class);
+err_venc_class_create:
+	unregister_chrdev_region(venc_dev_num, 1);
+	return ret;
+}
+
+static void __exit q6venc_exit(void)
+{
+	cdev_del(&(cdev));
+	device_destroy(venc_class, venc_dev_num);
+	class_destroy(venc_class);
+	unregister_chrdev_region(venc_dev_num, 1);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Video encoder driver for QDSP6");
+MODULE_VERSION("2.0");
+module_init(q6venc_init);
+module_exit(q6venc_exit);
diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c
new file mode 100644
index 0000000..c6bddb8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/pcm_in.c
@@ -0,0 +1,263 @@
+/* arch/arm/mach-msm/qdsp6/pcm_in.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct pcm {
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	uint32_t buffer_size;
+	uint32_t rec_mode;
+};
+
+#define BUFSZ (256)
+
+void audio_client_dump(struct audio_client *ac);
+
+static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS: {
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		rc = 0;
+
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (pcm->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			pcm->ac = q6audio_open_pcm(pcm->buffer_size,
+					pcm->sample_rate, pcm->channel_count,
+					pcm->rec_mode, acdb_id);
+			if (!pcm->ac) {
+				pr_err("[%s:%s] pcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (!config.channel_count || config.channel_count > 2) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+			__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		if (config.buffer_size < 128 || config.buffer_size > 8192) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid buffsize %d\n", __MM_FILE__,
+				__func__, config.buffer_size);
+			break;
+		}
+
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		break;
+	}
+	case AUDIO_SET_INCALL: {
+		struct msm_voicerec_mode voicerec_mode;
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&voicerec_mode, (void *)arg,
+			sizeof(struct msm_voicerec_mode)))
+			return -EFAULT;
+		if (voicerec_mode.rec_mode != AUDIO_FLAG_READ &&
+			voicerec_mode.rec_mode != AUDIO_FLAG_INCALL_MIXED) {
+			pcm->rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		} else
+			pcm->rec_mode = voicerec_mode.rec_mode;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = 2;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_in_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	pcm->channel_count = 1;
+	pcm->sample_rate = 8000;
+	pcm->buffer_size = BUFSZ;
+	pcm->rec_mode = AUDIO_FLAG_READ;
+	file->private_data = pcm;
+	return 0;
+}
+
+static ssize_t q6_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+	int res;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	ac = pcm->ac;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
+				audio_client_dump(ac);
+				pr_err("[%s:%s] timeout. dsp dead?\n",
+						__MM_FILE__, __func__);
+				q6audio_dsp_not_responding();
+			}
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+fail:
+	res = buf - start;
+	return res;
+}
+
+static int q6_in_release(struct inode *inode, struct file *file)
+{
+
+	int rc = 0;
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		rc = q6audio_close(pcm->ac);
+	kfree(pcm);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static struct file_operations q6_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_in_open,
+	.read		= q6_in_read,
+	.release	= q6_in_release,
+	.unlocked_ioctl	= q6_in_ioctl,
+};
+
+struct miscdevice q6_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &q6_in_fops,
+};
+
+static int __init q6_in_init(void) {
+	return misc_register(&q6_in_misc);
+}
+
+device_initcall(q6_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/pcm_out.c b/arch/arm/mach-msm/qdsp6/pcm_out.c
new file mode 100644
index 0000000..2e91cb2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/pcm_out.c
@@ -0,0 +1,276 @@
+/* arch/arm/mach-msm/qdsp6/pcm_out.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * 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/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+void audio_client_dump(struct audio_client *ac);
+
+#define BUFSZ (3072)
+
+struct pcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	size_t buffer_size;
+};
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (!pcm->ac) {
+			pr_err("%s: cannot set volume before AUDIO_START!\n",
+				__func__);
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_VOLUME: vol = %d\n", __MM_FILE__,
+			__func__, vol);
+		rc = q6audio_set_stream_volume(pcm->ac, vol);
+		break;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (pcm->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			pcm->ac = q6audio_open_pcm(pcm->buffer_size,
+						pcm->sample_rate,
+						pcm->channel_count,
+						AUDIO_FLAG_WRITE, acdb_id);
+			if (!pcm->ac) {
+				pr_err("[%s:%s] pcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (pcm->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+			__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		if (config.buffer_size < 128 || config.buffer_size > 8192) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid buffsize %d\n", __MM_FILE__,
+				__func__, config.buffer_size);
+			break;
+		}
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = 2;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	case AUDIO_SET_EQ: {
+		struct msm_audio_eq_stream_config eq_config;
+		pr_debug("[%s:%s] SET_EQ\n", __MM_FILE__, __func__);
+		if (copy_from_user(&eq_config, (void *) arg,
+						sizeof(eq_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6audio_set_stream_eq_pcm(pcm->ac, (void *) &eq_config);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&pcm->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int pcm_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	mutex_init(&pcm->lock);
+	pcm->channel_count = 2;
+	pcm->sample_rate = 44100;
+	pcm->buffer_size = BUFSZ;
+	file->private_data = pcm;
+	return 0;
+}
+
+static ssize_t pcm_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	if (!pcm->ac)
+		pcm_ioctl(file, AUDIO_START, 0);
+
+	ac = pcm->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
+				audio_client_dump(ac);
+				pr_err("[%s:%s] timeout. dsp dead?\n",
+						__MM_FILE__, __func__);
+				q6audio_dsp_not_responding();
+			}
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer)) 
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		ab->actual_size = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int pcm_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		q6audio_close(pcm->ac);
+	kfree(pcm);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_open,
+	.write		= pcm_write,
+	.release	= pcm_release,
+	.unlocked_ioctl	= pcm_ioctl,
+};
+
+struct miscdevice pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_fops,
+};
+
+static int __init pcm_init(void) {
+	return misc_register(&pcm_misc);
+}
+
+device_initcall(pcm_init);
diff --git a/arch/arm/mach-msm/qdsp6/q6audio.c b/arch/arm/mach-msm/qdsp6/q6audio.c
new file mode 100644
index 0000000..bf6f115
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/q6audio.c
@@ -0,0 +1,2155 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * 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/slab.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/android_pmem.h>
+#include <linux/firmware.h>
+#include <linux/miscdevice.h>
+
+#include "dal.h"
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include "dal_acdb.h"
+#include "dal_adie.h"
+#include <mach/msm_qdsp6_audio.h>
+
+#include <linux/msm_audio_aac.h>
+
+#include <linux/gpio.h>
+
+#include "q6audio_devices.h"
+#include <mach/debug_mm.h>
+
+
+struct q6_hw_info {
+	int min_gain;
+	int max_gain;
+};
+
+/* TODO: provide mechanism to configure from board file */
+
+static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
+	[Q6_HW_HANDSET] = {
+		.min_gain = -400,
+		.max_gain = 1100,
+	},
+	[Q6_HW_HEADSET] = {
+		.min_gain = -1100,
+		.max_gain = 400,
+	},
+	[Q6_HW_SPEAKER] = {
+		.min_gain = -1000,
+		.max_gain = 500,
+	},
+	[Q6_HW_TTY] = {
+		.min_gain = 0,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_SCO] = {
+		.min_gain = -1100,
+		.max_gain = 400,
+	},
+	[Q6_HW_BT_A2DP] = {
+		.min_gain = -1100,
+		.max_gain = 400,
+	},
+};
+
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+static int idlecount;
+static DEFINE_MUTEX(idlecount_lock);
+
+void audio_prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&wakelock);
+		wake_lock(&idlelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+void audio_allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static struct clk *icodec_rx_clk;
+static struct clk *icodec_tx_clk;
+static struct clk *ecodec_clk;
+static struct clk *sdac_clk;
+
+static struct q6audio_analog_ops default_analog_ops;
+static struct q6audio_analog_ops *analog_ops = &default_analog_ops;
+static uint32_t tx_clk_freq = 8000;
+static int tx_mute_status = 0;
+static int rx_vol_level = 100;
+static uint32_t tx_acdb = 0;
+static uint32_t rx_acdb = 0;
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops)
+{
+	analog_ops = ops;
+}
+
+static struct q6_device_info *q6_lookup_device(uint32_t device_id,
+						uint32_t acdb_id)
+{
+	struct q6_device_info *di = q6_audio_devices;
+
+	pr_debug("[%s:%s] device_id = 0x%x, acdb_id = %d\n", __MM_FILE__,
+		__func__, device_id, acdb_id);
+	if (acdb_id) {
+		for (;;) {
+			if (di->cad_id == acdb_id && di->id == device_id)
+				return di;
+			if (di->id == 0) {
+				pr_err("[%s:%s] bogus id 0x%08x\n",
+					__MM_FILE__, __func__, device_id);
+				return di;
+			}
+			di++;
+		}
+	} else {
+		for (;;) {
+			if (di->id == device_id)
+				return di;
+			if (di->id == 0) {
+				pr_err("[%s:%s] bogus id 0x%08x\n",
+					__MM_FILE__, __func__, device_id);
+				return di;
+			}
+			di++;
+		}
+	}
+}
+
+static uint32_t q6_device_to_codec(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->codec;
+}
+
+static uint32_t q6_device_to_dir(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->dir;
+}
+
+static uint32_t q6_device_to_cad_id(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->cad_id;
+}
+
+static uint32_t q6_device_to_path(uint32_t device_id, uint32_t acdb_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, acdb_id);
+	return di->path;
+}
+
+static uint32_t q6_device_to_rate(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->rate;
+}
+
+int q6_device_volume(uint32_t device_id, int level)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	struct q6_hw_info *hw;
+
+	hw = &q6_audio_hw[di->hw];
+
+	return hw->min_gain + ((hw->max_gain - hw->min_gain) * level) / 100;
+}
+
+static inline int adie_open(struct dal_client *client) 
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return dal_call_f0(client, DAL_OP_OPEN, 0);
+}
+
+static inline int adie_close(struct dal_client *client) 
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return dal_call_f0(client, DAL_OP_CLOSE, 0);
+}
+
+static inline int adie_set_path(struct dal_client *client,
+				uint32_t id, uint32_t path_type)
+{
+	pr_debug("[%s:%s] id = 0x%x, path_type = %d\n", __MM_FILE__,
+		__func__, id, path_type);
+	return dal_call_f1(client, ADIE_OP_SET_PATH, id, path_type);
+}
+
+static inline int adie_set_path_freq_plan(struct dal_client *client,
+					  uint32_t path_type, uint32_t plan) 
+{
+	pr_debug("[%s:%s] path_type = %d, plan = %d\n",	__MM_FILE__,
+		__func__, path_type, plan);
+	return dal_call_f1(client, ADIE_OP_SET_PATH_FREQUENCY_PLAN,
+			   path_type, plan);
+}
+
+static inline int adie_proceed_to_stage(struct dal_client *client,
+					uint32_t path_type, uint32_t stage)
+{
+	pr_debug("[%s:%s] path_type = %d, stage = 0x%x\n", __MM_FILE__,
+		__func__, path_type, stage);
+	return dal_call_f1(client, ADIE_OP_PROCEED_TO_STAGE,
+			   path_type, stage);
+}
+
+static inline int adie_mute_path(struct dal_client *client,
+				 uint32_t path_type, uint32_t mute_state)
+{
+	pr_debug("[%s:%s] path_type = %d, mute = %d\n",	__MM_FILE__, __func__,
+		 path_type, mute_state);
+	return dal_call_f1(client, ADIE_OP_MUTE_PATH, path_type, mute_state);
+}
+
+static int adie_refcount;
+
+static struct dal_client *adie;
+static struct dal_client *adsp;
+static struct dal_client *acdb;
+
+static int adie_enable(void)
+{
+	adie_refcount++;
+	if (adie_refcount == 1)
+		adie_open(adie);
+	return 0;
+}
+
+static int adie_disable(void)
+{
+	adie_refcount--;
+	if (adie_refcount == 0)
+		adie_close(adie);
+	return 0;
+}
+
+/* 4k PMEM used for exchanging acdb device config tables
+ * and stream format descriptions with the DSP.
+ */
+static char *audio_data;
+static int32_t audio_phys;
+
+#define SESSION_MIN 0
+#define SESSION_MAX 64
+
+static DEFINE_MUTEX(session_lock);
+static DEFINE_MUTEX(audio_lock);
+
+static struct audio_client *session[SESSION_MAX];
+
+static int session_alloc(struct audio_client *ac)
+{
+	int n;
+
+	mutex_lock(&session_lock);
+	for (n = SESSION_MIN; n < SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			pr_debug("[%s:%s] session = %d\n", __MM_FILE__,
+				__func__, n);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void session_free(int n, struct audio_client *ac)
+{
+	mutex_lock(&session_lock);
+	if (session[n] == ac) {
+		session[n] = 0;
+		pr_debug("[%s:%s] session = %d\n", __MM_FILE__, __func__, n);
+	}
+	mutex_unlock(&session_lock);
+}
+
+static void audio_client_free(struct audio_client *ac)
+{
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	session_free(ac->session, ac);
+
+	if (ac->buf[0].data) {
+		iounmap(ac->buf[0].data);
+		pmem_kfree(ac->buf[0].phys);
+	}
+	if (ac->buf[1].data) {
+		iounmap(ac->buf[1].data);
+		pmem_kfree(ac->buf[1].phys);
+	}
+	kfree(ac);
+}
+
+static struct audio_client *audio_client_alloc(unsigned bufsz)
+{
+	struct audio_client *ac;
+	int n;
+
+	pr_debug("[%s:%s] bufsz = %d\n", __MM_FILE__, __func__, bufsz);
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return 0;
+
+	n = session_alloc(ac);
+	if (n < 0)
+		goto fail_session;
+	ac->session = n;
+
+	if (bufsz > 0) {
+		ac->buf[0].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[0].data = ioremap(ac->buf[0].phys, bufsz);
+		if (!ac->buf[0].data)
+			goto fail;
+		ac->buf[1].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[1].data = ioremap(ac->buf[1].phys, bufsz);
+		if (!ac->buf[1].data)
+			goto fail;
+
+		ac->buf[0].size = bufsz;
+		ac->buf[1].size = bufsz;
+	}
+
+	init_waitqueue_head(&ac->wait);
+	ac->client = adsp;
+
+	return ac;
+
+fail:
+	session_free(n, ac);
+fail_session:
+	audio_client_free(ac);
+	return 0;
+}
+
+void audio_client_dump(struct audio_client *ac)
+{
+	dal_trace_dump(ac->client);
+}
+
+static int audio_ioctl(struct audio_client *ac, void *ptr, uint32_t len)
+{
+	struct adsp_command_hdr *hdr = ptr;
+	uint32_t tmp;
+	int r;
+
+	hdr->size = len - sizeof(u32);
+	hdr->dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	hdr->src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_APP);
+	hdr->context = ac->session;
+	ac->cb_status = -EBUSY;
+	r = dal_call(ac->client, AUDIO_OP_CONTROL, 5, ptr, len, &tmp, sizeof(tmp));
+	if (r != 4)
+		return -EIO;
+	if (!wait_event_timeout(ac->wait, (ac->cb_status != -EBUSY), 5*HZ)) {
+		dal_trace_dump(ac->client);
+		pr_err("[%s:%s] timeout. dsp dead?\n", __MM_FILE__, __func__);
+		q6audio_dsp_not_responding();
+	}
+	return ac->cb_status;
+}
+
+static int audio_command(struct audio_client *ac, uint32_t cmd)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = cmd;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_open_control(struct audio_client *ac)
+{
+	struct adsp_open_command rpc;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_out_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+	rpc.buf_max_size = bufsz;
+
+	pr_debug("[%s:%s]ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_in_open(struct audio_client *ac, uint32_t bufsz,
+			 uint32_t flags, uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+
+	rpc.buf_max_size = bufsz;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_auxpcm_out_open(struct audio_client *ac,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.mode =  ADSP_AUDIO_OPEN_STREAM_MODE_AUX_PCM;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_auxpcm_in_open(struct audio_client *ac, uint32_t rate,
+		uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.mode =  ADSP_AUDIO_OPEN_STREAM_MODE_AUX_PCM;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_mp3_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_MP3;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+	rpc.buf_max_size = bufsz;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_dtmf_open(struct audio_client *ac,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_DTMF;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_aac_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t sample_rate, uint32_t channels,
+			  uint32_t bit_rate, uint32_t flags,
+					uint32_t stream_format)
+{
+	struct adsp_open_command rpc;
+	int audio_object_type;
+	int index = sizeof(u32);
+	u32 *aac_type = NULL;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.binary.format = ADSP_AUDIO_FORMAT_MPEG4_AAC;
+	/* only 48k sample rate is supported */
+	sample_rate = 3;
+	/* AAC OBJECT LC */
+	audio_object_type = 2;
+
+	aac_type = (u32 *)rpc.format.binary.data;
+	switch (stream_format) {
+	case AUDIO_AAC_FORMAT_ADTS:
+		/* AAC Encoder expect MPEG4_ADTS media type */
+		*aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS;
+	break;
+	case AUDIO_AAC_FORMAT_RAW:
+		/* for ADIF recording */
+		*aac_type = ADSP_AUDIO_AAC_RAW;
+	break;
+	}
+
+	rpc.format.binary.data[index++] = (u8)(
+			((audio_object_type & 0x1F) << 3) |
+			((sample_rate >> 1) & 0x7));
+			rpc.format.binary.data[index] = (u8)(
+			((sample_rate & 0x1) << 7) |
+			((channels & 0x7) << 3));
+	rpc.format.binary.num_bytes = index + 1;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+
+	rpc.buf_max_size = bufsz;
+	rpc.config.aac.bit_rate = bit_rate;
+	rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE;
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_qcp_open(struct audio_client *ac, uint32_t bufsz,
+				uint32_t min_rate, uint32_t max_rate,
+				uint32_t flags, uint32_t format)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = format;
+	rpc.format.standard.channels = 1;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = 8000;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+	rpc.buf_max_size = bufsz;
+	rpc.config.evrc.min_rate = min_rate;
+	rpc.config.evrc.max_rate = max_rate;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_amrnb_open(struct audio_client *ac, uint32_t bufsz,
+					uint32_t enc_mode, uint32_t flags,
+					uint32_t dtx_enable)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_AMRNB_FS;
+	rpc.format.standard.channels = 1;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = 8000;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+
+	rpc.buf_max_size = bufsz;
+	rpc.config.amr.mode = enc_mode;
+	rpc.config.amr.dtx_mode = dtx_enable;
+	rpc.config.amr.enable = 1;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+
+
+static int audio_close(struct audio_client *ac)
+{
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_STOP);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_CLOSE);
+	return 0;
+}
+
+static int audio_set_table(struct audio_client *ac,
+			   uint32_t device_id, int size)
+{
+	struct adsp_set_dev_cfg_table_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE;
+	if (q6_device_to_dir(device_id) == Q6_TX) {
+		if (tx_clk_freq > 16000)
+			rpc.hdr.data = 48000;
+		else if (tx_clk_freq > 8000)
+			rpc.hdr.data = 16000;
+		else
+			rpc.hdr.data = 8000;
+	}
+	rpc.device_id = device_id;
+	rpc.phys_addr = audio_phys;
+	rpc.phys_size = size;
+	rpc.phys_used = size;
+
+	pr_debug("[%s:%s] ac = %p, device_id = 0x%x, size = %d\n", __MM_FILE__,
+		__func__, ac, device_id, size);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	rpc.hdr.src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_APP);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_TX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	rpc.hdr.src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_APP);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_RX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+static int audio_rx_volume(struct audio_client *ac, uint32_t dev_id, int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	pr_debug("[%s:%s] volume = %d\n", __MM_FILE__, __func__, volume);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_rx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	pr_debug("[%s:%s] mute = %d, dev_id = 0x%x\n", __MM_FILE__,
+			__func__, mute, dev_id);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	pr_debug("[%s:%s] mute = %d\n", __MM_FILE__, __func__, mute);
+	if (mute < 0  ||  mute > 3) {
+		pr_err("[%s:%s] invalid mute status %d\n", __MM_FILE__,
+				__func__, mute);
+		return -EINVAL;
+	}
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	if ((mute == STREAM_UNMUTE) || (mute == STREAM_MUTE)) {
+		rpc.device_id = ADSP_AUDIO_DEVICE_ID_VOICE;
+		rpc.path = ADSP_PATH_TX_CNG_DIS;
+	} else {
+		rpc.device_id = dev_id;
+		rpc.path = ADSP_PATH_TX;
+	}
+	mute &= 0x01;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_stream_volume(struct audio_client *ac, int volume)
+{
+	struct adsp_set_volume_command rpc;
+	int rc;
+
+	pr_debug("[%s:%s] volume = %d\n", __MM_FILE__, __func__, volume);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL;
+	rpc.volume = volume;
+	rc = audio_ioctl(ac, &rpc, sizeof(rpc));
+	return rc;
+}
+
+static int audio_stream_mute(struct audio_client *ac, int mute)
+{
+	struct adsp_set_mute_command rpc;
+	int rc;
+
+	pr_debug("[%s:%s] mute = %d\n", __MM_FILE__, __func__, mute);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;
+	rpc.mute = mute;
+	rc = audio_ioctl(ac, &rpc, sizeof(rpc));
+	return rc;
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct adsp_event_hdr *e = data;
+	struct audio_client *ac;
+	struct adsp_buffer_event *abe = data;
+
+	if (e->context >= SESSION_MAX) {
+		pr_err("[%s:%s] bogus session %d\n", __MM_FILE__, __func__,
+				e->context);
+		return;
+	}
+	ac = session[e->context];
+	if (!ac) {
+		pr_err("[%s:%s] unknown session %d\n", __MM_FILE__, __func__,
+				e->context);
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_IOCTL_CMD_STREAM_EOS) {
+		pr_debug("[%s:%s] CB Stream eos, ac = %p\n",
+			__MM_FILE__, __func__, ac);
+		if (e->status)
+			pr_err("[%s:%s] playback status %d\n", __MM_FILE__,
+					__func__, e->status);
+		if (ac->cb_status == -EBUSY) {
+			ac->cb_status = e->status;
+			wake_up(&ac->wait);
+		}
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) {
+		pr_debug("[%s:%s] CB done, ac = %p, status = %d\n",
+				__MM_FILE__, __func__, ac, e->status);
+		if (e->status)
+			pr_err("[%s:%s] buffer status %d\n", __MM_FILE__,
+					__func__, e->status);
+
+		ac->buf[ac->dsp_buf].actual_size = abe->buffer.actual_size;
+		ac->buf[ac->dsp_buf].used = 0;
+		ac->dsp_buf ^= 1;
+		wake_up(&ac->wait);
+		return;
+	}
+
+	pr_debug("[%s:%s] ac = %p, event_id = 0x%x, status = %d\n",
+			__MM_FILE__, __func__, ac, e->event_id, e->status);
+	if (e->status)
+		pr_warning("audio_cb: s=%d e=%08x status=%d\n",
+			   e->context, e->event_id, e->status);
+	if (ac->cb_status == -EBUSY) {
+		ac->cb_status = e->status;
+		wake_up(&ac->wait);
+	}
+}
+
+static void audio_init(struct dal_client *client)
+{
+	u32 tmp[3];
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	tmp[0] = 2 * sizeof(u32);
+	tmp[1] = 0;
+	tmp[2] = 0;
+	dal_call(client, AUDIO_OP_INIT, 5, tmp, sizeof(tmp),
+		 tmp, sizeof(u32));
+}
+
+static struct audio_client *ac_control;
+
+static int q6audio_init(void)
+{
+	struct audio_client *ac = 0;
+	int res;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	mutex_lock(&audio_lock);
+	if (ac_control) {
+		res = 0;
+		goto done;
+	}
+
+	pr_info("[%s:%s] codecs\n", __MM_FILE__, __func__);
+	icodec_rx_clk = clk_get(0, "icodec_rx_clk");
+	icodec_tx_clk = clk_get(0, "icodec_tx_clk");
+	ecodec_clk = clk_get(0, "ecodec_clk");
+	sdac_clk = clk_get(0, "sdac_clk");
+	audio_phys = pmem_kalloc(4096, PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+	audio_data = ioremap(audio_phys, 4096);
+
+	pr_info("[%s:%s] attach ADSP\n", __MM_FILE__, __func__);
+	adsp = dal_attach(AUDIO_DAL_DEVICE, AUDIO_DAL_PORT, 1,
+			  callback, 0);
+	if (!adsp) {
+		pr_err("[%s:%s] cannot attach to adsp\n", __MM_FILE__,
+				__func__);
+		res = -ENODEV;
+		goto done;
+	}
+	pr_info("[%s:%s] INIT\n", __MM_FILE__, __func__);
+	audio_init(adsp);
+	dal_trace(adsp);
+
+	ac = audio_client_alloc(0);
+	if (!ac) {
+		pr_err("[%s:%s] cannot allocate client\n",
+				__MM_FILE__, __func__);
+		res = -ENOMEM;
+		goto done;
+	}
+
+	pr_info("[%s:%s] OPEN control\n", __MM_FILE__, __func__);
+	if (audio_open_control(ac)) {
+		pr_err("[%s:%s] cannot open control channel\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+
+	pr_info("[%s:%s] attach ACDB\n", __MM_FILE__, __func__);
+	acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0, 0);
+	if (!acdb) {
+		pr_err("[%s:%s] cannot attach to acdb channel\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+
+	pr_info("[%s:%s] attach ADIE\n", __MM_FILE__, __func__);
+	adie = dal_attach(ADIE_DAL_DEVICE, ADIE_DAL_PORT, 0, 0, 0);
+	if (!adie) {
+		pr_err("[%s:%s] cannot attach to adie\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+	if (analog_ops->init)
+		analog_ops->init();
+
+	res = 0;
+	ac_control = ac;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "audio_pcm_suspend");
+done:
+	if ((res < 0) && ac)
+		audio_client_free(ac);
+	mutex_unlock(&audio_lock);
+
+	pr_debug("[%s:%s] res = %d\n", __MM_FILE__, __func__, res);
+	return res;
+}
+
+struct audio_config_data {
+	uint32_t device_id;
+	uint32_t sample_rate;
+	uint32_t offset;
+	uint32_t length;
+};
+
+struct audio_config_database {
+	uint8_t magic[8];
+	uint32_t entry_count;
+	uint32_t unused;
+	struct audio_config_data entry[0];
+};
+
+void *acdb_data;
+const struct firmware *acdb_fw;
+extern struct miscdevice q6_control_device;
+
+static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate)
+{
+	struct acdb_cmd_device_table rpc;
+	struct acdb_result res;
+	int r;
+
+	pr_debug("[%s:%s] device_id = 0x%x, samplerate = %d\n", __MM_FILE__,
+		__func__, device_id, sample_rate);
+	if (q6audio_init())
+		return 0;
+
+	memset(audio_data, 0, 4096);
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.size = sizeof(rpc) - (2 * sizeof(uint32_t));
+	rpc.command_id = ACDB_GET_DEVICE_TABLE;
+	rpc.device_id = device_id;
+	rpc.sample_rate_id = sample_rate;
+	rpc.total_bytes = 4096;
+	rpc.unmapped_buf = audio_phys;
+	rpc.res_size = sizeof(res) - (2 * sizeof(uint32_t));
+
+	r = dal_call(acdb, ACDB_OP_IOCTL, 8, &rpc, sizeof(rpc),
+		&res, sizeof(res));
+
+	if ((r == sizeof(res)) && (res.dal_status == 0))
+		return res.used_bytes;
+
+	return -EIO;
+}
+
+static uint32_t audio_rx_path_id = ADIE_PATH_HANDSET_RX;
+static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR;
+static uint32_t audio_rx_device_group = -1;
+static uint32_t audio_tx_path_id = ADIE_PATH_HANDSET_TX;
+static uint32_t audio_tx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC;
+static uint32_t audio_tx_device_group = -1;
+
+static int qdsp6_devchg_notify(struct audio_client *ac,
+			       uint32_t dev_type, uint32_t dev_id)
+{
+	struct adsp_device_switch_command rpc;
+
+	if (dev_type != ADSP_AUDIO_RX_DEVICE &&
+	    dev_type != ADSP_AUDIO_TX_DEVICE)
+		return -EINVAL;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE;
+	if (dev_type == ADSP_AUDIO_RX_DEVICE) {
+		rpc.old_device = audio_rx_device_id;
+		rpc.new_device = dev_id;
+	} else {
+		rpc.old_device = audio_tx_device_id;
+		rpc.new_device = dev_id;
+	}
+	rpc.device_class = 0;
+	rpc.device_type = dev_type;
+	pr_debug("[%s:%s] dev_id = 0x%x\n", __MM_FILE__, __func__, dev_id);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int qdsp6_standby(struct audio_client *ac)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY);
+}
+
+static int qdsp6_start(struct audio_client *ac)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT);
+}
+
+static void audio_rx_analog_enable(int en)
+{
+	pr_debug("[%s:%s] audio_rx_device_id = 0x%x, en = %d\n", __MM_FILE__,
+		__func__, audio_rx_device_id, en);
+	switch (audio_rx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO:
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO:
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR:
+		if (analog_ops->receiver_enable)
+			analog_ops->receiver_enable(en);
+		break;
+	}
+}
+
+static void audio_tx_analog_enable(int en)
+{
+	pr_debug("[%s:%s] audio_tx_device_id = 0x%x, en = %d\n", __MM_FILE__,
+		__func__, audio_tx_device_id, en);
+	switch (audio_tx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC:
+		if (analog_ops->int_mic_enable)
+			analog_ops->int_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC:
+		if (analog_ops->ext_mic_enable)
+			analog_ops->ext_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static int audio_update_acdb(uint32_t adev, uint32_t acdb_id)
+{
+	uint32_t sample_rate;
+	int sz;
+
+	pr_debug("[%s:%s] adev = 0x%x, acdb_id = 0x%x\n", __MM_FILE__,
+		__func__, adev, acdb_id);
+	if (q6_device_to_dir(adev) == Q6_RX) {
+		rx_acdb = acdb_id;
+		sample_rate = q6_device_to_rate(adev);
+	} else {
+
+		tx_acdb = acdb_id;
+		if (tx_clk_freq > 16000)
+			sample_rate = 48000;
+		else if (tx_clk_freq > 8000)
+			sample_rate = 16000;
+		else
+			sample_rate = 8000;
+	}
+
+	if (acdb_id == 0)
+		acdb_id = q6_device_to_cad_id(adev);
+
+	sz = acdb_get_config_table(acdb_id, sample_rate);
+	audio_set_table(ac_control, adev, sz);
+
+	return 0;
+}
+
+static void adie_rx_path_enable(uint32_t acdb_id)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	if (audio_rx_path_id) {
+		adie_enable();
+		adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX);
+		adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000);
+
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_READY);
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_ANALOG_READY);
+	}
+}
+
+static void q6_rx_path_enable(int reconf, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	if (!reconf)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id);
+	audio_update_acdb(audio_rx_device_id, acdb_id);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+}
+
+static void _audio_rx_path_enable(int reconf, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] reconf = %d\n", __MM_FILE__, __func__, reconf);
+	q6_rx_path_enable(reconf, acdb_id);
+	if (audio_rx_path_id)
+		adie_rx_path_enable(acdb_id);
+	audio_rx_analog_enable(1);
+}
+
+static void _audio_tx_path_enable(int reconf, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] reconf = %d, tx_clk_freq = %d\n", __MM_FILE__,
+			__func__, reconf, tx_clk_freq);
+	audio_tx_analog_enable(1);
+
+	if (audio_tx_path_id) {
+		adie_enable();
+		adie_set_path(adie, audio_tx_path_id, ADIE_PATH_TX);
+
+		if (tx_clk_freq > 16000)
+			adie_set_path_freq_plan(adie, ADIE_PATH_TX, 48000);
+		else if (tx_clk_freq > 8000)
+			adie_set_path_freq_plan(adie, ADIE_PATH_TX, 16000);
+		else
+			adie_set_path_freq_plan(adie, ADIE_PATH_TX, 8000);
+
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_DIGITAL_READY);
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_DIGITAL_ANALOG_READY);
+	}
+
+
+	if (!reconf)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+				audio_tx_device_id);
+	audio_update_acdb(audio_tx_device_id, acdb_id);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+
+	audio_tx_mute(ac_control, audio_tx_device_id, tx_mute_status);
+}
+
+static void _audio_rx_path_disable(void)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	audio_rx_analog_enable(0);
+
+	if (audio_rx_path_id) {
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_ANALOG_OFF);
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_OFF);
+		adie_disable();
+	}
+}
+
+static void _audio_tx_path_disable(void)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	audio_tx_analog_enable(0);
+
+	if (audio_tx_path_id) {
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_ANALOG_OFF);
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_DIGITAL_OFF);
+		adie_disable();
+	}
+}
+
+static int icodec_rx_clk_refcount;
+static int icodec_tx_clk_refcount;
+static int ecodec_clk_refcount;
+static int sdac_clk_refcount;
+
+static void ecodec_clk_enable(void)
+{
+	ecodec_clk_refcount++;
+	if (ecodec_clk_refcount == 1) {
+		clk_set_rate(ecodec_clk, 2048000);
+		clk_enable(ecodec_clk);
+	}
+}
+static void ecodec_clk_disable(int group_reset, int path)
+{
+	ecodec_clk_refcount--;
+	if (ecodec_clk_refcount == 0) {
+		clk_disable(ecodec_clk);
+		if (group_reset) {
+			if (path == ADSP_PATH_TX)
+				audio_tx_device_group = -1;
+			else
+				audio_rx_device_group = -1;
+		}
+	}
+}
+static void _audio_rx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_rx_device_id);
+
+	pr_debug("[%s:%s] rx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_rx_clk_refcount);
+	switch(device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount++;
+		if (icodec_rx_clk_refcount == 1) {
+			clk_set_rate(icodec_rx_clk, 12288000);
+			clk_enable(icodec_rx_clk);
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_enable();
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_rx_device_group = device_group;
+}
+
+static void _audio_tx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_tx_device_id);
+	uint32_t icodec_tx_clk_rate;
+
+	pr_debug("[%s:%s] tx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_tx_clk_refcount);
+	switch (device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount++;
+		if (icodec_tx_clk_refcount == 1) {
+			if (tx_clk_freq > 16000)
+				icodec_tx_clk_rate = 48000;
+			else if (tx_clk_freq > 8000)
+				icodec_tx_clk_rate = 16000;
+			else
+				icodec_tx_clk_rate = 8000;
+
+			clk_set_rate(icodec_tx_clk, icodec_tx_clk_rate * 256);
+			clk_enable(icodec_tx_clk);
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_enable();
+		break;
+	case Q6_SDAC_TX:
+		/* TODO: In QCT BSP, clk rate was set to 20480000 */
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_tx_device_group = device_group;
+}
+
+static void _audio_rx_clk_disable(void)
+{
+	pr_debug("[%s:%s] rx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_rx_clk_refcount);
+	switch (audio_rx_device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount--;
+		if (icodec_rx_clk_refcount == 0) {
+			clk_disable(icodec_rx_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_disable(1, ADSP_PATH_RX);
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("[%s:%s] invalid rx device group %d\n", __MM_FILE__,
+				__func__, audio_rx_device_group);
+		break;
+	}
+}
+
+static void _audio_tx_clk_disable(void)
+{
+	pr_debug("[%s:%s] tx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_tx_clk_refcount);
+	switch (audio_tx_device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount--;
+		if (icodec_tx_clk_refcount == 0) {
+			clk_disable(icodec_tx_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_disable(1, ADSP_PATH_TX);
+		break;
+	case Q6_SDAC_TX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("[%s:%s] invalid tx device group %d\n",
+			__MM_FILE__, __func__, audio_tx_device_group);
+		break;
+	}
+}
+
+static void _audio_rx_clk_reinit(uint32_t rx_device, uint32_t acdb_id)
+{
+	uint32_t device_group = q6_device_to_codec(rx_device);
+
+	pr_debug("[%s:%s] rx_device = 0x%x\n", __MM_FILE__, __func__,
+		rx_device);
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_disable();
+
+	audio_rx_device_id = rx_device;
+	audio_rx_path_id = q6_device_to_path(rx_device, acdb_id);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_enable();
+
+}
+
+static void _audio_tx_clk_reinit(uint32_t tx_device, uint32_t acdb_id)
+{
+	uint32_t device_group = q6_device_to_codec(tx_device);
+
+	pr_debug("[%s:%s] tx_device = 0x%x\n", __MM_FILE__, __func__,
+		tx_device);
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_disable();
+
+	audio_tx_device_id = tx_device;
+	audio_tx_path_id = q6_device_to_path(tx_device, acdb_id);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_enable();
+}
+
+static DEFINE_MUTEX(audio_path_lock);
+static int audio_rx_path_refcount;
+static int audio_tx_path_refcount;
+
+static int audio_rx_path_enable(int en, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_rx_path_refcount--;
+		if (audio_rx_path_refcount == 0) {
+			_audio_rx_path_disable();
+			_audio_rx_clk_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_tx_path_enable(int en, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_tx_path_refcount--;
+		if (audio_tx_path_refcount == 0) {
+			_audio_tx_path_disable();
+			_audio_tx_clk_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst)
+{
+	int res;
+
+	pr_debug("[%s:%s] id_src = 0x%x\n, id_dst = 0x%x\n", __MM_FILE__,
+		__func__, id_src, id_dst);
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (q6_device_to_dir(id_dst) == Q6_RX)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, id_dst);
+	else
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, id_dst);
+	res = audio_update_acdb(id_dst, id_src);
+	if (res)
+		goto done;
+
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+done:
+	mutex_unlock(&audio_path_lock);
+	return res;
+}
+
+int q6audio_set_tx_mute(int mute)
+{
+	uint32_t adev;
+	int rc;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (mute == tx_mute_status) {
+		mutex_unlock(&audio_path_lock);
+		return 0;
+	}
+
+	adev = audio_tx_device_id;
+	rc = audio_tx_mute(ac_control, adev, mute);
+
+	/* DSP caches the requested MUTE state when it cannot apply the state
+	  immediately. In that case, it returns EUNSUPPORTED and applies the
+	  cached state later */
+	if ((rc == ADSP_AUDIO_STATUS_SUCCESS) ||
+			(rc == ADSP_AUDIO_STATUS_EUNSUPPORTED)) {
+		pr_debug("[%s:%s] return status = %d\n",
+			__MM_FILE__, __func__, rc);
+		tx_mute_status = mute;
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_stream_volume(struct audio_client *ac, int vol)
+{
+	if (vol > 1200 || vol < -4000) {
+		pr_err("[%s:%s] unsupported volume level %d\n", __MM_FILE__,
+				__func__, vol);
+		return -EINVAL;
+	}
+	mutex_lock(&audio_path_lock);
+	audio_stream_mute(ac, 0);
+	audio_stream_volume(ac, vol);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_rx_volume(int level)
+{
+	uint32_t adev;
+	int vol;
+
+	pr_debug("[%s:%s] level = %d\n", __MM_FILE__, __func__, level);
+	if (q6audio_init())
+		return 0;
+
+	if (level < 0 || level > 100)
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	adev = ADSP_AUDIO_DEVICE_ID_VOICE;
+
+	if (level) {
+		vol = q6_device_volume(audio_rx_device_id, level);
+		audio_rx_mute(ac_control, adev, 0);
+		audio_rx_volume(ac_control, adev, vol);
+	} else
+		audio_rx_mute(ac_control, adev, 1);
+
+	rx_vol_level = level;
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static void do_rx_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] device_id = 0x%x, acdb_id = 0x%x\n", __MM_FILE__,
+		__func__, device_id, acdb_id);
+	if (device_id == audio_rx_device_id &&
+		audio_rx_path_id == q6_device_to_path(device_id, acdb_id)) {
+		if (acdb_id != rx_acdb) {
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id);
+			audio_update_acdb(device_id, acdb_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+		return;
+	}
+
+	if (audio_rx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id);
+		_audio_rx_path_disable();
+		_audio_rx_clk_reinit(device_id, acdb_id);
+		_audio_rx_path_enable(1, acdb_id);
+	} else {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE,
+					 device_id);
+		audio_update_acdb(device_id, acdb_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_rx_device_id = device_id;
+		audio_rx_path_id = q6_device_to_path(device_id, acdb_id);
+	}
+}
+
+static void do_tx_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] device_id = 0x%x, acdb_id = 0x%x\n", __MM_FILE__,
+		__func__, device_id, acdb_id);
+	if (device_id == audio_tx_device_id &&
+		audio_tx_path_id == q6_device_to_path(device_id, acdb_id)) {
+		if (acdb_id != tx_acdb) {
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+						 device_id);
+			audio_update_acdb(device_id, acdb_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+		return;
+	}
+
+	if (audio_tx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, device_id);
+		_audio_tx_path_disable();
+		_audio_tx_clk_reinit(device_id, acdb_id);
+		_audio_tx_path_enable(1, acdb_id);
+	} else {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+					 device_id);
+		audio_update_acdb(device_id, acdb_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_tx_device_id = device_id;
+		audio_tx_path_id = q6_device_to_path(device_id, acdb_id);
+		tx_acdb = acdb_id;
+	}
+}
+
+int q6audio_do_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	switch(q6_device_to_dir(device_id)) {
+	case Q6_RX:
+		do_rx_routing(device_id, acdb_id);
+		break;
+	case Q6_TX:
+		do_tx_routing(device_id, acdb_id);
+		break;
+	}
+
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_route(const char *name)
+{
+	uint32_t route;
+	if (!strcmp(name, "speaker")) {
+		route = ADIE_PATH_SPEAKER_STEREO_RX;
+	} else if (!strcmp(name, "headphones")) {
+		route = ADIE_PATH_HEADSET_STEREO_RX;
+	} else if (!strcmp(name, "handset")) {
+		route = ADIE_PATH_HANDSET_RX;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(&audio_path_lock);
+	if (route == audio_rx_path_id)
+		goto done;
+
+	audio_rx_path_id = route;
+
+	if (audio_rx_path_refcount > 0) {
+		_audio_rx_path_disable();
+		_audio_rx_path_enable(1, 0);
+	}
+	if (audio_tx_path_refcount > 0) {
+		_audio_tx_path_disable();
+		_audio_tx_path_enable(1, 0);
+	}
+done:
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_stream_equalizer(struct audio_client *ac, void *eq_config)
+{
+	int i;
+	struct adsp_set_equalizer_command rpc;
+	struct adsp_audio_eq_stream_config *eq_cfg;
+	eq_cfg = (struct adsp_audio_eq_stream_config *) eq_config;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG;
+	rpc.enable = eq_cfg->enable;
+	rpc.num_bands = eq_cfg->num_bands;
+	for (i = 0; i < eq_cfg->num_bands; i++) {
+		rpc.eq_bands[i].band_idx = eq_cfg->eq_bands[i].band_idx;
+		rpc.eq_bands[i].filter_type = eq_cfg->eq_bands[i].filter_type;
+		rpc.eq_bands[i].center_freq_hz =
+					eq_cfg->eq_bands[i].center_freq_hz;
+		rpc.eq_bands[i].filter_gain = eq_cfg->eq_bands[i].filter_gain;
+		rpc.eq_bands[i].q_factor = eq_cfg->eq_bands[i].q_factor;
+	}
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_set_stream_eq_pcm(struct audio_client *ac, void *eq_config)
+{
+	int rc = 0;
+	mutex_lock(&audio_path_lock);
+	rc = audio_stream_equalizer(ac, eq_config);
+	mutex_unlock(&audio_path_lock);
+	return rc;
+}
+
+struct audio_client *q6audio_open_auxpcm(uint32_t rate,
+				      uint32_t channels, uint32_t flags, uint32_t acdb_id)
+{
+	int rc, retry = 5;
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] rate = %d, channels = %d\n", __MM_FILE__, __func__,
+		rate, channels);
+	if (q6audio_init())
+		return NULL;
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return NULL;
+
+	ac->flags = flags;
+
+	mutex_lock(&audio_path_lock);
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			tx_clk_freq = rate;
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable(0, acdb_id);
+		}
+	}
+
+	ecodec_clk_enable();
+
+	for (retry = 5;; retry--) {
+		if (ac->flags & AUDIO_FLAG_WRITE)
+			rc = audio_auxpcm_out_open(ac, rate, channels);
+		else
+			rc = audio_auxpcm_in_open(ac, rate, channels);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] open pcm error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+		msleep(1);
+	}
+
+	mutex_unlock(&audio_path_lock);
+
+	for (retry = 5;; retry--) {
+		rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] stream start error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+	}
+	audio_prevent_sleep();
+	return ac;
+
+}
+
+struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate,
+		      uint32_t channels, uint32_t flags, uint32_t acdb_id)
+{
+	int rc, retry = 5;
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, rate = %d, channels = %d\n", __MM_FILE__,
+		__func__, bufsz, rate, channels);
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	mutex_lock(&audio_path_lock);
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			q6_rx_path_enable(0, acdb_id);
+			adie_rx_path_enable(acdb_id);
+		}
+	} else {
+		/* TODO: consider concurrency with voice call */
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			tx_clk_freq = rate;
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	}
+
+	for (retry = 5;;retry--) {
+		if (ac->flags & AUDIO_FLAG_WRITE)
+			rc = audio_out_open(ac, bufsz, rate, channels);
+		else
+			rc = audio_in_open(ac, bufsz, flags, rate, channels);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] open pcm error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+		msleep(1);
+	}
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		if (audio_rx_path_refcount == 1)
+			audio_rx_analog_enable(1);
+	}
+	mutex_unlock(&audio_path_lock);
+
+	for (retry = 5;;retry--) {
+		rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] stream start error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+	}
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+
+	audio_prevent_sleep();
+	return ac;
+}
+
+int q6audio_close(struct audio_client *ac)
+{
+	audio_close(ac);
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0, 0);
+	else
+		audio_tx_path_enable(0, 0);
+	audio_client_free(ac);
+	audio_allow_sleep();
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return 0;
+}
+
+int q6audio_auxpcm_close(struct audio_client *ac)
+{
+	audio_close(ac);
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_tx_path_enable(0, 0);
+		ecodec_clk_disable(0, ADSP_PATH_RX);
+	} else {
+		audio_rx_path_enable(0, 0);
+		ecodec_clk_disable(0, ADSP_PATH_TX);
+	}
+
+	audio_client_free(ac);
+	audio_allow_sleep();
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return 0;
+}
+struct audio_client *q6voice_open(uint32_t flags)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] flags = %d\n", __MM_FILE__, __func__, flags);
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, rx_acdb);
+	else {
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 8000;
+		audio_tx_path_enable(1, tx_acdb);
+	}
+
+	return ac;
+}
+
+int q6voice_close(struct audio_client *ac)
+{
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0, 0);
+	else
+		audio_tx_path_enable(0, 0);
+
+	tx_mute_status = 0;
+	audio_client_free(ac);
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, rate = %d\n, channels = %d",
+		__MM_FILE__, __func__, bufsz, rate, channels);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = AUDIO_FLAG_WRITE;
+	audio_rx_path_enable(1, acdb_id);
+
+	audio_mp3_open(ac, bufsz, rate, channels);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	mutex_lock(&audio_path_lock);
+	audio_rx_mute(ac_control, audio_rx_device_id, 0);
+	audio_rx_volume(ac_control, audio_rx_device_id,
+			q6_device_volume(audio_rx_device_id, rx_vol_level));
+	mutex_unlock(&audio_path_lock);
+	return ac;
+}
+
+struct audio_client *q6audio_open_dtmf(uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] rate = %d\n, channels = %d", __MM_FILE__, __func__,
+		 rate, channels);
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	ac->flags = AUDIO_FLAG_WRITE;
+	audio_rx_path_enable(1, acdb_id);
+
+	audio_dtmf_open(ac, rate, channels);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	mutex_lock(&audio_path_lock);
+	audio_rx_mute(ac_control, audio_rx_device_id, 0);
+	audio_rx_volume(ac_control, audio_rx_device_id,
+		q6_device_volume(audio_rx_device_id, rx_vol_level));
+	mutex_unlock(&audio_path_lock);
+
+	return ac;
+}
+
+int q6audio_play_dtmf(struct audio_client *ac, uint16_t dtmf_hi,
+			 uint16_t dtmf_low, uint16_t duration, uint16_t rx_gain)
+{
+	struct adsp_audio_dtmf_start_command dtmf_cmd;
+
+	pr_debug("[%s:%s] high = %d, low = %d\n", __MM_FILE__, __func__,
+		dtmf_hi, dtmf_low);
+
+	dtmf_cmd.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START;
+	dtmf_cmd.hdr.response_type = ADSP_AUDIO_RESPONSE_COMMAND;
+	dtmf_cmd.tone1_hz = dtmf_hi;
+	dtmf_cmd.tone2_hz = dtmf_low;
+	dtmf_cmd.duration_usec = duration * 1000;
+	dtmf_cmd.gain_mb = rx_gain;
+
+	return audio_ioctl(ac, &dtmf_cmd,
+		 sizeof(struct adsp_audio_dtmf_start_command));
+
+}
+
+int q6audio_mp3_close(struct audio_client *ac)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	audio_close(ac);
+	audio_rx_path_enable(0, 0);
+	audio_client_free(ac);
+	return 0;
+}
+
+
+struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t samplerate,
+					uint32_t channels, uint32_t bitrate,
+					uint32_t stream_format, uint32_t flags,
+					uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, samplerate = %d, channels = %d\n",
+		__MM_FILE__, __func__, bufsz, samplerate, channels);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else{
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 48000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	audio_aac_open(ac, bufsz, samplerate, channels, bitrate, flags,
+							stream_format);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+	audio_prevent_sleep();
+	return ac;
+}
+
+
+struct audio_client *q6audio_open_qcp(uint32_t bufsz, uint32_t min_rate,
+					uint32_t max_rate, uint32_t flags,
+					uint32_t format, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d\n", __MM_FILE__, __func__, bufsz);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else{
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 8000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	audio_qcp_open(ac, bufsz, min_rate, max_rate, flags, format);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+	audio_prevent_sleep();
+	return ac;
+}
+
+struct audio_client *q6audio_open_amrnb(uint32_t bufsz, uint32_t enc_mode,
+					uint32_t dtx_mode_enable,
+					uint32_t flags, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, dtx_mode = %d\n", __MM_FILE__,
+			__func__, bufsz, dtx_mode_enable);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else{
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 8000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	audio_amrnb_open(ac, bufsz, enc_mode, flags, dtx_mode_enable);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+	audio_prevent_sleep();
+	return ac;
+}
+
+int q6audio_async(struct audio_client *ac)
+{
+	struct adsp_command_hdr rpc;
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = ADSP_AUDIO_IOCTL_CMD_STREAM_EOS;
+	rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
diff --git a/arch/arm/mach-msm/qdsp6/q6audio_devices.h b/arch/arm/mach-msm/qdsp6/q6audio_devices.h
new file mode 100644
index 0000000..d316ab0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/q6audio_devices.h
@@ -0,0 +1,334 @@
+/* arch/arm/mach-msm/qdsp6/q6audio_devices.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * 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.
+ *
+ */
+
+struct q6_device_info {
+	uint32_t id;
+	uint32_t cad_id;
+	uint32_t path;
+	uint32_t rate;
+	uint8_t dir;
+	uint8_t codec;
+	uint8_t hw;
+};
+
+#define Q6_ICODEC_RX		0
+#define Q6_ICODEC_TX		1
+#define Q6_ECODEC_RX		2
+#define Q6_ECODEC_TX		3
+#define Q6_SDAC_RX		6
+#define Q6_SDAC_TX		7
+#define Q6_CODEC_NONE		255
+
+#define Q6_TX		1
+#define Q6_RX		2
+#define Q6_TX_RX	3
+
+#define Q6_HW_HANDSET	0
+#define Q6_HW_HEADSET	1
+#define Q6_HW_SPEAKER	2
+#define Q6_HW_TTY	3
+#define Q6_HW_BT_SCO	4
+#define Q6_HW_BT_A2DP	5
+
+#define Q6_HW_COUNT	6
+
+#define CAD_HW_DEVICE_ID_HANDSET_MIC		0x01
+#define CAD_HW_DEVICE_ID_HANDSET_SPKR		0x02
+#define CAD_HW_DEVICE_ID_HEADSET_MIC		0x03
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO	0x04
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO	0x05
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MIC		0x06
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MONO	0x07
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO	0x08
+#define CAD_HW_DEVICE_ID_BT_SCO_MIC		0x09
+#define CAD_HW_DEVICE_ID_BT_SCO_SPKR		0x0A
+#define CAD_HW_DEVICE_ID_BT_A2DP_SPKR		0x0B
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_MIC	0x0C
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR	0x0D
+
+#define CAD_HW_DEVICE_ID_DEFAULT_TX		0x0E
+#define CAD_HW_DEVICE_ID_DEFAULT_RX		0x0F
+
+
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_BROADSIDE      0x2B
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_ENDFIRE        0x2D
+#define CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_BROADSIDE         0x2C
+#define CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_ENDFIRE           0x2E
+
+/* Logical Device to indicate A2DP routing */
+#define CAD_HW_DEVICE_ID_BT_A2DP_TX             0x10
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX	0x12
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX	0x13
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+
+#define CAD_HW_DEVICE_ID_VOICE			0x15
+
+#define CAD_HW_DEVICE_ID_I2S_RX                 0x20
+#define CAD_HW_DEVICE_ID_I2S_TX                 0x21
+
+/* AUXPGA */
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO_LB 0x22
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO_LB   0x23
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_STEREO_LB 0x24
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_MONO_LB   0x25
+
+#define CAD_HW_DEVICE_ID_NULL_RX		0x2A
+
+#define CAD_HW_DEVICE_ID_MAX_NUM                0x2F
+
+#define CAD_HW_DEVICE_ID_INVALID                0xFF
+
+#define CAD_RX_DEVICE  0x00
+#define CAD_TX_DEVICE  0x01
+
+static struct q6_device_info q6_audio_devices[] = {
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_SPKR,
+		.path	= ADIE_PATH_HANDSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO,
+		.path	= ADIE_PATH_HEADSET_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.path	= ADIE_PATH_HEADSET_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MONO,
+		.path	= ADIE_PATH_SPEAKER_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO,
+		.path	= ADIE_PATH_SPEAKER_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR,
+		.path	= ADIE_PATH_TTY_HEADSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_TTY,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_MIC,
+		.path	= ADIE_PATH_HANDSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MIC,
+		.path	= ADIE_PATH_HEADSET_MONO_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MIC,
+		.path	= ADIE_PATH_SPEAKER_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_ENDFIRE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_EF_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_BROADSIDE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_BS_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_ENDFIRE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_EF_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_BROADSIDE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_BS_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_MIC,
+		.path	= ADIE_PATH_TTY_HEADSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_A2DP_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_A2DP,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_RX,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_SDAC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_TX,
+		.path	= 0, /* XXX */
+		.rate   = 16000,
+		.dir	= Q6_TX,
+		.codec	= Q6_SDAC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_AUXPCM_RX,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_AUXPCM_TX,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= 0,
+		.cad_id	= 0,
+		.path	= 0,
+		.rate   = 8000,
+		.dir	= 0,
+		.codec	= Q6_CODEC_NONE,
+		.hw	= 0,
+	},
+};
+
diff --git a/arch/arm/mach-msm/qdsp6/qcelp_in.c b/arch/arm/mach-msm/qdsp6/qcelp_in.c
new file mode 100644
index 0000000..ca0ab1a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/qcelp_in.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, 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/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audio.h>
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+#define QCELP_FC_BUFF_CNT 10
+#define QCELP_READ_TIMEOUT 2000
+struct qcelp_fc_buff {
+	struct mutex lock;
+	int empty;
+	void *data;
+	int size;
+	int actual_size;
+};
+
+struct qcelp_fc {
+	struct task_struct *task;
+	wait_queue_head_t fc_wq;
+	struct qcelp_fc_buff fc_buff[QCELP_FC_BUFF_CNT];
+	int buff_index;
+};
+
+struct qcelp {
+	struct mutex lock;
+	struct msm_audio_qcelp_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+	struct qcelp_fc *qcelp_fc;
+};
+
+
+static int q6_qcelp_flowcontrol(void *data)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	struct qcelp *qcelp = data;
+	int buff_index = 0;
+	int xfer = 0;
+	struct qcelp_fc *fc;
+
+
+	ac = qcelp->audio_client;
+	fc = qcelp->qcelp_fc;
+	if (!ac) {
+		pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__);
+		return 0;
+	}
+
+	while (!kthread_should_stop()) {
+		ab = ac->buf + ac->cpu_buf;
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+
+		mutex_lock(&(fc->fc_buff[buff_index].lock));
+		if (!fc->fc_buff[buff_index].empty) {
+			pr_err("[%s:%s] flow control buffer[%d] not read!\n",
+					__MM_FILE__, __func__, buff_index);
+		}
+
+		if (fc->fc_buff[buff_index].size < xfer) {
+			pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__,
+					__func__, buff_index);
+			memcpy(fc->fc_buff[buff_index].data, ab->data,
+					fc->fc_buff[buff_index].size);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size =
+					fc->fc_buff[buff_index].size;
+		} else {
+			memcpy(fc->fc_buff[buff_index].data, ab->data, xfer);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size = xfer;
+		}
+		mutex_unlock(&(fc->fc_buff[buff_index].lock));
+		/*wake up client, if any*/
+		wake_up(&fc->fc_wq);
+
+		buff_index++;
+		if (buff_index >= QCELP_FC_BUFF_CNT)
+			buff_index = 0;
+
+		ab->used = 1;
+
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return 0;
+}
+static long q6_qcelp_in_ioctl(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct qcelp *qcelp = file->private_data;
+	int rc = 0;
+	int i = 0;
+	struct qcelp_fc *fc;
+	int size = 0;
+
+	mutex_lock(&qcelp->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats,
+					sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id,
+				(void *) arg, sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (qcelp->audio_client) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+			break;
+		} else {
+			qcelp->audio_client = q6audio_open_qcp(
+				qcelp->str_cfg.buffer_size,
+				qcelp->cfg.min_bit_rate,
+				qcelp->cfg.max_bit_rate,
+				qcelp->voicerec_mode.rec_mode,
+				ADSP_AUDIO_FORMAT_V13K_FS,
+				acdb_id);
+
+			if (!qcelp->audio_client) {
+				pr_err("[%s:%s] qcelp open session failed\n",
+					__MM_FILE__, __func__);
+				kfree(qcelp);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		/*allocate flow control buffers*/
+		fc = qcelp->qcelp_fc;
+		size = qcelp->str_cfg.buffer_size;
+		for (i = 0; i < QCELP_FC_BUFF_CNT; ++i) {
+			mutex_init(&(fc->fc_buff[i].lock));
+			fc->fc_buff[i].empty = 1;
+			fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL);
+			if (fc->fc_buff[i].data == NULL) {
+				pr_err("[%s:%s] No memory for FC buffers\n",
+						__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				goto fc_fail;
+			}
+			fc->fc_buff[i].size = size;
+			fc->fc_buff[i].actual_size = 0;
+		}
+
+		/*create flow control thread*/
+		fc->task = kthread_run(q6_qcelp_flowcontrol,
+				qcelp, "qcelp_flowcontrol");
+		if (IS_ERR(fc->task)) {
+			rc = PTR_ERR(fc->task);
+			pr_err("[%s:%s] error creating flow control thread\n",
+					__MM_FILE__, __func__);
+			goto fc_fail;
+		}
+		break;
+fc_fail:
+		/*free flow control buffers*/
+		--i;
+		for (; i >=  0; i--) {
+			kfree(fc->fc_buff[i].data);
+			fc->fc_buff[i].data = NULL;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&qcelp->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (qcelp->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+			&& qcelp->voicerec_mode.rec_mode !=
+			AUDIO_FLAG_INCALL_MIXED) {
+			qcelp->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &qcelp->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, qcelp->str_cfg.buffer_size,
+			qcelp->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&qcelp->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, qcelp->str_cfg.buffer_size,
+			qcelp->str_cfg.buffer_count);
+
+		if (qcelp->str_cfg.buffer_size < 35) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (qcelp->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_QCELP_ENC_CONFIG:
+		if (copy_from_user(&qcelp->cfg, (void *) arg,
+				sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] SET_QCELP_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+
+		if (qcelp->cfg.min_bit_rate > 4 ||
+			 qcelp->cfg.min_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (qcelp->cfg.max_bit_rate > 4 ||
+			 qcelp->cfg.max_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+
+		break;
+	case AUDIO_GET_QCELP_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &qcelp->cfg,
+			 sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_QCELP_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&qcelp->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_qcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct qcelp *qcelp;
+	struct qcelp_fc *fc;
+	int i;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	qcelp = kmalloc(sizeof(struct qcelp), GFP_KERNEL);
+	if (qcelp == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for qcelp driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&qcelp->lock);
+	file->private_data = qcelp;
+	qcelp->audio_client = NULL;
+	qcelp->str_cfg.buffer_size = 35;
+	qcelp->str_cfg.buffer_count = 2;
+	qcelp->cfg.cdma_rate = CDMA_RATE_FULL;
+	qcelp->cfg.min_bit_rate = 1;
+	qcelp->cfg.max_bit_rate = 4;
+	qcelp->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	qcelp->qcelp_fc = kmalloc(sizeof(struct qcelp_fc), GFP_KERNEL);
+	if (qcelp->qcelp_fc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for qcelp_fc\n",
+				__MM_FILE__, __func__);
+		kfree(qcelp);
+		return -ENOMEM;
+	}
+	fc = qcelp->qcelp_fc;
+	fc->task = NULL;
+	fc->buff_index = 0;
+	for (i = 0; i < QCELP_FC_BUFF_CNT; ++i) {
+		fc->fc_buff[i].data = NULL;
+		fc->fc_buff[i].size = 0;
+		fc->fc_buff[i].actual_size = 0;
+	}
+	/*initialize wait queue head*/
+	init_waitqueue_head(&fc->fc_wq);
+	return 0;
+}
+
+static ssize_t q6_qcelp_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	const char __user *start = buf;
+	struct qcelp *qcelp = file->private_data;
+	struct qcelp_fc *fc;
+	int xfer = 0;
+	int res = 0;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&qcelp->lock);
+	ac = qcelp->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	fc = qcelp->qcelp_fc;
+	while (count > xfer) {
+		/*wait for buffer to full*/
+		if (fc->fc_buff[fc->buff_index].empty != 0) {
+			res = wait_event_interruptible_timeout(fc->fc_wq,
+				(fc->fc_buff[fc->buff_index].empty == 0),
+				msecs_to_jiffies(QCELP_READ_TIMEOUT));
+
+			pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__,
+				__func__, fc->buff_index);
+			if (res == 0) {
+				pr_err("[%s:%s] Timeout!\n", __MM_FILE__,
+						__func__);
+				res = -ETIMEDOUT;
+				goto fail;
+			} else if (res < 0) {
+				pr_err("[%s:%s] Returning on Interrupt\n",
+					__MM_FILE__, __func__);
+				goto fail;
+			}
+		}
+		/*lock the buffer*/
+		mutex_lock(&(fc->fc_buff[fc->buff_index].lock));
+		xfer = fc->fc_buff[fc->buff_index].actual_size;
+
+		if (xfer > count) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] read failed! byte count too small\n",
+					__MM_FILE__, __func__);
+			res = -EINVAL;
+			goto fail;
+		}
+
+		if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data,	xfer)) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] copy_to_user failed at index %d\n",
+					__MM_FILE__, __func__, fc->buff_index);
+			res = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		count -= xfer;
+
+		fc->fc_buff[fc->buff_index].empty = 1;
+		fc->fc_buff[fc->buff_index].actual_size = 0;
+
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		++(fc->buff_index);
+		if (fc->buff_index >= QCELP_FC_BUFF_CNT)
+			fc->buff_index = 0;
+	}
+	res = buf - start;
+
+fail:
+	mutex_unlock(&qcelp->lock);
+
+	return res;
+}
+
+static int q6_qcelp_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct qcelp *qcelp = file->private_data;
+	int i = 0;
+	struct qcelp_fc *fc;
+
+	mutex_lock(&qcelp->lock);
+	fc = qcelp->qcelp_fc;
+	kthread_stop(fc->task);
+	fc->task = NULL;
+
+	/*free flow control buffers*/
+	for (i = 0; i < QCELP_FC_BUFF_CNT; ++i) {
+		kfree(fc->fc_buff[i].data);
+		fc->fc_buff[i].data = NULL;
+	}
+	kfree(fc);
+
+	if (qcelp->audio_client)
+		rc = q6audio_close(qcelp->audio_client);
+	mutex_unlock(&qcelp->lock);
+	kfree(qcelp);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_qcelp_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_qcelp_in_open,
+	.read		= q6_qcelp_in_read,
+	.release	= q6_qcelp_in_release,
+	.unlocked_ioctl	= q6_qcelp_in_ioctl,
+};
+
+struct miscdevice q6_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &q6_qcelp_in_fops,
+};
+
+static int __init q6_qcelp_in_init(void)
+{
+	return misc_register(&q6_qcelp_in_misc);
+}
+
+device_initcall(q6_qcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/routing.c b/arch/arm/mach-msm/qdsp6/routing.c
new file mode 100644
index 0000000..f6533a4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/routing.c
@@ -0,0 +1,78 @@
+/* arch/arm/mach-msm/qdsp6/routing.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * 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/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <mach/debug_mm.h>
+
+extern int q6audio_set_route(const char *name);
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static ssize_t q6_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	pr_debug("[%s:%s] count = %d", __MM_FILE__, __func__, count);
+	if (count >= sizeof(cmd)) {
+		pr_err("[%s:%s] invalid count %d\n", __MM_FILE__,
+			__func__, count);
+			return -EINVAL;
+	}
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	q6audio_set_route(cmd);
+
+	return count;
+}
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations q6_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.write		= q6_write,
+	.release	= q6_release,
+};
+
+static struct miscdevice q6_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_route",
+	.fops	= &q6_fops,
+};
+
+
+static int __init q6_init(void) {
+	return misc_register(&q6_misc);
+}
+
+device_initcall(q6_init);