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/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);